##// END OF EJS Templates
hgfixes: added a fixer to convert changes in the email package...
Renato Cunha -
r11949:626fe5c9 default
parent child Browse files
Show More
@@ -0,0 +1,108
1 "Fixer that translates some APIs ignored by the default 2to3 fixers."
2
3 # FIXME: This fixer has some ugly hacks. Its main design is based on that of
4 # fix_imports, from lib2to3. Unfortunately, the fix_imports framework only
5 # changes module names "without dots", meaning it won't work for some changes
6 # in the email module/package. Thus this fixer was born. I believe that with a
7 # bit more thinking, a more generic fixer can be implemented, but I'll leave
8 # that as future work.
9
10 from lib2to3.fixer_util import Name
11 from lib2to3.fixes import fix_imports
12
13 # This maps the old names to the new names. Note that a drawback of the current
14 # design is that the dictionary keys MUST have EXACTLY one dot (.) in them,
15 # otherwise things will break. (If you don't need a module hierarchy, you're
16 # better of just inherit from fix_imports and overriding the MAPPING dict.)
17
18 MAPPING = {'email.Utils': 'email.utils',
19 'email.Errors': 'email.errors',
20 'email.Header': 'email.header',
21 'email.Parser': 'email.parser',
22 'email.Encoders': 'email.encoders',
23 'email.MIMEText': 'email.mime.text',
24 'email.MIMEBase': 'email.mime.base',
25 'email.Generator': 'email.generator',
26 'email.MIMEMultipart': 'email.mime.multipart',
27 }
28
29 def alternates(members):
30 return "(" + "|".join(map(repr, members)) + ")"
31
32 def build_pattern(mapping=MAPPING):
33 packages = {}
34 for key in mapping:
35 # What we are doing here is the following: with dotted names, we'll
36 # have something like package_name <trailer '.' module>. Then, we are
37 # making a dictionary to copy this structure. For example, if
38 # mapping={'A.B': 'a.b', 'A.C': 'a.c'}, it will generate the dictionary
39 # {'A': ['b', 'c']} to, then, generate something like "A <trailer '.'
40 # ('b' | 'c')".
41 name = key.split('.')
42 prefix = name[0]
43 if prefix in packages:
44 packages[prefix].append(name[1:][0])
45 else:
46 packages[prefix] = name[1:]
47
48 mod_list = ' | '.join(["'%s' '.' ('%s')" %
49 (key, "' | '".join(packages[key])) for key in packages])
50 mod_list = '(' + mod_list + ' )'
51 bare_names = alternates(mapping.keys())
52
53 yield """name_import=import_name< 'import' module_name=dotted_name< %s > >
54 """ % mod_list
55
56 yield """name_import=import_name< 'import'
57 multiple_imports=dotted_as_names< any*
58 module_name=dotted_name< %s >
59 any* >
60 >""" % mod_list
61
62 packs = ' | '.join(["'%s' trailer<'.' ('%s')>" % (key,
63 "' | '".join(packages[key])) for key in packages])
64
65 yield "power< package=(%s) trailer<'.' any > any* >" % packs
66
67 class FixLeftoverImports(fix_imports.FixImports):
68 # We want to run this fixer after fix_import has run (this shouldn't matter
69 # for hg, though, as setup3k prefers to run the default fixers first)
70 mapping = MAPPING
71
72 def build_pattern(self):
73 return "|".join(build_pattern(self.mapping))
74
75 def transform(self, node, results):
76 # Mostly copied from fix_imports.py
77 import_mod = results.get("module_name")
78 if import_mod:
79 try:
80 mod_name = import_mod.value
81 except AttributeError:
82 # XXX: A hack to remove whitespace prefixes and suffixes
83 mod_name = str(import_mod).strip()
84 new_name = self.mapping[mod_name]
85 import_mod.replace(Name(new_name, prefix=import_mod.prefix))
86 if "name_import" in results:
87 # If it's not a "from x import x, y" or "import x as y" import,
88 # marked its usage to be replaced.
89 self.replace[mod_name] = new_name
90 if "multiple_imports" in results:
91 # This is a nasty hack to fix multiple imports on a line (e.g.,
92 # "import StringIO, urlparse"). The problem is that I can't
93 # figure out an easy way to make a pattern recognize the keys of
94 # MAPPING randomly sprinkled in an import statement.
95 results = self.match(node)
96 if results:
97 self.transform(node, results)
98 else:
99 # Replace usage of the module.
100 # Now this is, mostly, a hack
101 bare_name = results["package"][0]
102 bare_name_text = ''.join(map(str, results['package'])).strip()
103 new_name = self.replace.get(bare_name_text)
104 prefix = results['package'][0].prefix
105 if new_name:
106 bare_name.replace(Name(new_name, prefix=prefix))
107 results["package"][1].replace(Name(''))
108
General Comments 0
You need to be logged in to leave comments. Login now