17db96d56Sopenharmony_ci"""Fix changes imports of urllib which are now incompatible.
27db96d56Sopenharmony_ci   This is rather similar to fix_imports, but because of the more
37db96d56Sopenharmony_ci   complex nature of the fixing for urllib, it has its own fixer.
47db96d56Sopenharmony_ci"""
57db96d56Sopenharmony_ci# Author: Nick Edds
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci# Local imports
87db96d56Sopenharmony_cifrom lib2to3.fixes.fix_imports import alternates, FixImports
97db96d56Sopenharmony_cifrom lib2to3.fixer_util import (Name, Comma, FromImport, Newline,
107db96d56Sopenharmony_ci                                find_indentation, Node, syms)
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciMAPPING = {"urllib":  [
137db96d56Sopenharmony_ci                ("urllib.request",
147db96d56Sopenharmony_ci                    ["URLopener", "FancyURLopener", "urlretrieve",
157db96d56Sopenharmony_ci                     "_urlopener", "urlopen", "urlcleanup",
167db96d56Sopenharmony_ci                     "pathname2url", "url2pathname", "getproxies"]),
177db96d56Sopenharmony_ci                ("urllib.parse",
187db96d56Sopenharmony_ci                    ["quote", "quote_plus", "unquote", "unquote_plus",
197db96d56Sopenharmony_ci                     "urlencode", "splitattr", "splithost", "splitnport",
207db96d56Sopenharmony_ci                     "splitpasswd", "splitport", "splitquery", "splittag",
217db96d56Sopenharmony_ci                     "splittype", "splituser", "splitvalue", ]),
227db96d56Sopenharmony_ci                ("urllib.error",
237db96d56Sopenharmony_ci                    ["ContentTooShortError"])],
247db96d56Sopenharmony_ci           "urllib2" : [
257db96d56Sopenharmony_ci                ("urllib.request",
267db96d56Sopenharmony_ci                    ["urlopen", "install_opener", "build_opener",
277db96d56Sopenharmony_ci                     "Request", "OpenerDirector", "BaseHandler",
287db96d56Sopenharmony_ci                     "HTTPDefaultErrorHandler", "HTTPRedirectHandler",
297db96d56Sopenharmony_ci                     "HTTPCookieProcessor", "ProxyHandler",
307db96d56Sopenharmony_ci                     "HTTPPasswordMgr",
317db96d56Sopenharmony_ci                     "HTTPPasswordMgrWithDefaultRealm",
327db96d56Sopenharmony_ci                     "AbstractBasicAuthHandler",
337db96d56Sopenharmony_ci                     "HTTPBasicAuthHandler", "ProxyBasicAuthHandler",
347db96d56Sopenharmony_ci                     "AbstractDigestAuthHandler",
357db96d56Sopenharmony_ci                     "HTTPDigestAuthHandler", "ProxyDigestAuthHandler",
367db96d56Sopenharmony_ci                     "HTTPHandler", "HTTPSHandler", "FileHandler",
377db96d56Sopenharmony_ci                     "FTPHandler", "CacheFTPHandler",
387db96d56Sopenharmony_ci                     "UnknownHandler"]),
397db96d56Sopenharmony_ci                ("urllib.error",
407db96d56Sopenharmony_ci                    ["URLError", "HTTPError"]),
417db96d56Sopenharmony_ci           ]
427db96d56Sopenharmony_ci}
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci# Duplicate the url parsing functions for urllib2.
457db96d56Sopenharmony_ciMAPPING["urllib2"].append(MAPPING["urllib"][1])
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci
487db96d56Sopenharmony_cidef build_pattern():
497db96d56Sopenharmony_ci    bare = set()
507db96d56Sopenharmony_ci    for old_module, changes in MAPPING.items():
517db96d56Sopenharmony_ci        for change in changes:
527db96d56Sopenharmony_ci            new_module, members = change
537db96d56Sopenharmony_ci            members = alternates(members)
547db96d56Sopenharmony_ci            yield """import_name< 'import' (module=%r
557db96d56Sopenharmony_ci                                  | dotted_as_names< any* module=%r any* >) >
567db96d56Sopenharmony_ci                  """ % (old_module, old_module)
577db96d56Sopenharmony_ci            yield """import_from< 'from' mod_member=%r 'import'
587db96d56Sopenharmony_ci                       ( member=%s | import_as_name< member=%s 'as' any > |
597db96d56Sopenharmony_ci                         import_as_names< members=any*  >) >
607db96d56Sopenharmony_ci                  """ % (old_module, members, members)
617db96d56Sopenharmony_ci            yield """import_from< 'from' module_star=%r 'import' star='*' >
627db96d56Sopenharmony_ci                  """ % old_module
637db96d56Sopenharmony_ci            yield """import_name< 'import'
647db96d56Sopenharmony_ci                                  dotted_as_name< module_as=%r 'as' any > >
657db96d56Sopenharmony_ci                  """ % old_module
667db96d56Sopenharmony_ci            # bare_with_attr has a special significance for FixImports.match().
677db96d56Sopenharmony_ci            yield """power< bare_with_attr=%r trailer< '.' member=%s > any* >
687db96d56Sopenharmony_ci                  """ % (old_module, members)
697db96d56Sopenharmony_ci
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ciclass FixUrllib(FixImports):
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci    def build_pattern(self):
747db96d56Sopenharmony_ci        return "|".join(build_pattern())
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ci    def transform_import(self, node, results):
777db96d56Sopenharmony_ci        """Transform for the basic import case. Replaces the old
787db96d56Sopenharmony_ci           import name with a comma separated list of its
797db96d56Sopenharmony_ci           replacements.
807db96d56Sopenharmony_ci        """
817db96d56Sopenharmony_ci        import_mod = results.get("module")
827db96d56Sopenharmony_ci        pref = import_mod.prefix
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci        names = []
857db96d56Sopenharmony_ci
867db96d56Sopenharmony_ci        # create a Node list of the replacement modules
877db96d56Sopenharmony_ci        for name in MAPPING[import_mod.value][:-1]:
887db96d56Sopenharmony_ci            names.extend([Name(name[0], prefix=pref), Comma()])
897db96d56Sopenharmony_ci        names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
907db96d56Sopenharmony_ci        import_mod.replace(names)
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci    def transform_member(self, node, results):
937db96d56Sopenharmony_ci        """Transform for imports of specific module elements. Replaces
947db96d56Sopenharmony_ci           the module to be imported from with the appropriate new
957db96d56Sopenharmony_ci           module.
967db96d56Sopenharmony_ci        """
977db96d56Sopenharmony_ci        mod_member = results.get("mod_member")
987db96d56Sopenharmony_ci        pref = mod_member.prefix
997db96d56Sopenharmony_ci        member = results.get("member")
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci        # Simple case with only a single member being imported
1027db96d56Sopenharmony_ci        if member:
1037db96d56Sopenharmony_ci            # this may be a list of length one, or just a node
1047db96d56Sopenharmony_ci            if isinstance(member, list):
1057db96d56Sopenharmony_ci                member = member[0]
1067db96d56Sopenharmony_ci            new_name = None
1077db96d56Sopenharmony_ci            for change in MAPPING[mod_member.value]:
1087db96d56Sopenharmony_ci                if member.value in change[1]:
1097db96d56Sopenharmony_ci                    new_name = change[0]
1107db96d56Sopenharmony_ci                    break
1117db96d56Sopenharmony_ci            if new_name:
1127db96d56Sopenharmony_ci                mod_member.replace(Name(new_name, prefix=pref))
1137db96d56Sopenharmony_ci            else:
1147db96d56Sopenharmony_ci                self.cannot_convert(node, "This is an invalid module element")
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci        # Multiple members being imported
1177db96d56Sopenharmony_ci        else:
1187db96d56Sopenharmony_ci            # a dictionary for replacements, order matters
1197db96d56Sopenharmony_ci            modules = []
1207db96d56Sopenharmony_ci            mod_dict = {}
1217db96d56Sopenharmony_ci            members = results["members"]
1227db96d56Sopenharmony_ci            for member in members:
1237db96d56Sopenharmony_ci                # we only care about the actual members
1247db96d56Sopenharmony_ci                if member.type == syms.import_as_name:
1257db96d56Sopenharmony_ci                    as_name = member.children[2].value
1267db96d56Sopenharmony_ci                    member_name = member.children[0].value
1277db96d56Sopenharmony_ci                else:
1287db96d56Sopenharmony_ci                    member_name = member.value
1297db96d56Sopenharmony_ci                    as_name = None
1307db96d56Sopenharmony_ci                if member_name != ",":
1317db96d56Sopenharmony_ci                    for change in MAPPING[mod_member.value]:
1327db96d56Sopenharmony_ci                        if member_name in change[1]:
1337db96d56Sopenharmony_ci                            if change[0] not in mod_dict:
1347db96d56Sopenharmony_ci                                modules.append(change[0])
1357db96d56Sopenharmony_ci                            mod_dict.setdefault(change[0], []).append(member)
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci            new_nodes = []
1387db96d56Sopenharmony_ci            indentation = find_indentation(node)
1397db96d56Sopenharmony_ci            first = True
1407db96d56Sopenharmony_ci            def handle_name(name, prefix):
1417db96d56Sopenharmony_ci                if name.type == syms.import_as_name:
1427db96d56Sopenharmony_ci                    kids = [Name(name.children[0].value, prefix=prefix),
1437db96d56Sopenharmony_ci                            name.children[1].clone(),
1447db96d56Sopenharmony_ci                            name.children[2].clone()]
1457db96d56Sopenharmony_ci                    return [Node(syms.import_as_name, kids)]
1467db96d56Sopenharmony_ci                return [Name(name.value, prefix=prefix)]
1477db96d56Sopenharmony_ci            for module in modules:
1487db96d56Sopenharmony_ci                elts = mod_dict[module]
1497db96d56Sopenharmony_ci                names = []
1507db96d56Sopenharmony_ci                for elt in elts[:-1]:
1517db96d56Sopenharmony_ci                    names.extend(handle_name(elt, pref))
1527db96d56Sopenharmony_ci                    names.append(Comma())
1537db96d56Sopenharmony_ci                names.extend(handle_name(elts[-1], pref))
1547db96d56Sopenharmony_ci                new = FromImport(module, names)
1557db96d56Sopenharmony_ci                if not first or node.parent.prefix.endswith(indentation):
1567db96d56Sopenharmony_ci                    new.prefix = indentation
1577db96d56Sopenharmony_ci                new_nodes.append(new)
1587db96d56Sopenharmony_ci                first = False
1597db96d56Sopenharmony_ci            if new_nodes:
1607db96d56Sopenharmony_ci                nodes = []
1617db96d56Sopenharmony_ci                for new_node in new_nodes[:-1]:
1627db96d56Sopenharmony_ci                    nodes.extend([new_node, Newline()])
1637db96d56Sopenharmony_ci                nodes.append(new_nodes[-1])
1647db96d56Sopenharmony_ci                node.replace(nodes)
1657db96d56Sopenharmony_ci            else:
1667db96d56Sopenharmony_ci                self.cannot_convert(node, "All module elements are invalid")
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    def transform_dot(self, node, results):
1697db96d56Sopenharmony_ci        """Transform for calls to module members in code."""
1707db96d56Sopenharmony_ci        module_dot = results.get("bare_with_attr")
1717db96d56Sopenharmony_ci        member = results.get("member")
1727db96d56Sopenharmony_ci        new_name = None
1737db96d56Sopenharmony_ci        if isinstance(member, list):
1747db96d56Sopenharmony_ci            member = member[0]
1757db96d56Sopenharmony_ci        for change in MAPPING[module_dot.value]:
1767db96d56Sopenharmony_ci            if member.value in change[1]:
1777db96d56Sopenharmony_ci                new_name = change[0]
1787db96d56Sopenharmony_ci                break
1797db96d56Sopenharmony_ci        if new_name:
1807db96d56Sopenharmony_ci            module_dot.replace(Name(new_name,
1817db96d56Sopenharmony_ci                                    prefix=module_dot.prefix))
1827db96d56Sopenharmony_ci        else:
1837db96d56Sopenharmony_ci            self.cannot_convert(node, "This is an invalid module element")
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci    def transform(self, node, results):
1867db96d56Sopenharmony_ci        if results.get("module"):
1877db96d56Sopenharmony_ci            self.transform_import(node, results)
1887db96d56Sopenharmony_ci        elif results.get("mod_member"):
1897db96d56Sopenharmony_ci            self.transform_member(node, results)
1907db96d56Sopenharmony_ci        elif results.get("bare_with_attr"):
1917db96d56Sopenharmony_ci            self.transform_dot(node, results)
1927db96d56Sopenharmony_ci        # Renaming and star imports are not supported for these modules.
1937db96d56Sopenharmony_ci        elif results.get("module_star"):
1947db96d56Sopenharmony_ci            self.cannot_convert(node, "Cannot handle star imports.")
1957db96d56Sopenharmony_ci        elif results.get("module_as"):
1967db96d56Sopenharmony_ci            self.cannot_convert(node, "This module is now multiple modules")
197