Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unsupported version checks for major 3.11 and 3.12 features #9792

Merged
merged 12 commits into from
Jul 16, 2024
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 @@
"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 @@
"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)
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved

@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)

Check warning on line 108 in pylint/checkers/unsupported_version.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/unsupported_version.py#L108

Added line #L108 was not covered by tests

@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(

Check warning on line 130 in pylint/checkers/unsupported_version.py

View check run for this annotation

Codecov / codecov/patch

pylint/checkers/unsupported_version.py#L130

Added line #L130 was not covered by tests
"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,13 @@
# 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")
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,2 @@
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pylint: disable=missing-function-docstring, missing-module-docstring, line-too-long
type Vector = list[float] # [using-generic-type-syntax-in-unsupported-version]
# +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,3 @@
using-generic-type-syntax-in-unsupported-version:2:0:2:25::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:4:0:4: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:4:11:4:14::Generic type syntax (PEP 695) is not supported by all versions included in the py-version setting:UNDEFINED