Skip to content

Commit a91b29a

Browse files
authored
Select all rules for Ruff (#1106)
1 parent 363bc74 commit a91b29a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+486
-432
lines changed

docs/conf.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515

1616
import os
1717
import sys
18-
19-
from packaging.version import Version, parse as parse_version
2018
from importlib.metadata import version as importlib_version
2119

20+
from packaging.version import Version, parse as parse_version
2221

23-
sys.path.insert(0, os.path.abspath(".."))
22+
sys.path.insert(0, os.path.abspath("..")) # noqa: PTH100
2423

2524

2625
# -- Project information -----------------------------------------------------
@@ -132,7 +131,7 @@ def mock_autodoc() -> None:
132131
133132
See also https://stackoverflow.com/a/75041544/20952782.
134133
"""
135-
from sphinx.ext import autodoc
134+
from sphinx.ext import autodoc # noqa: PLC0415
136135

137136
class MockedClassDocumenter(autodoc.ClassDocumenter):
138137
def add_line(self, line: str, source: str, *lineno: int) -> None:
@@ -147,8 +146,8 @@ def delete_doc_for_address_base() -> None:
147146
"""``__new__`` is appended to the docstring of ``AddressBase``.
148147
149148
And we do not want autogenerated nonsense docstring there.
150-
"""
151-
from mcstatus.address import _AddressBase
149+
""" # noqa: D401 # imperative mood
150+
from mcstatus.address import _AddressBase # noqa: PLC0415
152151

153152
del _AddressBase.__new__.__doc__
154153

docs/examples/code/ping_as_java_and_bedrock_in_one_time.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
23
import asyncio
34

45
from mcstatus import BedrockServer, JavaServer
@@ -31,7 +32,7 @@ async def status(host: str) -> JavaStatusResponse | BedrockStatusResponse:
3132
async def handle_exceptions(done: set[asyncio.Task], pending: set[asyncio.Task]) -> asyncio.Task | None:
3233
"""Handle exceptions from tasks.
3334
34-
Also, cancel all pending tasks, if found correct one.
35+
Also, cancel all pending tasks, if found the correct one.
3536
"""
3637
if len(done) == 0:
3738
raise ValueError("No tasks was given to `done` set.")
@@ -47,14 +48,15 @@ async def handle_exceptions(done: set[asyncio.Task], pending: set[asyncio.Task])
4748
for pending_task in pending:
4849
pending_task.cancel()
4950
return task
51+
return None
5052

5153

5254
async def handle_java(host: str) -> JavaStatusResponse:
53-
"""A wrapper around mcstatus, to compress it in one function."""
55+
"""Wrap mcstatus, to compress lookup and status into one function."""
5456
return await (await JavaServer.async_lookup(host)).async_status()
5557

5658

5759
async def handle_bedrock(host: str) -> BedrockStatusResponse:
58-
"""A wrapper around mcstatus, to compress it in one function."""
60+
"""Wrap mcstatus, to compress lookup and status into one function."""
5961
# note: `BedrockServer` doesn't have `async_lookup` method, see it's docstring
6062
return await BedrockServer.lookup(host).async_status()

mcstatus/__main__.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
# ruff: noqa: T201 # usage of `print`
12
from __future__ import annotations
23

3-
import dns.resolver
4-
import sys
5-
import json
64
import argparse
7-
import socket
85
import dataclasses
9-
from typing import TypeAlias
6+
import json
7+
import socket
8+
import sys
9+
from typing import TYPE_CHECKING, TypeAlias
10+
11+
import dns.resolver
1012

11-
from mcstatus import JavaServer, LegacyServer, BedrockServer
13+
from mcstatus import BedrockServer, JavaServer, LegacyServer
1214
from mcstatus.responses import JavaStatusResponse
13-
from mcstatus.motd import Motd
15+
16+
if TYPE_CHECKING:
17+
from mcstatus.motd import Motd
1418

1519
SupportedServers: TypeAlias = "JavaServer | LegacyServer | BedrockServer"
1620

@@ -30,21 +34,19 @@
3034

3135

3236
def _motd(motd: Motd) -> str:
33-
"""Formats MOTD for human-readable output, with leading line break
34-
if multiline."""
37+
"""Format MOTD for human-readable output, with leading line break if multiline."""
3538
s = motd.to_ansi()
3639
return f"\n{s}" if "\n" in s else f" {s}"
3740

3841

3942
def _kind(serv: SupportedServers) -> str:
4043
if isinstance(serv, JavaServer):
4144
return "Java"
42-
elif isinstance(serv, LegacyServer):
45+
if isinstance(serv, LegacyServer):
4346
return "Java (pre-1.7)"
44-
elif isinstance(serv, BedrockServer):
47+
if isinstance(serv, BedrockServer):
4548
return "Bedrock"
46-
else:
47-
raise ValueError(f"unsupported server for kind: {serv}")
49+
raise ValueError(f"unsupported server for kind: {serv}")
4850

4951

5052
def _ping_with_fallback(server: SupportedServers) -> float:
@@ -56,7 +58,7 @@ def _ping_with_fallback(server: SupportedServers) -> float:
5658
ping_exc = None
5759
try:
5860
return server.ping(tries=1)
59-
except Exception as e:
61+
except Exception as e: # noqa: BLE001 # blindly catching Exception
6062
ping_exc = e
6163

6264
latency = server.status().latency
@@ -103,13 +105,13 @@ def json_cmd(server: SupportedServers) -> int:
103105
status_res = query_res = exn = None
104106
try:
105107
status_res = server.status(tries=1)
106-
except Exception as e:
108+
except Exception as e: # noqa: BLE001 # blindly catching Exception
107109
exn = exn or e
108110

109111
try:
110112
if isinstance(server, JavaServer):
111113
query_res = server.query(tries=1)
112-
except Exception as e:
114+
except Exception as e: # noqa: BLE001 # blindly catching Exception
113115
exn = exn or e
114116

115117
# construct 'data' dict outside try/except to ensure data processing errors
@@ -147,7 +149,7 @@ def query_cmd(server: SupportedServers) -> int:
147149

148150
try:
149151
response = server.query()
150-
except socket.timeout:
152+
except TimeoutError:
151153
print(QUERY_FAIL_WARNING, file=sys.stderr)
152154
return 1
153155

@@ -199,7 +201,7 @@ def main(argv: list[str] = sys.argv[1:]) -> int:
199201
try:
200202
server = lookup(args.address)
201203
return args.func(server)
202-
except (socket.timeout, socket.gaierror, dns.resolver.NoNameservers, ConnectionError, TimeoutError) as e:
204+
except (socket.gaierror, dns.resolver.NoNameservers, ConnectionError, TimeoutError) as e:
203205
# catch and hide traceback for expected user-facing errors
204206
print(f"Error: {e!r}", file=sys.stderr)
205207
return 1

mcstatus/address.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import ipaddress
44
import sys
55
import warnings
6-
from pathlib import Path
76
from typing import NamedTuple, TYPE_CHECKING
87
from urllib.parse import urlparse
98

@@ -12,14 +11,16 @@
1211
import mcstatus.dns
1312

1413
if TYPE_CHECKING:
14+
from pathlib import Path
15+
1516
from typing_extensions import Self
1617

1718

1819
__all__ = ("Address", "async_minecraft_srv_address_lookup", "minecraft_srv_address_lookup")
1920

2021

2122
def _valid_urlparse(address: str) -> tuple[str, int | None]:
22-
"""Parses a string address like 127.0.0.1:25565 into host and port parts
23+
"""Parse a string address like 127.0.0.1:25565 into host and port parts.
2324
2425
If the address doesn't have a specified port, None will be returned instead.
2526
@@ -57,7 +58,7 @@ class Address(_AddressBase):
5758
The class is not a part of a Public API, but attributes :attr:`host` and :attr:`port` are a part of Public API.
5859
"""
5960

60-
def __init__(self, host: str, port: int):
61+
def __init__(self, host: str, port: int): # noqa: ARG002 # unused arguments
6162
# We don't pass the host & port args to super's __init__, because NamedTuples handle
6263
# everything from __new__ and the passed self already has all of the parameters set.
6364
super().__init__()
@@ -93,7 +94,7 @@ def from_path(cls, path: Path, *, default_port: int | None = None) -> Self:
9394

9495
@classmethod
9596
def parse_address(cls, address: str, *, default_port: int | None = None) -> Self:
96-
"""Parses a string address like ``127.0.0.1:25565`` into :attr:`.host` and :attr:`.port` parts.
97+
"""Parse a string address like ``127.0.0.1:25565`` into :attr:`.host` and :attr:`.port` parts.
9798
9899
If the address has a port specified, use it, if not, fall back to ``default_port`` kwarg.
99100
@@ -112,7 +113,7 @@ def parse_address(cls, address: str, *, default_port: int | None = None) -> Self
112113
return cls(host=hostname, port=port)
113114

114115
def resolve_ip(self, lifetime: float | None = None) -> ipaddress.IPv4Address | ipaddress.IPv6Address:
115-
"""Resolves a hostname's A record into an IP address.
116+
"""Resolve a hostname's A record into an IP address.
116117
117118
If the host is already an IP, this resolving is skipped
118119
and host is returned directly.
@@ -150,7 +151,7 @@ def resolve_ip(self, lifetime: float | None = None) -> ipaddress.IPv4Address | i
150151
return self._cached_ip
151152

152153
async def async_resolve_ip(self, lifetime: float | None = None) -> ipaddress.IPv4Address | ipaddress.IPv6Address:
153-
"""Resolves a hostname's A record into an IP address.
154+
"""Resolve a hostname's A record into an IP address.
154155
155156
See the docstring for :meth:`.resolve_ip` for further info. This function is purely
156157
an async alternative to it.

mcstatus/bedrock_status.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
import socket
55
import struct
66
from time import perf_counter
7+
from typing import TYPE_CHECKING
78

89
import asyncio_dgram
910

10-
from mcstatus.address import Address
1111
from mcstatus.responses import BedrockStatusResponse
1212

13+
if TYPE_CHECKING:
14+
from mcstatus.address import Address
15+
1316

1417
class BedrockServerStatus:
1518
request_status_data = bytes.fromhex(

mcstatus/dns.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
from __future__ import annotations
22

3-
from typing import cast
3+
from typing import TYPE_CHECKING, cast
44

55
import dns.asyncresolver
66
import dns.resolver
77
from dns.rdatatype import RdataType
8-
from dns.rdtypes.IN.A import A as ARecordAnswer
9-
from dns.rdtypes.IN.SRV import SRV as SRVRecordAnswer # noqa: N811 # constant imported as non constant (it's class)
8+
9+
if TYPE_CHECKING:
10+
from dns.rdtypes.IN.A import A as ARecordAnswer
11+
from dns.rdtypes.IN.SRV import SRV as SRVRecordAnswer # noqa: N811 # constant imported as non constant (it's class)
1012

1113

1214
def resolve_a_record(hostname: str, lifetime: float | None = None) -> str:
13-
"""Perform a DNS resolution for an A record to given hostname
15+
"""Perform a DNS resolution for an A record to given hostname.
1416
1517
:param hostname: The address to resolve for.
1618
:return: The resolved IP address from the A record
@@ -22,7 +24,7 @@ def resolve_a_record(hostname: str, lifetime: float | None = None) -> str:
2224
answers = dns.resolver.resolve(hostname, RdataType.A, lifetime=lifetime, search=True)
2325
# There should only be one answer here, though in case the server
2426
# does actually point to multiple IPs, we just pick the first one
25-
answer = cast(ARecordAnswer, answers[0])
27+
answer = cast("ARecordAnswer", answers[0])
2628
ip = str(answer).rstrip(".")
2729
return ip
2830

@@ -35,7 +37,7 @@ async def async_resolve_a_record(hostname: str, lifetime: float | None = None) -
3537
answers = await dns.asyncresolver.resolve(hostname, RdataType.A, lifetime=lifetime, search=True)
3638
# There should only be one answer here, though in case the server
3739
# does actually point to multiple IPs, we just pick the first one
38-
answer = cast(ARecordAnswer, answers[0])
40+
answer = cast("ARecordAnswer", answers[0])
3941
ip = str(answer).rstrip(".")
4042
return ip
4143

@@ -53,7 +55,7 @@ def resolve_srv_record(query_name: str, lifetime: float | None = None) -> tuple[
5355
answers = dns.resolver.resolve(query_name, RdataType.SRV, lifetime=lifetime, search=True)
5456
# There should only be one answer here, though in case the server
5557
# does actually point to multiple IPs, we just pick the first one
56-
answer = cast(SRVRecordAnswer, answers[0])
58+
answer = cast("SRVRecordAnswer", answers[0])
5759
host = str(answer.target).rstrip(".")
5860
port = int(answer.port)
5961
return host, port
@@ -67,7 +69,7 @@ async def async_resolve_srv_record(query_name: str, lifetime: float | None = Non
6769
answers = await dns.asyncresolver.resolve(query_name, RdataType.SRV, lifetime=lifetime, search=True)
6870
# There should only be one answer here, though in case the server
6971
# does actually point to multiple IPs, we just pick the first one
70-
answer = cast(SRVRecordAnswer, answers[0])
72+
answer = cast("SRVRecordAnswer", answers[0])
7173
host = str(answer.target).rstrip(".")
7274
port = int(answer.port)
7375
return host, port

mcstatus/forge_data.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,7 @@ def decode(cls, buffer: Connection) -> tuple[Self, list[ForgeDataChannel]]:
137137
if not is_server:
138138
mod_version = buffer.read_utf()
139139

140-
channels: list[ForgeDataChannel] = []
141-
for _ in range(channel_count):
142-
channels.append(ForgeDataChannel.decode(buffer, mod_id))
140+
channels = [ForgeDataChannel.decode(buffer, mod_id) for _ in range(channel_count)]
143141

144142
return cls(name=mod_id, marker=mod_version), channels
145143

@@ -161,7 +159,7 @@ def read(self, length: int) -> bytearray:
161159
while len(data) < length:
162160
result = self.stringio.read(1)
163161
if not result:
164-
raise IOError(f"Not enough data to read! {len(data)} < {length}")
162+
raise OSError(f"Not enough data to read! {len(data)} < {length}")
165163
data.extend(result.encode("utf-16be"))
166164
while len(data) > length:
167165
self.received.append(data.pop())
@@ -212,7 +210,7 @@ def _decode_optimized(string: str) -> Connection:
212210
return str_buffer.read_optimized_buffer()
213211

214212
@classmethod
215-
def build(cls, raw: RawForgeData) -> Self | None:
213+
def build(cls, raw: RawForgeData) -> Self:
216214
"""Build an object about Forge mods from raw response.
217215
218216
:param raw: ``forgeData`` attribute in raw response :class:`dict`.
@@ -248,9 +246,8 @@ def build(cls, raw: RawForgeData) -> Self | None:
248246
mods.append(mod)
249247

250248
non_mod_channel_count = buffer.read_varint()
251-
for _ in range(non_mod_channel_count):
252-
channels.append(ForgeDataChannel.decode(buffer))
253-
except IOError:
249+
channels.extend(ForgeDataChannel.decode(buffer) for _ in range(non_mod_channel_count))
250+
except OSError:
254251
if not truncated:
255252
raise # If answer wasn't truncated, we lost some data on the way
256253

mcstatus/legacy_status.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class _BaseLegacyServerStatus:
1414
def parse_response(data: bytes, latency: float) -> LegacyStatusResponse:
1515
decoded_data = data.decode("UTF-16BE").split("\0")
1616
if decoded_data[0] != "§1":
17-
raise IOError("Received invalid kick packet reason")
17+
raise OSError("Received invalid kick packet reason")
1818

1919
return LegacyStatusResponse.build(decoded_data[1:], latency)
2020

@@ -29,7 +29,7 @@ def read_status(self) -> LegacyStatusResponse:
2929
self.connection.write(self.request_status_data)
3030
id = self.connection.read(1)
3131
if id != b"\xff":
32-
raise IOError("Received invalid packet ID")
32+
raise OSError("Received invalid packet ID")
3333
length = self.connection.read_ushort()
3434
data = self.connection.read(length * 2)
3535
end = perf_counter()
@@ -46,7 +46,7 @@ async def read_status(self) -> LegacyStatusResponse:
4646
self.connection.write(self.request_status_data)
4747
id = await self.connection.read(1)
4848
if id != b"\xff":
49-
raise IOError("Received invalid packet ID")
49+
raise OSError("Received invalid packet ID")
5050
length = await self.connection.read_ushort()
5151
data = await self.connection.read(length * 2)
5252
end = perf_counter()

0 commit comments

Comments
 (0)