fix_features.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. u"""
  2. Warn about features that are not present in Python 2.5, giving a message that
  3. points to the earliest version of Python 2.x (or 3.x, if none) that supports it
  4. """
  5. from .feature_base import Feature, Features
  6. from lib2to3 import fixer_base
  7. FEATURES = [
  8. #(FeatureName,
  9. # FeaturePattern,
  10. # FeatureMinVersion,
  11. #),
  12. (u"memoryview",
  13. u"power < 'memoryview' trailer < '(' any* ')' > any* >",
  14. u"2.7",
  15. ),
  16. (u"numbers",
  17. u"""import_from< 'from' 'numbers' 'import' any* > |
  18. import_name< 'import' ('numbers' dotted_as_names< any* 'numbers' any* >) >""",
  19. u"2.6",
  20. ),
  21. (u"abc",
  22. u"""import_name< 'import' ('abc' dotted_as_names< any* 'abc' any* >) > |
  23. import_from< 'from' 'abc' 'import' any* >""",
  24. u"2.6",
  25. ),
  26. (u"io",
  27. u"""import_name< 'import' ('io' dotted_as_names< any* 'io' any* >) > |
  28. import_from< 'from' 'io' 'import' any* >""",
  29. u"2.6",
  30. ),
  31. (u"bin",
  32. u"power< 'bin' trailer< '(' any* ')' > any* >",
  33. u"2.6",
  34. ),
  35. (u"formatting",
  36. u"power< any trailer< '.' 'format' > trailer< '(' any* ')' > >",
  37. u"2.6",
  38. ),
  39. (u"nonlocal",
  40. u"global_stmt< 'nonlocal' any* >",
  41. u"3.0",
  42. ),
  43. (u"with_traceback",
  44. u"trailer< '.' 'with_traceback' >",
  45. u"3.0",
  46. ),
  47. ]
  48. class FixFeatures(fixer_base.BaseFix):
  49. run_order = 9 # Wait until all other fixers have run to check for these
  50. # To avoid spamming, we only want to warn for each feature once.
  51. features_warned = set()
  52. # Build features from the list above
  53. features = Features([Feature(name, pattern, version) for \
  54. name, pattern, version in FEATURES])
  55. PATTERN = features.PATTERN
  56. def match(self, node):
  57. to_ret = super(FixFeatures, self).match(node)
  58. # We want the mapping only to tell us the node's specific information.
  59. try:
  60. del to_ret[u'node']
  61. except Exception:
  62. # We want it to delete the 'node' from the results
  63. # if it's there, so we don't care if it fails for normal reasons.
  64. pass
  65. return to_ret
  66. def transform(self, node, results):
  67. for feature_name in results:
  68. if feature_name in self.features_warned:
  69. continue
  70. else:
  71. curr_feature = self.features[feature_name]
  72. if curr_feature.version >= u"3":
  73. fail = self.cannot_convert
  74. else:
  75. fail = self.warning
  76. fail(node, reason=curr_feature.message_text())
  77. self.features_warned.add(feature_name)