diff options
| author | Zubin Mithra <zubin.mithra@gmail.com> | 2010-07-17 02:24:57 +0530 |
|---|---|---|
| committer | Zubin Mithra <zubin.mithra@gmail.com> | 2010-07-17 02:24:57 +0530 |
| commit | a61d1d3469e871109ba07a2d0aba18160091520f (patch) | |
| tree | dbdb56bd4b2835df9b81c6c6d7f9edc5d6afdb96 /src/distutils2 | |
| parent | af8e2f4cc796a70fb942933c620039ec9ed16106 (diff) | |
| parent | 06a90309a179c76ef8a34944a17cc0a3e8b31832 (diff) | |
| download | disutils2-a61d1d3469e871109ba07a2d0aba18160091520f.tar.gz | |
Updated with Tareks branch
Diffstat (limited to 'src/distutils2')
| -rw-r--r-- | src/distutils2/command/build_py.py | 15 | ||||
| -rw-r--r-- | src/distutils2/core.py | 4 | ||||
| -rw-r--r-- | src/distutils2/dist.py | 5 | ||||
| -rw-r--r-- | src/distutils2/tests/fixer/__init__.py | 0 | ||||
| -rw-r--r-- | src/distutils2/tests/fixer/fix_idioms.py | 134 | ||||
| -rw-r--r-- | src/distutils2/tests/test_Mixin2to3.py | 18 | ||||
| -rw-r--r-- | src/distutils2/tests/test_util.py | 15 | ||||
| -rw-r--r-- | src/distutils2/util.py | 22 |
8 files changed, 199 insertions, 14 deletions
diff --git a/src/distutils2/command/build_py.py b/src/distutils2/command/build_py.py index 736c35e..c4f953d 100644 --- a/src/distutils2/command/build_py.py +++ b/src/distutils2/command/build_py.py @@ -19,6 +19,7 @@ __all__ = ['Mixin2to3', 'build_py'] try: from distutils2.util import Mixin2to3 as _Mixin2to3 + from distutils2 import run_2to3_on_doctests from lib2to3.refactor import get_fixers_from_package _CONVERT = True _KLASS = _Mixin2to3 @@ -33,13 +34,16 @@ class Mixin2to3(_KLASS): yet does nothing in particular with it. """ if _CONVERT: - def _run_2to3(self, files, doctests=[]): + def _run_2to3(self, files, doctests=[], fixers=[]): """ Takes a list of files and doctests, and performs conversion on those. - First, the files which contain the code(`files`) are converted. - Second, the doctests in `files` are converted. - Thirdly, the doctests in `doctests` are converted. """ + # if additional fixers are present, use them + if fixers: + self.fixer_names = fixers # Convert the ".py" files. logging.info("Converting Python code") @@ -56,12 +60,12 @@ class Mixin2to3(_KLASS): # containing doctests. It is set as # distutils2.run_2to3_on_doctests - if doctests != [] and distutils2.run_2to3_on_doctests: + if doctests != [] and run_2to3_on_doctests: logging.info("Converting text files which contain doctests") _KLASS.run_2to3(self, doctests, doctests_only=True) else: # If run on Python 2.x, there is nothing to do. - def _run_2to3(self, files, doctests=[]): + def _run_2to3(self, files, doctests=[], fixers=[]): pass class build_py(Command, Mixin2to3): @@ -146,8 +150,9 @@ class build_py(Command, Mixin2to3): self.build_packages() self.build_package_data() - if self.distribution.use_2to3 and self_updated_files: - self.run_2to3(self._updated_files, self._doctests_2to3) + if self.distribution.use_2to3 and self._updated_files: + self.run_2to3(self._updated_files, self._doctests_2to3, + self.distribution.use_2to3_fixers) self.byte_compile(self.get_outputs(include_bytecode=0)) diff --git a/src/distutils2/core.py b/src/distutils2/core.py index a81780b..eb368f8 100644 --- a/src/distutils2/core.py +++ b/src/distutils2/core.py @@ -49,8 +49,8 @@ setup_keywords = ('distclass', 'script_name', 'script_args', 'options', 'maintainer', 'maintainer_email', 'url', 'license', 'description', 'long_description', 'keywords', 'platforms', 'classifiers', 'download_url', - 'requires', 'provides', 'obsoletes', 'use_2to3', - 'convert_2to3_doctests', + 'requires', 'provides', 'obsoletes', 'use_2to3_fixers', + 'convert_2to3_doctests', 'use_2to3_fixers' ) # Legal keyword arguments for the Extension constructor diff --git a/src/distutils2/dist.py b/src/distutils2/dist.py index 96c4133..e0e2ea5 100644 --- a/src/distutils2/dist.py +++ b/src/distutils2/dist.py @@ -116,7 +116,9 @@ Common commands: (see '--help-commands' for more) ('use-2to3', None, "use 2to3 to make source python 3.x compatible"), ('convert-2to3-doctests', None, - "use 2to3 to convert doctests in seperate text files"), + "use 2to3 to convert doctests in seperate text files"), + ('use-2to3-fixers', None, + "list additional fixers opted for during 2to3 conversion") ] display_option_names = map(lambda x: translate_longopt(x[0]), display_options) @@ -212,6 +214,7 @@ Common commands: (see '--help-commands' for more) self.password = '' self.use_2to3 = False self.convert_2to3_doctests = [] + self.use_2to3_fixers = [] # And now initialize bookkeeping stuff that can't be supplied by # the caller at all. 'command_obj' maps command names to diff --git a/src/distutils2/tests/fixer/__init__.py b/src/distutils2/tests/fixer/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/distutils2/tests/fixer/__init__.py diff --git a/src/distutils2/tests/fixer/fix_idioms.py b/src/distutils2/tests/fixer/fix_idioms.py new file mode 100644 index 0000000..9cfac51 --- /dev/null +++ b/src/distutils2/tests/fixer/fix_idioms.py @@ -0,0 +1,134 @@ +"""Adjust some old Python 2 idioms to their modern counterparts. + +* Change some type comparisons to isinstance() calls: + type(x) == T -> isinstance(x, T) + type(x) is T -> isinstance(x, T) + type(x) != T -> not isinstance(x, T) + type(x) is not T -> not isinstance(x, T) + +* Change "while 1:" into "while True:". + +* Change both + + v = list(EXPR) + v.sort() + foo(v) + +and the more general + + v = EXPR + v.sort() + foo(v) + +into + + v = sorted(EXPR) + foo(v) +""" +# Author: Jacques Frechet, Collin Winter + +# Local imports +from lib2to3 import fixer_base +from lib2to3.fixer_util import Call, Comma, Name, Node, syms + +CMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)" +TYPE = "power< 'type' trailer< '(' x=any ')' > >" + +class FixIdioms(fixer_base.BaseFix): + + explicit = False # The user must ask for this fixer + + PATTERN = r""" + isinstance=comparison< %s %s T=any > + | + isinstance=comparison< T=any %s %s > + | + while_stmt< 'while' while='1' ':' any+ > + | + sorted=any< + any* + simple_stmt< + expr_stmt< id1=any '=' + power< list='list' trailer< '(' (not arglist<any+>) any ')' > > + > + '\n' + > + sort= + simple_stmt< + power< id2=any + trailer< '.' 'sort' > trailer< '(' ')' > + > + '\n' + > + next=any* + > + | + sorted=any< + any* + simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' > + sort= + simple_stmt< + power< id2=any + trailer< '.' 'sort' > trailer< '(' ')' > + > + '\n' + > + next=any* + > + """ % (TYPE, CMP, CMP, TYPE) + + def match(self, node): + r = super(FixIdioms, self).match(node) + # If we've matched one of the sort/sorted subpatterns above, we + # want to reject matches where the initial assignment and the + # subsequent .sort() call involve different identifiers. + if r and "sorted" in r: + if r["id1"] == r["id2"]: + return r + return None + return r + + def transform(self, node, results): + if "isinstance" in results: + return self.transform_isinstance(node, results) + elif "while" in results: + return self.transform_while(node, results) + elif "sorted" in results: + return self.transform_sort(node, results) + else: + raise RuntimeError("Invalid match") + + def transform_isinstance(self, node, results): + x = results["x"].clone() # The thing inside of type() + T = results["T"].clone() # The type being compared against + x.set_prefix("") + T.set_prefix(" ") + test = Call(Name("isinstance"), [x, Comma(), T]) + if "n" in results: + test.set_prefix(" ") + test = Node(syms.not_test, [Name("not"), test]) + test.set_prefix(node.get_prefix()) + return test + + def transform_while(self, node, results): + one = results["while"] + one.replace(Name("True", prefix=one.get_prefix())) + + def transform_sort(self, node, results): + sort_stmt = results["sort"] + next_stmt = results["next"] + list_call = results.get("list") + simple_expr = results.get("expr") + + if list_call: + list_call.replace(Name("sorted", prefix=list_call.get_prefix())) + elif simple_expr: + new = simple_expr.clone() + new.set_prefix("") + simple_expr.replace(Call(Name("sorted"), [new], + prefix=simple_expr.get_prefix())) + else: + raise RuntimeError("should not have reached here") + sort_stmt.remove() + if next_stmt: + next_stmt[0].set_prefix(sort_stmt.get_prefix()) diff --git a/src/distutils2/tests/test_Mixin2to3.py b/src/distutils2/tests/test_Mixin2to3.py index a455fc2..f6d93cb 100644 --- a/src/distutils2/tests/test_Mixin2to3.py +++ b/src/distutils2/tests/test_Mixin2to3.py @@ -47,6 +47,24 @@ class Mixin2to3TestCase(support.TempdirManager, unittest.TestCase): self.assertEquals(new_doctest_content, converted_doctest_content) + @unittest.skipUnless(sys.version > '2.6', 'Need >= 2.6') + def test_additional_fixers(self): + # used to check if use_2to3_fixers works + from distutils2.tests import fixer + code_content = "type(x) is T" + code_handle = self.mktempfile() + code_name = code_handle.name + + code_handle.write(code_content) + code_handle.flush() + + mixin2to3 = Mixin2to3() + + mixin2to3._run_2to3([code_name], None, ['distutils2.tests.fixer']) + converted_code_content = "isinstance(x, T)" + new_code_content = "".join(open(code_name).readlines()) + self.assertEquals(new_code_content, converted_code_content) + def test_suite(): return unittest.makeSuite(Mixin2to3TestCase) diff --git a/src/distutils2/tests/test_util.py b/src/distutils2/tests/test_util.py index c770c59..88a5e41 100644 --- a/src/distutils2/tests/test_util.py +++ b/src/distutils2/tests/test_util.py @@ -332,6 +332,21 @@ class UtilTestCase(support.EnvironGuard, file_handle.close() self.assertEquals(new_content, converted_content) + @unittest.skipUnless(sys.version > '2.6', 'Need Python 2.6 or more') + def test_use_additional_fixers(self): + # to check if additional fixers work + content = "type(x) is T" + converted_content = "isinstance(x, T)" + file_handle = self.mktempfile() + file_name = file_handle.name + file_handle.write(content) + file_handle.flush() + file_handle.seek(0) + from distutils2.util import run_2to3 + run_2to3([file_name], None, ['distutils2.tests.fixer']) + new_content = "".join(file_handle.read()) + file_handle.close() + self.assertEquals(new_content, converted_content) def test_suite(): return unittest.makeSuite(UtilTestCase) diff --git a/src/distutils2/util.py b/src/distutils2/util.py index b9aa3f7..83045c7 100644 --- a/src/distutils2/util.py +++ b/src/distutils2/util.py @@ -644,7 +644,7 @@ def find_packages(paths=('.',), exclude=()): # utility functions for 2to3 support -def run_2to3(files, doctests_only=False, fixer_names=None, options=None, +def run_2to3(files=[], doctests_only=False, fixer_names=[], options=None, explicit=None): """ Wrapper function around the refactor() class which performs the conversions on a list of python files. @@ -658,10 +658,20 @@ def run_2to3(files, doctests_only=False, fixer_names=None, options=None, from lib2to3.refactor import get_fixers_from_package from distutils2.converter.refactor import DistutilsRefactoringTool - if fixer_names is None: - fixer_names = get_fixers_from_package('lib2to3.fixes') + fixers = [] + + # select only the 'default fixers' from the lib2to3 package + for fixer in get_fixers_from_package('lib2to3.fixes'): + if fixers not in ('lib2to3.fixes.fix_buffer', 'lib2to3.fixes.fix_idioms', + 'lib2to3.fixes.fix_numliterals', 'lib2to3.fixes.fix_set_literal', + 'lib2to3.fixes.fix_ws_comma'): + fixers.append(fixer) - r = DistutilsRefactoringTool(fixer_names, options=options) + if fixer_names != []: + for fixer_package in fixer_names: + fixers.extend(get_fixers_from_package(fixer_package)) + + r = DistutilsRefactoringTool(fixers, options=options) if doctests_only: r.refactor(files, doctests_only=True, write=True) else: @@ -676,7 +686,7 @@ class Mixin2to3: """ # provide list of fixers to run. # defaults to all from lib2to3.fixers - fixer_names = None + fixer_names = [] # options dictionary options = None @@ -687,4 +697,4 @@ class Mixin2to3: def run_2to3(self, files, doctests_only=False): """ Issues a call to util.run_2to3. """ return run_2to3(files, doctests_only, self.fixer_names, - self.options, self.explicit) + self.options, self.explicit)
\ No newline at end of file |
