aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py
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/fixer_util.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py')
-rw-r--r--.venv/lib/python3.12/site-packages/libfuturize/fixer_util.py518
1 files changed, 518 insertions, 0 deletions
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)