_odoo_checker_markup.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. from typing import Optional
  2. import astroid
  3. from pylint import interfaces, checkers
  4. try:
  5. from pylint.checkers.utils import only_required_for_messages
  6. except ImportError:
  7. from pylint.checkers.utils import check_messages as only_required_for_messages
  8. class OdooBaseChecker(checkers.BaseChecker):
  9. __implements__ = interfaces.IAstroidChecker
  10. name = 'odoo'
  11. msgs = {
  12. 'E8504': (
  13. 'The Markup constructor called with a non-constant argument',
  14. 'non-const-markup',
  15. '',
  16. )
  17. }
  18. @only_required_for_messages('non-const-markup')
  19. def visit_call(self, node):
  20. if (isinstance(node.func, astroid.Name) and
  21. node.func.name == "Markup" and
  22. not self._is_constant(node.args[0])):
  23. self.add_message('non-const-markup', node=node, col_offset=len(node.as_string().split('\\n')))
  24. elif (isinstance(node.func, astroid.Attribute) and
  25. node.func.attrname == "Markup" and
  26. not self._is_constant(node.args[0])):
  27. self.add_message('non-const-markup', node=node, col_offset=len(node.as_string().split('\\n')))
  28. def _is_constant(self, node: Optional[astroid.node_classes.NodeNG]) -> bool:
  29. if isinstance(node, astroid.Const) or node is None:
  30. return True
  31. elif isinstance(node, astroid.JoinedStr):
  32. return all(map(self._is_constant, node.values))
  33. elif isinstance(node, astroid.FormattedValue):
  34. return self._is_constant(node.value)
  35. elif isinstance(node, astroid.Name):
  36. _, assignments = node.lookup(node.name)
  37. return all(map(self._is_constant, assignments))
  38. elif isinstance(node, astroid.AssignName):
  39. return self._is_constant(node.parent)
  40. elif isinstance(node, astroid.Assign):
  41. return self._is_constant(node.value)
  42. elif (isinstance(node, astroid.Call) and
  43. isinstance(node.func, astroid.Attribute) and
  44. node.func.attrname in ["format", "join"]):
  45. return (self._is_constant(node.func.expr) and
  46. all(map(self._is_constant, node.args)) and
  47. all(map(self._is_constant, node.keywords)))
  48. elif isinstance(node, astroid.Keyword):
  49. return self._is_constant(node.value)
  50. elif isinstance(node, (astroid.List, astroid.Set, astroid.Tuple)):
  51. return all(map(self._is_constant, node.elts))
  52. elif isinstance(node, astroid.Dict):
  53. return all(map(self._is_constant, node.values))
  54. elif isinstance(node, astroid.BinOp):
  55. return self._is_constant(node.left) and self._is_constant(node.right)
  56. elif isinstance(node, astroid.IfExp):
  57. return self._is_constant(node.body) and self._is_constant(node.orelse)
  58. return False
  59. def register(linter):
  60. linter.register_checker(OdooBaseChecker(linter))