From 2423171ab513603c7757d71f7d5142075eecf0e7 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:09:29 +0100 Subject: [PATCH 01/14] Add slotscheck package --- changes/14.internal.md | 1 + poetry.lock | 19 ++++++++++++++++++- pyproject.toml | 7 +++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 changes/14.internal.md diff --git a/changes/14.internal.md b/changes/14.internal.md new file mode 100644 index 00000000..c28dfa1a --- /dev/null +++ b/changes/14.internal.md @@ -0,0 +1 @@ +Add slotscheck, ensuring `__slots__` are defined properly everywhere. diff --git a/poetry.lock b/poetry.lock index 06dcba94..d0fbd51a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1328,6 +1328,23 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "slotscheck" +version = "0.16.1" +description = "Ensure your __slots__ are working properly." +category = "dev" +optional = false +python-versions = ">=3.7,<4" +files = [ + {file = "slotscheck-0.16.1-py3-none-any.whl", hash = "sha256:9d930279cae0a72369a2227b52318e267aba8bd6b68713e250357133ae104678"}, + {file = "slotscheck-0.16.1.tar.gz", hash = "sha256:2592c74456af0bf3f08abde8bb4c5ff2562f093e61ec12d12a97a9218f99ef2a"}, +] + +[package.dependencies] +click = ">=8.0,<9.0" +tomli = ">=0.2.6,<3.0.0" +typing-extensions = {version = ">=4.1,<5", markers = "python_version < \"3.10\""} + [[package]] name = "smmap" version = "5.0.0" @@ -1487,4 +1504,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4" -content-hash = "2c17706acd15b04ba552a427bff732d35417eb38befdec71ced6b412946a3e01" +content-hash = "08eb540e752f964f01c8ddc623246396f8222ff516617d5f752ddb9df4275513" diff --git a/pyproject.toml b/pyproject.toml index 62dd40d8..bccf8031 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ pep8-naming = "^0.12.1" black = "^22.3.0" isort = "^5.10.1" pyright = "^1.1.239" +slotscheck = "^0.16.1" [tool.poetry.group.release.dependencies] towncrier = "^22.12.0" @@ -133,6 +134,11 @@ type = [ { name = "Internal Changes", directory = "internal", showcontent = true }, ] +[tool.slotscheck] +strict-imports = true +require-superclass = true +require-subclass = true + [tool.taskipy.tasks] precommit = "pre-commit install" lint = "pre-commit run --all-files" @@ -140,6 +146,7 @@ black = "black ." isort = "isort ." pyright = "pyright ." flake8 = "flake8 ." +slotscheck = "slotscheck -m mcproto" test = "pytest -v --failed-first" retest = "pytest -v --last-failed" test-nocov = "pytest -v --no-cov --failed-first" From d3bb94de7e7082ffedfc0bff235cfe741a0ce344 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:09:39 +0100 Subject: [PATCH 02/14] Add slotscheck to pre-commit --- .pre-commit-config.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b01945b0..e8968854 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,6 +44,17 @@ repos: language: system types: [python] + - repo: local + hooks: + - id: slotscheck + name: Slotscheck + description: "Slotscheck: Ensure your __slots__ are working properly" + entry: poetry run slotscheck -v + language: python + require_serial: true + types: [python] + exclude: "^(?!mcproto/)" + - repo: local hooks: - id: pyright From fc8b3eb7d41a399ae9ddf1643c6bb3ca89377286 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:10:37 +0100 Subject: [PATCH 03/14] Run slotscheck separately in validation workflow --- .github/workflows/validation.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index cd0bce05..4225d34f 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -27,7 +27,7 @@ jobs: install_args: "--without release" - name: Run pre-commit hooks - run: SKIP=black,isort,flake8,pyright pre-commit run --all-files + run: SKIP=black,isort,flake8,slotscheck,pyright pre-commit run --all-files - name: Run black formatter check run: black --check --diff . @@ -38,5 +38,8 @@ jobs: - name: Run flake8 linter run: flake8 . + - name: Run slotscheck + run: slotscheck -m mcproto + - name: Run pyright type checker run: pyright . From 9c36fbce0d7e18c6c098838e1f930c7aa67b3cc1 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:14:00 +0100 Subject: [PATCH 04/14] Make connection classes slotted --- changes/14.feature.md | 2 ++ mcproto/connection.py | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 changes/14.feature.md diff --git a/changes/14.feature.md b/changes/14.feature.md new file mode 100644 index 00000000..c854e3e9 --- /dev/null +++ b/changes/14.feature.md @@ -0,0 +1,2 @@ +Add `__slots__` to most classes in the project + - All connection classes are now slotted diff --git a/mcproto/connection.py b/mcproto/connection.py index 3e3c2144..ea096199 100644 --- a/mcproto/connection.py +++ b/mcproto/connection.py @@ -31,6 +31,8 @@ class SyncConnection(BaseSyncReader, BaseSyncWriter, ABC): + __slots__ = ("closed",) + def __init__(self): self.closed = False @@ -59,6 +61,8 @@ def __exit__(self, *a, **kw) -> None: class AsyncConnection(BaseAsyncReader, BaseAsyncWriter, ABC): + __slots__ = ("closed",) + def __init__(self): self.closed = False @@ -87,6 +91,8 @@ async def __aexit__(self, *a, **kw) -> None: class TCPSyncConnection(SyncConnection, Generic[T_SOCK]): + __slots__ = ("socket",) + def __init__(self, socket: T_SOCK): super().__init__() self.socket = socket @@ -130,6 +136,8 @@ def _close(self) -> None: class TCPAsyncConnection(AsyncConnection, Generic[T_STREAMREADER, T_STREAMWRITER]): + __slots__ = ("reader", "writer", "timeout") + def __init__(self, reader: T_STREAMREADER, writer: T_STREAMWRITER, timeout: float): super().__init__() self.reader = reader @@ -180,6 +188,8 @@ def socket(self) -> socket.socket: class UDPSyncConnection(SyncConnection, Generic[T_SOCK]): + __slots__ = ("socket", "address") + BUFFER_SIZE = 65535 def __init__(self, socket: T_SOCK, address: tuple[str, int]): @@ -215,6 +225,8 @@ def _close(self) -> None: class UDPAsyncConnection(AsyncConnection, Generic[T_DATAGRAM_CLIENT]): + __slots__ = ("stream", "timeout") + def __init__(self, stream: T_DATAGRAM_CLIENT, timeout: float): super().__init__() self.stream = stream From 363de4ca2df1e5b8832d4f1a5e117cc99de35346 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:15:58 +0100 Subject: [PATCH 05/14] Make ABC classes use __slots__ --- changes/14.feature.md | 1 + mcproto/utils/abc.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/changes/14.feature.md b/changes/14.feature.md index c854e3e9..3f0ff26f 100644 --- a/changes/14.feature.md +++ b/changes/14.feature.md @@ -1,2 +1,3 @@ Add `__slots__` to most classes in the project - All connection classes are now slotted + - Classes in `mcproto.utils.abc` are now slotted diff --git a/mcproto/utils/abc.py b/mcproto/utils/abc.py index f592888d..f2821004 100644 --- a/mcproto/utils/abc.py +++ b/mcproto/utils/abc.py @@ -32,6 +32,8 @@ class RequiredParamsABCMixin: and if _REQUIRED_CLASS_VARS_NO_MRO isn't set, no such check will be performed. """ + __slots__ = () + _REQUIRRED_CLASS_VARS: ClassVar[Sequence[str]] _REQUIRED_CLASS_VARS_NO_MRO: ClassVar[Sequence[str]] @@ -64,6 +66,8 @@ def __new__(cls: type[Self], *a, **kw) -> Self: class Serializable(ABC): """Base class for any type that should be (de)serializable into/from given buffer data.""" + __slots__ = () + @abstractmethod def serialize(self) -> Buffer: """Represent the object as a transmittable sequence of bytes.""" From cd6f718d2725b325feaf2d89f438de3f0860c525 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:26:42 +0100 Subject: [PATCH 06/14] Ignore tests in slotscheck from config file --- .pre-commit-config.yaml | 1 - pyproject.toml | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e8968854..c49a29b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,7 +53,6 @@ repos: language: python require_serial: true types: [python] - exclude: "^(?!mcproto/)" - repo: local hooks: diff --git a/pyproject.toml b/pyproject.toml index bccf8031..cf2ac6f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -138,6 +138,11 @@ type = [ strict-imports = true require-superclass = true require-subclass = true +exclude-modules = ''' +( + ^test # ignore any tests +) +''' [tool.taskipy.tasks] precommit = "pre-commit install" From 12bfbd16d4c222c6c2dda6756c74be356210c107 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:44:13 +0100 Subject: [PATCH 07/14] Add __slots__ to SemanticVersion --- changes/14.feature.md | 1 + mcproto/utils/version.py | 2 ++ pyproject.toml | 1 + 3 files changed, 4 insertions(+) diff --git a/changes/14.feature.md b/changes/14.feature.md index 3f0ff26f..ba589258 100644 --- a/changes/14.feature.md +++ b/changes/14.feature.md @@ -1,3 +1,4 @@ Add `__slots__` to most classes in the project - All connection classes are now slotted - Classes in `mcproto.utils.abc` are now slotted + - `mcproto.utils.version.SemanticVersion` class is now slotted diff --git a/mcproto/utils/version.py b/mcproto/utils/version.py index 11b61d67..9cf412bb 100644 --- a/mcproto/utils/version.py +++ b/mcproto/utils/version.py @@ -29,6 +29,8 @@ class SemanticVersion: Relies on Semantic Versioning specification (see ). """ + __slots__ = ("version", "prerelease", "build_metadata") + version: tuple[int, int, int] prerelease: Optional[tuple[str, ...]] = None build_metadata: Optional[tuple[str, ...]] = None diff --git a/pyproject.toml b/pyproject.toml index cf2ac6f4..eb8ca5d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,6 +141,7 @@ require-subclass = true exclude-modules = ''' ( ^test # ignore any tests + |^mcproto\.utils\.version # Dataclasses cause false-positives; See: https://github.com/ariebovenberg/slotscheck/issues/129 ) ''' From 8b56bbc53f02fa5d44d1699ae7d3b4a40b6c7163 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 19:57:51 +0100 Subject: [PATCH 08/14] Ignore DecoratorFunction protocol class in slotscheck --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index eb8ca5d5..0215877c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,6 +142,7 @@ exclude-modules = ''' ( ^test # ignore any tests |^mcproto\.utils\.version # Dataclasses cause false-positives; See: https://github.com/ariebovenberg/slotscheck/issues/129 + |^mcproto\.utils\.deprecation # Protocol classes don't need __slots__; See: https://github.com/ariebovenberg/slotscheck/issues/130 ) ''' From c0b84e24e138590d94c2e5125f23dd601945e13e Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 20:00:02 +0100 Subject: [PATCH 09/14] Make ServerBoundPacket and ClientBoundPacket classes slotted --- changes/14.bugfix.md | 2 ++ mcproto/packets/abc.py | 4 ++++ 2 files changed, 6 insertions(+) create mode 100644 changes/14.bugfix.md diff --git a/changes/14.bugfix.md b/changes/14.bugfix.md new file mode 100644 index 00000000..1e1b9520 --- /dev/null +++ b/changes/14.bugfix.md @@ -0,0 +1,2 @@ +Add missing `__slots__` to `ServerBoundPacket` and `ClientBoundPacket` subclasses, which inherited from slotted +`Packet`, but didn't themselves define `__slots__`, causing `__dict__` to be needlessly created. diff --git a/mcproto/packets/abc.py b/mcproto/packets/abc.py index 2665e2dd..120134fe 100644 --- a/mcproto/packets/abc.py +++ b/mcproto/packets/abc.py @@ -42,6 +42,10 @@ class Packet(Serializable, RequiredParamsABCMixin): class ServerBoundPacket(Packet): """Packet bound to a server (Client -> Server).""" + __slots__ = () + class ClientBoundPacket(Packet): """Packet bound to a client (Server -> Client).""" + + __slots__ = () From 05998480051ba4cdd6e94c35fc0115550c347f7d Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Thu, 29 Dec 2022 20:19:33 +0100 Subject: [PATCH 10/14] Remove __slots__ from SemanticVersion dataclass (not supported by python) --- changes/14.feature.md | 1 - mcproto/utils/version.py | 2 -- pyproject.toml | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/changes/14.feature.md b/changes/14.feature.md index ba589258..3f0ff26f 100644 --- a/changes/14.feature.md +++ b/changes/14.feature.md @@ -1,4 +1,3 @@ Add `__slots__` to most classes in the project - All connection classes are now slotted - Classes in `mcproto.utils.abc` are now slotted - - `mcproto.utils.version.SemanticVersion` class is now slotted diff --git a/mcproto/utils/version.py b/mcproto/utils/version.py index 9cf412bb..11b61d67 100644 --- a/mcproto/utils/version.py +++ b/mcproto/utils/version.py @@ -29,8 +29,6 @@ class SemanticVersion: Relies on Semantic Versioning specification (see ). """ - __slots__ = ("version", "prerelease", "build_metadata") - version: tuple[int, int, int] prerelease: Optional[tuple[str, ...]] = None build_metadata: Optional[tuple[str, ...]] = None diff --git a/pyproject.toml b/pyproject.toml index 0215877c..cfedc5e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -141,7 +141,7 @@ require-subclass = true exclude-modules = ''' ( ^test # ignore any tests - |^mcproto\.utils\.version # Dataclasses cause false-positives; See: https://github.com/ariebovenberg/slotscheck/issues/129 + |^mcproto\.utils\.version # Dataclasses below python 3.10 don't support __slots__ due to default value fields being treated as classvars. |^mcproto\.utils\.deprecation # Protocol classes don't need __slots__; See: https://github.com/ariebovenberg/slotscheck/issues/130 ) ''' From ab24fd9c1a7662c645da6d67ff17d0ae57a8bb2e Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Fri, 30 Dec 2022 00:14:26 +0100 Subject: [PATCH 11/14] Update slotscheck --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index d0fbd51a..bea229b8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1330,14 +1330,14 @@ files = [ [[package]] name = "slotscheck" -version = "0.16.1" +version = "0.16.2" description = "Ensure your __slots__ are working properly." category = "dev" optional = false python-versions = ">=3.7,<4" files = [ - {file = "slotscheck-0.16.1-py3-none-any.whl", hash = "sha256:9d930279cae0a72369a2227b52318e267aba8bd6b68713e250357133ae104678"}, - {file = "slotscheck-0.16.1.tar.gz", hash = "sha256:2592c74456af0bf3f08abde8bb4c5ff2562f093e61ec12d12a97a9218f99ef2a"}, + {file = "slotscheck-0.16.2-py3-none-any.whl", hash = "sha256:e1e06183e381048dd83ce96e97a262464c8df26ccba987a89b4f79c78e002760"}, + {file = "slotscheck-0.16.2.tar.gz", hash = "sha256:92d33a6dc3125830b77460471c15c9b99224c8c6368813ea128dca299f4e55fa"}, ] [package.dependencies] From a3367a017ab498c5ee46aeb3070cd198f4a541ef Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Fri, 30 Dec 2022 00:25:55 +0100 Subject: [PATCH 12/14] Use typing-extensions directly on runtime --- mcproto/connection.py | 21 ++++++++----------- mcproto/packets/interactions.py | 4 ++-- mcproto/packets/map.py | 7 +++---- mcproto/packets/v757/handshaking/handshake.py | 8 +++---- mcproto/packets/v757/status/ping.py | 8 +++---- mcproto/packets/v757/status/status.py | 7 +++---- mcproto/protocol/base_io.py | 13 ++++++------ mcproto/utils/abc.py | 7 +++---- mcproto/utils/deprecation.py | 14 +++++-------- mcproto/utils/version.py | 5 ++--- mcproto/utils/version_map.py | 9 ++++---- poetry.lock | 4 ++-- pyproject.toml | 1 + tests/helpers.py | 8 +++---- 14 files changed, 49 insertions(+), 67 deletions(-) diff --git a/mcproto/connection.py b/mcproto/connection.py index ea096199..58dfa463 100644 --- a/mcproto/connection.py +++ b/mcproto/connection.py @@ -3,23 +3,13 @@ import asyncio import socket from abc import ABC, abstractmethod -from typing import Generic, Optional, TYPE_CHECKING, TypeVar +from typing import Generic, Optional, TypeVar import asyncio_dgram +from typing_extensions import ParamSpec, Self from mcproto.protocol.base_io import BaseAsyncReader, BaseAsyncWriter, BaseSyncReader, BaseSyncWriter -if TYPE_CHECKING: - from typing_extensions import ParamSpec, Self - - P = ParamSpec("P") - -R = TypeVar("R") -T_SOCK = TypeVar("T_SOCK", bound=socket.socket) -T_STREAMREADER = TypeVar("T_STREAMREADER", bound=asyncio.StreamReader) -T_STREAMWRITER = TypeVar("T_STREAMWRITER", bound=asyncio.StreamWriter) -T_DATAGRAM_CLIENT = TypeVar("T_DATAGRAM_CLIENT", bound=asyncio_dgram.aio.DatagramClient) - __all__ = [ "AsyncConnection", "SyncConnection", @@ -29,6 +19,13 @@ "UDPSyncConnection", ] +P = ParamSpec("P") +R = TypeVar("R") +T_SOCK = TypeVar("T_SOCK", bound=socket.socket) +T_STREAMREADER = TypeVar("T_STREAMREADER", bound=asyncio.StreamReader) +T_STREAMWRITER = TypeVar("T_STREAMWRITER", bound=asyncio.StreamWriter) +T_DATAGRAM_CLIENT = TypeVar("T_DATAGRAM_CLIENT", bound=asyncio_dgram.aio.DatagramClient) + class SyncConnection(BaseSyncReader, BaseSyncWriter, ABC): __slots__ = ("closed",) diff --git a/mcproto/packets/interactions.py b/mcproto/packets/interactions.py index 13e9e97b..17783cb5 100644 --- a/mcproto/packets/interactions.py +++ b/mcproto/packets/interactions.py @@ -9,10 +9,10 @@ from mcproto.packets.map import PacketMap from mcproto.protocol.base_io import BaseAsyncReader, BaseAsyncWriter, BaseSyncReader, BaseSyncWriter -T_Packet = TypeVar("T_Packet", bound=Packet) - __all__ = ["async_read_packet", "async_write_packet", "sync_read_packet", "sync_write_packet", "PACKET_MAP"] +T_Packet = TypeVar("T_Packet", bound=Packet) + # PACKET FORMAT: # | Field name | Field type | Notes | # |-------------|---------------|---------------------------------------| diff --git a/mcproto/packets/map.py b/mcproto/packets/map.py index 71296435..e8932f35 100644 --- a/mcproto/packets/map.py +++ b/mcproto/packets/map.py @@ -1,14 +1,13 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, ClassVar, Literal, TYPE_CHECKING, overload +from typing import Any, ClassVar, Literal, overload + +from typing_extensions import TypeGuard from mcproto.packets.abc import ClientBoundPacket, GameState, Packet, PacketDirection, ServerBoundPacket from mcproto.utils.version_map import VersionMap, WalkableModuleData -if TYPE_CHECKING: - from typing_extensions import TypeGuard - __all__ = ["PacketMap"] diff --git a/mcproto/packets/v757/handshaking/handshake.py b/mcproto/packets/v757/handshaking/handshake.py index 65cdb822..0ad6f0d9 100644 --- a/mcproto/packets/v757/handshaking/handshake.py +++ b/mcproto/packets/v757/handshaking/handshake.py @@ -1,16 +1,14 @@ from __future__ import annotations from enum import IntEnum -from typing import ClassVar, TYPE_CHECKING, Union +from typing import ClassVar, Union + +from typing_extensions import Self from mcproto.buffer import Buffer from mcproto.packets.abc import GameState, ServerBoundPacket from mcproto.protocol.base_io import StructFormat -if TYPE_CHECKING: - from typing_extensions import Self - - __all__ = [ "NextState", "Handshake", diff --git a/mcproto/packets/v757/status/ping.py b/mcproto/packets/v757/status/ping.py index 9fec7f3d..5094b18a 100644 --- a/mcproto/packets/v757/status/ping.py +++ b/mcproto/packets/v757/status/ping.py @@ -1,15 +1,13 @@ from __future__ import annotations -from typing import ClassVar, TYPE_CHECKING +from typing import ClassVar + +from typing_extensions import Self from mcproto.buffer import Buffer from mcproto.packets.abc import ClientBoundPacket, GameState, ServerBoundPacket from mcproto.protocol.base_io import StructFormat -if TYPE_CHECKING: - from typing_extensions import Self - - __all__ = ["PingPong"] diff --git a/mcproto/packets/v757/status/status.py b/mcproto/packets/v757/status/status.py index fa54aa91..ae28baef 100644 --- a/mcproto/packets/v757/status/status.py +++ b/mcproto/packets/v757/status/status.py @@ -1,14 +1,13 @@ from __future__ import annotations import json -from typing import Any, ClassVar, TYPE_CHECKING +from typing import Any, ClassVar + +from typing_extensions import Self from mcproto.buffer import Buffer from mcproto.packets.abc import ClientBoundPacket, GameState, ServerBoundPacket -if TYPE_CHECKING: - from typing_extensions import Self - __all__ = ["StatusRequest", "StatusResponse"] diff --git a/mcproto/protocol/base_io.py b/mcproto/protocol/base_io.py index ae775f8b..b7630f3d 100644 --- a/mcproto/protocol/base_io.py +++ b/mcproto/protocol/base_io.py @@ -5,15 +5,11 @@ from collections.abc import Awaitable, Callable from enum import Enum from itertools import count -from typing import Literal, Optional, TYPE_CHECKING, TypeVar, Union, overload +from typing import Literal, Optional, TypeVar, Union, overload -from mcproto.protocol.utils import from_twos_complement, to_twos_complement - -if TYPE_CHECKING: - from typing_extensions import TypeAlias +from typing_extensions import TypeAlias -T = TypeVar("T") -R = TypeVar("R") +from mcproto.protocol.utils import from_twos_complement, to_twos_complement __all__ = [ "BaseAsyncReader", @@ -25,6 +21,9 @@ "FLOAT_FORMATS_TYPE", ] +T = TypeVar("T") +R = TypeVar("R") + # region: Format types diff --git a/mcproto/utils/abc.py b/mcproto/utils/abc.py index f2821004..03803a25 100644 --- a/mcproto/utils/abc.py +++ b/mcproto/utils/abc.py @@ -2,12 +2,11 @@ from abc import ABC, abstractmethod from collections.abc import Sequence -from typing import ClassVar, TYPE_CHECKING +from typing import ClassVar -from mcproto.buffer import Buffer +from typing_extensions import Self -if TYPE_CHECKING: - from typing_extensions import Self +from mcproto.buffer import Buffer __all__ = ["RequiredParamsABCMixin", "Serializable"] diff --git a/mcproto/utils/deprecation.py b/mcproto/utils/deprecation.py index e973631f..9f56dba8 100644 --- a/mcproto/utils/deprecation.py +++ b/mcproto/utils/deprecation.py @@ -4,20 +4,16 @@ import warnings from collections.abc import Callable from functools import wraps -from typing import Optional, TYPE_CHECKING, TypeVar, Union +from typing import Optional, TypeVar, Union -from mcproto.utils.version import SemanticVersion +from typing_extensions import ParamSpec, Protocol -if TYPE_CHECKING: - from typing_extensions import ParamSpec, Protocol +from mcproto.utils.version import SemanticVersion - P = ParamSpec("P") -else: - Protocol = object +__all__ = ["deprecated", "deprecation_warn"] R = TypeVar("R") - -__all__ = ["deprecated", "deprecation_warn"] +P = ParamSpec("P") def deprecation_warn( diff --git a/mcproto/utils/version.py b/mcproto/utils/version.py index 11b61d67..850608f5 100644 --- a/mcproto/utils/version.py +++ b/mcproto/utils/version.py @@ -3,10 +3,9 @@ import re from dataclasses import dataclass from itertools import zip_longest -from typing import Any, Optional, TYPE_CHECKING +from typing import Any, Optional -if TYPE_CHECKING: - from typing_extensions import Self +from typing_extensions import Self __all__ = ["SemanticVersion"] diff --git a/mcproto/utils/version_map.py b/mcproto/utils/version_map.py index d0075195..a6d14f3f 100644 --- a/mcproto/utils/version_map.py +++ b/mcproto/utils/version_map.py @@ -6,18 +6,17 @@ from abc import ABC, abstractmethod from collections.abc import Hashable, Iterator, Sequence from types import ModuleType -from typing import Any, ClassVar, Generic, NamedTuple, NoReturn, TYPE_CHECKING, TypeVar +from typing import Any, ClassVar, Generic, NamedTuple, NoReturn, TypeVar + +from typing_extensions import TypeGuard from mcproto.utils.abc import RequiredParamsABCMixin -if TYPE_CHECKING: - from typing_extensions import TypeGuard +__all__ = ["VersionMap", "WalkableModuleData"] K = TypeVar("K", bound=Hashable) V = TypeVar("V") -__all__ = ["VersionMap", "WalkableModuleData"] - class WalkableModuleData(NamedTuple): module: ModuleType diff --git a/poetry.lock b/poetry.lock index bea229b8..6bd4ea8f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1456,7 +1456,7 @@ dev = ["furo", "packaging", "sphinx (>=5)", "twisted"] name = "typing-extensions" version = "4.4.0" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1504,4 +1504,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4" -content-hash = "08eb540e752f964f01c8ddc623246396f8222ff516617d5f752ddb9df4275513" +content-hash = "1242b1dc76ae09243775b0c6703fca3f8d0b30bc7f7ae623d0f05773ff61b0f2" diff --git a/pyproject.toml b/pyproject.toml index cfedc5e4..74e932f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,7 @@ packages = [{ include = "mcproto" }] [tool.poetry.dependencies] python = ">=3.8.1,<4" asyncio-dgram = "^2.1.2" +typing-extensions = "^4.4.0" [tool.poetry.group.dev.dependencies] pre-commit = "^2.18.1" diff --git a/tests/helpers.py b/tests/helpers.py index 7718b6cf..97014f37 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -4,14 +4,12 @@ import inspect import unittest.mock from collections.abc import Callable, Coroutine -from typing import Any, Generic, TYPE_CHECKING, TypeVar +from typing import Any, Generic, TypeVar -if TYPE_CHECKING: - from typing_extensions import ParamSpec - - P = ParamSpec("P") +from typing_extensions import ParamSpec T = TypeVar("T") +P = ParamSpec("P") T_Mock = TypeVar("T_Mock", bound=unittest.mock.Mock) From bc369662c5ca1792136b971019eaeb69d6fbc78e Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Fri, 30 Dec 2022 00:27:18 +0100 Subject: [PATCH 13/14] Remove resolved slotscheck exclude on Protocol class --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 74e932f1..0adfba82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -143,7 +143,6 @@ exclude-modules = ''' ( ^test # ignore any tests |^mcproto\.utils\.version # Dataclasses below python 3.10 don't support __slots__ due to default value fields being treated as classvars. - |^mcproto\.utils\.deprecation # Protocol classes don't need __slots__; See: https://github.com/ariebovenberg/slotscheck/issues/130 ) ''' From 87a164890850207f04f9192a67d40e5ae40d9157 Mon Sep 17 00:00:00 2001 From: ItsDrike Date: Fri, 30 Dec 2022 00:41:42 +0100 Subject: [PATCH 14/14] Split change fragment for #14 into 2 files --- changes/{14.internal.md => 14.internal.1.md} | 0 changes/14.internal.2.md | 1 + 2 files changed, 1 insertion(+) rename changes/{14.internal.md => 14.internal.1.md} (100%) create mode 100644 changes/14.internal.2.md diff --git a/changes/14.internal.md b/changes/14.internal.1.md similarity index 100% rename from changes/14.internal.md rename to changes/14.internal.1.md diff --git a/changes/14.internal.2.md b/changes/14.internal.2.md new file mode 100644 index 00000000..e844f65d --- /dev/null +++ b/changes/14.internal.2.md @@ -0,0 +1 @@ +Make `typing-extensions` a runtime dependency and use it directly, don't rely on `if typing.TYPE_CHECKING` blocks.