Skip to content

Commit

Permalink
drop Python 3.7 support, remove its dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ariebovenberg committed Jul 31, 2023
1 parent 62d0477 commit a95042f
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 240 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v1
Expand All @@ -25,7 +25,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install 'tox<5' tox-gh-actions 'poetry>=1.4,<1.5'
pip install 'tox<5' tox-gh-actions 'poetry>=1.5,<1.6'
- name: Test with tox
run: tox

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Changelog
=========

0.17.0 (2023-07-31)
-------------------

- Drop Python 3.7 support.
- Remove ``typing-extensions`` and ``importlib_metadata`` dependencies.
- More robust checks to prevent ``Protocol`` false positives.

0.16.5 (2023-03-01)
-------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Use the following configuration:
repos:
- repo: https://github.com/ariebovenberg/slotscheck
rev: v0.16.5
rev: v0.17.0
hooks:
- id: slotscheck
# If your Python files are not importable from the project root,
Expand Down
320 changes: 124 additions & 196 deletions poetry.lock

Large diffs are not rendered by default.

9 changes: 3 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
[tool.poetry]
name = "slotscheck"
version = "0.16.5"
version = "0.17.0"
description = "Ensure your __slots__ are working properly."
authors = ["Arie Bovenberg <[email protected]>"]
license = "MIT"
classifiers = [
"Typing :: Typed",
"Topic :: Software Development :: Quality Assurance",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -23,14 +22,12 @@ repository = "https://github.com/ariebovenberg/slotscheck"
homepage = "https://github.com/ariebovenberg/slotscheck"

[tool.poetry.dependencies]
python = ">=3.7,<4"
importlib-metadata = {version = ">=1,<6", python = "<3.8"}
typing-extensions = {version = ">=4.1,<5", python = "<3.10"}
python = ">=3.8.1,<4"
click = "^8.0"
tomli = {version = ">=0.2.6,<3.0.0", python = "<3.11"}

[tool.poetry.dev-dependencies]
flake8 = "^5.0.4"
flake8 = "^6.1"
isort = "^5.11.5"
mypy = "^1.4"
pytest = "^7.4.0"
Expand Down
5 changes: 1 addition & 4 deletions src/slotscheck/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# Single-sourcing the version number with poetry:
# https://github.com/python-poetry/poetry/pull/2366#issuecomment-652418094
try:
__version__ = __import__("importlib.metadata").metadata.version(__name__)
except ModuleNotFoundError: # pragma: no cover
__version__ = __import__("importlib_metadata").version(__name__)
__version__ = __import__("importlib.metadata").metadata.version(__name__)
18 changes: 2 additions & 16 deletions src/slotscheck/checks.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
"Slots-related checks and inspection tools"
import platform
import sys
from typing import Callable, Collection, Iterator, Optional
from typing import Collection, Iterator, Optional

from .common import either

is_typeddict: Callable[[type], bool]

try:
from typing import is_typeddict

try:
from typing_extensions import is_typeddict as _is_typing_ext_typeddict
except ImportError: # pragma: no cover
pass
else:
is_typeddict = either(is_typeddict, _is_typing_ext_typeddict)
except ImportError: # pragma: no cover
from typing_extensions import is_typeddict
from .common import is_typeddict


def slots(c: type) -> Optional[Collection[str]]:
Expand Down
8 changes: 2 additions & 6 deletions src/slotscheck/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
compose,
flatten,
groupby,
is_protocol,
map_optional,
)
from .discovery import (
Expand All @@ -51,11 +52,6 @@
walk_classes,
)

try:
from typing import Protocol
except ImportError: # pragma: no cover
from typing_extensions import Protocol # type: ignore[assignment]


@click.command("slotscheck")
@click.argument(
Expand Down Expand Up @@ -569,7 +565,7 @@ def slot_messages(
require_subclass
and not has_slots(c)
and not has_slotless_base(c)
and Protocol not in c.__bases__
and not is_protocol(c)
):
yield ShouldHaveSlots(c)

Expand Down
38 changes: 35 additions & 3 deletions src/slotscheck/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Iterator,
Mapping,
Optional,
Protocol,
Set,
Tuple,
TypeVar,
Expand Down Expand Up @@ -71,18 +72,18 @@ def both(__a: Predicate[_T1], __b: Predicate[_T1]) -> Predicate[_T1]:


@overload
def either(
def _either(
__a: Callable[[_T1], bool], __b: Callable[[_T1], bool]
) -> Callable[[_T1], bool]:
...


@overload
def either(__a: Predicate[_T1], __b: Predicate[_T1]) -> Predicate[_T1]:
def _either(__a: Predicate[_T1], __b: Predicate[_T1]) -> Predicate[_T1]:
...


def either(__a: Any, __b: Any) -> Any:
def _either(__a: Any, __b: Any) -> Any:
return lambda x: __a(x) or __b(x)


Expand All @@ -96,6 +97,37 @@ def _is_none(x: object) -> bool:
return x is None


is_typeddict: Callable[[type], bool]

from typing import is_typeddict # noqa: E402

try:
from typing_extensions import is_typeddict as _is_typing_ext_typeddict
except ImportError: # pragma: no cover
pass
else:
is_typeddict = _either(is_typeddict, _is_typing_ext_typeddict)


# Note that typing.is_protocol is not available yet (CPython PR 104878)
# The implementation below is derived from it.
def is_protocol(t: type) -> bool:
return getattr(t, "_is_protocol", False) and t != Protocol


try:
from typing_extensions import Protocol as _TypingExtProtocol
except ImportError: # pragma: no cover
pass
else:

def is_protocol(t: type) -> bool: # noqa: F811
return getattr(t, "_is_protocol", False) and t not in (
Protocol,
_TypingExtProtocol,
)


# From https://github.com/ericvsmith/dataclasses/blob/master/dataclass_tools.py
# License: https://github.com/ericvsmith/dataclasses/blob/master/LICENSE.txt
# Changed only `dataclass.fields` naming
Expand Down
6 changes: 2 additions & 4 deletions tests/examples/module_not_ok/foo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@

try:
from typing import Protocol
except ImportError:
from typing_extensions import Protocol
from typing import Protocol


class A:
Expand Down Expand Up @@ -107,6 +104,7 @@ class Za(Z):
__slots__ = ("b", "c")


# TODO: also typing extensions version
class MyProto(Protocol):
pass

Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tox]
isolated_build = true
envlist = py{37,38,39,310,311},lint,mypy,isort,slots
envlist = py{38,39,310,311},lint,mypy,isort,slots

[testenv]
allowlist_externals =
Expand Down Expand Up @@ -55,7 +55,6 @@ exclude_lines=

[gh-actions]
python =
3.7: py37
3.8: py38
3.9: py39
3.10: py310, mypy, lint, isort, docs, slots
Expand Down

0 comments on commit a95042f

Please sign in to comment.