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

Drop support for Python 3.7 #2137

Merged
merged 4 commits into from
Apr 23, 2023
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, 3.9, "3.10", "3.11"]
outputs:
python-key: ${{ steps.generate-python-key.outputs.key }}
steps:
Expand Down Expand Up @@ -140,7 +140,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
python-version: [3.8, 3.9, "3.10", "3.11"]
steps:
- name: Set temp directory
run: echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" >> $env:GITHUB_ENV
Expand Down Expand Up @@ -193,7 +193,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["pypy3.7", "pypy3.8", "pypy3.9"]
python-version: ["pypy3.8", "pypy3.9"]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v3.5.2
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ repos:
hooks:
- id: pyupgrade
exclude: tests/testdata
args: [--py37-plus]
args: [--py38-plus]
- repo: https://github.com/Pierre-Sassoulas/black-disable-checker/
rev: v1.1.3
hooks:
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ sphinx:
configuration: doc/conf.py

python:
version: 3.7
version: 3.8
install:
- requirements: doc/requirements.txt
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ What's New in astroid 2.16.0?
=============================
Release date: TBA

* Remove support for Python 3.7.

Refs #2137

* Remove ``@cached`` decorator (just use ``@cached_property`` from the stdlib).

Closes #1780
Expand Down Expand Up @@ -81,6 +85,7 @@ Release date: TBA

Refs #1490


What's New in astroid 2.15.4?
=============================
Release date: TBA
Expand Down
4 changes: 2 additions & 2 deletions astroid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,13 @@
from astroid.util import Uninferable

# Performance hack for tokenize. See https://bugs.python.org/issue43014
# Adapted from https://github.com/pylint-dev/pycodestyle/pull/993
# Adapted from https://github.com/PyCQA/pycodestyle/pull/993
Pierre-Sassoulas marked this conversation as resolved.
Show resolved Hide resolved
if (
not PY310_PLUS
and callable(getattr(tokenize, "_compile", None))
and getattr(tokenize._compile, "__wrapped__", None) is None # type: ignore[attr-defined]
):
tokenize._compile = functools.lru_cache()(tokenize._compile) # type: ignore[attr-defined]
tokenize._compile = functools.lru_cache(tokenize._compile) # type: ignore[attr-defined]

# load brain plugins
for module in BRAIN_MODULES_DIRECTORY.iterdir():
Expand Down
133 changes: 45 additions & 88 deletions astroid/_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,9 @@
from __future__ import annotations

import ast
import sys
import types
from collections.abc import Callable
from functools import partial
from typing import NamedTuple

from astroid.const import PY38_PLUS, Context

if sys.version_info >= (3, 8):
# On Python 3.8, typed_ast was merged back into `ast`
_ast_py3: types.ModuleType | None = ast
else:
try:
import typed_ast.ast3 as _ast_py3
except ImportError:
_ast_py3 = None
from astroid.const import Context


class FunctionType(NamedTuple):
Expand All @@ -29,49 +16,30 @@ class FunctionType(NamedTuple):


class ParserModule(NamedTuple):
module: types.ModuleType
unary_op_classes: dict[type[ast.unaryop], str]
cmp_op_classes: dict[type[ast.cmpop], str]
bool_op_classes: dict[type[ast.boolop], str]
bin_op_classes: dict[type[ast.operator], str]
context_classes: dict[type[ast.expr_context], Context]

def parse(self, string: str, type_comments: bool = True) -> ast.Module:
parse_func: Callable[[str], ast.Module]
if self.module is _ast_py3:
if PY38_PLUS:
parse_func = partial(self.module.parse, type_comments=type_comments)
else:
parse_func = partial(
self.module.parse, feature_version=sys.version_info.minor
)
else:
parse_func = self.module.parse
return parse_func(string)
return ast.parse(string, type_comments=type_comments)


def parse_function_type_comment(type_comment: str) -> FunctionType | None:
"""Given a correct type comment, obtain a FunctionType object."""
if _ast_py3 is None:
return None

func_type = _ast_py3.parse(type_comment, "<type_comment>", "func_type") # type: ignore[attr-defined]
func_type = ast.parse(type_comment, "<type_comment>", "func_type") # type: ignore[attr-defined]
return FunctionType(argtypes=func_type.argtypes, returns=func_type.returns)


def get_parser_module(type_comments: bool = True) -> ParserModule:
parser_module = ast
if type_comments and _ast_py3:
parser_module = _ast_py3

unary_op_classes = _unary_operators_from_module(parser_module)
cmp_op_classes = _compare_operators_from_module(parser_module)
bool_op_classes = _bool_operators_from_module(parser_module)
bin_op_classes = _binary_operators_from_module(parser_module)
context_classes = _contexts_from_module(parser_module)
unary_op_classes = _unary_operators_from_module()
cmp_op_classes = _compare_operators_from_module()
bool_op_classes = _bool_operators_from_module()
bin_op_classes = _binary_operators_from_module()
context_classes = _contexts_from_module()

return ParserModule(
parser_module,
unary_op_classes,
cmp_op_classes,
bool_op_classes,
Expand All @@ -80,62 +48,51 @@ def get_parser_module(type_comments: bool = True) -> ParserModule:
)


def _unary_operators_from_module(
module: types.ModuleType,
) -> dict[type[ast.unaryop], str]:
return {module.UAdd: "+", module.USub: "-", module.Not: "not", module.Invert: "~"}


