Skip to content

Commit

Permalink
Add unsupported version checks for major 3.11 and 3.12 features (#9792)
Browse files Browse the repository at this point in the history
* Bump DEFAULT_PYTHON checks.yaml to 3.12
  • Loading branch information
jacobtylerwalls authored Jul 16, 2024
1 parent 47fb321 commit e2c15e3
Show file tree
Hide file tree
Showing 22 changed files with 155 additions and 4 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ on:
- "maintenance/**"

env:
CACHE_VERSION: 1
CACHE_VERSION: 2
KEY_PREFIX: base-venv
DEFAULT_PYTHON: "3.11"
DEFAULT_PYTHON: "3.12"
PRE_COMMIT_CACHE: ~/.cache/pre-commit

concurrency:
Expand Down
2 changes: 1 addition & 1 deletion doc/data/messages/a/anomalous-backslash-in-string/bad.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
string = "\z" # [anomalous-backslash-in-string]
string = "\z" # [syntax-error]
4 changes: 4 additions & 0 deletions doc/data/messages/a/anomalous-backslash-in-string/details.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
``\z`` is same as ``\\z`` because there's no escape sequence for ``z``. But it is not clear
for the reader of the code.

The only reason this is demonstrated to raise ``syntax-error`` is because
pylint's CI now runs on Python 3.12, where this truly raises a ``SyntaxError``.
We hope to address this discrepancy in the documentation in the future.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
print(b"\u%b" % b"0394") # [anomalous-unicode-escape-in-string]
print(b"\u%b" % b"0394") # [syntax-error]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
def f():
excs = [OSError("error 1"), SystemError("error 2")]
# +1: [using-exception-groups-in-unsupported-version]
raise ExceptionGroup("there were problems", excs)


try: # [using-exception-groups-in-unsupported-version]
f()
except* OSError as e:
print("There were OSErrors")
except* SystemError as e:
print("There were SystemErrors")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Exception groups were introduced in Python 3.11; to use it, please use a more recent version of Python.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
def f():
raise OSError("error 1")


try:
f()
except OSError as e:
print("There were OSErrors")
except SystemError as e:
print("There were SystemErrors")
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[main]
py-version=3.10
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type Vector = list[float] # [using-generic-type-syntax-in-unsupported-version]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic type syntax was introduced in Python 3.12; to use it, please use a more recent version of Python.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from typing import TypeAlias

Vector: TypeAlias = list[float]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[main]
py-version=3.11
6 changes: 6 additions & 0 deletions doc/user_guide/checkers/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1351,9 +1351,15 @@ Verbatim name of the checker is ``unsupported_version``.

Unsupported Version checker Messages
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:using-exception-groups-in-unsupported-version (W2603): *Exception groups are not supported by all versions included in the py-version setting*
Used when the py-version set by the user is lower than 3.11 and pylint
encounters ``except*`` or `ExceptionGroup``.
:using-f-string-in-unsupported-version (W2601): *F-strings are not supported by all versions included in the py-version setting*
Used when the py-version set by the user is lower than 3.6 and pylint
encounters an f-string.
:using-generic-type-syntax-in-unsupported-version (W2604): *Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting*
Used when the py-version set by the user is lower than 3.12 and pylint
encounters generic type syntax.
:using-final-decorator-in-unsupported-version (W2602): *typing.final is not supported by all versions included in the py-version setting*
Used when the py-version set by the user is lower than 3.8 and pylint
encounters a ``typing.final`` decorator.
Expand Down
2 changes: 2 additions & 0 deletions doc/user_guide/messages/messages_overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,10 @@ All messages in the warning category:
warning/useless-type-doc
warning/useless-with-lock
warning/using-constant-test
warning/using-exception-groups-in-unsupported-version
warning/using-f-string-in-unsupported-version
warning/using-final-decorator-in-unsupported-version
warning/using-generic-type-syntax-in-unsupported-version
warning/while-used
warning/wildcard-import
warning/wrong-exception-operation
Expand Down
5 changes: 5 additions & 0 deletions doc/whatsnew/fragments/9791.new_check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Add `using-exception-group-in-unsupported-version` and
`using-generic-type-syntax-in-unsupported-version` for uses of Python 3.11+ or
3.12+ features on lower supported versions provided with `--py-version`.

Closes #9791
59 changes: 59 additions & 0 deletions pylint/checkers/unsupported_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,27 @@ class UnsupportedVersionChecker(BaseChecker):
"Used when the py-version set by the user is lower than 3.8 and pylint encounters "
"a ``typing.final`` decorator.",
),
"W2603": (
"Exception groups are not supported by all versions included in the py-version setting",
"using-exception-groups-in-unsupported-version",
"Used when the py-version set by the user is lower than 3.11 and pylint encounters "
"``except*`` or `ExceptionGroup``.",
),
"W2604": (
"Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting",
"using-generic-type-syntax-in-unsupported-version",
"Used when the py-version set by the user is lower than 3.12 and pylint encounters "
"generic type syntax.",
),
}

