Skip to content

Commit 08f9be9

Browse files
Add unsupported version checks for Python 3.8+ syntax
walrus operator #9820 positional-only args #9823
1 parent 2d484f5 commit 08f9be9

27 files changed

+151
-48
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import random
2+
3+
# +1: [using-assignment-expression-in-unsupported-version]
4+
if zero_or_one := random.randint(0, 1):
5+
assert zero_or_one == 1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The assignment expression (walrus) operator (`:=`) was introduced in Python 3.8; to use it, please use a more recent version of Python.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import random
2+
3+
zero_or_one = random.randint(0, 1)
4+
if zero_or_one:
5+
assert zero_or_one == 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[main]
2+
py-version=3.7
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def add(x, y, /): # [using-positional-only-args-in-unsupported-version]
2+
return x + y
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Positional-only arguments were introduced in Python 3.8; to use them, please use a more recent version of Python.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# pylint: disable=missing-function-docstring, missing-module-docstring
2+
def add(x, y):
3+
return x + y
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[main]
2+
py-version=3.7

doc/user_guide/checkers/features.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,9 @@ Verbatim name of the checker is ``unsupported_version``.
13511351

13521352
Unsupported Version checker Messages
13531353
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1354+
:using-assignment-expression-in-unsupported-version (W2605): *Assignment expression is not supported by all versions included in the py-version setting*
1355+
Used when the py-version set by the user is lower than 3.8 and pylint
1356+
encounters an assignment expression (walrus) operator.
13541357
:using-exception-groups-in-unsupported-version (W2603): *Exception groups are not supported by all versions included in the py-version setting*
13551358
Used when the py-version set by the user is lower than 3.11 and pylint
13561359
encounters ``except*`` or `ExceptionGroup``.
@@ -1360,6 +1363,9 @@ Unsupported Version checker Messages
13601363
: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*
13611364
Used when the py-version set by the user is lower than 3.12 and pylint
13621365
encounters generic type syntax.
1366+
:using-positional-only-args-in-unsupported-version (W2606): *Positional-only arguments are not supported by all versions included in the py-version setting*
1367+
Used when the py-version set by the user is lower than 3.8 and pylint
1368+
encounters positional-only arguments.
13631369
:using-final-decorator-in-unsupported-version (W2602): *typing.final is not supported by all versions included in the py-version setting*
13641370
Used when the py-version set by the user is lower than 3.8 and pylint
13651371
encounters a ``typing.final`` decorator.

doc/user_guide/messages/messages_overview.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,13 @@ All messages in the warning category:
348348
warning/useless-parent-delegation
349349
warning/useless-type-doc
350350
warning/useless-with-lock
351+
warning/using-assignment-expression-in-unsupported-version
351352
warning/using-constant-test
352353
warning/using-exception-groups-in-unsupported-version
353354
warning/using-f-string-in-unsupported-version
354355
warning/using-final-decorator-in-unsupported-version
355356
warning/using-generic-type-syntax-in-unsupported-version
357+
warning/using-positional-only-args-in-unsupported-version
356358
warning/while-used
357359
warning/wildcard-import
358360
warning/wrong-exception-operation

doc/whatsnew/fragments/9820.new_check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add `using-assignment-expression-in-unsupported-version` for uses of `:=` (walrus operator)
2+
on Python versions below 3.8 provided with `--py-version`.
3+
4+
Closes #9820

doc/whatsnew/fragments/9823.new_check

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add `using-positional-only-args-in-unsupported-version` for uses of positional-only args on
2+
Python versions below 3.8 provided with `--py-version`.
3+
4+
Closes #9823

pylint/checkers/unsupported_version.py

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
safe_infer,
1919
uninferable_final_decorators,
2020
)
21+
from pylint.interfaces import HIGH
2122

2223
if TYPE_CHECKING:
2324
from pylint.lint import PyLinter
@@ -54,6 +55,18 @@ class UnsupportedVersionChecker(BaseChecker):
5455
"Used when the py-version set by the user is lower than 3.12 and pylint encounters "
5556
"generic type syntax.",
5657
),
58+
"W2605": (
59+
"Assignment expression is not supported by all versions included in the py-version setting",
60+
"using-assignment-expression-in-unsupported-version",
61+
"Used when the py-version set by the user is lower than 3.8 and pylint encounters "
62+
"an assignment expression (walrus) operator.",
63+
),
64+
"W2606": (
65+
"Positional-only arguments are not supported by all versions included in the py-version setting",
66+
"using-positional-only-args-in-unsupported-version",
67+
"Used when the py-version set by the user is lower than 3.8 and pylint encounters "
68+
"positional-only arguments.",
69+
),
5770
}
5871

5972
def open(self) -> None:
@@ -68,7 +81,27 @@ def open(self) -> None:
6881
def visit_joinedstr(self, node: nodes.JoinedStr) -> None:
6982
"""Check f-strings."""
7083
if not self._py36_plus:
71-
self.add_message("using-f-string-in-unsupported-version", node=node)
84+
self.add_message(
85+
"using-f-string-in-unsupported-version", node=node, confidence=HIGH
86+
)
87+
88+
@only_required_for_messages("using-assignment-expression-in-unsupported-version")
89+
def visit_namedexpr(self, node: nodes.JoinedStr) -> None:
90+
if not self._py38_plus:
91+
self.add_message(
92+
"using-assignment-expression-in-unsupported-version",
93+
node=node,
94+
confidence=HIGH,
95+
)
96+
97+
@only_required_for_messages("using-positional-only-args-in-unsupported-version")
98+
def visit_arguments(self, node: nodes.Arguments) -> None:
99+
if not self._py38_plus and node.posonlyargs:
100+
self.add_message(
101+
"using-positional-only-args-in-unsupported-version",
102+
node=node,
103+
confidence=HIGH,
104+
)
72105

73106
@only_required_for_messages("using-final-decorator-in-unsupported-version")
74107
def visit_decorators(self, node: nodes.Decorators) -> None:
@@ -90,13 +123,19 @@ def _check_typing_final(self, node: nodes.Decorators) -> None:
90123

91124
for decorator in decorators or uninferable_final_decorators(node):
92125
self.add_message(
93-
"using-final-decorator-in-unsupported-version", node=decorator
126+
"using-final-decorator-in-unsupported-version",
127+
node=decorator,
128+
confidence=HIGH,
94129
)
95130

96131
@only_required_for_messages("using-exception-groups-in-unsupported-version")
97132
def visit_trystar(self, node: nodes.TryStar) -> None:
98133
if not self._py311_plus:
99-
self.add_message("using-exception-groups-in-unsupported-version", node=node)
134+
self.add_message(
135+
"using-exception-groups-in-unsupported-version",
136+
node=node,
137+
confidence=HIGH,
138+
)
100139

101140
@only_required_for_messages("using-exception-groups-in-unsupported-version")
102141
def visit_excepthandler(self, node: nodes.ExceptHandler) -> None:
@@ -105,7 +144,11 @@ def visit_excepthandler(self, node: nodes.ExceptHandler) -> None:
105144
and isinstance(node.type, nodes.Name)
106145
and node.type.name == "ExceptionGroup"
107146
):
108-
self.add_message("using-exception-groups-in-unsupported-version", node=node)
147+
self.add_message(
148+
"using-exception-groups-in-unsupported-version",
149+
node=node,
150+
confidence=HIGH,
151+
)
109152

110153
@only_required_for_messages("using-exception-groups-in-unsupported-version")
111154
def visit_raise(self, node: nodes.Raise) -> None:
@@ -115,27 +158,37 @@ def visit_raise(self, node: nodes.Raise) -> None:
115158
and isinstance(node.exc.func, nodes.Name)
116159
and node.exc.func.name == "ExceptionGroup"
117160
):
118-
self.add_message("using-exception-groups-in-unsupported-version", node=node)
161+
self.add_message(
162+
"using-exception-groups-in-unsupported-version",
163+
node=node,
164+
confidence=HIGH,
165+
)
119166

120167
@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
121168
def visit_typealias(self, node: nodes.TypeAlias) -> None:
122169
if not self._py312_plus:
123170
self.add_message(
124-
"using-generic-type-syntax-in-unsupported-version", node=node
171+
"using-generic-type-syntax-in-unsupported-version",
172+
node=node,
173+
confidence=HIGH,
125174
)
126175

127176
@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
128177
def visit_typevar(self, node: nodes.TypeVar) -> None:
129178
if not self._py312_plus:
130179
self.add_message(
131-
"using-generic-type-syntax-in-unsupported-version", node=node
180+
"using-generic-type-syntax-in-unsupported-version",
181+
node=node,
182+
confidence=HIGH,
132183
)
133184

134185
@only_required_for_messages("using-generic-type-syntax-in-unsupported-version")
135186
def visit_typevartuple(self, node: nodes.TypeVarTuple) -> None:
136187
if not self._py312_plus:
137188
self.add_message(
138-
"using-generic-type-syntax-in-unsupported-version", node=node
189+
"using-generic-type-syntax-in-unsupported-version",
190+
node=node,
191+
confidence=HIGH,
139192
)
140193

141194

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
broad-exception-caught:14:7:14:16::Catching too general exception Exception:INFERENCE
2-
broad-exception-caught:20:7:20:20::Catching too general exception BaseException:INFERENCE
3-
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
1+
broad-exception-caught:14:7:14:16::Catching too general exception Exception:INFERENCE
2+
broad-exception-caught:20:7:20:20::Catching too general exception BaseException:INFERENCE
3+
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
broad-exception-caught:14:8:14:17::Catching too general exception Exception:INFERENCE
2-
broad-exception-caught:20:8:20:21::Catching too general exception BaseException:INFERENCE
3-
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
1+
broad-exception-caught:14:8:14:17::Catching too general exception Exception:INFERENCE
2+
broad-exception-caught:20:8:20:21::Catching too general exception BaseException:INFERENCE
3+
broad-exception-caught:32:7:32:27::Catching too general exception CustomBroadException:INFERENCE
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
2-
broad-exception-raised:20:8:20:34:raise_and_catch:"Raising too general exception: Exception":INFERENCE
3-
broad-exception-caught:21:11:21:20:raise_and_catch:Catching too general exception Exception:INFERENCE
4-
broad-exception-raised:38:8:38:35:raise_catch_raise:"Raising too general exception: Exception":INFERENCE
5-
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias:"Raising too general exception: Exception":INFERENCE
6-
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
7-
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
8-
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
1+
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
2+
broad-exception-raised:20:8:20:34:raise_and_catch:"Raising too general exception: Exception":INFERENCE
3+
broad-exception-caught:21:11:21:20:raise_and_catch:Catching too general exception Exception:INFERENCE
4+
broad-exception-raised:38:8:38:35:raise_catch_raise:"Raising too general exception: Exception":INFERENCE
5+
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias:"Raising too general exception: Exception":INFERENCE
6+
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
7+
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
8+
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
2-
broad-exception-raised:20:8:20:34:raise_and_catch_star:"Raising too general exception: Exception":INFERENCE
3-
broad-exception-caught:21:12:21:21:raise_and_catch_star:Catching too general exception Exception:INFERENCE
4-
broad-exception-raised:38:8:38:35:raise_catch_raise_star:"Raising too general exception: Exception":INFERENCE
5-
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias_star:"Raising too general exception: Exception":INFERENCE
6-
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
7-
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
8-
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
1+
broad-exception-raised:15:4:15:41:exploding_apple:"Raising too general exception: Exception":INFERENCE
2+
broad-exception-raised:20:8:20:34:raise_and_catch_star:"Raising too general exception: Exception":INFERENCE
3+
broad-exception-caught:21:12:21:21:raise_and_catch_star:Catching too general exception Exception:INFERENCE
4+
broad-exception-raised:38:8:38:35:raise_catch_raise_star:"Raising too general exception: Exception":INFERENCE
5+
broad-exception-raised:46:8:46:40:raise_catch_raise_using_alias_star:"Raising too general exception: Exception":INFERENCE
6+
broad-exception-raised:48:0:48:17::"Raising too general exception: Exception":INFERENCE
7+
broad-exception-raised:49:0:49:21::"Raising too general exception: BaseException":INFERENCE
8+
broad-exception-raised:50:0:50:28::"Raising too general exception: CustomBroadException":INFERENCE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# pylint: disable=missing-function-docstring, missing-module-docstring
2+
import random
3+
if zero_or_one := random.randint(0, 1): # [using-assignment-expression-in-unsupported-version]
4+
assert zero_or_one == 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[main]
2+
py-version=3.7
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
using-assignment-expression-in-unsupported-version:3:3:3:38::Assignment expression is not supported by all versions included in the py-version setting:HIGH
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
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
2-
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
3-
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
1+
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:HIGH
2+
using-exception-groups-in-unsupported-version:8:0:13:36::Exception groups are not supported by all versions included in the py-version setting:HIGH
3+
using-exception-groups-in-unsupported-version:18:0:21:29::Exception groups are not supported by all versions included in the py-version setting:HIGH
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
using-f-string-in-unsupported-version:4:6:4:26::F-strings are not supported by all versions included in the py-version setting:UNDEFINED
2-
using-f-string-in-unsupported-version:5:10:5:53::F-strings are not supported by all versions included in the py-version setting:UNDEFINED
1+
using-f-string-in-unsupported-version:4:6:4:26::F-strings are not supported by all versions included in the py-version setting:HIGH
2+
using-f-string-in-unsupported-version:5:10:5:53::F-strings are not supported by all versions included in the py-version setting:HIGH
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
using-final-decorator-in-unsupported-version:10:1:10:6:MyClass1:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
2-
using-final-decorator-in-unsupported-version:12:5:12:10:MyClass1.my_method:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
3-
using-final-decorator-in-unsupported-version:13:5:13:10:MyClass1.my_method:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
4-
using-final-decorator-in-unsupported-version:18:1:18:8:MyClass2:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
5-
using-final-decorator-in-unsupported-version:20:5:20:12:MyClass2.my_method:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
6-
using-final-decorator-in-unsupported-version:25:1:25:13:MyClass3:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
7-
using-final-decorator-in-unsupported-version:27:5:27:17:MyClass3.my_method:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
8-
using-final-decorator-in-unsupported-version:32:1:32:15:MyClass4:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
9-
using-final-decorator-in-unsupported-version:34:5:34:19:MyClass4.my_method:typing.final is not supported by all versions included in the py-version setting:UNDEFINED
1+
using-final-decorator-in-unsupported-version:10:1:10:6:MyClass1:typing.final is not supported by all versions included in the py-version setting:HIGH
2+
using-final-decorator-in-unsupported-version:12:5:12:10:MyClass1.my_method:typing.final is not supported by all versions included in the py-version setting:HIGH
3+
using-final-decorator-in-unsupported-version:13:5:13:10:MyClass1.my_method:typing.final is not supported by all versions included in the py-version setting:HIGH
4+
using-final-decorator-in-unsupported-version:18:1:18:8:MyClass2:typing.final is not supported by all versions included in the py-version setting:HIGH
5+
using-final-decorator-in-unsupported-version:20:5:20:12:MyClass2.my_method:typing.final is not supported by all versions included in the py-version setting:HIGH
6+
using-final-decorator-in-unsupported-version:25:1:25:13:MyClass3:typing.final is not supported by all versions included in the py-version setting:HIGH
7+
using-final-decorator-in-unsupported-version:27:5:27:17:MyClass3.my_method:typing.final is not supported by all versions included in the py-version setting:HIGH
8+
using-final-decorator-in-unsupported-version:32:1:32:15:MyClass4:typing.final is not supported by all versions included in the py-version setting:HIGH
9+
using-final-decorator-in-unsupported-version:34:5:34:19:MyClass4.my_method:typing.final is not supported by all versions included in the py-version setting:HIGH
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
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
2-
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
3-
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
4-
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
1+
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:HIGH
2+
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:HIGH
3+
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:HIGH
4+
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:HIGH
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# pylint: disable=missing-function-docstring, missing-module-docstring
2+
def add(x, y, /): # [using-positional-only-args-in-unsupported-version]
3+
return x + y
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[main]
2+
py-version=3.7
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
using-positional-only-args-in-unsupported-version:2:0:None:None:add:Positional-only arguments are not supported by all versions included in the py-version setting:HIGH

0 commit comments

Comments
 (0)