17db96d56Sopenharmony_ci"""Fix incompatible imports and module references."""
27db96d56Sopenharmony_ci# Authors: Collin Winter, Nick Edds
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ci# Local imports
57db96d56Sopenharmony_cifrom .. import fixer_base
67db96d56Sopenharmony_cifrom ..fixer_util import Name, attr_chain
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ciMAPPING = {'StringIO':  'io',
97db96d56Sopenharmony_ci           'cStringIO': 'io',
107db96d56Sopenharmony_ci           'cPickle': 'pickle',
117db96d56Sopenharmony_ci           '__builtin__' : 'builtins',
127db96d56Sopenharmony_ci           'copy_reg': 'copyreg',
137db96d56Sopenharmony_ci           'Queue': 'queue',
147db96d56Sopenharmony_ci           'SocketServer': 'socketserver',
157db96d56Sopenharmony_ci           'ConfigParser': 'configparser',
167db96d56Sopenharmony_ci           'repr': 'reprlib',
177db96d56Sopenharmony_ci           'FileDialog': 'tkinter.filedialog',
187db96d56Sopenharmony_ci           'tkFileDialog': 'tkinter.filedialog',
197db96d56Sopenharmony_ci           'SimpleDialog': 'tkinter.simpledialog',
207db96d56Sopenharmony_ci           'tkSimpleDialog': 'tkinter.simpledialog',
217db96d56Sopenharmony_ci           'tkColorChooser': 'tkinter.colorchooser',
227db96d56Sopenharmony_ci           'tkCommonDialog': 'tkinter.commondialog',
237db96d56Sopenharmony_ci           'Dialog': 'tkinter.dialog',
247db96d56Sopenharmony_ci           'Tkdnd': 'tkinter.dnd',
257db96d56Sopenharmony_ci           'tkFont': 'tkinter.font',
267db96d56Sopenharmony_ci           'tkMessageBox': 'tkinter.messagebox',
277db96d56Sopenharmony_ci           'ScrolledText': 'tkinter.scrolledtext',
287db96d56Sopenharmony_ci           'Tkconstants': 'tkinter.constants',
297db96d56Sopenharmony_ci           'Tix': 'tkinter.tix',
307db96d56Sopenharmony_ci           'ttk': 'tkinter.ttk',
317db96d56Sopenharmony_ci           'Tkinter': 'tkinter',
327db96d56Sopenharmony_ci           'markupbase': '_markupbase',
337db96d56Sopenharmony_ci           '_winreg': 'winreg',
347db96d56Sopenharmony_ci           'thread': '_thread',
357db96d56Sopenharmony_ci           'dummy_thread': '_dummy_thread',
367db96d56Sopenharmony_ci           # anydbm and whichdb are handled by fix_imports2
377db96d56Sopenharmony_ci           'dbhash': 'dbm.bsd',
387db96d56Sopenharmony_ci           'dumbdbm': 'dbm.dumb',
397db96d56Sopenharmony_ci           'dbm': 'dbm.ndbm',
407db96d56Sopenharmony_ci           'gdbm': 'dbm.gnu',
417db96d56Sopenharmony_ci           'xmlrpclib': 'xmlrpc.client',
427db96d56Sopenharmony_ci           'DocXMLRPCServer': 'xmlrpc.server',
437db96d56Sopenharmony_ci           'SimpleXMLRPCServer': 'xmlrpc.server',
447db96d56Sopenharmony_ci           'httplib': 'http.client',
457db96d56Sopenharmony_ci           'htmlentitydefs' : 'html.entities',
467db96d56Sopenharmony_ci           'HTMLParser' : 'html.parser',
477db96d56Sopenharmony_ci           'Cookie': 'http.cookies',
487db96d56Sopenharmony_ci           'cookielib': 'http.cookiejar',
497db96d56Sopenharmony_ci           'BaseHTTPServer': 'http.server',
507db96d56Sopenharmony_ci           'SimpleHTTPServer': 'http.server',
517db96d56Sopenharmony_ci           'CGIHTTPServer': 'http.server',
527db96d56Sopenharmony_ci           #'test.test_support': 'test.support',
537db96d56Sopenharmony_ci           'commands': 'subprocess',
547db96d56Sopenharmony_ci           'UserString' : 'collections',
557db96d56Sopenharmony_ci           'UserList' : 'collections',
567db96d56Sopenharmony_ci           'urlparse' : 'urllib.parse',
577db96d56Sopenharmony_ci           'robotparser' : 'urllib.robotparser',
587db96d56Sopenharmony_ci}
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_cidef alternates(members):
627db96d56Sopenharmony_ci    return "(" + "|".join(map(repr, members)) + ")"
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_cidef build_pattern(mapping=MAPPING):
667db96d56Sopenharmony_ci    mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
677db96d56Sopenharmony_ci    bare_names = alternates(mapping.keys())
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci    yield """name_import=import_name< 'import' ((%s) |
707db96d56Sopenharmony_ci               multiple_imports=dotted_as_names< any* (%s) any* >) >
717db96d56Sopenharmony_ci          """ % (mod_list, mod_list)
727db96d56Sopenharmony_ci    yield """import_from< 'from' (%s) 'import' ['(']
737db96d56Sopenharmony_ci              ( any | import_as_name< any 'as' any > |
747db96d56Sopenharmony_ci                import_as_names< any* >)  [')'] >
757db96d56Sopenharmony_ci          """ % mod_list
767db96d56Sopenharmony_ci    yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
777db96d56Sopenharmony_ci               multiple_imports=dotted_as_names<
787db96d56Sopenharmony_ci                 any* dotted_as_name< (%s) 'as' any > any* >) >
797db96d56Sopenharmony_ci          """ % (mod_list, mod_list)
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci    # Find usages of module members in code e.g. thread.foo(bar)
827db96d56Sopenharmony_ci    yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci
857db96d56Sopenharmony_ciclass FixImports(fixer_base.BaseFix):
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci    BM_compatible = True
887db96d56Sopenharmony_ci    keep_line_order = True
897db96d56Sopenharmony_ci    # This is overridden in fix_imports2.
907db96d56Sopenharmony_ci    mapping = MAPPING
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci    # We want to run this fixer late, so fix_import doesn't try to make stdlib
937db96d56Sopenharmony_ci    # renames into relative imports.
947db96d56Sopenharmony_ci    run_order = 6
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ci    def build_pattern(self):
977db96d56Sopenharmony_ci        return "|".join(build_pattern(self.mapping))
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_ci    def compile_pattern(self):
1007db96d56Sopenharmony_ci        # We override this, so MAPPING can be pragmatically altered and the
1017db96d56Sopenharmony_ci        # changes will be reflected in PATTERN.
1027db96d56Sopenharmony_ci        self.PATTERN = self.build_pattern()
1037db96d56Sopenharmony_ci        super(FixImports, self).compile_pattern()
1047db96d56Sopenharmony_ci
1057db96d56Sopenharmony_ci    # Don't match the node if it's within another match.
1067db96d56Sopenharmony_ci    def match(self, node):
1077db96d56Sopenharmony_ci        match = super(FixImports, self).match
1087db96d56Sopenharmony_ci        results = match(node)
1097db96d56Sopenharmony_ci        if results:
1107db96d56Sopenharmony_ci            # Module usage could be in the trailer of an attribute lookup, so we
1117db96d56Sopenharmony_ci            # might have nested matches when "bare_with_attr" is present.
1127db96d56Sopenharmony_ci            if "bare_with_attr" not in results and \
1137db96d56Sopenharmony_ci                    any(match(obj) for obj in attr_chain(node, "parent")):
1147db96d56Sopenharmony_ci                return False
1157db96d56Sopenharmony_ci            return results
1167db96d56Sopenharmony_ci        return False
1177db96d56Sopenharmony_ci
1187db96d56Sopenharmony_ci    def start_tree(self, tree, filename):
1197db96d56Sopenharmony_ci        super(FixImports, self).start_tree(tree, filename)
1207db96d56Sopenharmony_ci        self.replace = {}
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci    def transform(self, node, results):
1237db96d56Sopenharmony_ci        import_mod = results.get("module_name")
1247db96d56Sopenharmony_ci        if import_mod:
1257db96d56Sopenharmony_ci            mod_name = import_mod.value
1267db96d56Sopenharmony_ci            new_name = self.mapping[mod_name]
1277db96d56Sopenharmony_ci            import_mod.replace(Name(new_name, prefix=import_mod.prefix))
1287db96d56Sopenharmony_ci            if "name_import" in results:
1297db96d56Sopenharmony_ci                # If it's not a "from x import x, y" or "import x as y" import,
1307db96d56Sopenharmony_ci                # marked its usage to be replaced.
1317db96d56Sopenharmony_ci                self.replace[mod_name] = new_name
1327db96d56Sopenharmony_ci            if "multiple_imports" in results:
1337db96d56Sopenharmony_ci                # This is a nasty hack to fix multiple imports on a line (e.g.,
1347db96d56Sopenharmony_ci                # "import StringIO, urlparse"). The problem is that I can't
1357db96d56Sopenharmony_ci                # figure out an easy way to make a pattern recognize the keys of
1367db96d56Sopenharmony_ci                # MAPPING randomly sprinkled in an import statement.
1377db96d56Sopenharmony_ci                results = self.match(node)
1387db96d56Sopenharmony_ci                if results:
1397db96d56Sopenharmony_ci                    self.transform(node, results)
1407db96d56Sopenharmony_ci        else:
1417db96d56Sopenharmony_ci            # Replace usage of the module.
1427db96d56Sopenharmony_ci            bare_name = results["bare_with_attr"][0]
1437db96d56Sopenharmony_ci            new_name = self.replace.get(bare_name.value)
1447db96d56Sopenharmony_ci            if new_name:
1457db96d56Sopenharmony_ci                bare_name.replace(Name(new_name, prefix=bare_name.prefix))
146