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 lib2to3.fixes.fix_imports import alternates, FixImports
|
---|
9 | from lib2to3 import fixer_base
|
---|
10 | from lib2to3.fixer_util import (Name, Comma, FromImport, Newline,
|
---|
11 | find_indentation, Node, syms)
|
---|
12 |
|
---|
13 | MAPPING = {"urllib": [
|
---|
14 | ("urllib.request",
|
---|
15 | ["URLopener", "FancyURLopener", "urlretrieve",
|
---|
16 | "_urlopener", "urlopen", "urlcleanup",
|
---|
17 | "pathname2url", "url2pathname"]),
|
---|
18 | ("urllib.parse",
|
---|
19 | ["quote", "quote_plus", "unquote", "unquote_plus",
|
---|
20 | "urlencode", "splitattr", "splithost", "splitnport",
|
---|
21 | "splitpasswd", "splitport", "splitquery", "splittag",
|
---|
22 | "splittype", "splituser", "splitvalue", ]),
|
---|
23 | ("urllib.error",
|
---|
24 | ["ContentTooShortError"])],
|
---|
25 | "urllib2" : [
|
---|
26 | ("urllib.request",
|
---|
27 | ["urlopen", "install_opener", "build_opener",
|
---|
28 | "Request", "OpenerDirector", "BaseHandler",
|
---|
29 | "HTTPDefaultErrorHandler", "HTTPRedirectHandler",
|
---|
30 | "HTTPCookieProcessor", "ProxyHandler",
|
---|
31 | "HTTPPasswordMgr",
|
---|
32 | "HTTPPasswordMgrWithDefaultRealm",
|
---|
33 | "AbstractBasicAuthHandler",
|
---|
34 | "HTTPBasicAuthHandler", "ProxyBasicAuthHandler",
|
---|
35 | "AbstractDigestAuthHandler",
|
---|
36 | "HTTPDigestAuthHandler", "ProxyDigestAuthHandler",
|
---|
37 | "HTTPHandler", "HTTPSHandler", "FileHandler",
|
---|
38 | "FTPHandler", "CacheFTPHandler",
|
---|
39 | "UnknownHandler"]),
|
---|
40 | ("urllib.error",
|
---|
41 | ["URLError", "HTTPError"]),
|
---|
42 | ]
|
---|
43 | }
|
---|
44 |
|
---|
45 | # Duplicate the url parsing functions for urllib2.
|
---|
46 | MAPPING["urllib2"].append(MAPPING["urllib"][1])
|
---|
47 |
|
---|
48 |
|
---|
49 | def build_pattern():
|
---|
50 | bare = set()
|
---|
51 | for old_module, changes in MAPPING.items():
|
---|
52 | for change in changes:
|
---|
53 | new_module, members = change
|
---|
54 | members = alternates(members)
|
---|
55 | yield """import_name< 'import' (module=%r
|
---|
56 | | dotted_as_names< any* module=%r any* >) >
|
---|
57 | """ % (old_module, old_module)
|
---|
58 | yield """import_from< 'from' mod_member=%r 'import'
|
---|
59 | ( member=%s | import_as_name< member=%s 'as' any > |
|
---|
60 | import_as_names< members=any* >) >
|
---|
61 | """ % (old_module, members, members)
|
---|
62 | yield """import_from< 'from' module_star=%r 'import' star='*' >
|
---|
63 | """ % old_module
|
---|
64 | yield """import_name< 'import'
|
---|
65 | dotted_as_name< module_as=%r 'as' any > >
|
---|
66 | """ % old_module
|
---|
67 | # bare_with_attr has a special significance for FixImports.match().
|
---|
68 | yield """power< bare_with_attr=%r trailer< '.' member=%s > any* >
|
---|
69 | """ % (old_module, members)
|
---|
70 |
|
---|
71 |
|
---|
72 | class FixUrllib(FixImports):
|
---|
73 |
|
---|
74 | def build_pattern(self):
|
---|
75 | return "|".join(build_pattern())
|
---|
76 |
|
---|
77 | def transform_import(self, node, results):
|
---|
78 | """Transform for the basic import case. Replaces the old
|
---|
79 | import name with a comma separated list of its
|
---|
80 | replacements.
|
---|
81 | """
|
---|
82 | import_mod = results.get("module")
|
---|
83 | pref = import_mod.prefix
|
---|
84 |
|
---|
85 | names = []
|
---|
86 |
|
---|
87 | # create a Node list of the replacement modules
|
---|
88 | for name in MAPPING[import_mod.value][:-1]:
|
---|
89 | names.extend([Name(name[0], prefix=pref), Comma()])
|
---|
90 | names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
|
---|
91 | import_mod.replace(names)
|
---|
92 |
|
---|
93 | def transform_member(self, node, results):
|
---|
94 | """Transform for imports of specific module elements. Replaces
|
---|
95 | the module to be imported from with the appropriate new
|
---|
96 | module.
|
---|
97 | """
|
---|
98 | mod_member = results.get("mod_member")
|
---|
99 | pref = mod_member.prefix
|
---|
100 | member = results.get("member")
|
---|
101 |
|
---|
102 | # Simple case with only a single member being imported
|
---|
103 | if member:
|
---|
104 | # this may be a list of length one, or just a node
|
---|
105 | if isinstance(member, list):
|
---|
106 | member = member[0]
|
---|
107 | new_name = None
|
---|
108 | for change in MAPPING[mod_member.value]:
|
---|
109 | if member.value in change[1]:
|
---|
110 | new_name = change[0]
|
---|
111 | break
|
---|
112 | if new_name:
|
---|
113 | mod_member.replace(Name(new_name, prefix=pref))
|
---|
114 | else:
|
---|
115 | self.cannot_convert(node, "This is an invalid module element")
|
---|
116 |
|
---|
117 | # Multiple members being imported
|
---|
118 | else:
|
---|
119 | # a dictionary for replacements, order matters
|
---|
120 | modules = []
|
---|
121 | mod_dict = {}
|
---|
122 | members = results["members"]
|
---|
123 | for member in members:
|
---|
124 | # we only care about the actual members
|
---|
125 | if member.type == syms.import_as_name:
|
---|
126 | as_name = member.children[2].value
|
---|
127 | member_name = member.children[0].value
|
---|
128 | else:
|
---|
129 | member_name = member.value
|
---|
130 | as_name = None
|
---|
131 | if member_name != u",":
|
---|
132 | for change in MAPPING[mod_member.value]:
|
---|
133 | if member_name in change[1]:
|
---|
134 | if change[0] not in mod_dict:
|
---|
135 | modules.append(change[0])
|
---|
136 | mod_dict.setdefault(change[0], []).append(member)
|
---|
137 |
|
---|
138 | new_nodes = []
|
---|
139 | indentation = find_indentation(node)
|
---|
140 | first = True
|
---|
141 | def handle_name(name, prefix):
|
---|
142 | if name.type == syms.import_as_name:
|
---|
143 | kids = [Name(name.children[0].value, prefix=prefix),
|
---|
144 | name.children[1].clone(),
|
---|
145 | name.children[2].clone()]
|
---|
146 | return [Node(syms.import_as_name, kids)]
|
---|
147 | return [Name(name.value, prefix=prefix)]
|
---|
148 | for module in modules:
|
---|
149 | elts = mod_dict[module]
|
---|
150 | names = []
|
---|
151 | for elt in elts[:-1]:
|
---|
152 | names.extend(handle_name(elt, pref))
|
---|
153 | names.append(Comma())
|
---|
154 | names.extend(handle_name(elts[-1], pref))
|
---|
155 | new = FromImport(module, names)
|
---|
156 | if not first or node.parent.prefix.endswith(indentation):
|
---|
157 | new.prefix = indentation
|
---|
158 | new_nodes.append(new)
|
---|
159 | first = False
|
---|
160 | if new_nodes:
|
---|
161 | nodes = []
|
---|
162 | for new_node in new_nodes[:-1]:
|
---|
163 | nodes.extend([new_node, Newline()])
|
---|
164 | nodes.append(new_nodes[-1])
|
---|
165 | node.replace(nodes)
|
---|
166 | else:
|
---|
167 | self.cannot_convert(node, "All module elements are invalid")
|
---|
168 |
|
---|
169 | def transform_dot(self, node, results):
|
---|
170 | """Transform for calls to module members in code."""
|
---|
171 | module_dot = results.get("bare_with_attr")
|
---|
172 | member = results.get("member")
|
---|
173 | new_name = None
|
---|
174 | if isinstance(member, list):
|
---|
175 | member = member[0]
|
---|
176 | for change in MAPPING[module_dot.value]:
|
---|
177 | if member.value in change[1]:
|
---|
178 | new_name = change[0]
|
---|
179 | break
|
---|
180 | if new_name:
|
---|
181 | module_dot.replace(Name(new_name,
|
---|
182 | prefix=module_dot.prefix))
|
---|
183 | else:
|
---|
184 | self.cannot_convert(node, "This is an invalid module element")
|
---|
185 |
|
---|
186 | def transform(self, node, results):
|
---|
187 | if results.get("module"):
|
---|
188 | self.transform_import(node, results)
|
---|
189 | elif results.get("mod_member"):
|
---|
190 | self.transform_member(node, results)
|
---|
191 | elif results.get("bare_with_attr"):
|
---|
192 | self.transform_dot(node, results)
|
---|
193 | # Renaming and star imports are not supported for these modules.
|
---|
194 | elif results.get("module_star"):
|
---|
195 | self.cannot_convert(node, "Cannot handle star imports.")
|
---|
196 | elif results.get("module_as"):
|
---|
197 | self.cannot_convert(node, "This module is now multiple modules")
|
---|