Skip to content

Commit

Permalink
Merge pull request #14 from py-mine/add-slotscheck
Browse files Browse the repository at this point in the history
Add slotscheck
  • Loading branch information
ItsDrike authored Dec 30, 2022
2 parents 7d1535f + d2f6035 commit 785b926
Show file tree
Hide file tree
Showing 21 changed files with 120 additions and 68 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 .
Expand All @@ -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 .
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ 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]

- repo: local
hooks:
- id: pyright
Expand Down
2 changes: 2 additions & 0 deletions changes/14.bugfix.md
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 3 additions & 0 deletions changes/14.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add `__slots__` to most classes in the project
- All connection classes are now slotted
- Classes in `mcproto.utils.abc` are now slotted
1 change: 1 addition & 0 deletions changes/14.internal.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add slotscheck, ensuring `__slots__` are defined properly everywhere.
1 change: 1 addition & 0 deletions changes/14.internal.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make `typing-extensions` a runtime dependency and use it directly, don't rely on `if typing.TYPE_CHECKING` blocks.
33 changes: 21 additions & 12 deletions mcproto/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -29,8 +19,17 @@
"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",)

def __init__(self):
self.closed = False

Expand Down Expand Up @@ -59,6 +58,8 @@ def __exit__(self, *a, **kw) -> None:


class AsyncConnection(BaseAsyncReader, BaseAsyncWriter, ABC):
__slots__ = ("closed",)

def __init__(self):
self.closed = False

Expand Down Expand Up @@ -87,6 +88,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
Expand Down Expand Up @@ -130,6 +133,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
Expand Down Expand Up @@ -180,6 +185,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]):
Expand Down Expand Up @@ -215,6 +222,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
Expand Down
4 changes: 4 additions & 0 deletions mcproto/packets/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__ = ()
4 changes: 2 additions & 2 deletions mcproto/packets/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
# |-------------|---------------|---------------------------------------|
Expand Down
7 changes: 3 additions & 4 deletions mcproto/packets/map.py
Original file line number Diff line number Diff line change
@@ -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"]


Expand Down
8 changes: 3 additions & 5 deletions mcproto/packets/v757/handshaking/handshake.py
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
8 changes: 3 additions & 5 deletions mcproto/packets/v757/status/ping.py
Original file line number Diff line number Diff line change
@@ -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"]


Expand Down
7 changes: 3 additions & 4 deletions mcproto/packets/v757/status/status.py
Original file line number Diff line number Diff line change
@@ -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"]


Expand Down
13 changes: 6 additions & 7 deletions mcproto/protocol/base_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -25,6 +21,9 @@
"FLOAT_FORMATS_TYPE",
]

T = TypeVar("T")
R = TypeVar("R")


# region: Format types

Expand Down
11 changes: 7 additions & 4 deletions mcproto/utils/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -32,6 +31,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]]

Expand Down Expand Up @@ -64,6 +65,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."""
Expand Down
14 changes: 5 additions & 9 deletions mcproto/utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
5 changes: 2 additions & 3 deletions mcproto/utils/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
9 changes: 4 additions & 5 deletions mcproto/utils/version_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 19 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 785b926

Please sign in to comment.