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

More ruff rules #154

Merged
merged 11 commits into from
Jul 16, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 0 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ repos:
- id: mixed-line-ending
args: [--fix=lf]

- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0
hooks:
- id: python-check-blanket-noqa # Enforce noqa annotations (noqa: F401,W203)
- id: python-use-type-annotations # Enforce type annotations instead of type comments

- repo: local
hooks:
- id: black
Expand Down
11 changes: 11 additions & 0 deletions changes/154.internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Enforce various new ruff linter rules:

- **PGH:** pygrep-hooks (replaces pre-commit version)
- **PL:** pylint (bunch of typing related linter rules)
- **UP:** pyupgrade (forces use of the newest possible standards, depending on target version)
- **RET:** flake8-return (various linter rules related to function returns)
- **Q:** flake8-quotes (always use double quotes)
- **ASYNC:** flake8-async (report blocking operations in async functions)
- **INT:** flake-gettext (gettext related linting rules)
- **PTH:** flake8-use-pathlib (always prefer pathlib alternatives to the os ones)
- **RUF:** ruff custom rules (various additional rules created by the ruff linter team)
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

# -- Basic project information -----------------------------------------------

with open("../pyproject.toml", "rb") as f:
with Path("../pyproject.toml").open("rb") as f:
pkg_meta: dict[str, str] = toml_parse(f)["tool"]["poetry"]

project = str(pkg_meta["name"])
Expand Down
2 changes: 1 addition & 1 deletion docs/extensions/attributetable.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class PyAttributeTable(SphinxDirective):
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = False
option_spec: OptionSpec = {}
option_spec: OptionSpec = {} # noqa: RUF012 # (from original impl)

def parse_name(self, content: str) -> tuple[str, str]:
match = _name_parser_regex.match(content)
Expand Down
6 changes: 3 additions & 3 deletions mcproto/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import errno
import socket
from abc import ABC, abstractmethod
from typing import Generic, Optional, TypeVar
from typing import Generic, TypeVar

import asyncio_dgram
from typing_extensions import ParamSpec, Self
Expand Down Expand Up @@ -262,7 +262,7 @@ def make_client(cls, address: tuple[str, int], timeout: float) -> Self:
sock.settimeout(timeout)
return cls(sock, address)

def read(self, length: Optional[int] = None) -> bytearray:
def read(self, length: int | None = None) -> bytearray:
"""Receive data sent through the connection.

:param length:
Expand Down Expand Up @@ -311,7 +311,7 @@ async def make_client(cls, address: tuple[str, int], timeout: float) -> Self:
stream = await asyncio.wait_for(conn, timeout=timeout)
return cls(stream, timeout)

async def read(self, length: Optional[int] = None) -> bytearray:
async def read(self, length: int | None = None) -> bytearray:
"""Receive data sent through the connection.

:param length:
Expand Down
4 changes: 2 additions & 2 deletions mcproto/packets/handshaking/handshake.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from enum import IntEnum
from typing import ClassVar, Union, final
from typing import ClassVar, final

from typing_extensions import Self

