PageRenderTime 423ms CodeModel.GetById 121ms app.highlight 94ms RepoModel.GetById 127ms app.codeStats 0ms

/Lib/lib2to3/fixes/fix_urllib.py

http://unladen-swallow.googlecode.com/
Python | 180 lines | 168 code | 5 blank | 7 comment | 4 complexity | c883d34902a6e74c08f4370a978e5b86 MD5 | raw file
  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
  8from .fix_imports import alternates, FixImports
  9from .. import fixer_base
 10from ..fixer_util import Name, Comma, FromImport, Newline, attr_chain
 11
 12MAPPING = {'urllib':  [
 13                ('urllib.request',
 14                    ['URLOpener', 'FancyURLOpener', 'urlretrieve',
 15                     '_urlopener', 'urlcleanup']),
 16                ('urllib.parse',
 17                    ['quote', 'quote_plus', 'unquote', 'unquote_plus',
 18                     'urlencode', 'pathname2url', 'url2pathname', 'splitattr',
 19                     'splithost', 'splitnport', 'splitpasswd', 'splitport',
 20                     'splitquery', 'splittag', 'splittype', 'splituser',
 21                     'splitvalue', ]),
 22                ('urllib.error',
 23                    ['ContentTooShortError'])],
 24           'urllib2' : [
 25                ('urllib.request',
 26                    ['urlopen', 'install_opener', 'build_opener',
 27                     'Request', 'OpenerDirector', 'BaseHandler',
 28                     'HTTPDefaultErrorHandler', 'HTTPRedirectHandler',
 29                     'HTTPCookieProcessor', 'ProxyHandler',
 30                     'HTTPPasswordMgr',
 31                     'HTTPPasswordMgrWithDefaultRealm',
 32                     'AbstractBasicAuthHandler',
 33                     'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler',
 34                     'AbstractDigestAuthHandler',
 35                     'HTTPDigestAuthHandler', 'ProxyDigestAuthHandler',
 36                     'HTTPHandler', 'HTTPSHandler', 'FileHandler',
 37                     'FTPHandler', 'CacheFTPHandler',
 38                     'UnknownHandler']),
 39                ('urllib.error',
 40                    ['URLError', 'HTTPError']),
 41           ]
 42}
 43
 44# Duplicate the url parsing functions for urllib2.
 45MAPPING["urllib2"].append(MAPPING["urllib"][1])
 46
 47
 48def build_pattern():
 49    bare = set()
 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='*' >
 62                  """ % old_module
 63            yield """import_name< 'import'
 64                                  dotted_as_name< module_as=%r 'as' any > >
 65                  """ % old_module
 66            yield """power< module_dot=%r trailer< '.' member=%s > any* >
 67                  """ % (old_module, members)
 68
 69
 70class FixUrllib(FixImports):
 71
 72    def build_pattern(self):
 73        return "|".join(build_pattern())
 74
 75    def transform_import(self, node, results):
 76        """Transform for the basic import case. Replaces the old
 77           import name with a comma separated list of its
 78           replacements.
 79        """
 80        import_mod = results.get('module')
 81        pref = import_mod.get_prefix()
 82
 83        names = []
 84
 85        # create a Node list of the replacement modules
 86        for name in MAPPING[import_mod.value][:-1]:
 87            names.extend([Name(name[0], prefix=pref), Comma()])
 88        names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
 89        import_mod.replace(names)
 90
 91    def transform_member(self, node, results):
 92        """Transform for imports of specific module elements. Replaces
 93           the module to be imported from with the appropriate new
 94           module.
 95        """
 96        mod_member = results.get('mod_member')
 97        pref = mod_member.get_prefix()
 98        member = results.get('member')
 99
100        # Simple case with only a single member being imported
101        if member:
102            # this may be a list of length one, or just a node
103            if isinstance(member, list):
104                member = member[0]
105            new_name = None
106            for change in MAPPING[mod_member.value]:
107                if member.value in change[1]:
108                    new_name = change[0]
109                    break
110            if new_name:
111                mod_member.replace(Name(new_name, prefix=pref))
112            else:
113                self.cannot_convert(node,
114                                    'This is an invalid module element')
115
116        # Multiple members being imported
117        else:
118            # a dictionary for replacements, order matters
119            modules = []
120            mod_dict = {}
121            members = results.get('members')
122            for member in members:
123                member = member.value
124                # we only care about the actual members
125                if member != ',':
126                    for change in MAPPING[mod_member.value]:
127                        if member in change[1]:
128                            if change[0] in mod_dict:
129                                mod_dict[change[0]].append(member)
130                            else:
131                                mod_dict[change[0]] = [member]
132                                modules.append(change[0])
133
134            new_nodes = []
135            for module in modules:
136                elts = mod_dict[module]
137                names = []
138                for elt in elts[:-1]:
139                    names.extend([Name(elt, prefix=pref), Comma()])
140                names.append(Name(elts[-1], prefix=pref))
141                new_nodes.append(FromImport(module, names))
142            if new_nodes:
143                nodes = []
144                for new_node in new_nodes[:-1]:
145                    nodes.extend([new_node, Newline()])
146                nodes.append(new_nodes[-1])
147                node.replace(nodes)
148            else:
149                self.cannot_convert(node, 'All module elements are invalid')
150
151    def transform_dot(self, node, results):
152        """Transform for calls to module members in code."""
153        module_dot = results.get('module_dot')
154        member = results.get('member')
155        # this may be a list of length one, or just a node
156        if isinstance(member, list):
157            member = member[0]
158        new_name = None
159        for change in MAPPING[module_dot.value]:
160            if member.value in change[1]:
161                new_name = change[0]
162                break
163        if new_name:
164            module_dot.replace(Name(new_name,
165                                    prefix=module_dot.get_prefix()))
166        else:
167            self.cannot_convert(node, 'This is an invalid module element')
168
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('module_dot'):
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')