From 744ade6ca49f769f8f86dbe31ad81e51c7601af5 Mon Sep 17 00:00:00 2001 From: Peter Kolbus Date: Thu, 6 May 2021 07:53:56 -0500 Subject: [PATCH 1/4] tox: Enable testing python 3.6.0 The requirements_test.txt includes black, pre-commit, and pyupgrade which are not compatible with Python 3.6.0. Add python_full_version markers so that `tox -e py36` works with 3.6.0. --- requirements_test.txt | 2 +- requirements_test_pre_commit.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements_test.txt b/requirements_test.txt index 90c06b0c28..4b033937d5 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -2,7 +2,7 @@ -r requirements_test_min.txt coveralls~=3.0 coverage~=5.5 -pre-commit~=2.12 +pre-commit~=2.12;python_full_version>="3.6.2" pyenchant~=3.2 pytest-cov~=2.11 pytest-profiling~=1.7 diff --git a/requirements_test_pre_commit.txt b/requirements_test_pre_commit.txt index b75f36fc18..ec9a56b8cb 100644 --- a/requirements_test_pre_commit.txt +++ b/requirements_test_pre_commit.txt @@ -1,7 +1,7 @@ autoflake==1.4 -black==21.5b1 +black==21.5b1;python_full_version>="3.6.2" flake8==3.9.2 isort==5.8.0 mypy==0.812 -pyupgrade==2.15.0 +pyupgrade==2.15.0;python_full_version>="3.6.1" black-disable-checker==1.0.1 From 419c91f829b80e7aebda9356a1f9b60d4800f12a Mon Sep 17 00:00:00 2001 From: Peter Kolbus Date: Mon, 26 Apr 2021 19:51:23 -0500 Subject: [PATCH 2/4] Fix typing.Counter import for Python 3.6.0 typing.Counter was added in Python 3.6.1. In the strings checker, guard the import with TYPE_CHECKING and use a type annotation comment to fix usage with Python 3.6.0. --- pylint/checkers/strings.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pylint/checkers/strings.py b/pylint/checkers/strings.py index 33544bca0b..6c23c9c71c 100644 --- a/pylint/checkers/strings.py +++ b/pylint/checkers/strings.py @@ -38,7 +38,7 @@ import numbers import re import tokenize -from typing import Counter, Iterable +from typing import TYPE_CHECKING, Iterable import astroid @@ -46,6 +46,9 @@ from pylint.checkers.utils import check_messages from pylint.interfaces import IAstroidChecker, IRawChecker, ITokenChecker +if TYPE_CHECKING: + from typing import Counter # typing.Counter added in Python 3.6.1 + _AST_NODE_STR_TYPES = ("__builtin__.unicode", "__builtin__.str", "builtins.str") # Prefixes for both strings and bytes literals per # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals @@ -750,7 +753,8 @@ def check_for_consistent_string_delimiters( Args: tokens: The tokens to be checked against for consistent usage. """ - string_delimiters: Counter[str] = collections.Counter() + # typing.Counter added in Python 3.6.1 so this type hint must be a comment + string_delimiters = collections.Counter() # type: Counter[str] # First, figure out which quote character predominates in the module for tok_type, token, _, _, _ in tokens: From 644b3ba44a2b05e3986f159de93a6b5dfee45c1e Mon Sep 17 00:00:00 2001 From: Peter Kolbus Date: Thu, 6 May 2021 08:21:56 -0500 Subject: [PATCH 3/4] Skip typing.NoReturn tests on Python < 3.6.2 typing.NoReturn was introduced in Python 3.6.2. Move the tests for issue #4122 to a separate file and skip when Python is too old. Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com> --- .../i/inconsistent/inconsistent_returns.py | 53 ------------------ .../i/inconsistent/inconsistent_returns.txt | 3 +- .../inconsistent_returns_noreturn.py | 55 +++++++++++++++++++ .../inconsistent_returns_noreturn.rc | 5 ++ .../inconsistent_returns_noreturn.txt | 1 + 5 files changed, 62 insertions(+), 55 deletions(-) create mode 100644 tests/functional/i/inconsistent/inconsistent_returns_noreturn.py create mode 100644 tests/functional/i/inconsistent/inconsistent_returns_noreturn.rc create mode 100644 tests/functional/i/inconsistent/inconsistent_returns_noreturn.txt diff --git a/tests/functional/i/inconsistent/inconsistent_returns.py b/tests/functional/i/inconsistent/inconsistent_returns.py index cc8458e6a8..08dde253e9 100644 --- a/tests/functional/i/inconsistent/inconsistent_returns.py +++ b/tests/functional/i/inconsistent/inconsistent_returns.py @@ -336,59 +336,6 @@ def bug_pylint_3873_2(): nothing_to_do() return False -import typing # pylint: disable=wrong-import-position - -def parser_error(msg) -> typing.NoReturn: #pylint:disable=unused-argument - sys.exit(1) - -def parser_error_nortype(msg): #pylint:disable=unused-argument - sys.exit(2) - - -from typing import NoReturn # pylint: disable=wrong-import-position - -def parser_error_name(msg) -> NoReturn: #pylint:disable=unused-argument - sys.exit(3) - -def bug_pylint_4122(s): - """ - Every returns is consistent because parser_error has type hints - indicating it never returns - """ - try: - n = int(s) - if n < 1: - raise ValueError() - return n - except ValueError: - parser_error('parser error') - -def bug_pylint_4122_wrong(s): # [inconsistent-return-statements] - """ - Every returns is not consistent because parser_error_nortype has no type hints - """ - try: - n = int(s) - if n < 1: - raise ValueError() - return n - except ValueError: - parser_error_nortype('parser error') - -def bug_pylint_4122_bis(s): - """ - Every returns is consistent because parser_error has type hints - indicating it never returns - """ - try: - n = int(s) - if n < 1: - raise ValueError() - return n - except ValueError: - parser_error_name('parser error') - - # https://github.com/PyCQA/pylint/issues/4019 def bug_pylint_4019(x): """ diff --git a/tests/functional/i/inconsistent/inconsistent_returns.txt b/tests/functional/i/inconsistent/inconsistent_returns.txt index 749797f91e..d0a6dd1338 100644 --- a/tests/functional/i/inconsistent/inconsistent_returns.txt +++ b/tests/functional/i/inconsistent/inconsistent_returns.txt @@ -14,5 +14,4 @@ inconsistent-return-statements:262:8:bug_1794_inner_func_in_if_counter_example_3 inconsistent-return-statements:267:0:bug_3468:Either all return statements in a function should return an expression, or none of them should. inconsistent-return-statements:277:0:bug_3468_variant:Either all return statements in a function should return an expression, or none of them should. inconsistent-return-statements:322:0:bug_pylint_3873_1:Either all return statements in a function should return an expression, or none of them should. -inconsistent-return-statements:366:0:bug_pylint_4122_wrong:Either all return statements in a function should return an expression, or none of them should. -inconsistent-return-statements:402:0:bug_pylint_4019_wrong:Either all return statements in a function should return an expression, or none of them should. +inconsistent-return-statements:349:0:bug_pylint_4019_wrong:Either all return statements in a function should return an expression, or none of them should. diff --git a/tests/functional/i/inconsistent/inconsistent_returns_noreturn.py b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.py new file mode 100644 index 0000000000..768d6e6585 --- /dev/null +++ b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.py @@ -0,0 +1,55 @@ +"""Testing inconsistent returns involving typing.NoReturn annotations.""" +# pylint: disable=missing-docstring, invalid-name + +import sys +import typing + +def parser_error(msg) -> typing.NoReturn: # pylint: disable=unused-argument + sys.exit(1) + +def parser_error_nortype(msg): # pylint: disable=unused-argument + sys.exit(2) + + +from typing import NoReturn # pylint: disable=wrong-import-position + +def parser_error_name(msg) -> NoReturn: # pylint: disable=unused-argument + sys.exit(3) + +def bug_pylint_4122(s): + """ + Every returns is consistent because parser_error has type hints + indicating it never returns + """ + try: + n = int(s) + if n < 1: + raise ValueError() + return n + except ValueError: + parser_error('parser error') + +def bug_pylint_4122_wrong(s): # [inconsistent-return-statements] + """ + Every returns is not consistent because parser_error_nortype has no type hints + """ + try: + n = int(s) + if n < 1: + raise ValueError() + return n + except ValueError: + parser_error_nortype('parser error') + +def bug_pylint_4122_bis(s): + """ + Every returns is consistent because parser_error has type hints + indicating it never returns + """ + try: + n = int(s) + if n < 1: + raise ValueError() + return n + except ValueError: + parser_error_name('parser error') diff --git a/tests/functional/i/inconsistent/inconsistent_returns_noreturn.rc b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.rc new file mode 100644 index 0000000000..bf9569ba24 --- /dev/null +++ b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.rc @@ -0,0 +1,5 @@ +[testoptions] +min_pyver=3.6.2 + +[REFACTORING] +never-returning-functions=sys.exit,sys.getdefaultencoding diff --git a/tests/functional/i/inconsistent/inconsistent_returns_noreturn.txt b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.txt new file mode 100644 index 0000000000..9b23552d19 --- /dev/null +++ b/tests/functional/i/inconsistent/inconsistent_returns_noreturn.txt @@ -0,0 +1 @@ +inconsistent-return-statements:32:0:bug_pylint_4122_wrong:Either all return statements in a function should return an expression, or none of them should. From d6e5e89c7cbed9b3b737139ea9202957534c4b36 Mon Sep 17 00:00:00 2001 From: Peter Kolbus Date: Tue, 11 May 2021 18:49:07 -0500 Subject: [PATCH 4/4] Update ChangeLog and whatsnew --- ChangeLog | 4 ++++ doc/whatsnew/2.9.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 82da849a03..b4aa2906e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -40,6 +40,10 @@ modules are added. * Don't emit ``import-error`` if import guarded behind ``if sys.version_info >= (x, x)`` +* Fix incompatibility with Python 3.6.0 caused by ``typing.Counter`` and ``typing.NoReturn`` usage + + Closes #4412 + What's New in Pylint 2.8.2? =========================== diff --git a/doc/whatsnew/2.9.rst b/doc/whatsnew/2.9.rst index 8f5bd43f2f..0a353d68ef 100644 --- a/doc/whatsnew/2.9.rst +++ b/doc/whatsnew/2.9.rst @@ -26,3 +26,5 @@ Other Changes * The output messages for ``arguments-differ`` error message have been customized based on the different error cases. * New option ``--fail-on=`` to return non-zero exit codes regardless of ``fail-under`` value. + +* Fix incompatibility with Python 3.6.0 caused by ``typing.Counter`` and ``typing.NoReturn`` usage