(root)/
Python-3.12.0/
Lib/
lib2to3/
fixes/
fix_imports.py
       1  """Fix incompatible imports and module references."""
       2  # Authors: Collin Winter, Nick Edds
       3  
       4  # Local imports
       5  from .. import fixer_base
       6  from ..fixer_util import Name, attr_chain
       7  
       8  MAPPING = {'StringIO':  'io',
       9             'cStringIO': 'io',
      10             'cPickle': 'pickle',
      11             '__builtin__' : 'builtins',
      12             'copy_reg': 'copyreg',
      13             'Queue': 'queue',
      14             'SocketServer': 'socketserver',
      15             'ConfigParser': 'configparser',
      16             'repr': 'reprlib',
      17             'FileDialog': 'tkinter.filedialog',
      18             'tkFileDialog': 'tkinter.filedialog',
      19             'SimpleDialog': 'tkinter.simpledialog',
      20             'tkSimpleDialog': 'tkinter.simpledialog',
      21             'tkColorChooser': 'tkinter.colorchooser',
      22             'tkCommonDialog': 'tkinter.commondialog',
      23             'Dialog': 'tkinter.dialog',
      24             'Tkdnd': 'tkinter.dnd',
      25             'tkFont': 'tkinter.font',
      26             'tkMessageBox': 'tkinter.messagebox',
      27             'ScrolledText': 'tkinter.scrolledtext',
      28             'Tkconstants': 'tkinter.constants',
      29             'Tix': 'tkinter.tix',
      30             'ttk': 'tkinter.ttk',
      31             'Tkinter': 'tkinter',
      32             'markupbase': '_markupbase',
      33             '_winreg': 'winreg',
      34             'thread': '_thread',
      35             'dummy_thread': '_dummy_thread',
      36             # anydbm and whichdb are handled by fix_imports2
      37             'dbhash': 'dbm.bsd',
      38             'dumbdbm': 'dbm.dumb',
      39             'dbm': 'dbm.ndbm',
      40             'gdbm': 'dbm.gnu',
      41             'xmlrpclib': 'xmlrpc.client',
      42             'DocXMLRPCServer': 'xmlrpc.server',
      43             'SimpleXMLRPCServer': 'xmlrpc.server',
      44             'httplib': 'http.client',
      45             'htmlentitydefs' : 'html.entities',
      46             'HTMLParser' : 'html.parser',
      47             'Cookie': 'http.cookies',
      48             'cookielib': 'http.cookiejar',
      49             'BaseHTTPServer': 'http.server',
      50             'SimpleHTTPServer': 'http.server',
      51             'CGIHTTPServer': 'http.server',
      52             #'test.test_support': 'test.support',
      53             'commands': 'subprocess',
      54             'UserString' : 'collections',
      55             'UserList' : 'collections',
      56             'urlparse' : 'urllib.parse',
      57             'robotparser' : 'urllib.robotparser',
      58  }
      59  
      60  
      61  def alternates(members):
      62      return "(" + "|".join(map(repr, members)) + ")"
      63  
      64  
      65  def build_pattern(mapping=MAPPING):
      66      mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
      67      bare_names = alternates(mapping.keys())
      68  
      69      yield """name_import=import_name< 'import' ((%s) |
      70                 multiple_imports=dotted_as_names< any* (%s) any* >) >
      71            """ % (mod_list, mod_list)
      72      yield """import_from< 'from' (%s) 'import' ['(']
      73                ( any | import_as_name< any 'as' any > |
      74                  import_as_names< any* >)  [')'] >
      75            """ % mod_list
      76      yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
      77                 multiple_imports=dotted_as_names<
      78                   any* dotted_as_name< (%s) 'as' any > any* >) >
      79            """ % (mod_list, mod_list)
      80  
      81      # Find usages of module members in code e.g. thread.foo(bar)
      82      yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
      83  
      84  
      85  class ESC[4;38;5;81mFixImports(ESC[4;38;5;149mfixer_baseESC[4;38;5;149m.ESC[4;38;5;149mBaseFix):
      86  
      87      BM_compatible = True
      88      keep_line_order = True
      89      # This is overridden in fix_imports2.
      90      mapping = MAPPING
      91  
      92      # We want to run this fixer late, so fix_import doesn't try to make stdlib
      93      # renames into relative imports.
      94      run_order = 6
      95  
      96      def build_pattern(self):
      97          return "|".join(build_pattern(self.mapping))
      98  
      99      def compile_pattern(self):
     100          # We override this, so MAPPING can be pragmatically altered and the
     101          # changes will be reflected in PATTERN.
     102          self.PATTERN = self.build_pattern()
     103          super(FixImports, self).compile_pattern()
     104  
     105      # Don't match the node if it's within another match.
     106      def match(self, node):
     107          match = super(FixImports, self).match
     108          results = match(node)
     109          if results:
     110              # Module usage could be in the trailer of an attribute lookup, so we
     111              # might have nested matches when "bare_with_attr" is present.
     112              if "bare_with_attr" not in results and \
     113                      any(match(obj) for obj in attr_chain(node, "parent")):
     114                  return False
     115              return results
     116          return False
     117  
     118      def start_tree(self, tree, filename):
     119          super(FixImports, self).start_tree(tree, filename)
     120          self.replace = {}
     121  
     122      def transform(self, node, results):
     123          import_mod = results.get("module_name")
     124          if import_mod:
     125              mod_name = import_mod.value
     126              new_name = self.mapping[mod_name]
     127              import_mod.replace(Name(new_name, prefix=import_mod.prefix))
     128              if "name_import" in results:
     129                  # If it's not a "from x import x, y" or "import x as y" import,
     130                  # marked its usage to be replaced.
     131                  self.replace[mod_name] = new_name
     132              if "multiple_imports" in results:
     133                  # This is a nasty hack to fix multiple imports on a line (e.g.,
     134                  # "import StringIO, urlparse"). The problem is that I can't
     135                  # figure out an easy way to make a pattern recognize the keys of
     136                  # MAPPING randomly sprinkled in an import statement.
     137                  results = self.match(node)
     138                  if results:
     139                      self.transform(node, results)
     140          else:
     141              # Replace usage of the module.
     142              bare_name = results["bare_with_attr"][0]
     143              new_name = self.replace.get(bare_name.value)
     144              if new_name:
     145                  bare_name.replace(Name(new_name, prefix=bare_name.prefix))