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.
8 from .fix_imports
import alternates
, FixImports
9 from .. import fixer_base
10 from ..fixer_util
import Name
, Comma
, FromImport
, Newline
, attr_chain
12 MAPPING
= {'urllib': [
14 ['URLOpener', 'FancyURLOpener', 'urlretrieve',
15 '_urlopener', 'urlopen', 'urlcleanup',
16 'pathname2url', 'url2pathname']),
18 ['quote', 'quote_plus', 'unquote', 'unquote_plus',
19 'urlencode', 'splitattr', 'splithost', 'splitnport',
20 'splitpasswd', 'splitport', 'splitquery', 'splittag',
21 'splittype', 'splituser', 'splitvalue', ]),
23 ['ContentTooShortError'])],
26 ['urlopen', 'install_opener', 'build_opener',
27 'Request', 'OpenerDirector', 'BaseHandler',
28 'HTTPDefaultErrorHandler', 'HTTPRedirectHandler',
29 'HTTPCookieProcessor', 'ProxyHandler',
31 'HTTPPasswordMgrWithDefaultRealm',
32 'AbstractBasicAuthHandler',
33 'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler',
34 'AbstractDigestAuthHandler',
35 'HTTPDigestAuthHandler', 'ProxyDigestAuthHandler',
36 'HTTPHandler', 'HTTPSHandler', 'FileHandler',
37 'FTPHandler', 'CacheFTPHandler',
40 ['URLError', 'HTTPError']),
44 # Duplicate the url parsing functions for urllib2.
45 MAPPING
["urllib2"].append(MAPPING
["urllib"][1])
50 for old_module
, changes
in MAPPING
.items():
51 for change
in changes
:
52 new_module
, members
= change
53 members
= alternates(members
)
54 yield """import_name< 'import' (module=%r
55 | dotted_as_names< any* module=%r any* >) >
56 """ % (old_module
, old_module
)
57 yield """import_from< 'from' mod_member=%r 'import'
58 ( member=%s | import_as_name< member=%s 'as' any > |
59 import_as_names< members=any* >) >
60 """ % (old_module
, members
, members
)
61 yield """import_from< 'from' module_star=%r 'import' star='*' >
63 yield """import_name< 'import'
64 dotted_as_name< module_as=%r 'as' any > >
66 # bare_with_attr has a special significance for FixImports.match().
67 yield """power< bare_with_attr=%r trailer< '.' member=%s > any* >
68 """ % (old_module
, members
)
71 class FixUrllib(FixImports
):
73 def build_pattern(self
):
74 return "|".join(build_pattern())
76 def transform_import(self
, node
, results
):
77 """Transform for the basic import case. Replaces the old
78 import name with a comma separated list of its
81 import_mod
= results
.get('module')
82 pref
= import_mod
.prefix
86 # create a Node list of the replacement modules
87 for name
in MAPPING
[import_mod
.value
][:-1]:
88 names
.extend([Name(name
[0], prefix
=pref
), Comma()])
89 names
.append(Name(MAPPING
[import_mod
.value
][-1][0], prefix
=pref
))
90 import_mod
.replace(names
)
92 def transform_member(self
, node
, results
):
93 """Transform for imports of specific module elements. Replaces
94 the module to be imported from with the appropriate new
97 mod_member
= results
.get('mod_member')
98 pref
= mod_member
.prefix
99 member
= results
.get('member')
101 # Simple case with only a single member being imported
103 # this may be a list of length one, or just a node
104 if isinstance(member
, list):
107 for change
in MAPPING
[mod_member
.value
]:
108 if member
.value
in change
[1]:
112 mod_member
.replace(Name(new_name
, prefix
=pref
))
114 self
.cannot_convert(node
,
115 'This is an invalid module element')
117 # Multiple members being imported
119 # a dictionary for replacements, order matters
122 members
= results
.get('members')
123 for member
in members
:
124 member
= member
.value
125 # we only care about the actual members
127 for change
in MAPPING
[mod_member
.value
]:
128 if member
in change
[1]:
129 if change
[0] in mod_dict
:
130 mod_dict
[change
[0]].append(member
)
132 mod_dict
[change
[0]] = [member
]
133 modules
.append(change
[0])
136 for module
in modules
:
137 elts
= mod_dict
[module
]
139 for elt
in elts
[:-1]:
140 names
.extend([Name(elt
, prefix
=pref
), Comma()])
141 names
.append(Name(elts
[-1], prefix
=pref
))
142 new_nodes
.append(FromImport(module
, names
))
145 for new_node
in new_nodes
[:-1]:
146 nodes
.extend([new_node
, Newline()])
147 nodes
.append(new_nodes
[-1])
150 self
.cannot_convert(node
, 'All module elements are invalid')
152 def transform_dot(self
, node
, results
):
153 """Transform for calls to module members in code."""
154 module_dot
= results
.get('bare_with_attr')
155 member
= results
.get('member')
157 if isinstance(member
, list):
159 for change
in MAPPING
[module_dot
.value
]:
160 if member
.value
in change
[1]:
164 module_dot
.replace(Name(new_name
,
165 prefix
=module_dot
.prefix
))
167 self
.cannot_convert(node
, 'This is an invalid module element')
169 def transform(self
, node
, results
):
170 if results
.get('module'):
171 self
.transform_import(node
, results
)
172 elif results
.get('mod_member'):
173 self
.transform_member(node
, results
)
174 elif results
.get('bare_with_attr'):
175 self
.transform_dot(node
, results
)
176 # Renaming and star imports are not supported for these modules.
177 elif results
.get('module_star'):
178 self
.cannot_convert(node
, 'Cannot handle star imports.')
179 elif results
.get('module_as'):
180 self
.cannot_convert(node
, 'This module is now multiple modules')