diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml new file mode 100644 index 0000000..3c40a2b --- /dev/null +++ b/.github/workflows/tox.yml @@ -0,0 +1,41 @@ +name: Run tox + +on: + pull_request: + push: + branches: + - main + - github-actions + +defaults: + run: + shell: bash + +jobs: + tox: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + toxenv: [core, lint] + include: + - python-version: "3.10" + toxenv: docs + fail-fast: false + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - run: | + python_version="${{ matrix.python-version }}" + toxenv="${{ matrix.toxenv }}" + if [[ "$toxenv" == "docs" ]]; then + echo "TOXENV=docs" | tee -a "$GITHUB_ENV" + else + echo "TOXENV=py${python_version}-${toxenv}" | tr -d '.' | tee -a "$GITHUB_ENV" + fi + python -m pip install --upgrade pip + python -m pip install "tox>=4.10" + - run: | + python -m tox run -r diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dc01a54..de81a1f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: rev: v3.15.0 hooks: - id: pyupgrade - args: [--py39-plus] + args: [--py310-plus] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.11.10 hooks: diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..dbdb0b5 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +version: 2 + +build: + os: ubuntu-24.04 + tools: + python: "3.10" + +sphinx: + configuration: docs/conf.py + fail_on_warning: true + +python: + install: + - method: pip + path: . + extra_requirements: + - dev + +formats: + - epub + - htmlzip diff --git a/COPYRIGHT b/COPYRIGHT index 8604c10..39e6a3b 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1 +1 @@ -This library is dual-licensed under Apache 2.0 and MIT terms. \ No newline at end of file +This library is dual-licensed under Apache 2.0 and MIT terms. diff --git a/Makefile b/Makefile index 1285f25..dd61da3 100644 --- a/Makefile +++ b/Makefile @@ -35,13 +35,7 @@ setup: pip install -r requirements_dev.txt lint: - python -m ruff check --fix - -fix: - python -m ruff check --fix - -typecheck: - pre-commit run pyright-pretty --all-files + pre-commit run --all-files test: python -m pytest tests @@ -56,12 +50,14 @@ coverage: coverage html $(BROWSER) htmlcov/index.html -docs: +docs-ci: rm -f docs/multiaddr.rst rm -f docs/modules.rst sphinx-apidoc -o docs/ multiaddr $(MAKE) -C docs clean - $(MAKE) -C docs html + $(MAKE) -C docs html SPHINXOPTS="-W" + +docs: docs-ci $(BROWSER) docs/_build/html/index.html servedocs: docs diff --git a/docs/conf.py b/docs/conf.py index 5d8b15d..4308e2e 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -142,7 +142,7 @@ # here, relative to this directory. They are copied after the builtin # static files, so a file named "default.css" will overwrite the builtin # "default.css". -html_static_path = ['_static'] +# html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. diff --git a/docs/installation.rst b/docs/installation.rst index bc57e10..674b1dd 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -5,7 +5,7 @@ Installation ============ Requirements: -- Python 3.9 or newer +- Python 3.10 or newer Install from PyPI: diff --git a/examples/dns/dns_examples.py b/examples/dns/dns_examples.py index 1941ce6..26f11b3 100644 --- a/examples/dns/dns_examples.py +++ b/examples/dns/dns_examples.py @@ -85,7 +85,7 @@ ## Requirements -- Python 3.9+ +- Python 3.10+ - py-multiaddr library - trio library - Internet connection for DNS resolution diff --git a/examples/thin_waist/README.md b/examples/thin_waist/README.md index 378bbbb..4cbc9fb 100644 --- a/examples/thin_waist/README.md +++ b/examples/thin_waist/README.md @@ -85,7 +85,7 @@ result = get_thin_waist_addresses(addr, port=9000) ## Requirements -- Python 3.9+ +- Python 3.10+ - `multiaddr` library with `psutil` dependency - Network interfaces to demonstrate wildcard expansion diff --git a/multiaddr/__init__.py b/multiaddr/__init__.py index b9d71ad..d3eafe3 100755 --- a/multiaddr/__init__.py +++ b/multiaddr/__init__.py @@ -1,5 +1,5 @@ from .multiaddr import Multiaddr # NOQA -__author__ = 'Steven Buss' -__email__ = 'steven.buss@gmail.com' -__version__ = '0.0.9' +__author__ = "Steven Buss" +__email__ = "steven.buss@gmail.com" +__version__ = "0.0.9" diff --git a/multiaddr/codecs/__init__.py b/multiaddr/codecs/__init__.py index 2092dca..fb827fd 100644 --- a/multiaddr/codecs/__init__.py +++ b/multiaddr/codecs/__init__.py @@ -1,5 +1,5 @@ import importlib -from typing import Any, Dict, Union +from typing import Any # These are special sizes LENGTH_PREFIXED_VAR_SIZE = -1 @@ -27,10 +27,10 @@ def to_bytes(self, proto: Any, string: str) -> bytes: return b"" -CODEC_CACHE: Dict[str, CodecBase] = {} +CODEC_CACHE: dict[str, CodecBase] = {} -def codec_by_name(name: Union[str, None]) -> CodecBase: +def codec_by_name(name: str | None) -> CodecBase: if name is None: # Special "do nothing - expect nothing" pseudo-codec return NoneCodec() codec = CODEC_CACHE.get(name) diff --git a/multiaddr/codecs/ip4.py b/multiaddr/codecs/ip4.py index ab0d3e7..b3ddfa3 100644 --- a/multiaddr/codecs/ip4.py +++ b/multiaddr/codecs/ip4.py @@ -16,6 +16,6 @@ def to_bytes(self, proto, string): def to_string(self, proto, buf): try: - return str(netaddr.IPAddress(int.from_bytes(buf, byteorder='big'), version=4)) + return str(netaddr.IPAddress(int.from_bytes(buf, byteorder="big"), version=4)) except (ValueError, netaddr.AddrFormatError): raise BinaryParseError("Invalid IPv4 address bytes", buf, "ip4") diff --git a/multiaddr/codecs/ip6.py b/multiaddr/codecs/ip6.py index 346e3a7..5ccf420 100644 --- a/multiaddr/codecs/ip6.py +++ b/multiaddr/codecs/ip6.py @@ -14,4 +14,4 @@ def to_bytes(self, proto, string): return netaddr.IPAddress(string, version=6).packed def to_string(self, proto, buf): - return str(netaddr.IPAddress(int.from_bytes(buf, byteorder='big'), version=6)) + return str(netaddr.IPAddress(int.from_bytes(buf, byteorder="big"), version=6)) diff --git a/multiaddr/codecs/onion.py b/multiaddr/codecs/onion.py index f53c763..86a5d1e 100644 --- a/multiaddr/codecs/onion.py +++ b/multiaddr/codecs/onion.py @@ -14,8 +14,8 @@ class Codec(CodecBase): def to_bytes(self, proto, string): try: - addr, port = string.split(':', 1) - if addr.endswith('.onion'): + addr, port = string.split(":", 1) + if addr.endswith(".onion"): addr = addr[:-6] if len(addr) != 16: raise ValueError("Invalid onion address length") @@ -28,7 +28,7 @@ def to_bytes(self, proto, string): addr_bytes = base64.b32decode(addr.upper()) if len(addr_bytes) != 10: raise ValueError("Decoded onion address must be 10 bytes") - return addr_bytes + port_num.to_bytes(2, byteorder='big') + return addr_bytes + port_num.to_bytes(2, byteorder="big") except (ValueError, UnicodeEncodeError, binascii.Error) as e: raise BinaryParseError(str(e), string.encode(), proto) @@ -38,14 +38,14 @@ def to_string(self, proto, buf): raise ValueError("Invalid onion address length") # Base32 encode the address try: - addr = base64.b32encode(buf[:10]).decode('ascii').lower() + addr = base64.b32encode(buf[:10]).decode("ascii").lower() except binascii.Error: raise ValueError("Invalid base32 encoding") # Remove padding - addr = addr.rstrip('=') + addr = addr.rstrip("=") if len(addr) != 16: raise ValueError("Invalid onion address length") - port = str(int.from_bytes(buf[10:12], byteorder='big')) + port = str(int.from_bytes(buf[10:12], byteorder="big")) if not 1 <= int(port) <= 65535: raise ValueError("Invalid onion port range") return f"{addr}:{port}" diff --git a/multiaddr/codecs/onion3.py b/multiaddr/codecs/onion3.py index 90f1b1a..c53019b 100644 --- a/multiaddr/codecs/onion3.py +++ b/multiaddr/codecs/onion3.py @@ -14,8 +14,8 @@ class Codec(CodecBase): def to_bytes(self, proto, string): try: - addr, port = string.split(':', 1) - if addr.endswith('.onion'): + addr, port = string.split(":", 1) + if addr.endswith(".onion"): addr = addr[:-6] if len(addr) != 56: raise ValueError("Invalid onion3 address length") @@ -31,7 +31,7 @@ def to_bytes(self, proto, string): raise ValueError("Invalid base32 encoding") if len(addr_bytes) != 35: raise ValueError("Decoded onion3 address must be 35 bytes") - return addr_bytes + port_num.to_bytes(2, byteorder='big') + return addr_bytes + port_num.to_bytes(2, byteorder="big") except (ValueError, UnicodeEncodeError, binascii.Error) as e: raise BinaryParseError(str(e), string.encode(), proto) @@ -40,14 +40,14 @@ def to_string(self, proto, buf): if len(buf) != 37: raise ValueError("Invalid onion3 address length") try: - addr = base64.b32encode(buf[:35]).decode('ascii').lower() + addr = base64.b32encode(buf[:35]).decode("ascii").lower() except binascii.Error: raise ValueError("Invalid base32 encoding") # Remove padding - addr = addr.rstrip('=') + addr = addr.rstrip("=") if len(addr) != 56: raise ValueError("Invalid onion3 address length") - port = str(int.from_bytes(buf[35:], byteorder='big')) + port = str(int.from_bytes(buf[35:], byteorder="big")) if not 1 <= int(port) <= 65535: raise ValueError("Invalid onion3 port range") return f"{addr}:{port}" diff --git a/multiaddr/codecs/uint16be.py b/multiaddr/codecs/uint16be.py index 41c112b..de01bc3 100644 --- a/multiaddr/codecs/uint16be.py +++ b/multiaddr/codecs/uint16be.py @@ -15,9 +15,9 @@ def to_bytes(self, proto, string): raise ValueError("invalid base 10 integer") if n < 0 or n >= 65536: raise ValueError("integer not in range [0, 65536)") - return n.to_bytes(2, byteorder='big') + return n.to_bytes(2, byteorder="big") def to_string(self, proto, buf): if len(buf) != 2: raise ValueError("buffer length must be 2 bytes") - return str(int.from_bytes(buf, byteorder='big')) + return str(int.from_bytes(buf, byteorder="big")) diff --git a/multiaddr/exceptions.py b/multiaddr/exceptions.py index dd17b92..e49aa0e 100644 --- a/multiaddr/exceptions.py +++ b/multiaddr/exceptions.py @@ -1,4 +1,4 @@ -from typing import Any, Optional, Union +from typing import Any class Error(Exception): @@ -34,8 +34,8 @@ def __init__( self, message: str, string: str, - protocol: Optional[str] = None, - original: Optional[Exception] = None, + protocol: str | None = None, + original: Exception | None = None, ) -> None: self.message = message self.string = string @@ -43,7 +43,7 @@ def __init__( self.original = original if protocol: - message = "Invalid MultiAddr {!r} protocol {}: {}".format(string, protocol, message) + message = f"Invalid MultiAddr {string!r} protocol {protocol}: {message}" else: message = f"Invalid MultiAddr {string!r}: {message}" @@ -69,8 +69,8 @@ def __init__( self, message: str, binary: bytes, - protocol: Union[str, int], - original: Optional[Exception] = None, + protocol: str | int, + original: Exception | None = None, ) -> None: self.message = message self.binary = binary @@ -119,7 +119,7 @@ def __init__(self, proto: Any, kind: str = "name") -> None: class ProtocolNotFoundError(ProtocolRegistryError): """No protocol with the given name or code found""" - def __init__(self, value: Union[str, int], kind: str = "name") -> None: + def __init__(self, value: str | int, kind: str = "name") -> None: self.value = value self.kind = kind diff --git a/multiaddr/multiaddr.py b/multiaddr/multiaddr.py index 3a57343..a832495 100644 --- a/multiaddr/multiaddr.py +++ b/multiaddr/multiaddr.py @@ -1,6 +1,6 @@ import collections.abc from collections.abc import Iterator, Sequence -from typing import Any, Optional, TypeVar, Union, overload +from typing import Any, TypeVar, Union, overload import varint @@ -24,7 +24,7 @@ def __contains__(self, proto: object) -> bool: proto = self._mapping.registry.find(proto) return collections.abc.Sequence.__contains__(self, proto) - def __getitem__(self, idx: Union[int, slice]) -> Union[Any, Sequence[Any]]: + def __getitem__(self, idx: int | slice) -> Any | Sequence[Any]: if isinstance(idx, slice): return list(self)[idx] if idx < 0: @@ -62,9 +62,7 @@ def __getitem__(self, idx: int) -> tuple[Any, Any]: ... @overload def __getitem__(self, idx: slice) -> Sequence[tuple[Any, Any]]: ... - def __getitem__( - self, idx: Union[int, slice] - ) -> Union[tuple[Any, Any], Sequence[tuple[Any, Any]]]: + def __getitem__(self, idx: int | slice) -> tuple[Any, Any] | Sequence[tuple[Any, Any]]: if isinstance(idx, slice): return list(self)[idx] if idx < 0: @@ -101,7 +99,7 @@ def __init__(self, mapping: "Multiaddr") -> None: def __contains__(self, value: object) -> bool: return collections.abc.Sequence.__contains__(self, value) - def __getitem__(self, idx: Union[int, slice]) -> Union[Any, Sequence[Any]]: + def __getitem__(self, idx: int | slice) -> Any | Sequence[Any]: if isinstance(idx, slice): return list(self)[idx] if idx < 0: @@ -272,7 +270,7 @@ def decapsulate_code(self, code: int) -> "Multiaddr": return self.__class__("") return self.__class__(self._bytes[:cut_offset]) - def value_for_protocol(self, proto: Any) -> Optional[Any]: + def value_for_protocol(self, proto: Any) -> Any | None: """Return the value (if any) following the specified protocol Returns @@ -465,7 +463,7 @@ def _from_bytes(self, addr: bytes) -> None: self._bytes = addr - def get_peer_id(self) -> Optional[str]: + def get_peer_id(self) -> str | None: """Get the peer ID from the multiaddr. For circuit addresses, returns the target peer ID, not the relay peer ID. diff --git a/multiaddr/protocols.py b/multiaddr/protocols.py index 580e517..eb25f63 100644 --- a/multiaddr/protocols.py +++ b/multiaddr/protocols.py @@ -34,7 +34,7 @@ print(proto.name) # 'tcp' """ -from typing import Any, Optional, Union +from typing import Any import varint @@ -87,7 +87,7 @@ class Protocol: "name", # string ] - def __init__(self, code: int, name: str, codec: Optional[str]) -> None: + def __init__(self, code: int, name: str, codec: str | None) -> None: if not isinstance(code, int): raise TypeError("code must be an integer") if not isinstance(name, str): @@ -174,7 +174,7 @@ class ProtocolRegistry: __slots__ = ("_codes_to_protocols", "_locked", "_names_to_protocols") - def __init__(self, protocols: Union[list[Protocol], tuple[Protocol, ...]] = ()) -> None: + def __init__(self, protocols: list[Protocol] | tuple[Protocol, ...] = ()) -> None: self._locked = False protocols_tuple = tuple(protocols) if isinstance(protocols, list) else protocols self._codes_to_protocols: dict[int, Protocol] = { @@ -210,7 +210,7 @@ def add(self, proto: Protocol) -> Protocol: self._codes_to_protocols[proto.code] = proto return proto - def add_alias_name(self, proto: Union[Protocol, str], alias_name: str) -> None: + def add_alias_name(self, proto: Protocol | str, alias_name: str) -> None: """Add an alternate name for an existing protocol description to the registry Raises @@ -238,7 +238,7 @@ def add_alias_name(self, proto: Union[Protocol, str], alias_name: str) -> None: self._names_to_protocols[alias_name] = proto - def add_alias_code(self, proto: Union[Protocol, int], alias_code: int) -> None: + def add_alias_code(self, proto: Protocol | int, alias_code: int) -> None: """Add an alternate code for an existing protocol description to the registry Raises @@ -316,7 +316,7 @@ def find_by_code(self, code: int) -> Protocol: except KeyError: raise exceptions.ProtocolNotFoundError(code) - def find(self, proto: Union[Protocol, str, int]) -> Protocol: + def find(self, proto: Protocol | str | int) -> Protocol: """Find a protocol by its name, code, or Protocol instance Raises @@ -361,7 +361,7 @@ def protocol_with_code(code: int) -> Protocol: return REGISTRY.find_by_code(code) -def protocol_with_any(proto: Union[Protocol, str, int]) -> Protocol: +def protocol_with_any(proto: Protocol | str | int) -> Protocol: """Find a protocol by its name, code, or Protocol instance Raises diff --git a/multiaddr/resolvers/dns.py b/multiaddr/resolvers/dns.py index 927c0bb..f911718 100644 --- a/multiaddr/resolvers/dns.py +++ b/multiaddr/resolvers/dns.py @@ -21,7 +21,7 @@ import logging import re -from typing import Optional, cast +from typing import cast import dns.asyncresolver import dns.rdataclass @@ -53,9 +53,7 @@ def __init__(self): """Initialize the DNS resolver.""" self._resolver = dns.asyncresolver.Resolver() - async def resolve( - self, maddr: "Multiaddr", options: Optional[dict] = None - ) -> list["Multiaddr"]: + async def resolve(self, maddr: "Multiaddr", options: dict | None = None) -> list["Multiaddr"]: """ Resolve a DNS multiaddr to its actual addresses. @@ -132,7 +130,7 @@ async def _resolve_dnsaddr( hostname: str, original_ma: "Multiaddr", max_depth: int, - signal: Optional[trio.CancelScope] = None, + signal: trio.CancelScope | None = None, ) -> list["Multiaddr"]: """ Resolve a DNSADDR record according to libp2p specification. @@ -191,9 +189,9 @@ async def _resolve_dnsaddr( async def _query_dnsaddr_txt_records( self, dnsaddr_hostname: str, - peer_id: Optional[str], + peer_id: str | None, max_depth: int, - signal: Optional[trio.CancelScope] = None, + signal: trio.CancelScope | None = None, _debug_level: int = 0, ) -> list["Multiaddr"]: """ @@ -282,7 +280,7 @@ async def _query_dnsaddr_txt_records( return results async def _resolve_dns( - self, hostname: str, protocol_code: int, signal: Optional[trio.CancelScope] = None + self, hostname: str, protocol_code: int, signal: trio.CancelScope | None = None ) -> list["Multiaddr"]: """Resolve a DNS record. @@ -344,7 +342,7 @@ async def _resolve_dns( raise ResolutionError(f"Failed to resolve DNS {hostname}: {e!s}") async def _resolve_dns_with_stack( - self, maddr: "Multiaddr", signal: Optional[trio.CancelScope] = None + self, maddr: "Multiaddr", signal: trio.CancelScope | None = None ) -> list["Multiaddr"]: """Resolve a DNS record while preserving the rest of the multiaddr stack. diff --git a/multiaddr/utils.py b/multiaddr/utils.py index ef5dbdd..f795038 100644 --- a/multiaddr/utils.py +++ b/multiaddr/utils.py @@ -1,5 +1,5 @@ import socket -from typing import Any, Optional +from typing import Any import psutil @@ -35,7 +35,7 @@ def is_link_local_ip(ip: str) -> bool: return len(parts) == 4 and parts[0] == "169" and parts[1] == "254" -def get_multiaddr_options(ma: Multiaddr) -> Optional[dict[str, Any]]: +def get_multiaddr_options(ma: Multiaddr) -> dict[str, Any] | None: """Extract options from a multiaddr (similar to toOptions() in JS). Returns a dictionary with 'family', 'host', 'transport', and 'port' keys, @@ -78,7 +78,7 @@ def get_multiaddr_options(ma: Multiaddr) -> Optional[dict[str, Any]]: def get_thin_waist_addresses( - ma: Optional[Multiaddr] = None, port: Optional[int] = None + ma: Multiaddr | None = None, port: int | None = None ) -> list[Multiaddr]: """Get all thin waist addresses on the current host that match the family of the passed multiaddr and optionally override the port. diff --git a/newsfragments/85.internal.rst b/newsfragments/85.internal.rst new file mode 100644 index 0000000..d85433e --- /dev/null +++ b/newsfragments/85.internal.rst @@ -0,0 +1 @@ +Drop python3.9 and run py-upgrade, set up CI, add readthedocs config, updates to Makefile diff --git a/pyproject.toml b/pyproject.toml index 1b48ed0..5e673cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,13 +16,12 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", ] -requires-python = ">=3.9, <4.0" +requires-python = ">=3.10, <4.0" dependencies = [ "base58", "dnspython>=2.7.0", diff --git a/tests/test_protocols.py b/tests/test_protocols.py index 80cf7d0..fabfede 100644 --- a/tests/test_protocols.py +++ b/tests/test_protocols.py @@ -6,23 +6,21 @@ def test_code_to_varint(): vi = varint.encode(5) - assert vi == b'\x05' + assert vi == b"\x05" vi = varint.encode(150) - assert vi == b'\x96\x01' + assert vi == b"\x96\x01" def test_varint_to_code(): - cc = varint.decode_bytes(b'\x05') + cc = varint.decode_bytes(b"\x05") assert cc == 5 - cc = varint.decode_bytes(b'\x96\x01') + cc = varint.decode_bytes(b"\x96\x01") assert cc == 150 @pytest.fixture def valid_params(): - return {'code': protocols.P_IP4, - 'name': 'ipb4', - 'codec': 'ipb'} + return {"code": protocols.P_IP4, "name": "ipb4", "codec": "ipb"} def test_valid(valid_params): @@ -31,55 +29,55 @@ def test_valid(valid_params): assert getattr(proto, key) == valid_params[key] -@pytest.mark.parametrize("invalid_code", ['abc']) +@pytest.mark.parametrize("invalid_code", ["abc"]) def test_invalid_code(valid_params, invalid_code): - valid_params['code'] = invalid_code + valid_params["code"] = invalid_code with pytest.raises(TypeError): protocols.Protocol(**valid_params) @pytest.mark.parametrize("invalid_name", [123, 1.0]) def test_invalid_name(valid_params, invalid_name): - valid_params['name'] = invalid_name + valid_params["name"] = invalid_name with pytest.raises(TypeError): protocols.Protocol(**valid_params) @pytest.mark.parametrize("invalid_codec", [b"ip4", 123, 0.123]) def test_invalid_codec(valid_params, invalid_codec): - valid_params['codec'] = invalid_codec + valid_params["codec"] = invalid_codec with pytest.raises(TypeError): protocols.Protocol(**valid_params) @pytest.mark.parametrize("name", ["foo-str", "foo-u"]) def test_valid_names(valid_params, name): - valid_params['name'] = name + valid_params["name"] = name test_valid(valid_params) @pytest.mark.parametrize("codec", ["ip4", "ip6"]) def test_valid_codecs(valid_params, codec): - valid_params['codec'] = codec + valid_params["codec"] = codec test_valid(valid_params) def test_protocol_with_name(): - proto = protocols.protocol_with_name('ip4') - assert proto.name == 'ip4' + proto = protocols.protocol_with_name("ip4") + assert proto.name == "ip4" assert proto.code == protocols.P_IP4 assert proto.size == 32 assert proto.vcode == varint.encode(protocols.P_IP4) - assert protocols.protocol_with_any('ip4') == proto + assert protocols.protocol_with_any("ip4") == proto assert protocols.protocol_with_any(proto) == proto with pytest.raises(exceptions.ProtocolNotFoundError): - proto = protocols.protocol_with_name('foo') + proto = protocols.protocol_with_name("foo") def test_protocol_with_code(): proto = protocols.protocol_with_code(protocols.P_IP4) - assert proto.name == 'ip4' + assert proto.name == "ip4" assert proto.code == protocols.P_IP4 assert proto.size == 32 assert proto.vcode == varint.encode(protocols.P_IP4) @@ -91,10 +89,10 @@ def test_protocol_with_code(): def test_protocol_equality(): - proto1 = protocols.protocol_with_name('ip4') + proto1 = protocols.protocol_with_name("ip4") proto2 = protocols.protocol_with_code(protocols.P_IP4) - proto3 = protocols.protocol_with_name('onion') - proto4 = protocols.protocol_with_name('onion3') + proto3 = protocols.protocol_with_name("onion") + proto4 = protocols.protocol_with_name("onion3") assert proto1 == proto2 assert proto1 != proto3 @@ -103,9 +101,7 @@ def test_protocol_equality(): assert proto2 != str(proto2) -@pytest.mark.parametrize("names", [['ip4'], - ['ip4', 'tcp'], - ['ip4', 'tcp', 'udp']]) +@pytest.mark.parametrize("names", [["ip4"], ["ip4", "tcp"], ["ip4", "tcp", "udp"]]) def test_protocols_with_string(names): expected = [protocols.protocol_with_name(name) for name in names] ins = "/".join(names) @@ -120,7 +116,7 @@ def test_protocols_with_string_invalid(invalid_name): def test_protocols_with_string_mixed(): - names = ['ip4'] + names = ["ip4"] ins = "/".join(names) test_protocols_with_string(names) with pytest.raises(exceptions.StringParseError): @@ -182,5 +178,5 @@ def test_add_protocol_lock(valid_params): def test_protocol_repr(): - proto = protocols.protocol_with_name('ip4') + proto = protocols.protocol_with_name("ip4") assert "Protocol(code=4, name='ip4', codec='ip4')" == repr(proto) diff --git a/tox.ini b/tox.ini index b8da13d..1e6238a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,26 @@ [tox] -envlist = py311,py313 +envlist= + py{310,311,312,313}-core + py{310,311,312,313}-lint + docs [testenv] -deps = - pytest - pytest-cov - ruff -commands = - pytest {posargs:tests} - ruff check . - ruff format --check . +deps= + trio +extras= + dev +commands= + core: pytest {posargs:tests} + docs: make docs-ci +[testenv:py{310,311,312,313}-lint] +deps=pre-commit +commands= + ; pre-commit install + pre-commit run --all-files --show-diff-on-failure +[testenv:docs] +commands = + make docs-ci +allowlist_externals= + make