__init__.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. '''pylint_flask module'''
  2. from astroid import MANAGER
  3. from astroid import nodes
  4. import re
  5. def register(_):
  6. '''register is expected by pylint for plugins, but we are creating a
  7. transform, not registering a checker.
  8. '''
  9. pass
  10. def copy_node_info(src, dest):
  11. """Copy information from src to dest
  12. Every node in the AST has to have line number information. Get
  13. the information from the old stmt."""
  14. for attr in ['lineno', 'fromlineno', 'tolineno',
  15. 'col_offset', 'parent']:
  16. if hasattr(src, attr):
  17. setattr(dest, attr, getattr(src, attr))
  18. def mark_transformed(node):
  19. '''Mark a node as transformed so we don't process it multiple times.'''
  20. node.pylint_flask_was_transformed = True
  21. def is_transformed(node):
  22. '''Return True if `node` was already transformed.'''
  23. return getattr(node, 'pylint_flask_was_transformed', False)
  24. def make_non_magical_flask_import(flask_ext_name):
  25. '''Convert a flask.ext.admin into flask_admin.'''
  26. match = re.match(r'flask\.ext\.(.*)', flask_ext_name)
  27. if match is None:
  28. raise LookupError("Module name `{}` doesn't match"
  29. "`flask.ext` style import.")
  30. from_name = match.group(1)
  31. actual_module_name = 'flask_{}'.format(from_name)
  32. return actual_module_name
  33. def transform_flask_from_import(node):
  34. '''Translates a flask.ext from-style import into a non-magical import.
  35. Translates:
  36. from flask.ext import wtf, bcrypt as fcrypt
  37. Into:
  38. import flask_wtf as wtf, flask_bcrypt as fcrypt
  39. '''
  40. new_names = []
  41. # node.names is a list of 2-tuples. Each tuple consists of (name, as_name).
  42. # So, the import would be represented as:
  43. #
  44. # from flask.ext import wtf as ftw, admin
  45. #
  46. # node.names = [('wtf', 'ftw'), ('admin', None)]
  47. for (name, as_name) in node.names:
  48. actual_module_name = 'flask_{}'.format(name)
  49. new_names.append((actual_module_name, as_name or name))
  50. new_node = nodes.Import()
  51. copy_node_info(node, new_node)
  52. new_node.names = new_names
  53. mark_transformed(new_node)
  54. return new_node
  55. def is_flask_from_import(node):
  56. '''Predicate for checking if we have the flask module.'''
  57. # Check for transformation first so we don't double process
  58. return not is_transformed(node) and node.modname == 'flask.ext'
  59. MANAGER.register_transform(nodes.ImportFrom,
  60. transform_flask_from_import,
  61. is_flask_from_import)
  62. def transform_flask_from_long(node):
  63. '''Translates a flask.ext.wtf from-style import into a non-magical import.
  64. Translates:
  65. from flask.ext.wtf import Form
  66. from flask.ext.admin.model import InlineFormAdmin
  67. Into:
  68. from flask_wtf import Form
  69. from flask_admin.model import InlineFormAdmin
  70. '''
  71. actual_module_name = make_non_magical_flask_import(node.modname)
  72. new_node = nodes.ImportFrom(actual_module_name, node.names, node.level)
  73. copy_node_info(node, new_node)
  74. mark_transformed(new_node)
  75. return new_node
  76. def is_flask_from_import_long(node):
  77. '''Check if an import is like `from flask.ext.wtf import Form`.'''
  78. # Check for transformation first so we don't double process
  79. return not is_transformed(node) and node.modname.startswith('flask.ext.')
  80. MANAGER.register_transform(nodes.ImportFrom,
  81. transform_flask_from_long,
  82. is_flask_from_import_long)
  83. def transform_flask_bare_import(node):
  84. '''Translates a flask.ext.wtf bare import into a non-magical import.
  85. Translates:
  86. import flask.ext.admin as admin
  87. Into:
  88. import flask_admin as admin
  89. '''
  90. new_names = []
  91. for (name, as_name) in node.names:
  92. match = re.match(r'flask\.ext\.(.*)', name)
  93. from_name = match.group(1)
  94. actual_module_name = 'flask_{}'.format(from_name)
  95. new_names.append((actual_module_name, as_name))
  96. new_node = nodes.Import()
  97. copy_node_info(node, new_node)
  98. new_node.names = new_names
  99. mark_transformed(new_node)
  100. return new_node
  101. def is_flask_bare_import(node):
  102. '''Check if an import is like `import flask.ext.admin as admin`.'''
  103. return (not is_transformed(node) and
  104. any(['flask.ext' in pair[0] for pair in node.names]))
  105. MANAGER.register_transform(nodes.Import,
  106. transform_flask_bare_import,
  107. is_flask_bare_import)