Skip to content

Commit

Permalink
Require Python 3.6.2 (#5068)
Browse files Browse the repository at this point in the history
* Bump python_requires to >= 3.6.2

* Import typing names directly
* Use typing.NamedTuple for MessageTest
* Add default value to MessageStyle

* Revert "Add an exception at install for python < 3.6.2 (#5171)"

This reverts commit 37e330c.

Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
  • Loading branch information
cdce8p and Pierre-Sassoulas committed Nov 25, 2021
1 parent 1f7f2e9 commit a9c1017
Show file tree
Hide file tree
Showing 12 changed files with 34 additions and 61 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -22,6 +22,10 @@ Release date: TBA
..
Put bug fixes that should not wait for a new minor version here

* Require Python ``3.6.2`` to run pylint.

Closes #5065

..
Insert your changelog randomly, it will reduce merge conflicts
(Ie. not necessarily at the end)
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -75,7 +75,7 @@ Pylint can be simply installed by running::

pip install pylint

If you are using Python 3.6+, upgrade to get full support for your version::
If you are using Python 3.6.2+, upgrade to get full support for your version::

pip install pylint --upgrade

Expand Down
2 changes: 1 addition & 1 deletion doc/faq.rst
Expand Up @@ -48,7 +48,7 @@ supported.
2.4 What versions of Python is Pylint supporting?
--------------------------------------------------

The supported running environment since Pylint 2.7.X is Python 3.6+.
The supported running environment since Pylint 2.12.1 is Python 3.6.2+.


3. Running Pylint
Expand Down
4 changes: 4 additions & 0 deletions doc/whatsnew/2.13.rst
Expand Up @@ -19,3 +19,7 @@ Extensions

Other Changes
=============

* Require Python ``3.6.2`` to run pylint.

Closes #5065
8 changes: 2 additions & 6 deletions pylint/checkers/strings.py
Expand Up @@ -41,7 +41,7 @@
import numbers
import re
import tokenize
from typing import TYPE_CHECKING, Iterable
from typing import Counter, Iterable

import astroid
from astroid import nodes
Expand All @@ -50,9 +50,6 @@
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
Expand Down Expand Up @@ -774,8 +771,7 @@ def check_for_consistent_string_delimiters(
Args:
tokens: The tokens to be checked against for consistent usage.
"""
# typing.Counter added in Python 3.6.1 so this type hint must be a comment
string_delimiters = collections.Counter() # type: Counter[str]
string_delimiters: Counter[str] = collections.Counter()

# First, figure out which quote character predominates in the module
for tok_type, token, _, _, _ in tokens:
Expand Down
8 changes: 1 addition & 7 deletions pylint/message/message_id_store.py
@@ -1,15 +1,9 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
import sys
from typing import Dict, List, Optional, Tuple
from typing import Dict, List, NoReturn, Optional, Tuple

from pylint.exceptions import InvalidMessageError, UnknownMessageError

if sys.version_info >= (3, 6, 2):
from typing import NoReturn
else:
from typing_extensions import NoReturn


class MessageIdStore:

Expand Down
8 changes: 4 additions & 4 deletions pylint/reporters/text.py
Expand Up @@ -59,7 +59,7 @@ class MessageStyle(NamedTuple):
"""The color name (see `ANSI_COLORS` for available values)
or the color number when 256 colors are available
"""
style: Tuple[str, ...]
style: Tuple[str, ...] = ()
"""Tuple of style strings (see `ANSI_COLORS` for available values).
"""

Expand Down Expand Up @@ -264,10 +264,10 @@ class ColorizedTextReporter(TextReporter):

name = "colorized"
COLOR_MAPPING: ColorMappingDict = {
"I": MessageStyle("green", ()),
"I": MessageStyle("green"),
"C": MessageStyle(None, ("bold",)),
"R": MessageStyle("magenta", ("bold", "italic")),
"W": MessageStyle("magenta", ()),
"W": MessageStyle("magenta"),
"E": MessageStyle("red", ("bold",)),
"F": MessageStyle("red", ("bold", "underline")),
"S": MessageStyle("yellow", ("inverse",)), # S stands for module Separator
Expand Down Expand Up @@ -326,7 +326,7 @@ def __init__(

def _get_decoration(self, msg_id: str) -> MessageStyle:
"""Returns the message style as defined in self.color_mapping"""
return self.color_mapping.get(msg_id[0]) or MessageStyle(None, ())
return self.color_mapping.get(msg_id[0]) or MessageStyle(None)

def handle_message(self, msg: Message) -> None:
"""manage message of different types, and colorize output
Expand Down
30 changes: 14 additions & 16 deletions pylint/testutils/lint_module_test.py
Expand Up @@ -7,7 +7,8 @@
import sys
from collections import Counter
from io import StringIO
from typing import TYPE_CHECKING, Dict, List, Optional, TextIO, Tuple
from typing import Counter as CounterType
from typing import Dict, List, Optional, TextIO, Tuple

import pytest
from _pytest.config import Config
Expand All @@ -25,10 +26,7 @@
from pylint.testutils.reporter_for_tests import FunctionalTestReporter
from pylint.utils import utils

if TYPE_CHECKING:
from typing import Counter as CounterType # typing.Counter added in Python 3.6.1

MessageCounter = CounterType[Tuple[int, str]]
MessageCounter = CounterType[Tuple[int, str]]


class LintModuleTest:
Expand Down Expand Up @@ -99,15 +97,15 @@ def __str__(self) -> str:
return f"{self._test_file.base} ({self.__class__.__module__}.{self.__class__.__name__})"

@staticmethod
def get_expected_messages(stream: TextIO) -> "MessageCounter":
def get_expected_messages(stream: TextIO) -> MessageCounter:
"""Parses a file and get expected messages.
:param stream: File-like input stream.
:type stream: enumerable
:returns: A dict mapping line,msg-symbol tuples to the count on this line.
:rtype: dict
"""
messages: "MessageCounter" = Counter()
messages: MessageCounter = Counter()
for i, line in enumerate(stream):
match = _EXPECTED_RE.search(line)
if match is None:
Expand All @@ -133,9 +131,9 @@ def get_expected_messages(stream: TextIO) -> "MessageCounter":

@staticmethod
def multiset_difference(
expected_entries: "MessageCounter",
actual_entries: "MessageCounter",
) -> Tuple["MessageCounter", Dict[Tuple[int, str], int]]:
expected_entries: MessageCounter,
actual_entries: MessageCounter,
) -> Tuple[MessageCounter, Dict[Tuple[int, str], int]]:
"""Takes two multisets and compares them.
A multiset is a dict with the cardinality of the key as the value."""
Expand All @@ -162,7 +160,7 @@ def _open_source_file(self) -> TextIO:
return open(self._test_file.source, encoding="latin1")
return open(self._test_file.source, encoding="utf8")

def _get_expected(self) -> Tuple["MessageCounter", List[OutputLine]]:
def _get_expected(self) -> Tuple[MessageCounter, List[OutputLine]]:
with self._open_source_file() as f:
expected_msgs = self.get_expected_messages(f)
if not expected_msgs:
Expand All @@ -174,10 +172,10 @@ def _get_expected(self) -> Tuple["MessageCounter", List[OutputLine]]:
]
return expected_msgs, expected_output_lines

