=== added file 'lib2to3/fixes/fix_userdict.py' --- lib2to3/fixes/fix_userdict.py 1970-01-01 00:00:00 +0000 +++ lib2to3/fixes/fix_userdict.py 2008-09-27 16:03:13 +0000 @@ -0,0 +1,134 @@ +"""Fix UserDict superclass change. Can also serve as a template + for similar changes to other classes. +""" +# Author: Nick Edds + +#Local imports +from .fix_imports import alternates, FixImports +from .. import fixer_base +from ..fixer_util import FromImport, Name, Comma, Newline + +METHODS = {'UserDict' : 'Deprecated', + 'IterableUserDict' : 'UserDict', + 'Mixin' : 'MutableMapping', +} + +OLD = 'UserDict' +NEW = 'collections' + +DEPRECATIONS = [key for key in METHODS.keys() if METHODS[key] == 'Deprecated'] + +def build_pattern(): + """ + This pattern can be similarly applied to other superclass changes. + """ + old_methods = alternates(METHODS.keys()) + yield """import_name< 'import' (super=%r + | dotted_as_names< any* super=%r any* >) > + """ % (OLD, OLD) + yield """import_from< 'from' from_super=%r 'import' + ( member=%s | import_as_name< member=%s 'as' any > | + import_as_names< members=any* >) > + """ % (OLD, old_methods, old_methods) + yield """import_from< 'from' super=%r 'import' star='*' > + """ % OLD + yield """import_name< 'import' + dotted_as_name< super=%r 'as' any > > + """ % OLD + yield """power< super_dot=%r trailer< '.' member=%s > any* > + """ % (OLD, old_methods) + + +class FixUserdict(FixImports): + PATTERN = "|".join(build_pattern()) + + def transform_import(self, node, results): + """Transform for the basic import case. Replaces the old + import name with the new one, and warns of any deprecations. + """ + import_super = results.get('super') + self.replace[import_super.value] = NEW + import_super.replace(Name(NEW, prefix=import_super.get_prefix())) + if DEPRECATIONS: + self.warning(node, 'This contains deprecated classes: %s' % + DEPRECATIONS) + + def transform_member(self, node, results): + """Transform for imports of specific module elements. Replaces + the module to be imported from and changes names and gives + deprecation warnings as appropriate. + """ + from_super = results.get('from_super') + pref = from_super.get_prefix() + member = results.get('member') + + # Only a single member is being imported + if member: + # this may be a list of length one, or just a node + if isinstance(member, list): + member = member[0] + if member.value in DEPRECATIONS: + self.warning(node, 'This is a deprecated import.') + else: + self.replace[from_super.value] = NEW + from_super.replace(Name(NEW, prefix=pref)) + self.replace[member.value] = METHODS[member.value] + member.replace(Name(METHODS[member.value], + prefix=member.get_prefix())) + + # Multiple members being imported + else: + new_members = [] + members = results.get('members') + for member in members: + m_pref = member.get_prefix() + member = member.value + # we only care about the actual members + if member != ',': + if member in DEPRECATIONS: + self.warning(node, '%s is deprecated' % member) + elif member in METHODS.keys(): + new_members.append((member, m_pref)) + if new_members: + self.replace[from_super.value] = NEW + names = [] + for member in new_members[:-1]: + names.extend([Name(METHODS[member[0]], prefix=member[1]), + Comma()]) + names.append(Name(METHODS[new_members[-1][0]], + prefix=new_members[-1][1])) + node.replace(FromImport(NEW, names)) + else: + self.warning(node, 'This is a deprecated import.') + + def transform_dot(self, node, results): + """Transform for calls to specific module elements in code. + Does not currently handle cases where the superclass is + imported as a different name. + """ + super_dot = results.get('super_dot') + member = results.get('member') + # this may be a list of length one, or just a node + if isinstance(member, list): + member = member[0] + if member.value in DEPRECATIONS: + self.warning(node, '%s is deprecated' % member) + else: + self.replace[super_dot.value] = NEW + super_dot.replace(Name(NEW, prefix=super_dot.get_prefix())) + new_val = METHODS[member.value] + self.replace[member.value] = new_val + member.replace(Name(new_val, prefix=member.get_prefix())) + + def transform(self, node, results): + import_super = results.get('super') + from_super = results.get('from_super') + + if results.get('super'): + self.transform_import(node, results) + elif results.get('from_super'): + self.transform_member(node, results) + elif results.get('super_dot'): + self.transform_dot(node, results) + + === modified file 'lib2to3/tests/test_fixers.py' --- lib2to3/tests/test_fixers.py 2008-08-04 15:51:12 +0000 +++ lib2to3/tests/test_fixers.py 2008-09-27 16:22:37 +0000 @@ -1483,6 +1483,72 @@ self.modules[key] = mapping1[key] +class Test_userdict(FixerTestCase): + """These test cases can be used as a template for testing + similar fixers. + """ + fixer = "userdict" + from ..fixes.fix_userdict import METHODS, OLD, NEW, DEPRECATIONS + + def test_import_module(self): + b = "import %s" % self.OLD + a = "import %s" % self.NEW + if self.DEPRECATIONS: + self.warns(b, a, "This contains deprecated classes: %s" + % self.DEPRECATIONS) + else: + self.check(b, a) + + def test_import_from(self): + # all the non-warning keys must be tested first + for key in self.METHODS.keys(): + if not key in self.DEPRECATIONS: + b = "from %s import %s" % (self.OLD, key) + a = "from %s import %s" % (self.NEW, self.METHODS[key]) + self.check(b, a) + for key in self.DEPRECATIONS: + b = "from %s import %s" % (self.OLD, key) + self.warns_unchanged(b, "This is a deprecated import.") + + b = "from %s import %s" % (self.OLD, ', '.join(self.METHODS.keys())) + a = "from %s import %s" % (self.NEW, ', '.join([val for val in + self.METHODS.values() if val + != "Deprecated"])) + if self.DEPRECATIONS: + for dep in self.DEPRECATIONS: + self.warns(b, a, "%s is deprecated" % dep) + else: + self.check(b, a) + + def test_import_module_as(self): + b = "import %s as foo" % self.OLD + a = "import %s as foo" % self.NEW + if self.DEPRECATIONS: + self.warns(b, a, "This contains deprecated classes: %s" + % self.DEPRECATIONS) + else: + self.check(b, a) + + def test_import_from_as(self): + for key in self.METHODS.keys(): + if not key in self.DEPRECATIONS: + b = "from %s import %s as foo" % (self.OLD, key) + a = "from %s import %s as foo" % (self.NEW, self.METHODS[key]) + self.check(b, a) + for key in self.DEPRECATIONS: + b = "from %s import %s as foo" % (self.OLD, key) + self.warns_unchanged(b, "This is a deprecated import.") + + def test_import_module_usage(self): + for key in self.METHODS.keys(): + if not key in self.DEPRECATIONS: + b = "foo(%s.%s)" % (self.OLD, key) + a = "foo(%s.%s)" % (self.NEW, self.METHODS[key]) + self.check(b, a) + for key in self.DEPRECATIONS: + b = "foo(%s.%s)" % (self.OLD, key) + self.warns_unchanged(b, "%s is deprecated" % key) + class Test_urllib(FixerTestCase): fixer = "urllib" from ..fixes.fix_urllib import MAPPING as modules