|
1 """Fix changes imports of urllib which are now incompatible. |
|
2 This is rather similar to fix_imports, but because of the more |
|
3 complex nature of the fixing for urllib, it has its own fixer. |
|
4 """ |
|
5 # Author: Nick Edds |
|
6 |
|
7 # Local imports |
|
8 from .fix_imports import alternates, FixImports |
|
9 from .. import fixer_base |
|
10 from ..fixer_util import Name, Comma, FromImport, Newline, attr_chain |
|
11 |
|
12 MAPPING = {'urllib': [ |
|
13 ('urllib.request', |
|
14 ['URLOpener', 'FancyURLOpener', 'urlretrieve', |
|
15 '_urlopener', 'urlcleanup']), |
|
16 ('urllib.parse', |
|
17 ['quote', 'quote_plus', 'unquote', 'unquote_plus', |
|
18 'urlencode', 'pahtname2url', 'url2pathname']), |
|
19 ('urllib.error', |
|
20 ['ContentTooShortError'])], |
|
21 'urllib2' : [ |
|
22 ('urllib.request', |
|
23 ['urlopen', 'install_opener', 'build_opener', |
|
24 'Request', 'OpenerDirector', 'BaseHandler', |
|
25 'HTTPDefaultErrorHandler', 'HTTPRedirectHandler', |
|
26 'HTTPCookieProcessor', 'ProxyHandler', |
|
27 'HTTPPasswordMgr', |
|
28 'HTTPPasswordMgrWithDefaultRealm', |
|
29 'AbstractBasicAuthHandler', |
|
30 'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler', |
|
31 'AbstractDigestAuthHandler', |
|
32 'HTTPDigestAuthHander', 'ProxyDigestAuthHandler', |
|
33 'HTTPHandler', 'HTTPSHandler', 'FileHandler', |
|
34 'FTPHandler', 'CacheFTPHandler', |
|
35 'UnknownHandler']), |
|
36 ('urllib.error', |
|
37 ['URLError', 'HTTPError'])], |
|
38 } |
|
39 |
|
40 |
|
41 # def alternates(members): |
|
42 # return "(" + "|".join(map(repr, members)) + ")" |
|
43 |
|
44 |
|
45 def build_pattern(): |
|
46 bare = set() |
|
47 for old_module, changes in MAPPING.items(): |
|
48 for change in changes: |
|
49 new_module, members = change |
|
50 members = alternates(members) |
|
51 yield """import_name< 'import' (module=%r |
|
52 | dotted_as_names< any* module=%r any* >) > |
|
53 """ % (old_module, old_module) |
|
54 yield """import_from< 'from' mod_member=%r 'import' |
|
55 ( member=%s | import_as_name< member=%s 'as' any > | |
|
56 import_as_names< members=any* >) > |
|
57 """ % (old_module, members, members) |
|
58 yield """import_from< 'from' module_star=%r 'import' star='*' > |
|
59 """ % old_module |
|
60 yield """import_name< 'import' |
|
61 dotted_as_name< module_as=%r 'as' any > > |
|
62 """ % old_module |
|
63 yield """power< module_dot=%r trailer< '.' member=%s > any* > |
|
64 """ % (old_module, members) |
|
65 |
|
66 |
|
67 class FixUrllib(FixImports): |
|
68 |
|
69 def build_pattern(self): |
|
70 return "|".join(build_pattern()) |
|
71 |
|
72 def transform_import(self, node, results): |
|
73 """Transform for the basic import case. Replaces the old |
|
74 import name with a comma separated list of its |
|
75 replacements. |
|
76 """ |
|
77 import_mod = results.get('module') |
|
78 pref = import_mod.get_prefix() |
|
79 |
|
80 names = [] |
|
81 |
|
82 # create a Node list of the replacement modules |
|
83 for name in MAPPING[import_mod.value][:-1]: |
|
84 names.extend([Name(name[0], prefix=pref), Comma()]) |
|
85 names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref)) |
|
86 import_mod.replace(names) |
|
87 |
|
88 def transform_member(self, node, results): |
|
89 """Transform for imports of specific module elements. Replaces |
|
90 the module to be imported from with the appropriate new |
|
91 module. |
|
92 """ |
|
93 mod_member = results.get('mod_member') |
|
94 pref = mod_member.get_prefix() |
|
95 member = results.get('member') |
|
96 |
|
97 # Simple case with only a single member being imported |
|
98 if member: |
|
99 # this may be a list of length one, or just a node |
|
100 if isinstance(member, list): |
|
101 member = member[0] |
|
102 new_name = None |
|
103 for change in MAPPING[mod_member.value]: |
|
104 if member.value in change[1]: |
|
105 new_name = change[0] |
|
106 break |
|
107 if new_name: |
|
108 mod_member.replace(Name(new_name, prefix=pref)) |
|
109 else: |
|
110 self.cannot_convert(node, |
|
111 'This is an invalid module element') |
|
112 |
|
113 # Multiple members being imported |
|
114 else: |
|
115 # a dictionary for replacements, order matters |
|
116 modules = [] |
|
117 mod_dict = {} |
|
118 members = results.get('members') |
|
119 for member in members: |
|
120 member = member.value |
|
121 # we only care about the actual members |
|
122 if member != ',': |
|
123 for change in MAPPING[mod_member.value]: |
|
124 if member in change[1]: |
|
125 if change[0] in mod_dict: |
|
126 mod_dict[change[0]].append(member) |
|
127 else: |
|
128 mod_dict[change[0]] = [member] |
|
129 modules.append(change[0]) |
|
130 |
|
131 new_nodes = [] |
|
132 for module in modules: |
|
133 elts = mod_dict[module] |
|
134 names = [] |
|
135 for elt in elts[:-1]: |
|
136 names.extend([Name(elt, prefix=pref), Comma()]) |
|
137 names.append(Name(elts[-1], prefix=pref)) |
|
138 new_nodes.append(FromImport(module, names)) |
|
139 if new_nodes: |
|
140 nodes = [] |
|
141 for new_node in new_nodes[:-1]: |
|
142 nodes.extend([new_node, Newline()]) |
|
143 nodes.append(new_nodes[-1]) |
|
144 node.replace(nodes) |
|
145 else: |
|
146 self.cannot_convert(node, 'All module elements are invalid') |
|
147 |
|
148 def transform_dot(self, node, results): |
|
149 """Transform for calls to module members in code.""" |
|
150 module_dot = results.get('module_dot') |
|
151 member = results.get('member') |
|
152 # this may be a list of length one, or just a node |
|
153 if isinstance(member, list): |
|
154 member = member[0] |
|
155 new_name = None |
|
156 for change in MAPPING[module_dot.value]: |
|
157 if member.value in change[1]: |
|
158 new_name = change[0] |
|
159 break |
|
160 if new_name: |
|
161 module_dot.replace(Name(new_name, |
|
162 prefix=module_dot.get_prefix())) |
|
163 else: |
|
164 self.cannot_convert(node, 'This is an invalid module element') |
|
165 |
|
166 def transform(self, node, results): |
|
167 if results.get('module'): |
|
168 self.transform_import(node, results) |
|
169 elif results.get('mod_member'): |
|
170 self.transform_member(node, results) |
|
171 elif results.get('module_dot'): |
|
172 self.transform_dot(node, results) |
|
173 # Renaming and star imports are not supported for these modules. |
|
174 elif results.get('module_star'): |
|
175 self.cannot_convert(node, 'Cannot handle star imports.') |
|
176 elif results.get('module_as'): |
|
177 self.cannot_convert(node, 'This module is now multiple modules') |