Update to 2.7.3
[profile/ivi/python.git] / Lib / lib2to3 / fixes / fix_urllib.py
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")