aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/libfuturize
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/libfuturize
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/libfuturize')
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/__init__.py1
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py518
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/__init__.py97
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_UserDict.py102
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_absolute_import.py91
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_add__future__imports_except_unicode_literals.py26
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_basestring.py17
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_bytes.py24
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_cmp.py33
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division.py12
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division_safe.py109
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_execfile.py37
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_builtins.py59
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library.py24
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library_urllib.py28
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_input.py32
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_metaclass.py262
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_next_call.py104
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_object.py17
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_oldstr_wrap.py39
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_order___future__imports.py36
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print.py104
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print_with_import.py22
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_raise.py107
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_remove_old__future__imports.py26
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_keep_u.py24
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_literals_import.py18
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_xrange_with_import.py20
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/main.py322
29 files changed, 2311 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/__init__.py b/.venv/lib/python3.12/site-packages/libfuturize/__init__.py
new file mode 100644
index 00000000..4cb1cbcd
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/__init__.py
@@ -0,0 +1 @@
+# empty to make this a package
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py b/.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py
new file mode 100644
index 00000000..b5c123f6
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py
@@ -0,0 +1,518 @@
+"""
+Utility functions from 2to3, 3to2 and python-modernize (and some home-grown
+ones).
+
+Licences:
+2to3: PSF License v2
+3to2: Apache Software License (from 3to2/setup.py)
+python-modernize licence: BSD (from python-modernize/LICENSE)
+"""
+
+from lib2to3.fixer_util import (FromImport, Newline, is_import,
+ find_root, does_tree_import,
+ Call, Name, Comma)
+from lib2to3.pytree import Leaf, Node
+from lib2to3.pygram import python_symbols as syms
+from lib2to3.pygram import token
+import re
+
+
+def canonical_fix_name(fix, avail_fixes):
+ """
+ Examples:
+ >>> canonical_fix_name('fix_wrap_text_literals')
+ 'libfuturize.fixes.fix_wrap_text_literals'
+ >>> canonical_fix_name('wrap_text_literals')
+ 'libfuturize.fixes.fix_wrap_text_literals'
+ >>> canonical_fix_name('wrap_te')
+ ValueError("unknown fixer name")
+ >>> canonical_fix_name('wrap')
+ ValueError("ambiguous fixer name")
+ """
+ if ".fix_" in fix:
+ return fix
+ else:
+ if fix.startswith('fix_'):
+ fix = fix[4:]
+ # Infer the full module name for the fixer.
+ # First ensure that no names clash (e.g.
+ # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah):
+ found = [f for f in avail_fixes
+ if f.endswith('fix_{0}'.format(fix))]
+ if len(found) > 1:
+ raise ValueError("Ambiguous fixer name. Choose a fully qualified "
+ "module name instead from these:\n" +
+ "\n".join(" " + myf for myf in found))
+ elif len(found) == 0:
+ raise ValueError("Unknown fixer. Use --list-fixes or -l for a list.")
+ return found[0]
+
+
+
+## These functions are from 3to2 by Joe Amenta:
+
+def Star(prefix=None):
+ return Leaf(token.STAR, u'*', prefix=prefix)
+
+def DoubleStar(prefix=None):
+ return Leaf(token.DOUBLESTAR, u'**', prefix=prefix)
+
+def Minus(prefix=None):
+ return Leaf(token.MINUS, u'-', prefix=prefix)
+
+def commatize(leafs):
+ """
+ Accepts/turns: (Name, Name, ..., Name, Name)
+ Returns/into: (Name, Comma, Name, Comma, ..., Name, Comma, Name)
+ """
+ new_leafs = []
+ for leaf in leafs:
+ new_leafs.append(leaf)
+ new_leafs.append(Comma())
+ del new_leafs[-1]
+ return new_leafs
+
+def indentation(node):
+ """
+ Returns the indentation for this node
+ Iff a node is in a suite, then it has indentation.
+ """
+ while node.parent is not None and node.parent.type != syms.suite:
+ node = node.parent
+ if node.parent is None:
+ return u""
+ # The first three children of a suite are NEWLINE, INDENT, (some other node)
+ # INDENT.value contains the indentation for this suite
+ # anything after (some other node) has the indentation as its prefix.
+ if node.type == token.INDENT:
+ return node.value
+ elif node.prev_sibling is not None and node.prev_sibling.type == token.INDENT:
+ return node.prev_sibling.value
+ elif node.prev_sibling is None:
+ return u""
+ else:
+ return node.prefix
+
+def indentation_step(node):
+ """
+ Dirty little trick to get the difference between each indentation level
+ Implemented by finding the shortest indentation string
+ (technically, the "least" of all of the indentation strings, but
+ tabs and spaces mixed won't get this far, so those are synonymous.)
+ """
+ r = find_root(node)
+ # Collect all indentations into one set.
+ all_indents = set(i.value for i in r.pre_order() if i.type == token.INDENT)
+ if not all_indents:
+ # nothing is indented anywhere, so we get to pick what we want
+ return u" " # four spaces is a popular convention
+ else:
+ return min(all_indents)
+
+def suitify(parent):
+ """
+ Turn the stuff after the first colon in parent's children
+ into a suite, if it wasn't already
+ """
+ for node in parent.children:
+ if node.type == syms.suite:
+ # already in the preferred format, do nothing
+ return
+
+ # One-liners have no suite node, we have to fake one up
+ for i, node in enumerate(parent.children):
+ if node.type == token.COLON:
+ break
+ else:
+ raise ValueError(u"No class suite and no ':'!")
+ # Move everything into a suite node
+ suite = Node(syms.suite, [Newline(), Leaf(token.INDENT, indentation(node) + indentation_step(node))])
+ one_node = parent.children[i+1]
+ one_node.remove()
+ one_node.prefix = u''
+ suite.append_child(one_node)
+ parent.append_child(suite)
+
+def NameImport(package, as_name=None, prefix=None):
+ """
+ Accepts a package (Name node), name to import it as (string), and
+ optional prefix and returns a node:
+ import <package> [as <as_name>]
+ """
+ if prefix is None:
+ prefix = u""
+ children = [Name(u"import", prefix=prefix), package]
+ if as_name is not None:
+ children.extend([Name(u"as", prefix=u" "),
+ Name(as_name, prefix=u" ")])
+ return Node(syms.import_name, children)
+
+_compound_stmts = (syms.if_stmt, syms.while_stmt, syms.for_stmt, syms.try_stmt, syms.with_stmt)
+_import_stmts = (syms.import_name, syms.import_from)
+
+def import_binding_scope(node):
+ """
+ Generator yields all nodes for which a node (an import_stmt) has scope
+ The purpose of this is for a call to _find() on each of them
+ """
+ # import_name / import_from are small_stmts
+ assert node.type in _import_stmts
+ test = node.next_sibling
+ # A small_stmt can only be followed by a SEMI or a NEWLINE.
+ while test.type == token.SEMI:
+ nxt = test.next_sibling
+ # A SEMI can only be followed by a small_stmt or a NEWLINE
+ if nxt.type == token.NEWLINE:
+ break
+ else:
+ yield nxt
+ # A small_stmt can only be followed by either a SEMI or a NEWLINE
+ test = nxt.next_sibling
+ # Covered all subsequent small_stmts after the import_stmt
+ # Now to cover all subsequent stmts after the parent simple_stmt
+ parent = node.parent
+ assert parent.type == syms.simple_stmt
+ test = parent.next_sibling
+ while test is not None:
+ # Yes, this will yield NEWLINE and DEDENT. Deal with it.
+ yield test
+ test = test.next_sibling
+
+ context = parent.parent
+ # Recursively yield nodes following imports inside of a if/while/for/try/with statement
+ if context.type in _compound_stmts:
+ # import is in a one-liner
+ c = context
+ while c.next_sibling is not None:
+ yield c.next_sibling
+ c = c.next_sibling
+ context = context.parent
+
+ # Can't chain one-liners on one line, so that takes care of that.
+
+ p = context.parent
+ if p is None:
+ return
+
+ # in a multi-line suite
+
+ while p.type in _compound_stmts:
+
+ if context.type == syms.suite:
+ yield context
+
+ context = context.next_sibling
+
+ if context is None:
+ context = p.parent
+ p = context.parent
+ if p is None:
+ break
+
+def ImportAsName(name, as_name, prefix=None):
+ new_name = Name(name)
+ new_as = Name(u"as", prefix=u" ")
+ new_as_name = Name(as_name, prefix=u" ")
+ new_node = Node(syms.import_as_name, [new_name, new_as, new_as_name])
+ if prefix is not None:
+ new_node.prefix = prefix
+ return new_node
+
+
+def is_docstring(node):
+ """
+ Returns True if the node appears to be a docstring
+ """
+ return (node.type == syms.simple_stmt and
+ len(node.children) > 0 and node.children[0].type == token.STRING)
+
+
+def future_import(feature, node):
+ """
+ This seems to work
+ """
+ root = find_root(node)
+
+ if does_tree_import(u"__future__", feature, node):
+ return
+
+ # Look for a shebang or encoding line
+ shebang_encoding_idx = None
+
+ for idx, node in enumerate(root.children):
+ # Is it a shebang or encoding line?
+ if is_shebang_comment(node) or is_encoding_comment(node):
+ shebang_encoding_idx = idx
+ if is_docstring(node):
+ # skip over docstring
+ continue
+ names = check_future_import(node)
+ if not names:
+ # not a future statement; need to insert before this
+ break
+ if feature in names:
+ # already imported
+ return
+
+ import_ = FromImport(u'__future__', [Leaf(token.NAME, feature, prefix=" ")])
+ if shebang_encoding_idx == 0 and idx == 0:
+ # If this __future__ import would go on the first line,
+ # detach the shebang / encoding prefix from the current first line.
+ # and attach it to our new __future__ import node.
+ import_.prefix = root.children[0].prefix
+ root.children[0].prefix = u''
+ # End the __future__ import line with a newline and add a blank line
+ # afterwards:
+ children = [import_ , Newline()]
+ root.insert_child(idx, Node(syms.simple_stmt, children))
+
+
+def future_import2(feature, node):
+ """
+ An alternative to future_import() which might not work ...
+ """
+ root = find_root(node)
+
+ if does_tree_import(u"__future__", feature, node):
+ return
+
+ insert_pos = 0
+ for idx, node in enumerate(root.children):
+ if node.type == syms.simple_stmt and node.children and \
+ node.children[0].type == token.STRING:
+ insert_pos = idx + 1
+ break
+
+ for thing_after in root.children[insert_pos:]:
+ if thing_after.type == token.NEWLINE:
+ insert_pos += 1
+ continue
+
+ prefix = thing_after.prefix
+ thing_after.prefix = u""
+ break
+ else:
+ prefix = u""
+
+ import_ = FromImport(u"__future__", [Leaf(token.NAME, feature, prefix=u" ")])
+
+ children = [import_, Newline()]
+ root.insert_child(insert_pos, Node(syms.simple_stmt, children, prefix=prefix))
+
+def parse_args(arglist, scheme):
+ u"""
+ Parse a list of arguments into a dict
+ """
+ arglist = [i for i in arglist if i.type != token.COMMA]
+
+ ret_mapping = dict([(k, None) for k in scheme])
+
+ for i, arg in enumerate(arglist):
+ if arg.type == syms.argument and arg.children[1].type == token.EQUAL:
+ # argument < NAME '=' any >
+ slot = arg.children[0].value
+ ret_mapping[slot] = arg.children[2]
+ else:
+ slot = scheme[i]
+ ret_mapping[slot] = arg
+
+ return ret_mapping
+
+
+# def is_import_from(node):
+# """Returns true if the node is a statement "from ... import ..."
+# """
+# return node.type == syms.import_from
+
+
+def is_import_stmt(node):
+ return (node.type == syms.simple_stmt and node.children and
+ is_import(node.children[0]))
+
+
+def touch_import_top(package, name_to_import, node):
+ """Works like `does_tree_import` but adds an import statement at the
+ top if it was not imported (but below any __future__ imports) and below any
+ comments such as shebang lines).
+
+ Based on lib2to3.fixer_util.touch_import()
+
+ Calling this multiple times adds the imports in reverse order.
+
+ Also adds "standard_library.install_aliases()" after "from future import
+ standard_library". This should probably be factored into another function.
+ """
+
+ root = find_root(node)
+
+ if does_tree_import(package, name_to_import, root):
+ return
+
+ # Ideally, we would look for whether futurize --all-imports has been run,
+ # as indicated by the presence of ``from builtins import (ascii, ...,
+ # zip)`` -- and, if it has, we wouldn't import the name again.
+
+ # Look for __future__ imports and insert below them
+ found = False
+ for name in ['absolute_import', 'division', 'print_function',
+ 'unicode_literals']:
+ if does_tree_import('__future__', name, root):
+ found = True
+ break
+ if found:
+ # At least one __future__ import. We want to loop until we've seen them
+ # all.
+ start, end = None, None
+ for idx, node in enumerate(root.children):
+ if check_future_import(node):
+ start = idx
+ # Start looping
+ idx2 = start
+ while node:
+ node = node.next_sibling
+ idx2 += 1
+ if not check_future_import(node):
+ end = idx2
+ break
+ break
+ assert start is not None
+ assert end is not None
+ insert_pos = end
+ else:
+ # No __future__ imports.
+ # We look for a docstring and insert the new node below that. If no docstring
+ # exists, just insert the node at the top.
+ for idx, node in enumerate(root.children):
+ if node.type != syms.simple_stmt:
+ break
+ if not is_docstring(node):
+ # This is the usual case.
+ break
+ insert_pos = idx
+
+ children_hooks = []
+ if package is None:
+ import_ = Node(syms.import_name, [
+ Leaf(token.NAME, u"import"),
+ Leaf(token.NAME, name_to_import, prefix=u" ")
+ ])
+ else:
+ import_ = FromImport(package, [Leaf(token.NAME, name_to_import, prefix=u" ")])
+ if name_to_import == u'standard_library':
+ # Add:
+ # standard_library.install_aliases()
+ # after:
+ # from future import standard_library
+ install_hooks = Node(syms.simple_stmt,
+ [Node(syms.power,
+ [Leaf(token.NAME, u'standard_library'),
+ Node(syms.trailer, [Leaf(token.DOT, u'.'),
+ Leaf(token.NAME, u'install_aliases')]),
+ Node(syms.trailer, [Leaf(token.LPAR, u'('),
+ Leaf(token.RPAR, u')')])
+ ])
+ ]
+ )
+ children_hooks = [install_hooks, Newline()]
+
+ # FromImport(package, [Leaf(token.NAME, name_to_import, prefix=u" ")])
+
+ children_import = [import_, Newline()]
+ old_prefix = root.children[insert_pos].prefix
+ root.children[insert_pos].prefix = u''
+ root.insert_child(insert_pos, Node(syms.simple_stmt, children_import, prefix=old_prefix))
+ if len(children_hooks) > 0:
+ root.insert_child(insert_pos + 1, Node(syms.simple_stmt, children_hooks))
+
+
+## The following functions are from python-modernize by Armin Ronacher:
+# (a little edited).
+
+def check_future_import(node):
+ """If this is a future import, return set of symbols that are imported,
+ else return None."""
+ # node should be the import statement here
+ savenode = node
+ if not (node.type == syms.simple_stmt and node.children):
+ return set()
+ node = node.children[0]
+ # now node is the import_from node
+ if not (node.type == syms.import_from and
+ # node.type == token.NAME and # seems to break it
+ hasattr(node.children[1], 'value') and
+ node.children[1].value == u'__future__'):
+ return set()
+ if node.children[3].type == token.LPAR:
+ node = node.children[4]
+ else:
+ node = node.children[3]
+ # now node is the import_as_name[s]
+ if node.type == syms.import_as_names:
+ result = set()
+ for n in node.children:
+ if n.type == token.NAME:
+ result.add(n.value)
+ elif n.type == syms.import_as_name:
+ n = n.children[0]
+ assert n.type == token.NAME
+ result.add(n.value)
+ return result
+ elif node.type == syms.import_as_name:
+ node = node.children[0]
+ assert node.type == token.NAME
+ return set([node.value])
+ elif node.type == token.NAME:
+ return set([node.value])
+ else:
+ # TODO: handle brackets like this:
+ # from __future__ import (absolute_import, division)
+ assert False, "strange import: %s" % savenode
+
+
+SHEBANG_REGEX = r'^#!.*python'
+ENCODING_REGEX = r"^#.*coding[:=]\s*([-\w.]+)"
+
+
+def is_shebang_comment(node):
+ """
+ Comments are prefixes for Leaf nodes. Returns whether the given node has a
+ prefix that looks like a shebang line or an encoding line:
+
+ #!/usr/bin/env python
+ #!/usr/bin/python3
+ """
+ return bool(re.match(SHEBANG_REGEX, node.prefix))
+
+
+def is_encoding_comment(node):
+ """
+ Comments are prefixes for Leaf nodes. Returns whether the given node has a
+ prefix that looks like an encoding line:
+
+ # coding: utf-8
+ # encoding: utf-8
+ # -*- coding: <encoding name> -*-
+ # vim: set fileencoding=<encoding name> :
+ """
+ return bool(re.match(ENCODING_REGEX, node.prefix))
+
+
+def wrap_in_fn_call(fn_name, args, prefix=None):
+ """
+ Example:
+ >>> wrap_in_fn_call("oldstr", (arg,))
+ oldstr(arg)
+
+ >>> wrap_in_fn_call("olddiv", (arg1, arg2))
+ olddiv(arg1, arg2)
+
+ >>> wrap_in_fn_call("olddiv", [arg1, comma, arg2, comma, arg3])
+ olddiv(arg1, arg2, arg3)
+ """
+ assert len(args) > 0
+ if len(args) == 2:
+ expr1, expr2 = args
+ newargs = [expr1, Comma(), expr2]
+ else:
+ newargs = args
+ return Call(Name(fn_name), newargs, prefix=prefix)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/__init__.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/__init__.py
new file mode 100644
index 00000000..0b562501
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/__init__.py
@@ -0,0 +1,97 @@
+import sys
+from lib2to3 import refactor
+
+# The following fixers are "safe": they convert Python 2 code to more
+# modern Python 2 code. They should be uncontroversial to apply to most
+# projects that are happy to drop support for Py2.5 and below. Applying
+# them first will reduce the size of the patch set for the real porting.
+lib2to3_fix_names_stage1 = set([
+ 'lib2to3.fixes.fix_apply',
+ 'lib2to3.fixes.fix_except',
+ 'lib2to3.fixes.fix_exec',
+ 'lib2to3.fixes.fix_exitfunc',
+ 'lib2to3.fixes.fix_funcattrs',
+ 'lib2to3.fixes.fix_has_key',
+ 'lib2to3.fixes.fix_idioms',
+ # 'lib2to3.fixes.fix_import', # makes any implicit relative imports explicit. (Use with ``from __future__ import absolute_import)
+ 'lib2to3.fixes.fix_intern',
+ 'lib2to3.fixes.fix_isinstance',
+ 'lib2to3.fixes.fix_methodattrs',
+ 'lib2to3.fixes.fix_ne',
+ # 'lib2to3.fixes.fix_next', # would replace ``next`` method names
+ # with ``__next__``.
+ 'lib2to3.fixes.fix_numliterals', # turns 1L into 1, 0755 into 0o755
+ 'lib2to3.fixes.fix_paren',
+ # 'lib2to3.fixes.fix_print', # see the libfuturize fixer that also
+ # adds ``from __future__ import print_function``
+ # 'lib2to3.fixes.fix_raise', # uses incompatible with_traceback() method on exceptions
+ 'lib2to3.fixes.fix_reduce', # reduce is available in functools on Py2.6/Py2.7
+ 'lib2to3.fixes.fix_renames', # sys.maxint -> sys.maxsize
+ # 'lib2to3.fixes.fix_set_literal', # this is unnecessary and breaks Py2.6 support
+ 'lib2to3.fixes.fix_repr',
+ 'lib2to3.fixes.fix_standarderror',
+ 'lib2to3.fixes.fix_sys_exc',
+ 'lib2to3.fixes.fix_throw',
+ 'lib2to3.fixes.fix_tuple_params',
+ 'lib2to3.fixes.fix_types',
+ 'lib2to3.fixes.fix_ws_comma', # can perhaps decrease readability: see issue #58
+ 'lib2to3.fixes.fix_xreadlines',
+])
+
+# The following fixers add a dependency on the ``future`` package on order to
+# support Python 2:
+lib2to3_fix_names_stage2 = set([
+ # 'lib2to3.fixes.fix_buffer', # perhaps not safe. Test this.
+ # 'lib2to3.fixes.fix_callable', # not needed in Py3.2+
+ 'lib2to3.fixes.fix_dict', # TODO: add support for utils.viewitems() etc. and move to stage2
+ # 'lib2to3.fixes.fix_execfile', # some problems: see issue #37.
+ # We use a custom fixer instead (see below)
+ # 'lib2to3.fixes.fix_future', # we don't want to remove __future__ imports
+ 'lib2to3.fixes.fix_getcwdu',
+ # 'lib2to3.fixes.fix_imports', # called by libfuturize.fixes.fix_future_standard_library
+ # 'lib2to3.fixes.fix_imports2', # we don't handle this yet (dbm)
+ # 'lib2to3.fixes.fix_input', # Called conditionally by libfuturize.fixes.fix_input
+ 'lib2to3.fixes.fix_itertools',
+ 'lib2to3.fixes.fix_itertools_imports',
+ 'lib2to3.fixes.fix_filter',
+ 'lib2to3.fixes.fix_long',
+ 'lib2to3.fixes.fix_map',
+ # 'lib2to3.fixes.fix_metaclass', # causes SyntaxError in Py2! Use the one from ``six`` instead
+ 'lib2to3.fixes.fix_next',
+ 'lib2to3.fixes.fix_nonzero', # TODO: cause this to import ``object`` and/or add a decorator for mapping __bool__ to __nonzero__
+ 'lib2to3.fixes.fix_operator', # we will need support for this by e.g. extending the Py2 operator module to provide those functions in Py3
+ 'lib2to3.fixes.fix_raw_input',
+ # 'lib2to3.fixes.fix_unicode', # strips off the u'' prefix, which removes a potentially helpful source of information for disambiguating unicode/byte strings
+ # 'lib2to3.fixes.fix_urllib', # included in libfuturize.fix_future_standard_library_urllib
+ # 'lib2to3.fixes.fix_xrange', # custom one because of a bug with Py3.3's lib2to3
+ 'lib2to3.fixes.fix_zip',
+])
+
+libfuturize_fix_names_stage1 = set([
+ 'libfuturize.fixes.fix_absolute_import',
+ 'libfuturize.fixes.fix_next_call', # obj.next() -> next(obj). Unlike
+ # lib2to3.fixes.fix_next, doesn't change
+ # the ``next`` method to ``__next__``.
+ 'libfuturize.fixes.fix_print_with_import',
+ 'libfuturize.fixes.fix_raise',
+ # 'libfuturize.fixes.fix_order___future__imports', # TODO: consolidate to a single line to simplify testing
+])
+
+libfuturize_fix_names_stage2 = set([
+ 'libfuturize.fixes.fix_basestring',
+ # 'libfuturize.fixes.fix_add__future__imports_except_unicode_literals', # just in case
+ 'libfuturize.fixes.fix_cmp',
+ 'libfuturize.fixes.fix_division_safe',
+ 'libfuturize.fixes.fix_execfile',
+ 'libfuturize.fixes.fix_future_builtins',
+ 'libfuturize.fixes.fix_future_standard_library',
+ 'libfuturize.fixes.fix_future_standard_library_urllib',
+ 'libfuturize.fixes.fix_input',
+ 'libfuturize.fixes.fix_metaclass',
+ 'libpasteurize.fixes.fix_newstyle',
+ 'libfuturize.fixes.fix_object',
+ # 'libfuturize.fixes.fix_order___future__imports', # TODO: consolidate to a single line to simplify testing
+ 'libfuturize.fixes.fix_unicode_keep_u',
+ # 'libfuturize.fixes.fix_unicode_literals_import',
+ 'libfuturize.fixes.fix_xrange_with_import', # custom one because of a bug with Py3.3's lib2to3
+])
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_UserDict.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_UserDict.py
new file mode 100644
index 00000000..cb0cfacc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_UserDict.py
@@ -0,0 +1,102 @@
+"""Fix UserDict.
+
+Incomplete!
+
+TODO: base this on fix_urllib perhaps?
+"""
+
+
+# Local imports
+from lib2to3 import fixer_base
+from lib2to3.fixer_util import Name, attr_chain
+from lib2to3.fixes.fix_imports import alternates, build_pattern, FixImports
+
+MAPPING = {'UserDict': 'collections',
+}
+
+# def alternates(members):
+# return "(" + "|".join(map(repr, members)) + ")"
+#
+#
+# def build_pattern(mapping=MAPPING):
+# mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
+# bare_names = alternates(mapping.keys())
+#
+# yield """name_import=import_name< 'import' ((%s) |
+# multiple_imports=dotted_as_names< any* (%s) any* >) >
+# """ % (mod_list, mod_list)
+# yield """import_from< 'from' (%s) 'import' ['(']
+# ( any | import_as_name< any 'as' any > |
+# import_as_names< any* >) [')'] >
+# """ % mod_list
+# yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
+# multiple_imports=dotted_as_names<
+# any* dotted_as_name< (%s) 'as' any > any* >) >
+# """ % (mod_list, mod_list)
+#
+# # Find usages of module members in code e.g. thread.foo(bar)
+# yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
+
+
+# class FixUserDict(fixer_base.BaseFix):
+class FixUserdict(FixImports):
+
+ BM_compatible = True
+ keep_line_order = True
+ # This is overridden in fix_imports2.
+ mapping = MAPPING
+
+ # We want to run this fixer late, so fix_import doesn't try to make stdlib
+ # renames into relative imports.
+ run_order = 6
+
+ def build_pattern(self):
+ return "|".join(build_pattern(self.mapping))
+
+ def compile_pattern(self):
+ # We override this, so MAPPING can be pragmatically altered and the
+ # changes will be reflected in PATTERN.
+ self.PATTERN = self.build_pattern()
+ super(FixImports, self).compile_pattern()
+
+ # Don't match the node if it's within another match.
+ def match(self, node):
+ match = super(FixImports, self).match
+ results = match(node)
+ if results:
+ # Module usage could be in the trailer of an attribute lookup, so we
+ # might have nested matches when "bare_with_attr" is present.
+ if "bare_with_attr" not in results and \
+ any(match(obj) for obj in attr_chain(node, "parent")):
+ return False
+ return results
+ return False
+
+ def start_tree(self, tree, filename):
+ super(FixImports, self).start_tree(tree, filename)
+ self.replace = {}
+
+ def transform(self, node, results):
+ import_mod = results.get("module_name")
+ if import_mod:
+ mod_name = import_mod.value
+ new_name = unicode(self.mapping[mod_name])
+ import_mod.replace(Name(new_name, prefix=import_mod.prefix))
+ if "name_import" in results:
+ # If it's not a "from x import x, y" or "import x as y" import,
+ # marked its usage to be replaced.
+ self.replace[mod_name] = new_name
+ if "multiple_imports" in results:
+ # This is a nasty hack to fix multiple imports on a line (e.g.,
+ # "import StringIO, urlparse"). The problem is that I can't
+ # figure out an easy way to make a pattern recognize the keys of
+ # MAPPING randomly sprinkled in an import statement.
+ results = self.match(node)
+ if results:
+ self.transform(node, results)
+ else:
+ # Replace usage of the module.
+ bare_name = results["bare_with_attr"][0]
+ new_name = self.replace.get(bare_name.value)
+ if new_name:
+ bare_name.replace(Name(new_name, prefix=bare_name.prefix))
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_absolute_import.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_absolute_import.py
new file mode 100644
index 00000000..eab9c527
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_absolute_import.py
@@ -0,0 +1,91 @@
+"""
+Fixer for import statements, with a __future__ import line.
+
+Based on lib2to3/fixes/fix_import.py, but extended slightly so it also
+supports Cython modules.
+
+If spam is being imported from the local directory, this import:
+ from spam import eggs
+becomes:
+ from __future__ import absolute_import
+ from .spam import eggs
+
+and this import:
+ import spam
+becomes:
+ from __future__ import absolute_import
+ from . import spam
+"""
+
+from os.path import dirname, join, exists, sep
+from lib2to3.fixes.fix_import import FixImport
+from lib2to3.fixer_util import FromImport, syms
+from lib2to3.fixes.fix_import import traverse_imports
+
+from libfuturize.fixer_util import future_import
+
+
+class FixAbsoluteImport(FixImport):
+ run_order = 9
+
+ def transform(self, node, results):
+ """
+ Copied from FixImport.transform(), but with this line added in
+ any modules that had implicit relative imports changed:
+
+ from __future__ import absolute_import"
+ """
+ if self.skip:
+ return
+ imp = results['imp']
+
+ if node.type == syms.import_from:
+ # Some imps are top-level (eg: 'import ham')
+ # some are first level (eg: 'import ham.eggs')
+ # some are third level (eg: 'import ham.eggs as spam')
+ # Hence, the loop
+ while not hasattr(imp, 'value'):
+ imp = imp.children[0]
+ if self.probably_a_local_import(imp.value):
+ imp.value = u"." + imp.value
+ imp.changed()
+ future_import(u"absolute_import", node)
+ else:
+ have_local = False
+ have_absolute = False
+ for mod_name in traverse_imports(imp):
+ if self.probably_a_local_import(mod_name):
+ have_local = True
+ else:
+ have_absolute = True
+ if have_absolute:
+ if have_local:
+ # We won't handle both sibling and absolute imports in the
+ # same statement at the moment.
+ self.warning(node, "absolute and local imports together")
+ return
+
+ new = FromImport(u".", [imp])
+ new.prefix = node.prefix
+ future_import(u"absolute_import", node)
+ return new
+
+ def probably_a_local_import(self, imp_name):
+ """
+ Like the corresponding method in the base class, but this also
+ supports Cython modules.
+ """
+ if imp_name.startswith(u"."):
+ # Relative imports are certainly not local imports.
+ return False
+ imp_name = imp_name.split(u".", 1)[0]
+ base_path = dirname(self.filename)
+ base_path = join(base_path, imp_name)
+ # If there is no __init__.py next to the file its not in a package
+ # so can't be a relative import.
+ if not exists(join(dirname(base_path), "__init__.py")):
+ return False
+ for ext in [".py", sep, ".pyc", ".so", ".sl", ".pyd", ".pyx"]:
+ if exists(base_path + ext):
+ return True
+ return False
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_add__future__imports_except_unicode_literals.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_add__future__imports_except_unicode_literals.py
new file mode 100644
index 00000000..37d7feec
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_add__future__imports_except_unicode_literals.py
@@ -0,0 +1,26 @@
+"""
+Fixer for adding:
+
+ from __future__ import absolute_import
+ from __future__ import division
+ from __future__ import print_function
+
+This is "stage 1": hopefully uncontroversial changes.
+
+Stage 2 adds ``unicode_literals``.
+"""
+
+from lib2to3 import fixer_base
+from libfuturize.fixer_util import future_import
+
+class FixAddFutureImportsExceptUnicodeLiterals(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "file_input"
+
+ run_order = 9
+
+ def transform(self, node, results):
+ # Reverse order:
+ future_import(u"absolute_import", node)
+ future_import(u"division", node)
+ future_import(u"print_function", node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_basestring.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_basestring.py
new file mode 100644
index 00000000..5676d08f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_basestring.py
@@ -0,0 +1,17 @@
+"""
+Fixer that adds ``from past.builtins import basestring`` if there is a
+reference to ``basestring``
+"""
+
+from lib2to3 import fixer_base
+
+from libfuturize.fixer_util import touch_import_top
+
+
+class FixBasestring(fixer_base.BaseFix):
+ BM_compatible = True
+
+ PATTERN = "'basestring'"
+
+ def transform(self, node, results):
+ touch_import_top(u'past.builtins', 'basestring', node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_bytes.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_bytes.py
new file mode 100644
index 00000000..42021223
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_bytes.py
@@ -0,0 +1,24 @@
+"""Optional fixer that changes all unprefixed string literals "..." to b"...".
+
+br'abcd' is a SyntaxError on Python 2 but valid on Python 3.
+ur'abcd' is a SyntaxError on Python 3 but valid on Python 2.
+
+"""
+from __future__ import unicode_literals
+
+import re
+from lib2to3.pgen2 import token
+from lib2to3 import fixer_base
+
+_literal_re = re.compile(r"[^bBuUrR]?[\'\"]")
+
+class FixBytes(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "STRING"
+
+ def transform(self, node, results):
+ if node.type == token.STRING:
+ if _literal_re.match(node.value):
+ new = node.clone()
+ new.value = u'b' + new.value
+ return new
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_cmp.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_cmp.py
new file mode 100644
index 00000000..762eb4b4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_cmp.py
@@ -0,0 +1,33 @@
+# coding: utf-8
+"""
+Fixer for the cmp() function on Py2, which was removed in Py3.
+
+Adds this import line::
+
+ from past.builtins import cmp
+
+if cmp() is called in the code.
+"""
+
+from __future__ import unicode_literals
+from lib2to3 import fixer_base
+
+from libfuturize.fixer_util import touch_import_top
+
+
+expression = "name='cmp'"
+
+
+class FixCmp(fixer_base.BaseFix):
+ BM_compatible = True
+ run_order = 9
+
+ PATTERN = """
+ power<
+ ({0}) trailer< '(' args=[any] ')' >
+ rest=any* >
+ """.format(expression)
+
+ def transform(self, node, results):
+ name = results["name"]
+ touch_import_top(u'past.builtins', name.value, node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division.py
new file mode 100644
index 00000000..6975a52b
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division.py
@@ -0,0 +1,12 @@
+"""
+UNFINISHED
+For the ``future`` package.
+
+Adds this import line:
+
+ from __future__ import division
+
+at the top so the code runs identically on Py3 and Py2.6/2.7
+"""
+
+from libpasteurize.fixes.fix_division import FixDivision
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division_safe.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division_safe.py
new file mode 100644
index 00000000..65c8c1da
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_division_safe.py
@@ -0,0 +1,109 @@
+"""
+For the ``future`` package.
+
+Adds this import line:
+
+ from __future__ import division
+
+at the top and changes any old-style divisions to be calls to
+past.utils.old_div so the code runs as before on Py2.6/2.7 and has the same
+behaviour on Py3.
+
+If "from __future__ import division" is already in effect, this fixer does
+nothing.
+"""
+
+import re
+from lib2to3.fixer_util import Leaf, Node, Comma
+from lib2to3 import fixer_base
+from libfuturize.fixer_util import (token, future_import, touch_import_top,
+ wrap_in_fn_call)
+
+
+def match_division(node):
+ u"""
+ __future__.division redefines the meaning of a single slash for division,
+ so we match that and only that.
+ """
+ slash = token.SLASH
+ return node.type == slash and not node.next_sibling.type == slash and \
+ not node.prev_sibling.type == slash
+
+const_re = re.compile('^[0-9]*[.][0-9]*$')
+
+def is_floaty(node):
+ return _is_floaty(node.prev_sibling) or _is_floaty(node.next_sibling)
+
+
+def _is_floaty(expr):
+ if isinstance(expr, list):
+ expr = expr[0]
+
+ if isinstance(expr, Leaf):
+ # If it's a leaf, let's see if it's a numeric constant containing a '.'
+ return const_re.match(expr.value)
+ elif isinstance(expr, Node):
+ # If the expression is a node, let's see if it's a direct cast to float
+ if isinstance(expr.children[0], Leaf):
+ return expr.children[0].value == u'float'
+ return False
+
+
+class FixDivisionSafe(fixer_base.BaseFix):
+ # BM_compatible = True
+ run_order = 4 # this seems to be ignored?
+
+ _accept_type = token.SLASH
+
+ PATTERN = """
+ term<(not('/') any)+ '/' ((not('/') any))>
+ """
+
+ def start_tree(self, tree, name):
+ """
+ Skip this fixer if "__future__.division" is already imported.
+ """
+ super(FixDivisionSafe, self).start_tree(tree, name)
+ self.skip = "division" in tree.future_features
+
+ def match(self, node):
+ u"""
+ Since the tree needs to be fixed once and only once if and only if it
+ matches, we can start discarding matches after the first.
+ """
+ if node.type == self.syms.term:
+ matched = False
+ skip = False
+ children = []
+ for child in node.children:
+ if skip:
+ skip = False
+ continue
+ if match_division(child) and not is_floaty(child):
+ matched = True
+
+ # Strip any leading space for the first number:
+ children[0].prefix = u''
+
+ children = [wrap_in_fn_call("old_div",
+ children + [Comma(), child.next_sibling.clone()],
+ prefix=node.prefix)]
+ skip = True
+ else:
+ children.append(child.clone())
+ if matched:
+ # In Python 2.6, `Node` does not have the fixers_applied attribute
+ # https://github.com/python/cpython/blob/8493c0cd66cfc181ac1517268a74f077e9998701/Lib/lib2to3/pytree.py#L235
+ if hasattr(Node, "fixers_applied"):
+ return Node(node.type, children, fixers_applied=node.fixers_applied)
+ else:
+ return Node(node.type, children)
+
+ return False
+
+ def transform(self, node, results):
+ if self.skip:
+ return
+ future_import(u"division", node)
+ touch_import_top(u'past.utils', u'old_div', node)
+ return results
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_execfile.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_execfile.py
new file mode 100644
index 00000000..cfe9d8d0
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_execfile.py
@@ -0,0 +1,37 @@
+# coding: utf-8
+"""
+Fixer for the execfile() function on Py2, which was removed in Py3.
+
+The Lib/lib2to3/fixes/fix_execfile.py module has some problems: see
+python-future issue #37. This fixer merely imports execfile() from
+past.builtins and leaves the code alone.
+
+Adds this import line::
+
+ from past.builtins import execfile
+
+for the function execfile() that was removed from Py3.
+"""
+
+from __future__ import unicode_literals
+from lib2to3 import fixer_base
+
+from libfuturize.fixer_util import touch_import_top
+
+
+expression = "name='execfile'"
+
+
+class FixExecfile(fixer_base.BaseFix):
+ BM_compatible = True
+ run_order = 9
+
+ PATTERN = """
+ power<
+ ({0}) trailer< '(' args=[any] ')' >
+ rest=any* >
+ """.format(expression)
+
+ def transform(self, node, results):
+ name = results["name"]
+ touch_import_top(u'past.builtins', name.value, node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_builtins.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_builtins.py
new file mode 100644
index 00000000..eea6c6a1
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_builtins.py
@@ -0,0 +1,59 @@
+"""
+For the ``future`` package.
+
+Adds this import line::
+
+ from builtins import XYZ
+
+for each of the functions XYZ that is used in the module.
+
+Adds these imports after any other imports (in an initial block of them).
+"""
+
+from __future__ import unicode_literals
+
+from lib2to3 import fixer_base
+from lib2to3.pygram import python_symbols as syms
+from lib2to3.fixer_util import Name, Call, in_special_context
+
+from libfuturize.fixer_util import touch_import_top
+
+# All builtins are:
+# from future.builtins.iterators import (filter, map, zip)
+# from future.builtins.misc import (ascii, chr, hex, input, isinstance, oct, open, round, super)
+# from future.types import (bytes, dict, int, range, str)
+# We don't need isinstance any more.
+
+replaced_builtin_fns = '''filter map zip
+ ascii chr hex input next oct
+ bytes range str raw_input'''.split()
+ # This includes raw_input as a workaround for the
+ # lib2to3 fixer for raw_input on Py3 (only), allowing
+ # the correct import to be included. (Py3 seems to run
+ # the fixers the wrong way around, perhaps ignoring the
+ # run_order class attribute below ...)
+
+expression = '|'.join(["name='{0}'".format(name) for name in replaced_builtin_fns])
+
+
+class FixFutureBuiltins(fixer_base.BaseFix):
+ BM_compatible = True
+ run_order = 7
+
+ # Currently we only match uses as a function. This doesn't match e.g.:
+ # if isinstance(s, str):
+ # ...
+ PATTERN = """
+ power<
+ ({0}) trailer< '(' [arglist=any] ')' >
+ rest=any* >
+ |
+ power<
+ 'map' trailer< '(' [arglist=any] ')' >
+ >
+ """.format(expression)
+
+ def transform(self, node, results):
+ name = results["name"]
+ touch_import_top(u'builtins', name.value, node)
+ # name.replace(Name(u"input", prefix=name.prefix))
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library.py
new file mode 100644
index 00000000..a1c3f3d4
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library.py
@@ -0,0 +1,24 @@
+"""
+For the ``future`` package.
+
+Changes any imports needed to reflect the standard library reorganization. Also
+Also adds these import lines:
+
+ from future import standard_library
+ standard_library.install_aliases()
+
+after any __future__ imports but before any other imports.
+"""
+
+from lib2to3.fixes.fix_imports import FixImports
+from libfuturize.fixer_util import touch_import_top
+
+
+class FixFutureStandardLibrary(FixImports):
+ run_order = 8
+
+ def transform(self, node, results):
+ result = super(FixFutureStandardLibrary, self).transform(node, results)
+ # TODO: add a blank line between any __future__ imports and this?
+ touch_import_top(u'future', u'standard_library', node)
+ return result
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library_urllib.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library_urllib.py
new file mode 100644
index 00000000..cf673884
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_future_standard_library_urllib.py
@@ -0,0 +1,28 @@
+"""
+For the ``future`` package.
+
+A special fixer that ensures that these lines have been added::
+
+ from future import standard_library
+ standard_library.install_hooks()
+
+even if the only module imported was ``urllib``, in which case the regular fixer
+wouldn't have added these lines.
+
+"""
+
+from lib2to3.fixes.fix_urllib import FixUrllib
+from libfuturize.fixer_util import touch_import_top, find_root
+
+
+class FixFutureStandardLibraryUrllib(FixUrllib): # not a subclass of FixImports
+ run_order = 8
+
+ def transform(self, node, results):
+ # transform_member() in lib2to3/fixes/fix_urllib.py breaks node so find_root(node)
+ # no longer works after the super() call below. So we find the root first:
+ root = find_root(node)
+ result = super(FixFutureStandardLibraryUrllib, self).transform(node, results)
+ # TODO: add a blank line between any __future__ imports and this?
+ touch_import_top(u'future', u'standard_library', root)
+ return result
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_input.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_input.py
new file mode 100644
index 00000000..8a43882e
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_input.py
@@ -0,0 +1,32 @@
+"""
+Fixer for input.
+
+Does a check for `from builtins import input` before running the lib2to3 fixer.
+The fixer will not run when the input is already present.
+
+
+this:
+ a = input()
+becomes:
+ from builtins import input
+ a = eval(input())
+
+and this:
+ from builtins import input
+ a = input()
+becomes (no change):
+ from builtins import input
+ a = input()
+"""
+
+import lib2to3.fixes.fix_input
+from lib2to3.fixer_util import does_tree_import
+
+
+class FixInput(lib2to3.fixes.fix_input.FixInput):
+ def transform(self, node, results):
+
+ if does_tree_import('builtins', 'input', node):
+ return
+
+ return super(FixInput, self).transform(node, results)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_metaclass.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_metaclass.py
new file mode 100644
index 00000000..a7eee40d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_metaclass.py
@@ -0,0 +1,262 @@
+# coding: utf-8
+"""Fixer for __metaclass__ = X -> (future.utils.with_metaclass(X)) methods.
+
+ The various forms of classef (inherits nothing, inherits once, inherints
+ many) don't parse the same in the CST so we look at ALL classes for
+ a __metaclass__ and if we find one normalize the inherits to all be
+ an arglist.
+
+ For one-liner classes ('class X: pass') there is no indent/dedent so
+ we normalize those into having a suite.
+
+ Moving the __metaclass__ into the classdef can also cause the class
+ body to be empty so there is some special casing for that as well.
+
+ This fixer also tries very hard to keep original indenting and spacing
+ in all those corner cases.
+"""
+# This is a derived work of Lib/lib2to3/fixes/fix_metaclass.py under the
+# copyright of the Python Software Foundation, licensed under the Python
+# Software Foundation License 2.
+#
+# Copyright notice:
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012, 2013 Python Software Foundation. All rights reserved.
+#
+# Full license text: http://docs.python.org/3.4/license.html
+
+# Author: Jack Diederich, Daniel Neuhäuser
+
+# Local imports
+from lib2to3 import fixer_base
+from lib2to3.pygram import token
+from lib2to3.fixer_util import Name, syms, Node, Leaf, touch_import, Call, \
+ String, Comma, parenthesize
+
+
+def has_metaclass(parent):
+ """ we have to check the cls_node without changing it.
+ There are two possibilities:
+ 1) clsdef => suite => simple_stmt => expr_stmt => Leaf('__meta')
+ 2) clsdef => simple_stmt => expr_stmt => Leaf('__meta')
+ """
+ for node in parent.children:
+ if node.type == syms.suite:
+ return has_metaclass(node)
+ elif node.type == syms.simple_stmt and node.children:
+ expr_node = node.children[0]
+ if expr_node.type == syms.expr_stmt and expr_node.children:
+ left_side = expr_node.children[0]
+ if isinstance(left_side, Leaf) and \
+ left_side.value == '__metaclass__':
+ return True
+ return False
+
+
+def fixup_parse_tree(cls_node):
+ """ one-line classes don't get a suite in the parse tree so we add
+ one to normalize the tree
+ """
+ for node in cls_node.children:
+ if node.type == syms.suite:
+ # already in the preferred format, do nothing
+ return
+
+ # !%@#! one-liners have no suite node, we have to fake one up
+ for i, node in enumerate(cls_node.children):
+ if node.type == token.COLON:
+ break
+ else:
+ raise ValueError("No class suite and no ':'!")
+
+ # move everything into a suite node
+ suite = Node(syms.suite, [])
+ while cls_node.children[i+1:]:
+ move_node = cls_node.children[i+1]
+ suite.append_child(move_node.clone())
+ move_node.remove()
+ cls_node.append_child(suite)
+ node = suite
+
+
+def fixup_simple_stmt(parent, i, stmt_node):
+ """ if there is a semi-colon all the parts count as part of the same
+ simple_stmt. We just want the __metaclass__ part so we move
+ everything efter the semi-colon into its own simple_stmt node
+ """
+ for semi_ind, node in enumerate(stmt_node.children):
+ if node.type == token.SEMI: # *sigh*
+ break
+ else:
+ return
+
+ node.remove() # kill the semicolon
+ new_expr = Node(syms.expr_stmt, [])
+ new_stmt = Node(syms.simple_stmt, [new_expr])
+ while stmt_node.children[semi_ind:]:
+ move_node = stmt_node.children[semi_ind]
+ new_expr.append_child(move_node.clone())
+ move_node.remove()
+ parent.insert_child(i, new_stmt)
+ new_leaf1 = new_stmt.children[0].children[0]
+ old_leaf1 = stmt_node.children[0].children[0]
+ new_leaf1.prefix = old_leaf1.prefix
+
+
+def remove_trailing_newline(node):
+ if node.children and node.children[-1].type == token.NEWLINE:
+ node.children[-1].remove()
+
+
+def find_metas(cls_node):
+ # find the suite node (Mmm, sweet nodes)
+ for node in cls_node.children:
+ if node.type == syms.suite:
+ break
+ else:
+ raise ValueError("No class suite!")
+
+ # look for simple_stmt[ expr_stmt[ Leaf('__metaclass__') ] ]
+ for i, simple_node in list(enumerate(node.children)):
+ if simple_node.type == syms.simple_stmt and simple_node.children:
+ expr_node = simple_node.children[0]
+ if expr_node.type == syms.expr_stmt and expr_node.children:
+ # Check if the expr_node is a simple assignment.
+ left_node = expr_node.children[0]
+ if isinstance(left_node, Leaf) and \
+ left_node.value == u'__metaclass__':
+ # We found a assignment to __metaclass__.
+ fixup_simple_stmt(node, i, simple_node)
+ remove_trailing_newline(simple_node)
+ yield (node, i, simple_node)
+
+
+def fixup_indent(suite):
+ """ If an INDENT is followed by a thing with a prefix then nuke the prefix
+ Otherwise we get in trouble when removing __metaclass__ at suite start
+ """
+ kids = suite.children[::-1]
+ # find the first indent
+ while kids:
+ node = kids.pop()
+ if node.type == token.INDENT:
+ break
+
+ # find the first Leaf
+ while kids:
+ node = kids.pop()
+ if isinstance(node, Leaf) and node.type != token.DEDENT:
+ if node.prefix:
+ node.prefix = u''
+ return
+ else:
+ kids.extend(node.children[::-1])
+
+
+class FixMetaclass(fixer_base.BaseFix):
+ BM_compatible = True
+
+ PATTERN = """
+ classdef<any*>
+ """
+
+ def transform(self, node, results):
+ if not has_metaclass(node):
+ return
+
+ fixup_parse_tree(node)
+
+ # find metaclasses, keep the last one
+ last_metaclass = None
+ for suite, i, stmt in find_metas(node):
+ last_metaclass = stmt
+ stmt.remove()
+
+ text_type = node.children[0].type # always Leaf(nnn, 'class')
+
+ # figure out what kind of classdef we have
+ if len(node.children) == 7:
+ # Node(classdef, ['class', 'name', '(', arglist, ')', ':', suite])
+ # 0 1 2 3 4 5 6
+ if node.children[3].type == syms.arglist:
+ arglist = node.children[3]
+ # Node(classdef, ['class', 'name', '(', 'Parent', ')', ':', suite])
+ else:
+ parent = node.children[3].clone()
+ arglist = Node(syms.arglist, [parent])
+ node.set_child(3, arglist)
+ elif len(node.children) == 6:
+ # Node(classdef, ['class', 'name', '(', ')', ':', suite])
+ # 0 1 2 3 4 5
+ arglist = Node(syms.arglist, [])
+ node.insert_child(3, arglist)
+ elif len(node.children) == 4:
+ # Node(classdef, ['class', 'name', ':', suite])
+ # 0 1 2 3
+ arglist = Node(syms.arglist, [])
+ node.insert_child(2, Leaf(token.RPAR, u')'))
+ node.insert_child(2, arglist)
+ node.insert_child(2, Leaf(token.LPAR, u'('))
+ else:
+ raise ValueError("Unexpected class definition")
+
+ # now stick the metaclass in the arglist
+ meta_txt = last_metaclass.children[0].children[0]
+ meta_txt.value = 'metaclass'
+ orig_meta_prefix = meta_txt.prefix
+
+ # Was: touch_import(None, u'future.utils', node)
+ touch_import(u'future.utils', u'with_metaclass', node)
+
+ metaclass = last_metaclass.children[0].children[2].clone()
+ metaclass.prefix = u''
+
+ arguments = [metaclass]
+
+ if arglist.children:
+ if len(arglist.children) == 1:
+ base = arglist.children[0].clone()
+ base.prefix = u' '
+ else:
+ # Unfortunately six.with_metaclass() only allows one base
+ # class, so we have to dynamically generate a base class if
+ # there is more than one.
+ bases = parenthesize(arglist.clone())
+ bases.prefix = u' '
+ base = Call(Name('type'), [
+ String("'NewBase'"),
+ Comma(),
+ bases,
+ Comma(),
+ Node(
+ syms.atom,
+ [Leaf(token.LBRACE, u'{'), Leaf(token.RBRACE, u'}')],
+ prefix=u' '
+ )
+ ], prefix=u' ')
+ arguments.extend([Comma(), base])
+
+ arglist.replace(Call(
+ Name(u'with_metaclass', prefix=arglist.prefix),
+ arguments
+ ))
+
+ fixup_indent(suite)
+
+ # check for empty suite
+ if not suite.children:
+ # one-liner that was just __metaclass_
+ suite.remove()
+ pass_leaf = Leaf(text_type, u'pass')
+ pass_leaf.prefix = orig_meta_prefix
+ node.append_child(pass_leaf)
+ node.append_child(Leaf(token.NEWLINE, u'\n'))
+
+ elif len(suite.children) > 1 and \
+ (suite.children[-2].type == token.INDENT and
+ suite.children[-1].type == token.DEDENT):
+ # there was only one line in the class body and it was __metaclass__
+ pass_leaf = Leaf(text_type, u'pass')
+ suite.insert_child(-1, pass_leaf)
+ suite.insert_child(-1, Leaf(token.NEWLINE, u'\n'))
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_next_call.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_next_call.py
new file mode 100644
index 00000000..282f1852
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_next_call.py
@@ -0,0 +1,104 @@
+"""
+Based on fix_next.py by Collin Winter.
+
+Replaces it.next() -> next(it), per PEP 3114.
+
+Unlike fix_next.py, this fixer doesn't replace the name of a next method with __next__,
+which would break Python 2 compatibility without further help from fixers in
+stage 2.
+"""
+
+# Local imports
+from lib2to3.pgen2 import token
+from lib2to3.pygram import python_symbols as syms
+from lib2to3 import fixer_base
+from lib2to3.fixer_util import Name, Call, find_binding
+
+bind_warning = "Calls to builtin next() possibly shadowed by global binding"
+
+
+class FixNextCall(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = """
+ power< base=any+ trailer< '.' attr='next' > trailer< '(' ')' > >
+ |
+ power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > >
+ |
+ global=global_stmt< 'global' any* 'next' any* >
+ """
+
+ order = "pre" # Pre-order tree traversal
+
+ def start_tree(self, tree, filename):
+ super(FixNextCall, self).start_tree(tree, filename)
+
+ n = find_binding('next', tree)
+ if n:
+ self.warning(n, bind_warning)
+ self.shadowed_next = True
+ else:
+ self.shadowed_next = False
+
+ def transform(self, node, results):
+ assert results
+
+ base = results.get("base")
+ attr = results.get("attr")
+ name = results.get("name")
+
+ if base:
+ if self.shadowed_next:
+ # Omit this:
+ # attr.replace(Name("__next__", prefix=attr.prefix))
+ pass
+ else:
+ base = [n.clone() for n in base]
+ base[0].prefix = ""
+ node.replace(Call(Name("next", prefix=node.prefix), base))
+ elif name:
+ # Omit this:
+ # n = Name("__next__", prefix=name.prefix)
+ # name.replace(n)
+ pass
+ elif attr:
+ # We don't do this transformation if we're assigning to "x.next".
+ # Unfortunately, it doesn't seem possible to do this in PATTERN,
+ # so it's being done here.
+ if is_assign_target(node):
+ head = results["head"]
+ if "".join([str(n) for n in head]).strip() == '__builtin__':
+ self.warning(node, bind_warning)
+ return
+ # Omit this:
+ # attr.replace(Name("__next__"))
+ elif "global" in results:
+ self.warning(node, bind_warning)
+ self.shadowed_next = True
+
+
+### The following functions help test if node is part of an assignment
+### target.
+
+def is_assign_target(node):
+ assign = find_assign(node)
+ if assign is None:
+ return False
+
+ for child in assign.children:
+ if child.type == token.EQUAL:
+ return False
+ elif is_subtree(child, node):
+ return True
+ return False
+
+def find_assign(node):
+ if node.type == syms.expr_stmt:
+ return node
+ if node.type == syms.simple_stmt or node.parent is None:
+ return None
+ return find_assign(node.parent)
+
+def is_subtree(root, node):
+ if root == node:
+ return True
+ return any(is_subtree(c, node) for c in root.children)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_object.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_object.py
new file mode 100644
index 00000000..accf2c52
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_object.py
@@ -0,0 +1,17 @@
+"""
+Fixer that adds ``from builtins import object`` if there is a line
+like this:
+ class Foo(object):
+"""
+
+from lib2to3 import fixer_base
+
+from libfuturize.fixer_util import touch_import_top
+
+
+class FixObject(fixer_base.BaseFix):
+
+ PATTERN = u"classdef< 'class' NAME '(' name='object' ')' colon=':' any >"
+
+ def transform(self, node, results):
+ touch_import_top(u'builtins', 'object', node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_oldstr_wrap.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_oldstr_wrap.py
new file mode 100644
index 00000000..ad58771d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_oldstr_wrap.py
@@ -0,0 +1,39 @@
+"""
+For the ``future`` package.
+
+Adds this import line:
+
+ from past.builtins import str as oldstr
+
+at the top and wraps any unadorned string literals 'abc' or explicit byte-string
+literals b'abc' in oldstr() calls so the code has the same behaviour on Py3 as
+on Py2.6/2.7.
+"""
+
+from __future__ import unicode_literals
+import re
+from lib2to3 import fixer_base
+from lib2to3.pgen2 import token
+from lib2to3.fixer_util import syms
+from libfuturize.fixer_util import (future_import, touch_import_top,
+ wrap_in_fn_call)
+
+
+_literal_re = re.compile(r"[^uUrR]?[\'\"]")
+
+
+class FixOldstrWrap(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "STRING"
+
+ def transform(self, node, results):
+ if node.type == token.STRING:
+ touch_import_top(u'past.types', u'oldstr', node)
+ if _literal_re.match(node.value):
+ new = node.clone()
+ # Strip any leading space or comments:
+ # TODO: check: do we really want to do this?
+ new.prefix = u''
+ new.value = u'b' + new.value
+ wrapped = wrap_in_fn_call("oldstr", [new], prefix=node.prefix)
+ return wrapped
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_order___future__imports.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_order___future__imports.py
new file mode 100644
index 00000000..00d7ef60
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_order___future__imports.py
@@ -0,0 +1,36 @@
+"""
+UNFINISHED
+
+Fixer for turning multiple lines like these:
+
+ from __future__ import division
+ from __future__ import absolute_import
+ from __future__ import print_function
+
+into a single line like this:
+
+ from __future__ import (absolute_import, division, print_function)
+
+This helps with testing of ``futurize``.
+"""
+
+from lib2to3 import fixer_base
+from libfuturize.fixer_util import future_import
+
+class FixOrderFutureImports(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "file_input"
+
+ run_order = 10
+
+ # def match(self, node):
+ # """
+ # Match only once per file
+ # """
+ # if hasattr(node, 'type') and node.type == syms.file_input:
+ # return True
+ # return False
+
+ def transform(self, node, results):
+ # TODO # write me
+ pass
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print.py
new file mode 100644
index 00000000..2554717c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print.py
@@ -0,0 +1,104 @@
+# Copyright 2006 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Fixer for print.
+
+Change:
+ "print" into "print()"
+ "print ..." into "print(...)"
+ "print(...)" not changed
+ "print ... ," into "print(..., end=' ')"
+ "print >>x, ..." into "print(..., file=x)"
+
+No changes are applied if print_function is imported from __future__
+
+"""
+
+# Local imports
+from lib2to3 import patcomp, pytree, fixer_base
+from lib2to3.pgen2 import token
+from lib2to3.fixer_util import Name, Call, Comma, String
+# from libmodernize import add_future
+
+parend_expr = patcomp.compile_pattern(
+ """atom< '(' [arith_expr|atom|power|term|STRING|NAME] ')' >"""
+ )
+
+
+class FixPrint(fixer_base.BaseFix):
+
+ BM_compatible = True
+
+ PATTERN = """
+ simple_stmt< any* bare='print' any* > | print_stmt
+ """
+
+ def transform(self, node, results):
+ assert results
+
+ bare_print = results.get("bare")
+
+ if bare_print:
+ # Special-case print all by itself.
+ bare_print.replace(Call(Name(u"print"), [],
+ prefix=bare_print.prefix))
+ # The "from __future__ import print_function"" declaration is added
+ # by the fix_print_with_import fixer, so we skip it here.
+ # add_future(node, u'print_function')
+ return
+ assert node.children[0] == Name(u"print")
+ args = node.children[1:]
+ if len(args) == 1 and parend_expr.match(args[0]):
+ # We don't want to keep sticking parens around an
+ # already-parenthesised expression.
+ return
+
+ sep = end = file = None
+ if args and args[-1] == Comma():
+ args = args[:-1]
+ end = " "
+
+ # try to determine if the string ends in a non-space whitespace character, in which
+ # case there should be no space at the end of the conversion
+ string_leaves = [leaf for leaf in args[-1].leaves() if leaf.type == token.STRING]
+ if (
+ string_leaves
+ and string_leaves[-1].value[0] != "r" # "raw" string
+ and string_leaves[-1].value[-3:-1] in (r"\t", r"\n", r"\r")
+ ):
+ end = ""
+ if args and args[0] == pytree.Leaf(token.RIGHTSHIFT, u">>"):
+ assert len(args) >= 2
+ file = args[1].clone()
+ args = args[3:] # Strip a possible comma after the file expression
+ # Now synthesize a print(args, sep=..., end=..., file=...) node.
+ l_args = [arg.clone() for arg in args]
+ if l_args:
+ l_args[0].prefix = u""
+ if sep is not None or end is not None or file is not None:
+ if sep is not None:
+ self.add_kwarg(l_args, u"sep", String(repr(sep)))
+ if end is not None:
+ self.add_kwarg(l_args, u"end", String(repr(end)))
+ if file is not None:
+ self.add_kwarg(l_args, u"file", file)
+ n_stmt = Call(Name(u"print"), l_args)
+ n_stmt.prefix = node.prefix
+
+ # Note that there are corner cases where adding this future-import is
+ # incorrect, for example when the file also has a 'print ()' statement
+ # that was intended to print "()".
+ # add_future(node, u'print_function')
+ return n_stmt
+
+ def add_kwarg(self, l_nodes, s_kwd, n_expr):
+ # XXX All this prefix-setting may lose comments (though rarely)
+ n_expr.prefix = u""
+ n_argument = pytree.Node(self.syms.argument,
+ (Name(s_kwd),
+ pytree.Leaf(token.EQUAL, u"="),
+ n_expr))
+ if l_nodes:
+ l_nodes.append(Comma())
+ n_argument.prefix = u" "
+ l_nodes.append(n_argument)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print_with_import.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print_with_import.py
new file mode 100644
index 00000000..34490461
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_print_with_import.py
@@ -0,0 +1,22 @@
+"""
+For the ``future`` package.
+
+Turns any print statements into functions and adds this import line:
+
+ from __future__ import print_function
+
+at the top to retain compatibility with Python 2.6+.
+"""
+
+from libfuturize.fixes.fix_print import FixPrint
+from libfuturize.fixer_util import future_import
+
+class FixPrintWithImport(FixPrint):
+ run_order = 7
+ def transform(self, node, results):
+ # Add the __future__ import first. (Otherwise any shebang or encoding
+ # comment line attached as a prefix to the print statement will be
+ # copied twice and appear twice.)
+ future_import(u'print_function', node)
+ n_stmt = super(FixPrintWithImport, self).transform(node, results)
+ return n_stmt
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_raise.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_raise.py
new file mode 100644
index 00000000..d113401c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_raise.py
@@ -0,0 +1,107 @@
+"""Fixer for 'raise E, V'
+
+From Armin Ronacher's ``python-modernize``.
+
+raise -> raise
+raise E -> raise E
+raise E, 5 -> raise E(5)
+raise E, 5, T -> raise E(5).with_traceback(T)
+raise E, None, T -> raise E.with_traceback(T)
+
+raise (((E, E'), E''), E'''), 5 -> raise E(5)
+raise "foo", V, T -> warns about string exceptions
+
+raise E, (V1, V2) -> raise E(V1, V2)
+raise E, (V1, V2), T -> raise E(V1, V2).with_traceback(T)
+
+
+CAVEATS:
+1) "raise E, V, T" cannot be translated safely in general. If V
+ is not a tuple or a (number, string, None) literal, then:
+
+ raise E, V, T -> from future.utils import raise_
+ raise_(E, V, T)
+"""
+# Author: Collin Winter, Armin Ronacher, Mark Huang
+
+# Local imports
+from lib2to3 import pytree, fixer_base
+from lib2to3.pgen2 import token
+from lib2to3.fixer_util import Name, Call, is_tuple, Comma, Attr, ArgList
+
+from libfuturize.fixer_util import touch_import_top
+
+
+class FixRaise(fixer_base.BaseFix):
+
+ BM_compatible = True
+ PATTERN = """
+ raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] >
+ """
+
+ def transform(self, node, results):
+ syms = self.syms
+
+ exc = results["exc"].clone()
+ if exc.type == token.STRING:
+ msg = "Python 3 does not support string exceptions"
+ self.cannot_convert(node, msg)
+ return
+
+ # Python 2 supports
+ # raise ((((E1, E2), E3), E4), E5), V
+ # as a synonym for
+ # raise E1, V
+ # Since Python 3 will not support this, we recurse down any tuple
+ # literals, always taking the first element.
+ if is_tuple(exc):
+ while is_tuple(exc):
+ # exc.children[1:-1] is the unparenthesized tuple
+ # exc.children[1].children[0] is the first element of the tuple
+ exc = exc.children[1].children[0].clone()
+ exc.prefix = u" "
+
+ if "tb" in results:
+ tb = results["tb"].clone()
+ else:
+ tb = None
+
+ if "val" in results:
+ val = results["val"].clone()
+ if is_tuple(val):
+ # Assume that exc is a subclass of Exception and call exc(*val).
+ args = [c.clone() for c in val.children[1:-1]]
+ exc = Call(exc, args)
+ elif val.type in (token.NUMBER, token.STRING):
+ # Handle numeric and string literals specially, e.g.
+ # "raise Exception, 5" -> "raise Exception(5)".
+ val.prefix = u""
+ exc = Call(exc, [val])
+ elif val.type == token.NAME and val.value == u"None":
+ # Handle None specially, e.g.
+ # "raise Exception, None" -> "raise Exception".
+ pass
+ else:
+ # val is some other expression. If val evaluates to an instance
+ # of exc, it should just be raised. If val evaluates to None,
+ # a default instance of exc should be raised (as above). If val
+ # evaluates to a tuple, exc(*val) should be called (as
+ # above). Otherwise, exc(val) should be called. We can only
+ # tell what to do at runtime, so defer to future.utils.raise_(),
+ # which handles all of these cases.
+ touch_import_top(u"future.utils", u"raise_", node)
+ exc.prefix = u""
+ args = [exc, Comma(), val]
+ if tb is not None:
+ args += [Comma(), tb]
+ return Call(Name(u"raise_"), args, prefix=node.prefix)
+
+ if tb is not None:
+ tb.prefix = ""
+ exc_list = Attr(exc, Name('with_traceback')) + [ArgList([tb])]
+ else:
+ exc_list = [exc]
+
+ return pytree.Node(syms.raise_stmt,
+ [Name(u"raise")] + exc_list,
+ prefix=node.prefix)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_remove_old__future__imports.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_remove_old__future__imports.py
new file mode 100644
index 00000000..9336f75f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_remove_old__future__imports.py
@@ -0,0 +1,26 @@
+"""
+Fixer for removing any of these lines:
+
+ from __future__ import with_statement
+ from __future__ import nested_scopes
+ from __future__ import generators
+
+The reason is that __future__ imports like these are required to be the first
+line of code (after docstrings) on Python 2.6+, which can get in the way.
+
+These imports are always enabled in Python 2.6+, which is the minimum sane
+version to target for Py2/3 compatibility.
+"""
+
+from lib2to3 import fixer_base
+from libfuturize.fixer_util import remove_future_import
+
+class FixRemoveOldFutureImports(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "file_input"
+ run_order = 1
+
+ def transform(self, node, results):
+ remove_future_import(u"with_statement", node)
+ remove_future_import(u"nested_scopes", node)
+ remove_future_import(u"generators", node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_keep_u.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_keep_u.py
new file mode 100644
index 00000000..2e9a4e47
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_keep_u.py
@@ -0,0 +1,24 @@
+"""Fixer that changes unicode to str and unichr to chr, but -- unlike the
+lib2to3 fix_unicode.py fixer, does not change u"..." into "...".
+
+The reason is that Py3.3+ supports the u"..." string prefix, and, if
+present, the prefix may provide useful information for disambiguating
+between byte strings and unicode strings, which is often the hardest part
+of the porting task.
+
+"""
+
+from lib2to3.pgen2 import token
+from lib2to3 import fixer_base
+
+_mapping = {u"unichr" : u"chr", u"unicode" : u"str"}
+
+class FixUnicodeKeepU(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "'unicode' | 'unichr'"
+
+ def transform(self, node, results):
+ if node.type == token.NAME:
+ new = node.clone()
+ new.value = _mapping[node.value]
+ return new
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_literals_import.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_literals_import.py
new file mode 100644
index 00000000..51c50620
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_unicode_literals_import.py
@@ -0,0 +1,18 @@
+"""
+Adds this import:
+
+ from __future__ import unicode_literals
+
+"""
+
+from lib2to3 import fixer_base
+from libfuturize.fixer_util import future_import
+
+class FixUnicodeLiteralsImport(fixer_base.BaseFix):
+ BM_compatible = True
+ PATTERN = "file_input"
+
+ run_order = 9
+
+ def transform(self, node, results):
+ future_import(u"unicode_literals", node)
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_xrange_with_import.py b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_xrange_with_import.py
new file mode 100644
index 00000000..c910f816
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/fixes/fix_xrange_with_import.py
@@ -0,0 +1,20 @@
+"""
+For the ``future`` package.
+
+Turns any xrange calls into range calls and adds this import line:
+
+ from builtins import range
+
+at the top.
+"""
+
+from lib2to3.fixes.fix_xrange import FixXrange
+
+from libfuturize.fixer_util import touch_import_top
+
+
+class FixXrangeWithImport(FixXrange):
+ def transform(self, node, results):
+ result = super(FixXrangeWithImport, self).transform(node, results)
+ touch_import_top('builtins', 'range', node)
+ return result
diff --git a/.venv/lib/python3.12/site-packages/libfuturize/main.py b/.venv/lib/python3.12/site-packages/libfuturize/main.py
new file mode 100644
index 00000000..634c2f25
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/libfuturize/main.py
@@ -0,0 +1,322 @@
+"""
+futurize: automatic conversion to clean 2/3 code using ``python-future``
+======================================================================
+
+Like Armin Ronacher's modernize.py, ``futurize`` attempts to produce clean
+standard Python 3 code that runs on both Py2 and Py3.
+
+One pass
+--------
+
+Use it like this on Python 2 code:
+
+ $ futurize --verbose mypython2script.py
+
+This will attempt to port the code to standard Py3 code that also
+provides Py2 compatibility with the help of the right imports from
+``future``.
+
+To write changes to the files, use the -w flag.
+
+Two stages
+----------
+
+The ``futurize`` script can also be called in two separate stages. First:
+
+ $ futurize --stage1 mypython2script.py
+
+This produces more modern Python 2 code that is not yet compatible with Python
+3. The tests should still run and the diff should be uncontroversial to apply to
+most Python projects that are willing to drop support for Python 2.5 and lower.
+
+After this, the recommended approach is to explicitly mark all strings that must
+be byte-strings with a b'' prefix and all text (unicode) strings with a u''
+prefix, and then invoke the second stage of Python 2 to 2/3 conversion with::
+
+ $ futurize --stage2 mypython2script.py
+
+Stage 2 adds a dependency on ``future``. It converts most remaining Python
+2-specific code to Python 3 code and adds appropriate imports from ``future``
+to restore Py2 support.
+
+The command above leaves all unadorned string literals as native strings
+(byte-strings on Py2, unicode strings on Py3). If instead you would like all
+unadorned string literals to be promoted to unicode, you can also pass this
+flag:
+
+ $ futurize --stage2 --unicode-literals mypython2script.py
+
+This adds the declaration ``from __future__ import unicode_literals`` to the
+top of each file, which implicitly declares all unadorned string literals to be
+unicode strings (``unicode`` on Py2).
+
+All imports
+-----------
+
+The --all-imports option forces adding all ``__future__`` imports,
+``builtins`` imports, and standard library aliases, even if they don't
+seem necessary for the current state of each module. (This can simplify
+testing, and can reduce the need to think about Py2 compatibility when editing
+the code further.)
+
+"""
+
+from __future__ import (absolute_import, print_function, unicode_literals)
+import future.utils
+from future import __version__
+
+import sys
+import logging
+import optparse
+import os
+
+from lib2to3.main import warn, StdoutRefactoringTool
+from lib2to3 import refactor
+
+from libfuturize.fixes import (lib2to3_fix_names_stage1,
+ lib2to3_fix_names_stage2,
+ libfuturize_fix_names_stage1,
+ libfuturize_fix_names_stage2)
+
+fixer_pkg = 'libfuturize.fixes'
+
+
+def main(args=None):
+ """Main program.
+
+ Args:
+ fixer_pkg: the name of a package where the fixers are located.
+ args: optional; a list of command line arguments. If omitted,
+ sys.argv[1:] is used.
+
+ Returns a suggested exit status (0, 1, 2).
+ """
+
+ # Set up option parser
+ parser = optparse.OptionParser(usage="futurize [options] file|dir ...")
+ parser.add_option("-V", "--version", action="store_true",
+ help="Report the version number of futurize")
+ parser.add_option("-a", "--all-imports", action="store_true",
+ help="Add all __future__ and future imports to each module")
+ parser.add_option("-1", "--stage1", action="store_true",
+ help="Modernize Python 2 code only; no compatibility with Python 3 (or dependency on ``future``)")
+ parser.add_option("-2", "--stage2", action="store_true",
+ help="Take modernized (stage1) code and add a dependency on ``future`` to provide Py3 compatibility.")
+ parser.add_option("-0", "--both-stages", action="store_true",
+ help="Apply both stages 1 and 2")
+ parser.add_option("-u", "--unicode-literals", action="store_true",
+ help="Add ``from __future__ import unicode_literals`` to implicitly convert all unadorned string literals '' into unicode strings")
+ parser.add_option("-f", "--fix", action="append", default=[],
+ help="Each FIX specifies a transformation; default: all.\nEither use '-f division -f metaclass' etc. or use the fully-qualified module name: '-f lib2to3.fixes.fix_types -f libfuturize.fixes.fix_unicode_keep_u'")
+ parser.add_option("-j", "--processes", action="store", default=1,
+ type="int", help="Run 2to3 concurrently")
+ parser.add_option("-x", "--nofix", action="append", default=[],
+ help="Prevent a fixer from being run.")
+ parser.add_option("-l", "--list-fixes", action="store_true",
+ help="List available transformations")
+ parser.add_option("-p", "--print-function", action="store_true",
+ help="Modify the grammar so that print() is a function")
+ parser.add_option("-v", "--verbose", action="store_true",
+ help="More verbose logging")
+ parser.add_option("--no-diffs", action="store_true",
+ help="Don't show diffs of the refactoring")
+ parser.add_option("-w", "--write", action="store_true",
+ help="Write back modified files")
+ parser.add_option("-n", "--nobackups", action="store_true", default=False,
+ help="Don't write backups for modified files.")
+ parser.add_option("-o", "--output-dir", action="store", type="str",
+ default="", help="Put output files in this directory "
+ "instead of overwriting the input files. Requires -n. "
+ "For Python >= 2.7 only.")
+ parser.add_option("-W", "--write-unchanged-files", action="store_true",
+ help="Also write files even if no changes were required"
+ " (useful with --output-dir); implies -w.")
+ parser.add_option("--add-suffix", action="store", type="str", default="",
+ help="Append this string to all output filenames."
+ " Requires -n if non-empty. For Python >= 2.7 only."
+ "ex: --add-suffix='3' will generate .py3 files.")
+
+ # Parse command line arguments
+ flags = {}
+ refactor_stdin = False
+ options, args = parser.parse_args(args)
+
+ if options.write_unchanged_files:
+ flags["write_unchanged_files"] = True
+ if not options.write:
+ warn("--write-unchanged-files/-W implies -w.")
+ options.write = True
+ # If we allowed these, the original files would be renamed to backup names
+ # but not replaced.
+ if options.output_dir and not options.nobackups:
+ parser.error("Can't use --output-dir/-o without -n.")
+ if options.add_suffix and not options.nobackups:
+ parser.error("Can't use --add-suffix without -n.")
+
+ if not options.write and options.no_diffs:
+ warn("not writing files and not printing diffs; that's not very useful")
+ if not options.write and options.nobackups:
+ parser.error("Can't use -n without -w")
+ if "-" in args:
+ refactor_stdin = True
+ if options.write:
+ print("Can't write to stdin.", file=sys.stderr)
+ return 2
+ # Is this ever necessary?
+ if options.print_function:
+ flags["print_function"] = True
+
+ # Set up logging handler
+ level = logging.DEBUG if options.verbose else logging.INFO
+ logging.basicConfig(format='%(name)s: %(message)s', level=level)
+ logger = logging.getLogger('libfuturize.main')
+
+ if options.stage1 or options.stage2:
+ assert options.both_stages is None
+ options.both_stages = False
+ else:
+ options.both_stages = True
+
+ avail_fixes = set()
+
+ if options.stage1 or options.both_stages:
+ avail_fixes.update(lib2to3_fix_names_stage1)
+ avail_fixes.update(libfuturize_fix_names_stage1)
+ if options.stage2 or options.both_stages:
+ avail_fixes.update(lib2to3_fix_names_stage2)
+ avail_fixes.update(libfuturize_fix_names_stage2)
+
+ if options.unicode_literals:
+ avail_fixes.add('libfuturize.fixes.fix_unicode_literals_import')
+
+ if options.version:
+ print(__version__)
+ return 0
+ if options.list_fixes:
+ print("Available transformations for the -f/--fix option:")
+ # for fixname in sorted(refactor.get_all_fix_names(fixer_pkg)):
+ for fixname in sorted(avail_fixes):
+ print(fixname)
+ if not args:
+ return 0
+ if not args:
+ print("At least one file or directory argument required.",
+ file=sys.stderr)
+ print("Use --help to show usage.", file=sys.stderr)
+ return 2
+
+ unwanted_fixes = set()
+ for fix in options.nofix:
+ if ".fix_" in fix:
+ unwanted_fixes.add(fix)
+ else:
+ # Infer the full module name for the fixer.
+ # First ensure that no names clash (e.g.
+ # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah):
+ found = [f for f in avail_fixes
+ if f.endswith('fix_{0}'.format(fix))]
+ if len(found) > 1:
+ print("Ambiguous fixer name. Choose a fully qualified "
+ "module name instead from these:\n" +
+ "\n".join(" " + myf for myf in found),
+ file=sys.stderr)
+ return 2
+ elif len(found) == 0:
+ print("Unknown fixer. Use --list-fixes or -l for a list.",
+ file=sys.stderr)
+ return 2
+ unwanted_fixes.add(found[0])
+
+ extra_fixes = set()
+ if options.all_imports:
+ if options.stage1:
+ prefix = 'libfuturize.fixes.'
+ extra_fixes.add(prefix +
+ 'fix_add__future__imports_except_unicode_literals')
+ else:
+ # In case the user hasn't run stage1 for some reason:
+ prefix = 'libpasteurize.fixes.'
+ extra_fixes.add(prefix + 'fix_add_all__future__imports')
+ extra_fixes.add(prefix + 'fix_add_future_standard_library_import')
+ extra_fixes.add(prefix + 'fix_add_all_future_builtins')
+ explicit = set()
+ if options.fix:
+ all_present = False
+ for fix in options.fix:
+ if fix == 'all':
+ all_present = True
+ else:
+ if ".fix_" in fix:
+ explicit.add(fix)
+ else:
+ # Infer the full module name for the fixer.
+ # First ensure that no names clash (e.g.
+ # lib2to3.fixes.fix_blah and libfuturize.fixes.fix_blah):
+ found = [f for f in avail_fixes
+ if f.endswith('fix_{0}'.format(fix))]
+ if len(found) > 1:
+ print("Ambiguous fixer name. Choose a fully qualified "
+ "module name instead from these:\n" +
+ "\n".join(" " + myf for myf in found),
+ file=sys.stderr)
+ return 2
+ elif len(found) == 0:
+ print("Unknown fixer. Use --list-fixes or -l for a list.",
+ file=sys.stderr)
+ return 2
+ explicit.add(found[0])
+ if len(explicit & unwanted_fixes) > 0:
+ print("Conflicting usage: the following fixers have been "
+ "simultaneously requested and disallowed:\n" +
+ "\n".join(" " + myf for myf in (explicit & unwanted_fixes)),
+ file=sys.stderr)
+ return 2
+ requested = avail_fixes.union(explicit) if all_present else explicit
+ else:
+ requested = avail_fixes.union(explicit)
+ fixer_names = (requested | extra_fixes) - unwanted_fixes
+
+ input_base_dir = os.path.commonprefix(args)
+ if (input_base_dir and not input_base_dir.endswith(os.sep)
+ and not os.path.isdir(input_base_dir)):
+ # One or more similar names were passed, their directory is the base.
+ # os.path.commonprefix() is ignorant of path elements, this corrects
+ # for that weird API.
+ input_base_dir = os.path.dirname(input_base_dir)
+ if options.output_dir:
+ input_base_dir = input_base_dir.rstrip(os.sep)
+ logger.info('Output in %r will mirror the input directory %r layout.',
+ options.output_dir, input_base_dir)
+
+ # Initialize the refactoring tool
+ if future.utils.PY26:
+ extra_kwargs = {}
+ else:
+ extra_kwargs = {
+ 'append_suffix': options.add_suffix,
+ 'output_dir': options.output_dir,
+ 'input_base_dir': input_base_dir,
+ }
+
+ rt = StdoutRefactoringTool(
+ sorted(fixer_names), flags, sorted(explicit),
+ options.nobackups, not options.no_diffs,
+ **extra_kwargs)
+
+ # Refactor all files and directories passed as arguments
+ if not rt.errors:
+ if refactor_stdin:
+ rt.refactor_stdin()
+ else:
+ try:
+ rt.refactor(args, options.write, None,
+ options.processes)
+ except refactor.MultiprocessingUnsupported:
+ assert options.processes > 1
+ print("Sorry, -j isn't " \
+ "supported on this platform.", file=sys.stderr)
+ return 1
+ rt.summarize()
+
+ # Return error status (0 if rt.errors is zero)
+ return int(bool(rt.errors))