def _get_actual(self) -> Tuple["MessageCounter", List[OutputLine]]:
def _get_actual(self) -> Tuple[MessageCounter, List[OutputLine]]:
messages: List[Message] = self._linter.reporter.messages
messages.sort(key=lambda m: (m.line, m.symbol, m.msg))
received_msgs: "MessageCounter" = Counter()
received_msgs: MessageCounter = Counter()
received_output_lines = []
for msg in messages:
assert (
Expand All @@ -204,8 +202,8 @@ def _runTest(self) -> None:

def error_msg_for_unequal_messages(
self,
actual_messages: "MessageCounter",
expected_messages: "MessageCounter",
actual_messages: MessageCounter,
expected_messages: MessageCounter,
actual_output: List[OutputLine],
) -> str:
msg = [f'Wrong results for file "{self._test_file.base}":']
Expand Down Expand Up @@ -250,7 +248,7 @@ def error_msg_for_unequal_output(

def _check_output_text(
self,
_: "MessageCounter",
_: MessageCounter,
expected_output: List[OutputLine],
actual_output: List[OutputLine],
) -> None:
Expand Down
2 changes: 1 addition & 1 deletion pylintrc
Expand Up @@ -44,7 +44,7 @@ unsafe-load-any-extension=no
extension-pkg-allow-list=

# Minimum supported python version
py-version = 3.6
py-version = 3.6.2


[MESSAGES CONTROL]
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_pre_commit.txt
@@ -1,6 +1,6 @@
# Everything in this file should reflect the pre-commit configuration
# in .pre-commit-config.yaml
black==21.11b1;python_full_version>="3.6.2"
black==21.11b1
flake8==4.0.1
flake8-typing-imports==1.10.1
isort==5.10.1
Expand Down
17 changes: 0 additions & 17 deletions setup.py
@@ -1,20 +1,3 @@
import sys

from setuptools import setup


class PylintIncompatiblePythonError(Exception):
def __init__(self) -> None:
super().__init__(
"The last version compatible with Python <= 3.6.2 is pylint '2.9.3'. "
f"You're using {'.'.join([str(v) for v in sys.version_info[:3]])}. "
"Please install pylint 2.9.3 explicitly or upgrade your python interpreter "
"to at least 3.6.2. Remember that Python 3.6 end life is December 2021. "
"See https://github.com/PyCQA/pylint/issues/5065 for more detail."
)


if sys.version_info < (3, 6, 2):
raise PylintIncompatiblePythonError()

setup()
8 changes: 1 addition & 7 deletions tests/lint/test_pylinter.py
@@ -1,5 +1,4 @@
import sys
from typing import Any
from typing import Any, NoReturn
from unittest.mock import patch

from astroid import AstroidBuildingError
Expand All @@ -9,11 +8,6 @@
from pylint.lint.pylinter import PyLinter
from pylint.utils import FileState

if sys.version_info >= (3, 6, 2):
from typing import NoReturn
else:
from typing_extensions import NoReturn


def raise_exception(*args: Any, **kwargs: Any) -> NoReturn:
raise AstroidBuildingError(modname="spam")
Expand Down

0 comments on commit a9c1017

Please sign in to comment.