Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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