def open(self) -> None:
"""Initialize visit variables and statistics."""
py_version = self.linter.config.py_version
self._py36_plus = py_version >= (3, 6)
self._py38_plus = py_version >= (3, 8)
self._py311_plus = py_version >= (3, 11)
self._py312_plus = py_version >= (3, 12)

@only_required_for_messages("using-f-string-in-unsupported-version")
def visit_joinedstr(self, node: nodes.JoinedStr) -> None:
Expand Down Expand Up @@ -79,6 +93,51 @@ def _check_typing_final(self, node: nodes.Decorators) -> None:
"using-final-decorator-in-unsupported-version", node=decorator
)

@only_required_for_messages("using-exception-groups-in-unsupported-version")
def visit_trystar(self, node: nodes.TryStar) -> None:
if not self._py311_plus:
self.add_message("using-exception-groups-in-unsupported-version", node=node)

@only_required_for_messages("using-exception-groups-in-unsupported-version")
def visit_excepthandler(self, node: nodes.ExceptHandler) -> None:
if (
not self._py311_plus
and isinstance(node.type, nodes.Name)
and node.type.name == "ExceptionGroup"
):
self.add_message("using-exception-groups-in-unsupported-version", node=node)

@only_required_for_messages("using-exception-groups-in-unsupported-version")
def visit_raise(self, node: nodes.Raise) -> None:
if (
not self._py311_plus
and isinstance(node.exc, nodes.Call)
and isinstance(node.exc.func, nodes.Name)
and node.exc.func.name == "ExceptionGroup"
):
self.add_message("using-exception-groups-in-unsupported-version", node=node)

@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
def visit_typealias(self, node: nodes.TypeAlias) -> None:
if not self._py312_plus:
self.add_message(
"using-generic-type-syntax-in-unsupported-version", node=node
)

@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
def visit_typevar(self, node: nodes.TypeVar) -> None:
if not self._py312_plus:
self.add_message(
"using-generic-type-syntax-in-unsupported-version", node=node
)

@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
def visit_typevartuple(self, node: nodes.TypeVarTuple) -> None:
if not self._py312_plus:
self.add_message(
"using-generic-type-syntax-in-unsupported-version", node=node
)


def register(linter: PyLinter) -> None:
linter.register_checker(UnsupportedVersionChecker(linter))
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# pylint: disable=missing-function-docstring, missing-module-docstring
def f():
excs = [OSError("error 1"), SystemError("error 2")]
# +1: [using-exception-groups-in-unsupported-version]
raise ExceptionGroup("there were problems", excs)


try: # [using-exception-groups-in-unsupported-version]
f()
except* OSError as e:
print("There were OSErrors")
except* SystemError as e:
print("There were SystemErrors")


try:
f()
except ExceptionGroup as group: # [using-exception-groups-in-unsupported-version]
# https://github.com/pylint-dev/pylint/issues/8985
for exc in group.exceptions: # pylint: disable=not-an-iterable
print("ERROR: ", exc)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[main]
py-version=3.10

[testoptions]
min_pyver=3.11
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using-exception-groups-in-unsupported-version:5:4:5:53:f:Exception groups are not supported by all versions included in the py-version setting:UNDEFINED
using-exception-groups-in-unsupported-version:8:0:13:36::Exception groups are not supported by all versions included in the py-version setting:UNDEFINED
using-exception-groups-in-unsupported-version:18:0:21:29::Exception groups are not supported by all versions included in the py-version setting:UNDEFINED
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# pylint: disable=missing-function-docstring, missing-module-docstring, line-too-long
# +1: [using-generic-type-syntax-in-unsupported-version, using-generic-type-syntax-in-unsupported-version]
type Point[T] = tuple[float, float]
# +1: [using-generic-type-syntax-in-unsupported-version, using-generic-type-syntax-in-unsupported-version]
type Alias[*Ts] = tuple[*Ts]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[main]
py-version=3.11

[testoptions]
min_pyver=3.12
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using-generic-type-syntax-in-unsupported-version:3:0:3:35::Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting:UNDEFINED
using-generic-type-syntax-in-unsupported-version:3:11:3:12::Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting:UNDEFINED
using-generic-type-syntax-in-unsupported-version:5:0:5:28::Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting:UNDEFINED
using-generic-type-syntax-in-unsupported-version:5:11:5:14::Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting:UNDEFINED

0 comments on commit e2c15e3

Please sign in to comment.