def _binary_operators_from_module(
module: types.ModuleType,
) -> dict[type[ast.operator], str]:
binary_operators = {
module.Add: "+",
module.BitAnd: "&",
module.BitOr: "|",
module.BitXor: "^",
module.Div: "/",
module.FloorDiv: "//",
module.MatMult: "@",
module.Mod: "%",
module.Mult: "*",
module.Pow: "**",
module.Sub: "-",
module.LShift: "<<",
module.RShift: ">>",
def _unary_operators_from_module() -> dict[type[ast.unaryop], str]:
return {ast.UAdd: "+", ast.USub: "-", ast.Not: "not", ast.Invert: "~"}


def _binary_operators_from_module() -> dict[type[ast.operator], str]:
return {
ast.Add: "+",
ast.BitAnd: "&",
ast.BitOr: "|",
ast.BitXor: "^",
ast.Div: "/",
ast.FloorDiv: "//",
ast.MatMult: "@",
ast.Mod: "%",
ast.Mult: "*",
ast.Pow: "**",
ast.Sub: "-",
ast.LShift: "<<",
ast.RShift: ">>",
}
return binary_operators


def _bool_operators_from_module(
module: types.ModuleType,
) -> dict[type[ast.boolop], str]:
return {module.And: "and", module.Or: "or"}
def _bool_operators_from_module() -> dict[type[ast.boolop], str]:
return {ast.And: "and", ast.Or: "or"}


def _compare_operators_from_module(
module: types.ModuleType,
) -> dict[type[ast.cmpop], str]:
def _compare_operators_from_module() -> dict[type[ast.cmpop], str]:
return {
module.Eq: "==",
module.Gt: ">",
module.GtE: ">=",
module.In: "in",
module.Is: "is",
module.IsNot: "is not",
module.Lt: "<",
module.LtE: "<=",
module.NotEq: "!=",
module.NotIn: "not in",
ast.Eq: "==",
ast.Gt: ">",
ast.GtE: ">=",
ast.In: "in",
ast.Is: "is",
ast.IsNot: "is not",
ast.Lt: "<",
ast.LtE: "<=",
ast.NotEq: "!=",
ast.NotIn: "not in",
}


def _contexts_from_module(
module: types.ModuleType,
) -> dict[type[ast.expr_context], Context]:
def _contexts_from_module() -> dict[type[ast.expr_context], Context]:
return {
module.Load: Context.Load,
module.Store: Context.Store,
module.Del: Context.Del,
module.Param: Context.Store,
ast.Load: Context.Load,
ast.Store: Context.Store,
ast.Del: Context.Del,
ast.Param: Context.Store,
}
8 changes: 1 addition & 7 deletions astroid/bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@

import collections
import collections.abc
import sys
from collections.abc import Iterator, Sequence
from typing import TYPE_CHECKING, Any, ClassVar
from typing import TYPE_CHECKING, Any, ClassVar, Literal

from astroid import nodes
from astroid.const import PY310_PLUS
Expand All @@ -36,11 +35,6 @@
)
from astroid.util import Uninferable, UninferableBase, lazy_descriptor

if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal

if TYPE_CHECKING:
from astroid.constraint import Constraint

Expand Down
8 changes: 1 addition & 7 deletions astroid/brain/brain_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@

from __future__ import annotations

import sys
from collections.abc import Iterator
from typing import Tuple, Union
from typing import Literal, Tuple, Union

from astroid import bases, context, helpers, nodes
from astroid.builder import parse
Expand All @@ -27,11 +26,6 @@
from astroid.typing import InferenceResult
from astroid.util import Uninferable, UninferableBase

if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal

_FieldDefaultReturn = Union[
None,
Tuple[Literal["default"], nodes.NodeNG],
Expand Down
8 changes: 1 addition & 7 deletions astroid/brain/brain_namedtuple_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

import functools
import keyword
import sys
from collections.abc import Iterator
from textwrap import dedent
from typing import Final

import astroid
from astroid import arguments, bases, inference_tip, nodes, util
Expand All @@ -25,12 +25,6 @@
)
from astroid.manager import AstroidManager

if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final


ENUM_BASE_NAMES = {
"Enum",
"IntEnum",
Expand Down
7 changes: 1 addition & 6 deletions astroid/brain/brain_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

from __future__ import annotations

import sys
import typing
from collections.abc import Iterator
from functools import partial
from typing import Final

from astroid import context, extract_node, inference_tip
from astroid.builder import _extract_single_node
Expand All @@ -34,11 +34,6 @@
)
from astroid.nodes.scoped_nodes import ClassDef, FunctionDef

if sys.version_info >= (3, 8):
from typing import Final
else:
from typing_extensions import Final

TYPING_TYPEVARS = {"TypeVar", "NewType"}
TYPING_TYPEVARS_QUALIFIED: Final = {
"typing.TypeVar",
Expand Down
16 changes: 7 additions & 9 deletions astroid/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
_P = ParamSpec("_P")


# TODO: Remove when support for 3.7 is dropped
# TODO: astroid 3.0 -> move class behind sys.version_info < (3, 8) guard
# TODO: Remove for astroid 3.0
class cachedproperty:
"""Provides a cached property equivalent to the stacking of
@cached and @property, but more efficient.
Expand All @@ -47,13 +46,12 @@ class cachedproperty:
__slots__ = ("wrapped",)

def __init__(self, wrapped):
if sys.version_info >= (3, 8):
warnings.warn(
"cachedproperty has been deprecated and will be removed in astroid 3.0 for Python 3.8+. "
"Use functools.cached_property instead.",
DeprecationWarning,
stacklevel=2,
)
warnings.warn(
"cachedproperty has been deprecated and will be removed in astroid 3.0"
"Use functools.cached_property instead.",
DeprecationWarning,
stacklevel=2,
)
try:
wrapped.__name__ # noqa[B018]
except AttributeError as exc:
Expand Down
Loading