unsupported_version.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. # Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com>
  2. # Copyright (c) 2021 Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
  3. # Copyright (c) 2021 Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
  4. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  5. # For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
  6. """Checker for features used that are not supported by all python versions
  7. indicated by the py-version setting.
  8. """
  9. from astroid import nodes
  10. from pylint.checkers import BaseChecker
  11. from pylint.checkers.utils import (
  12. check_messages,
  13. safe_infer,
  14. uninferable_final_decorators,
  15. )
  16. from pylint.interfaces import IAstroidChecker
  17. from pylint.lint import PyLinter
  18. from pylint.utils import get_global_option
  19. class UnsupportedVersionChecker(BaseChecker):
  20. """Checker for features that are not supported by all python versions
  21. indicated by the py-version setting.
  22. """
  23. __implements__ = (IAstroidChecker,)
  24. name = "unsupported_version"
  25. msgs = {
  26. "W1601": (
  27. "F-strings are not supported by all versions included in the py-version setting",
  28. "using-f-string-in-unsupported-version",
  29. "Used when the py-version set by the user is lower than 3.6 and pylint encounters "
  30. "a f-string.",
  31. ),
  32. "W1602": (
  33. "typing.final is not supported by all versions included in the py-version setting",
  34. "using-final-decorator-in-unsupported-version",
  35. "Used when the py-version set by the user is lower than 3.8 and pylint encounters "
  36. "a ``typing.final`` decorator.",
  37. ),
  38. }
  39. def open(self) -> None:
  40. """Initialize visit variables and statistics."""
  41. py_version = get_global_option(self, "py-version")
  42. self._py36_plus = py_version >= (3, 6)
  43. self._py38_plus = py_version >= (3, 8)
  44. @check_messages("using-f-string-in-unsupported-version")
  45. def visit_joinedstr(self, node: nodes.JoinedStr) -> None:
  46. """Check f-strings"""
  47. if not self._py36_plus:
  48. self.add_message("using-f-string-in-unsupported-version", node=node)
  49. @check_messages("using-final-decorator-in-unsupported-version")
  50. def visit_decorators(self, node: nodes.Decorators) -> None:
  51. """Check decorators"""
  52. self._check_typing_final(node)
  53. def _check_typing_final(self, node: nodes.Decorators) -> None:
  54. """Add a message when the `typing.final` decorator is used and the
  55. py-version is lower than 3.8"""
  56. if self._py38_plus:
  57. return
  58. decorators = []
  59. for decorator in node.get_children():
  60. inferred = safe_infer(decorator)
  61. if inferred and inferred.qname() == "typing.final":
  62. decorators.append(decorator)
  63. for decorator in decorators or uninferable_final_decorators(node):
  64. self.add_message(
  65. "using-final-decorator-in-unsupported-version", node=decorator
  66. )
  67. def register(linter: PyLinter) -> None:
  68. """Required method to auto register this checker"""
  69. linter.register_checker(UnsupportedVersionChecker(linter))