Expand Down Expand Up @@ -35,7 +35,7 @@ def __init__(
protocol_version: int,
server_address: str,
server_port: int,
next_state: Union[NextState, int],
next_state: NextState | int,
):
"""
:param protocol_version: Protocol version number to be used.
Expand Down
3 changes: 1 addition & 2 deletions mcproto/packets/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ def _serialize_packet(packet: Packet, *, compressed: bool = False) -> Buffer:
data_buf.write_varint(data_length)
data_buf.write(packet_buf)
return data_buf
else:
return packet_buf
return packet_buf


def _deserialize_packet(
Expand Down
4 changes: 2 additions & 2 deletions mcproto/packets/login/login.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import ClassVar, Optional, final
from typing import ClassVar, final

from typing_extensions import Self

Expand Down Expand Up @@ -215,7 +215,7 @@ class LoginPluginResponse(ServerBoundPacket):
PACKET_ID: ClassVar[int] = 0x02
GAME_STATE: ClassVar[GameState] = GameState.LOGIN

def __init__(self, message_id: int, data: Optional[bytes]):
def __init__(self, message_id: int, data: bytes | None):
"""
:param message_id: Message id, generated by the server, should be unique to the connection.
:param data: Optional response data, present if client understood request.
Expand Down
2 changes: 1 addition & 1 deletion mcproto/packets/packet_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def generate_packet_map(
...


@lru_cache()
@lru_cache
def generate_packet_map(direction: PacketDirection, state: GameState) -> Mapping[int, type[Packet]]:
"""Dynamically generated a packet map for given ``direction`` and ``state``.

Expand Down
30 changes: 13 additions & 17 deletions mcproto/protocol/base_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from collections.abc import Awaitable, Callable
from enum import Enum
from itertools import count
from typing import Literal, Optional, TypeVar, Union, overload
from typing import Literal, TypeVar, Union, overload

from typing_extensions import TypeAlias

Expand Down Expand Up @@ -105,7 +105,7 @@ async def write_value(self, fmt: StructFormat, value: object, /) -> None:
"""Write a given ``value`` as given struct format (``fmt``) in big-endian mode."""
await self.write(struct.pack(">" + fmt.value, value))

async def _write_varuint(self, value: int, /, *, max_bits: Optional[int] = None) -> None:
async def _write_varuint(self, value: int, /, *, max_bits: int | None = None) -> None:
"""Write an arbitrarily big unsigned integer in a variable length format.

This is a standard way of transmitting ints, and it allows smaller numbers to take less bytes.
Expand Down Expand Up @@ -179,7 +179,7 @@ async def write_utf(self, value: str, /) -> None:
await self.write_varint(len(data))
await self.write(data)

async def write_optional(self, value: Optional[T], /, writer: Callable[[T], Awaitable[R]]) -> Optional[R]:
async def write_optional(self, value: T | None, /, writer: Callable[[T], Awaitable[R]]) -> R | None:
"""Writes a bool showing if a ``value`` is present, if so, also writes this value with ``writer`` function.

* When ``value`` is ``None``, a bool of ``False`` will be written, and ``None`` is returned.
Expand Down Expand Up @@ -223,7 +223,7 @@ def write_value(self, fmt: StructFormat, value: object, /) -> None:
"""Write a given ``value`` as given struct format (``fmt``) in big-endian mode."""
self.write(struct.pack(">" + fmt.value, value))

def _write_varuint(self, value: int, /, *, max_bits: Optional[int] = None) -> None:
def _write_varuint(self, value: int, /, *, max_bits: int | None = None) -> None:
"""Write an arbitrarily big unsigned integer in a variable length format.

This is a standard way of transmitting ints, and it allows smaller numbers to take less bytes.
Expand Down Expand Up @@ -297,7 +297,7 @@ def write_utf(self, value: str, /) -> None:
self.write_varint(len(data))
self.write(data)

def write_optional(self, value: Optional[T], /, writer: Callable[[T], R]) -> Optional[R]:
def write_optional(self, value: T | None, /, writer: Callable[[T], R]) -> R | None:
"""Writes a bool showing if a ``value`` is present, if so, also writes this value with ``writer`` function.

* When ``value`` is ``None``, a bool of ``False`` will be written, and ``None`` is returned.
Expand Down Expand Up @@ -351,7 +351,7 @@ async def read_value(self, fmt: StructFormat, /) -> object:
unpacked = struct.unpack(">" + fmt.value, data)
return unpacked[0]

async def _read_varuint(self, *, max_bits: Optional[int] = None) -> int:
async def _read_varuint(self, *, max_bits: int | None = None) -> int:
"""Read an arbitrarily big unsigned integer in a variable length format.

This is a standard way of transmitting ints, and it allows smaller numbers to take less bytes.
Expand Down Expand Up @@ -391,17 +391,15 @@ async def read_varint(self) -> int:
For more information about variable length format check :meth:`._read_varuint`.
"""
unsigned_num = await self._read_varuint(max_bits=32)
val = from_twos_complement(unsigned_num, bits=32)
return val
return from_twos_complement(unsigned_num, bits=32)

async def read_varlong(self) -> int:
"""Read a 64-bit signed integer in a variable length format.

For more information about variable length format check :meth:`._read_varuint`.
"""
unsigned_num = await self._read_varuint(max_bits=64)
val = from_twos_complement(unsigned_num, bits=64)
return val
return from_twos_complement(unsigned_num, bits=64)

async def read_bytearray(self, /) -> bytearray:
"""Read an arbitrary sequence of bytes, prefixed with a varint of it's size."""
Expand Down Expand Up @@ -446,7 +444,7 @@ async def read_utf(self) -> str:

return chars

async def read_optional(self, reader: Callable[[], Awaitable[R]]) -> Optional[R]:
async def read_optional(self, reader: Callable[[], Awaitable[R]]) -> R | None:
"""Reads a bool showing if a value is present, if so, also reads this value with ``reader`` function.

* When ``False`` is read, the function will not read anything and ``None`` is returned.
Expand Down Expand Up @@ -493,7 +491,7 @@ def read_value(self, fmt: StructFormat, /) -> object:
unpacked = struct.unpack(">" + fmt.value, data)
return unpacked[0]

def _read_varuint(self, *, max_bits: Optional[int] = None) -> int:
def _read_varuint(self, *, max_bits: int | None = None) -> int:
"""Read an arbitrarily big unsigned integer in a variable length format.

This is a standard way of transmitting ints, and it allows smaller numbers to take less bytes.
Expand Down Expand Up @@ -533,17 +531,15 @@ def read_varint(self) -> int:
For more information about variable length format check :meth:`._read_varuint`.
"""
unsigned_num = self._read_varuint(max_bits=32)
val = from_twos_complement(unsigned_num, bits=32)
return val
return from_twos_complement(unsigned_num, bits=32)

def read_varlong(self) -> int:
"""Read a 64-bit signed integer in a variable length format.

For more information about variable length format check :meth:`._read_varuint`.
"""
unsigned_num = self._read_varuint(max_bits=64)
val = from_twos_complement(unsigned_num, bits=64)
return val
return from_twos_complement(unsigned_num, bits=64)

def read_bytearray(self) -> bytearray:
"""Read an arbitrary sequence of bytes, prefixed with a varint of it's size."""
Expand Down Expand Up @@ -588,7 +584,7 @@ def read_utf(self) -> str:

return chars

def read_optional(self, reader: Callable[[], R]) -> Optional[R]:
def read_optional(self, reader: Callable[[], R]) -> R | None:
"""Reads a bool showing if a value is present, if so, also reads this value with ``reader`` function.

* When ``False`` is read, the function will not read anything and ``None`` is returned.
Expand Down
8 changes: 4 additions & 4 deletions mcproto/types/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ def as_dict(self) -> RawChatMessageDict:
"""Convert received ``raw`` into a stadard :class:`dict` form."""
if isinstance(self.raw, list):
return RawChatMessageDict(extra=self.raw)
elif isinstance(self.raw, str):
if isinstance(self.raw, str):
return RawChatMessageDict(text=self.raw)
elif isinstance(self.raw, dict): # pyright: ignore[reportUnnecessaryIsInstance]
if isinstance(self.raw, dict): # pyright: ignore[reportUnnecessaryIsInstance]
return self.raw
else: # pragma: no cover
raise TypeError(f"Found unexpected type ({self.raw.__class__!r}) ({self.raw!r}) in `raw` attribute")
# pragma: no cover
raise TypeError(f"Found unexpected type ({self.raw.__class__!r}) ({self.raw!r}) in `raw` attribute")

def __eq__(self, other: Self) -> bool:
"""Check equality between two chat messages.
Expand Down
16 changes: 8 additions & 8 deletions mcproto/utils/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import warnings
from collections.abc import Callable
from functools import wraps
from typing import Optional, TypeVar, Union
from typing import TypeVar

from semantic_version import Version
from typing_extensions import ParamSpec, Protocol
Expand All @@ -18,9 +18,9 @@
def deprecation_warn(
*,
obj_name: str,
removal_version: Union[str, Version],
replacement: Optional[str] = None,
extra_msg: Optional[str] = None,
removal_version: str | Version,
replacement: str | None = None,
extra_msg: str | None = None,
stack_level: int = 3,
) -> None:
"""Produce an appropriate deprecation warning given the parameters.
Expand Down Expand Up @@ -76,10 +76,10 @@ def __call__(self, __x: Callable[P, R]) -> Callable[P, R]:


def deprecated(
removal_version: Union[str, Version],
display_name: Optional[str] = None,
replacement: Optional[str] = None,
extra_msg: Optional[str] = None,
removal_version: str | Version,
display_name: str | None = None,
replacement: str | None = None,
extra_msg: str | None = None,
) -> DecoratorFunction:
"""Mark an object as deprecated.

Expand Down
58 changes: 34 additions & 24 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,33 +99,43 @@ target-version = "py38"
line-length = 119

select = [
"F", # Pyflakes
"W", # Pycodestyle (warnigns)
"E", # Pycodestyle (errors)
"N", # pep8-naming
"YTT", # flake8-2020
"ANN", # flake8-annotations
"S", # flake8-bandit
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"FA", # flake8-future-annotations
"T20", # flake8-print
"PT", # flake8-pytest-style
"RSE", # flake8-raise
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"RUF100", # flake8-noqa
"UP006", # flake8-pep585
"F", # Pyflakes
"W", # Pycodestyle (warnigns)
"E", # Pycodestyle (errors)
"N", # pep8-naming
"YTT", # flake8-2020
"ANN", # flake8-annotations
"ASYNC", # flake8-async
"S", # flake8-bandit
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"FA", # flake8-future-annotations
"T20", # flake8-print
"PT", # flake8-pytest-style
"Q", # flake8-quotes
"RSE", # flake8-raise
"RET", # flake8-return
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"INT", # flake8-gettext
"PTH", # flake8-use-pathlib
"PGH", # pygrep-hooks
"PL", # pylint
"RUF", # ruff-specific rules
"UP", # pyupgrade
]

ignore = [
"ANN002", # Missing type annotation for *args
"ANN003", # Missing type annotation for **kwargs
"ANN101", # Missing type annotation for self in method
"ANN102", # Missing type annotation for cls in classmethod
"ANN204", # Missing return type annotation for special method
"PT011", # pytest.raises without match parameter is too broad
"ANN002", # Missing type annotation for *args
"ANN003", # Missing type annotation for **kwargs
"ANN101", # Missing type annotation for self in method
"ANN102", # Missing type annotation for cls in classmethod
"ANN204", # Missing return type annotation for special method
"PT011", # pytest.raises without match parameter is too broad # TODO: Unignore this
"UP024", # Using errors that alias OSError
"PLR2004", # Using unnamed numerical constants
"PGH003", # Using specific rule codes in type ignores
]

[tool.ruff.extend-per-file-ignores]
Expand Down
3 changes: 1 addition & 2 deletions tests/mcproto/protocol/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

from typing import Optional
from unittest.mock import AsyncMock, Mock


Expand Down Expand Up @@ -33,7 +32,7 @@ class WriteFunctionAsyncMock(WriteFunctionMock, AsyncMock):


class ReadFunctionMock(Mock):
def __init__(self, *a, combined_data: Optional[bytearray] = None, **kw):
def __init__(self, *a, combined_data: bytearray | None = None, **kw):
super().__init__(*a, **kw)
if combined_data is None:
combined_data = bytearray()
Expand Down