(root)/
Python-3.12.0/
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.fixer_util import (Name, Comma, FromImport, Newline,
      10                                  find_indentation, Node, syms)
      11  
      12  MAPPING = {"urllib":  [
      13                  ("urllib.request",
      14                      ["URLopener", "FancyURLopener", "urlretrieve",
      15                       "_urlopener", "urlopen", "urlcleanup",
      16                       "pathname2url", "url2pathname", "getproxies"]),
      17                  ("urllib.parse",
      18                      ["quote", "quote_plus", "unquote", "unquote_plus",
      19                       "urlencode", "splitattr", "splithost", "splitnport",
      20                       "splitpasswd", "splitport", "splitquery", "splittag",
      21                       "splittype", "splituser", "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.
      45  MAPPING["urllib2"].append(MAPPING["urllib"][1])
      46  
      47  
      48  def 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              # bare_with_attr has a special significance for FixImports.match().
      67              yield """power< bare_with_attr=%r trailer< '.' member=%s > any* >
      68                    """ % (old_module, members)
      69  
      70  
      71  class ESC[4;38;5;81mFixUrllib(ESC[4;38;5;149mFixImports):
      72  
      73      def build_pattern(self):
      74          return "|".join(build_pattern())
      75  
      76      def transform_import(self, node, results):
      77          """Transform for the basic import case. Replaces the old
      78             import name with a comma separated list of its
      79             replacements.
      80          """
      81          import_mod = results.get("module")
      82          pref = import_mod.prefix
      83  
      84          names = []
      85  
      86          # create a Node list of the replacement modules
      87          for name in MAPPING[import_mod.value][:-1]:
      88              names.extend([Name(name[0], prefix=pref), Comma()])
      89          names.append(Name(MAPPING[import_mod.value][-1][0], prefix=pref))
      90          import_mod.replace(names)
      91  
      92      def transform_member(self, node, results):
      93          """Transform for imports of specific module elements. Replaces
      94             the module to be imported from with the appropriate new
      95             module.
      96          """
      97          mod_member = results.get("mod_member")
      98          pref = mod_member.prefix
      99          member = results.get("member")
     100  
     101          # Simple case with only a single member being imported
     102          if member:
     103              # this may be a list of length one, or just a node
     104              if isinstance(member, list):
     105                  member = member[0]
     106              new_name = None
     107              for change in MAPPING[mod_member.value]:
     108                  if member.value in change[1]:
     109                      new_name = change[0]
     110                      break
     111              if new_name:
     112                  mod_member.replace(Name(new_name, prefix=pref))
     113              else:
     114                  self.cannot_convert(node, "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["members"]
     122              for member in members:
     123                  # we only care about the actual members
     124                  if member.type == syms.import_as_name:
     125                      as_name = member.children[2].value
     126                      member_name = member.children[0].value
     127                  else:
     128                      member_name = member.value
     129                      as_name = None
     130                  if member_name != ",":
     131                      for change in MAPPING[mod_member.value]:
     132                          if member_name in change[1]:
     133                              if change[0] not in mod_dict:
     134                                  modules.append(change[0])
     135                              mod_dict.setdefault(change[0], []).append(member)
     136  
     137              new_nodes = []
     138              indentation = find_indentation(node)
     139              first = True
     140              def handle_name(name, prefix):
     141                  if name.type == syms.import_as_name:
     142                      kids = [Name(name.children[0].value, prefix=prefix),
     143                              name.children[1].clone(),
     144                              name.children[2].clone()]
     145                      return [Node(syms.import_as_name, kids)]
     146                  return [Name(name.value, prefix=prefix)]
     147              for module in modules:
     148                  elts = mod_dict[module]
     149                  names = []
     150                  for elt in elts[:-1]:
     151                      names.extend(handle_name(elt, pref))
     152                      names.append(Comma())
     153                  names.extend(handle_name(elts[-1], pref))
     154                  new = FromImport(module, names)
     155                  if not first or node.parent.prefix.endswith(indentation):
     156                      new.prefix = indentation
     157                  new_nodes.append(new)
     158                  first = False
     159              if new_nodes:
     160                  nodes = []
     161                  for new_node in new_nodes[:-1]:
     162                      nodes.extend([new_node, Newline()])
     163                  nodes.append(new_nodes[-1])
     164                  node.replace(nodes)
     165              else:
     166                  self.cannot_convert(node, "All module elements are invalid")
     167  
     168      def transform_dot(self, node, results):
     169          """Transform for calls to module members in code."""
     170          module_dot = results.get("bare_with_attr")
     171          member = results.get("member")
     172          new_name = None
     173          if isinstance(member, list):
     174              member = member[0]
     175          for change in MAPPING[module_dot.value]:
     176              if member.value in change[1]:
     177                  new_name = change[0]
     178                  break
     179          if new_name:
     180              module_dot.replace(Name(new_name,
     181                                      prefix=module_dot.prefix))
     182          else:
     183              self.cannot_convert(node, "This is an invalid module element")
     184  
     185      def transform(self, node, results):
     186          if results.get("module"):
     187              self.transform_import(node, results)
     188          elif results.get("mod_member"):
     189              self.transform_member(node, results)
     190          elif results.get("bare_with_attr"):
     191              self.transform_dot(node, results)
     192          # Renaming and star imports are not supported for these modules.
     193          elif results.get("module_star"):
     194              self.cannot_convert(node, "Cannot handle star imports.")
     195          elif results.get("module_as"):
     196              self.cannot_convert(node, "This module is now multiple modules")