fix_UserDict.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. """Fix UserDict.
  2. Incomplete!
  3. TODO: base this on fix_urllib perhaps?
  4. """
  5. # Local imports
  6. from lib2to3 import fixer_base
  7. from lib2to3.fixer_util import Name, attr_chain
  8. from lib2to3.fixes.fix_imports import alternates, build_pattern, FixImports
  9. MAPPING = {'UserDict': 'collections',
  10. }
  11. # def alternates(members):
  12. # return "(" + "|".join(map(repr, members)) + ")"
  13. #
  14. #
  15. # def build_pattern(mapping=MAPPING):
  16. # mod_list = ' | '.join(["module_name='%s'" % key for key in mapping])
  17. # bare_names = alternates(mapping.keys())
  18. #
  19. # yield """name_import=import_name< 'import' ((%s) |
  20. # multiple_imports=dotted_as_names< any* (%s) any* >) >
  21. # """ % (mod_list, mod_list)
  22. # yield """import_from< 'from' (%s) 'import' ['(']
  23. # ( any | import_as_name< any 'as' any > |
  24. # import_as_names< any* >) [')'] >
  25. # """ % mod_list
  26. # yield """import_name< 'import' (dotted_as_name< (%s) 'as' any > |
  27. # multiple_imports=dotted_as_names<
  28. # any* dotted_as_name< (%s) 'as' any > any* >) >
  29. # """ % (mod_list, mod_list)
  30. #
  31. # # Find usages of module members in code e.g. thread.foo(bar)
  32. # yield "power< bare_with_attr=(%s) trailer<'.' any > any* >" % bare_names
  33. # class FixUserDict(fixer_base.BaseFix):
  34. class FixUserdict(FixImports):
  35. BM_compatible = True
  36. keep_line_order = True
  37. # This is overridden in fix_imports2.
  38. mapping = MAPPING
  39. # We want to run this fixer late, so fix_import doesn't try to make stdlib
  40. # renames into relative imports.
  41. run_order = 6
  42. def build_pattern(self):
  43. return "|".join(build_pattern(self.mapping))
  44. def compile_pattern(self):
  45. # We override this, so MAPPING can be pragmatically altered and the
  46. # changes will be reflected in PATTERN.
  47. self.PATTERN = self.build_pattern()
  48. super(FixImports, self).compile_pattern()
  49. # Don't match the node if it's within another match.
  50. def match(self, node):
  51. match = super(FixImports, self).match
  52. results = match(node)
  53. if results:
  54. # Module usage could be in the trailer of an attribute lookup, so we
  55. # might have nested matches when "bare_with_attr" is present.
  56. if "bare_with_attr" not in results and \
  57. any(match(obj) for obj in attr_chain(node, "parent")):
  58. return False
  59. return results
  60. return False
  61. def start_tree(self, tree, filename):
  62. super(FixImports, self).start_tree(tree, filename)
  63. self.replace = {}
  64. def transform(self, node, results):
  65. import_mod = results.get("module_name")
  66. if import_mod:
  67. mod_name = import_mod.value
  68. new_name = unicode(self.mapping[mod_name])
  69. import_mod.replace(Name(new_name, prefix=import_mod.prefix))
  70. if "name_import" in results:
  71. # If it's not a "from x import x, y" or "import x as y" import,
  72. # marked its usage to be replaced.
  73. self.replace[mod_name] = new_name
  74. if "multiple_imports" in results:
  75. # This is a nasty hack to fix multiple imports on a line (e.g.,
  76. # "import StringIO, urlparse"). The problem is that I can't
  77. # figure out an easy way to make a pattern recognize the keys of
  78. # MAPPING randomly sprinkled in an import statement.
  79. results = self.match(node)
  80. if results:
  81. self.transform(node, results)
  82. else:
  83. # Replace usage of the module.
  84. bare_name = results["bare_with_attr"][0]
  85. new_name = self.replace.get(bare_name.value)
  86. if new_name:
  87. bare_name.replace(Name(new_name, prefix=bare_name.prefix))