Mercurial > hg
changeset 28400:a84fc98a8af5
contrib: remove references to 2to3
The custom porting fixers are removed. A comment related to 2to3
has been removed from the import checker.
After this patch, no references to 2to3 remain.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Sat, 27 Feb 2016 21:15:16 -0800 |
parents | 2af0156cebaa |
children | 2565fe39a76c |
files | contrib/hgfixes/__init__.py contrib/hgfixes/fix_bytes.py contrib/hgfixes/fix_bytesmod.py contrib/hgfixes/fix_leftover_imports.py contrib/import-checker.py tests/test-check-py3-compat.t |
diffstat | 5 files changed, 0 insertions(+), 275 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/hgfixes/fix_bytes.py Sat Feb 27 21:14:17 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -"""Fixer that changes plain strings to bytes strings.""" - -import re - -from lib2to3 import fixer_base -from lib2to3.pgen2 import token -from lib2to3.fixer_util import Name -from lib2to3.pygram import python_symbols as syms - -_re = re.compile(r'[rR]?[\'\"]') - -# XXX: Implementing a blacklist in 2to3 turned out to be more troublesome than -# blacklisting some modules inside the fixers. So, this is what I came with. - -blacklist = ('mercurial/demandimport.py', - 'mercurial/py3kcompat.py', # valid python 3 already - 'mercurial/i18n.py', - ) - -def isdocstring(node): - def isclassorfunction(ancestor): - symbols = (syms.funcdef, syms.classdef) - # if the current node is a child of a function definition, a class - # definition or a file, then it is a docstring - if ancestor.type == syms.simple_stmt: - try: - while True: - if ancestor.type in symbols: - return True - ancestor = ancestor.parent - except AttributeError: - return False - return False - - def ismodule(ancestor): - # Our child is a docstring if we are a simple statement, and our - # ancestor is file_input. In other words, our child is a lone string in - # the source file. - try: - if (ancestor.type == syms.simple_stmt and - ancestor.parent.type == syms.file_input): - return True - except AttributeError: - return False - - def isdocassignment(ancestor): - # Assigning to __doc__, definitely a string - try: - while True: - if (ancestor.type == syms.expr_stmt and - Name('__doc__') in ancestor.children): - return True - ancestor = ancestor.parent - except AttributeError: - return False - - if ismodule(node.parent) or \ - isdocassignment(node.parent) or \ - isclassorfunction(node.parent): - return True - return False - -def shouldtransform(node): - specialnames = ['__main__'] - - if node.value in specialnames: - return False - - ggparent = node.parent.parent.parent - sggparent = str(ggparent) - - if 'getattr' in sggparent or \ - 'hasattr' in sggparent or \ - 'setattr' in sggparent or \ - 'encode' in sggparent or \ - 'decode' in sggparent: - return False - - return True - -class FixBytes(fixer_base.BaseFix): - - PATTERN = 'STRING' - - def transform(self, node, results): - # The filename may be prefixed with a build directory. - if self.filename.endswith(blacklist): - return - if node.type == token.STRING: - if _re.match(node.value): - if isdocstring(node): - return - if not shouldtransform(node): - return - new = node.clone() - new.value = 'b' + new.value - return new -
--- a/contrib/hgfixes/fix_bytesmod.py Sat Feb 27 21:14:17 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -"""Fixer that changes bytes % whatever to a function that actually formats -it.""" - -from lib2to3 import fixer_base -from lib2to3.fixer_util import is_tuple, Call, Comma, Name, touch_import - -# XXX: Implementing a blacklist in 2to3 turned out to be more troublesome than -# blacklisting some modules inside the fixers. So, this is what I came with. - -blacklist = ['mercurial/demandimport.py', - 'mercurial/py3kcompat.py', - 'mercurial/i18n.py', - ] - -def isnumberremainder(formatstr, data): - try: - if data.value.isdigit(): - return True - except AttributeError: - return False - -class FixBytesmod(fixer_base.BaseFix): - # XXX: There's one case (I suppose) I can't handle: when a remainder - # operation like foo % bar is performed, I can't really know what the - # contents of foo and bar are. I believe the best approach is to "correct" - # the to-be-converted code and let bytesformatter handle that case in - # runtime. - PATTERN = ''' - term< formatstr=STRING '%' data=STRING > | - term< formatstr=STRING '%' data=atom > | - term< formatstr=NAME '%' data=any > | - term< formatstr=any '%' data=any > - ''' - - def transform(self, node, results): - for bfn in blacklist: - if self.filename.endswith(bfn): - return - if not self.filename.endswith('mercurial/py3kcompat.py'): - touch_import('mercurial', 'py3kcompat', node=node) - - formatstr = results['formatstr'].clone() - data = results['data'].clone() - formatstr.prefix = '' # remove spaces from start - - if isnumberremainder(formatstr, data): - return - - # We have two possibilities: - # 1- An identifier or name is passed, it is going to be a leaf, thus, we - # just need to copy its value as an argument to the formatter; - # 2- A tuple is explicitly passed. In this case, we're gonna explode it - # to pass to the formatter - # TODO: Check for normal strings. They don't need to be translated - - if is_tuple(data): - args = [formatstr, Comma().clone()] + \ - [c.clone() for c in data.children[:]] - else: - args = [formatstr, Comma().clone(), data] - - call = Call(Name('bytesformatter', prefix=' '), args) - return call
--- a/contrib/hgfixes/fix_leftover_imports.py Sat Feb 27 21:14:17 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -"Fixer that translates some APIs ignored by the default 2to3 fixers." - -# FIXME: This fixer has some ugly hacks. Its main design is based on that of -# fix_imports, from lib2to3. Unfortunately, the fix_imports framework only -# changes module names "without dots", meaning it won't work for some changes -# in the email module/package. Thus this fixer was born. I believe that with a -# bit more thinking, a more generic fixer can be implemented, but I'll leave -# that as future work. - -from lib2to3.fixer_util import Name -from lib2to3.fixes import fix_imports - -# This maps the old names to the new names. Note that a drawback of the current -# design is that the dictionary keys MUST have EXACTLY one dot (.) in them, -# otherwise things will break. (If you don't need a module hierarchy, you're -# better of just inherit from fix_imports and overriding the MAPPING dict.) - -MAPPING = {'email.Utils': 'email.utils', - 'email.Errors': 'email.errors', - 'email.Header': 'email.header', - 'email.Parser': 'email.parser', - 'email.Encoders': 'email.encoders', - 'email.MIMEText': 'email.mime.text', - 'email.MIMEBase': 'email.mime.base', - 'email.Generator': 'email.generator', - 'email.MIMEMultipart': 'email.mime.multipart', -} - -def alternates(members): - return "(" + "|".join(map(repr, members)) + ")" - -def build_pattern(mapping=MAPPING): - packages = {} - for key in mapping: - # What we are doing here is the following: with dotted names, we'll - # have something like package_name <trailer '.' module>. Then, we are - # making a dictionary to copy this structure. For example, if - # mapping={'A.B': 'a.b', 'A.C': 'a.c'}, it will generate the dictionary - # {'A': ['b', 'c']} to, then, generate something like "A <trailer '.' - # ('b' | 'c')". - name = key.split('.') - prefix = name[0] - if prefix in packages: - packages[prefix].append(name[1:][0]) - else: - packages[prefix] = name[1:] - - mod_list = ' | '.join(["'%s' '.' ('%s')" % - (key, "' | '".join(packages[key])) for key in packages]) - mod_list = '(' + mod_list + ' )' - - yield """name_import=import_name< 'import' module_name=dotted_name< %s > > - """ % mod_list - - yield """name_import=import_name< 'import' - multiple_imports=dotted_as_names< any* - module_name=dotted_name< %s > - any* > - >""" % mod_list - - packs = ' | '.join(["'%s' trailer<'.' ('%s')>" % (key, - "' | '".join(packages[key])) for key in packages]) - - yield "power< package=(%s) trailer<'.' any > any* >" % packs - -class FixLeftoverImports(fix_imports.FixImports): - # We want to run this fixer after fix_import has run (this shouldn't matter - # for hg, though, as setup3k prefers to run the default fixers first) - mapping = MAPPING - - def build_pattern(self): - return "|".join(build_pattern(self.mapping)) - - def transform(self, node, results): - # Mostly copied from fix_imports.py - import_mod = results.get("module_name") - if import_mod: - try: - mod_name = import_mod.value - except AttributeError: - # XXX: A hack to remove whitespace prefixes and suffixes - mod_name = str(import_mod).strip() - new_name = 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. - # Now this is, mostly, a hack - bare_name = results["package"][0] - bare_name_text = ''.join(map(str, results['package'])).strip() - new_name = self.replace.get(bare_name_text) - prefix = results['package'][0].prefix - if new_name: - bare_name.replace(Name(new_name, prefix=prefix)) - results["package"][1].replace(Name('')) -
--- a/contrib/import-checker.py Sat Feb 27 21:14:17 2016 -0800 +++ b/contrib/import-checker.py Sat Feb 27 21:15:16 2016 -0800 @@ -495,10 +495,6 @@ """Given some python source, verify that stdlib imports are done in separate statements from relative local module imports. - Observing this limitation is important as it works around an - annoying lib2to3 bug in relative import rewrites: - http://bugs.python.org/issue19510. - >>> list(verify_stdlib_on_own_line(ast.parse('import sys, foo'))) [('mixed imports\\n stdlib: sys\\n relative: foo', 1)] >>> list(verify_stdlib_on_own_line(ast.parse('import sys, os')))
--- a/tests/test-check-py3-compat.t Sat Feb 27 21:14:17 2016 -0800 +++ b/tests/test-check-py3-compat.t Sat Feb 27 21:15:16 2016 -0800 @@ -6,9 +6,6 @@ contrib/check-code.py not using absolute_import contrib/check-code.py requires print_function contrib/debugshell.py not using absolute_import - contrib/hgfixes/fix_bytes.py not using absolute_import - contrib/hgfixes/fix_bytesmod.py not using absolute_import - contrib/hgfixes/fix_leftover_imports.py not using absolute_import contrib/import-checker.py not using absolute_import contrib/import-checker.py requires print_function contrib/memory.py not using absolute_import