/Lib/lib2to3/fixes/fix_urllib.py

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