From 597e1b13f20b2ee36e583c347542c857c6dc9b37 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Fri, 10 Jan 2025 17:16:45 -0500 Subject: [PATCH 1/8] python 3.13 support --- Install.ps1 | 2 +- install.sh | 2 +- poetry.lock | 2 +- pyproject.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Install.ps1 b/Install.ps1 index 0d2e40c5653f..3c70498d4809 100644 --- a/Install.ps1 +++ b/Install.ps1 @@ -48,7 +48,7 @@ if ($null -eq (Get-Command py -ErrorAction SilentlyContinue)) Exit 1 } -$supportedPythonVersions = "3.12", "3.11", "3.10", "3.9" +$supportedPythonVersions = "3.13", "3.12", "3.11", "3.10", "3.9" if ("$env:INSTALL_PYTHON_VERSION" -ne "") { $pythonVersion = $env:INSTALL_PYTHON_VERSION diff --git a/install.sh b/install.sh index 516e6e0845c2..89a281864334 100755 --- a/install.sh +++ b/install.sh @@ -74,7 +74,7 @@ OPENSSL_VERSION_INT= find_python() { set +e unset BEST_VERSION - for V in 312 3.12 311 3.11 310 3.10 39 3.9 3; do + for V in 313 3.13 312 3.12 311 3.11 310 3.10 39 3.9 3; do if command -v python$V >/dev/null; then if [ "$BEST_VERSION" = "" ]; then BEST_VERSION=$V diff --git a/poetry.lock b/poetry.lock index 057c5ca3ac94..5e3ea82456a2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3336,4 +3336,4 @@ upnp = ["miniupnpc"] [metadata] lock-version = "2.0" python-versions = ">=3.9, <4" -content-hash = "78821e547fe0580a1c646c3e8f5329ae5b6f7190da85127869e2ccd1030830f9" +content-hash = "a13a8d2038f8e85c272f36df5f62292d24b4fa200a2345c36e5db5475e43b680" diff --git a/pyproject.toml b/pyproject.toml index 23f3e2752a76..d0c1ceb7233f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,7 +84,7 @@ diff-cover = { version = ">=9.2.0", optional = true } mypy = { version = ">=1.11.1", optional = true } pre-commit = { version = ">=3.7.1", optional = true } py3createtorrent = { version = ">=1.2.1", optional = true } -pyinstaller = { version = ">=6.9.0", python = "<3.13", optional = true } +pyinstaller = { version = ">=6.9.0", python = "<3.14", optional = true } pytest = { version = ">=8.3.3", optional = true } pytest-cov = { version = ">=5.0.0", optional = true } pytest-mock = { version = ">=3.14.0", optional = true } From 1f66b2f6fe6dc90139de7e4e3d83837e731477c6 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Mon, 13 Jan 2025 08:03:31 -0500 Subject: [PATCH 2/8] some more --- install.sh | 4 ++-- poetry.lock | 2 +- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index 89a281864334..3c6730005e25 100755 --- a/install.sh +++ b/install.sh @@ -137,8 +137,8 @@ if ! command -v "$INSTALL_PYTHON_PATH" >/dev/null; then exit 1 fi -if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "7" ] || [ "$PYTHON_MINOR_VER" -ge "13" ]; then - echo "Chia requires Python version >= 3.9 and < 3.13.0" >&2 +if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "7" ] || [ "$PYTHON_MINOR_VER" -ge "14" ]; then + echo "Chia requires Python version >= 3.9 and < 3.14.0" >&2 echo "Current Python version = $INSTALL_PYTHON_VERSION" >&2 # If Arch, direct to Arch Wiki if type pacman >/dev/null 2>&1 && [ -f "/etc/arch-release" ]; then diff --git a/poetry.lock b/poetry.lock index 5e3ea82456a2..06cbcd905a24 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3336,4 +3336,4 @@ upnp = ["miniupnpc"] [metadata] lock-version = "2.0" python-versions = ">=3.9, <4" -content-hash = "a13a8d2038f8e85c272f36df5f62292d24b4fa200a2345c36e5db5475e43b680" +content-hash = "2b4d45a11d03af13afb68e506690e6a55eda77d51b85ce2c0de860214fd6456f" diff --git a/pyproject.toml b/pyproject.toml index d0c1ceb7233f..b8c89323e93e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ typing-extensions = ">=4.12.2" # typing backports like Protocol and TypedDict watchdog = ">=4.0.1" # Filesystem event watching - watches keyring.yaml zstd = [ {version=">=1.5.5.1", python = "<3.12"}, - {version=">=1.5.5.1", python = "3.12", source="chia"}, + {version=">=1.5.5.1", python = ">=3.12", source="chia"}, ] importlib-resources = ">=6.4.5" hsms = ">=0.3.1" From 7459a8b2e4c412db3a42d511ee3e0d1177f2c115 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 17 Jul 2025 09:36:32 -0400 Subject: [PATCH 3/8] 3.13 for dep checks --- .github/workflows/check_wheel_availability.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_wheel_availability.yaml b/.github/workflows/check_wheel_availability.yaml index 2ee5fca74f6a..9f2eaf536d64 100644 --- a/.github/workflows/check_wheel_availability.yaml +++ b/.github/workflows/check_wheel_availability.yaml @@ -43,7 +43,7 @@ jobs: matrix: arm - name: Intel matrix: intel - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] exclude: - os: matrix: windows From aa4fe30c9af478ae16a325962ea6dbb78e04c5cd Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 17 Jul 2025 09:39:14 -0400 Subject: [PATCH 4/8] more 3.13 *confused* --- .github/workflows/pre-commit.yml | 1 + .github/workflows/test-install-scripts.yml | 2 +- .github/workflows/test-single.yml | 9 +++++++++ .github/workflows/upload-pypi-source.yml | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index becd6fb7d295..75c545899dee 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -45,6 +45,7 @@ jobs: - major_dot_minor: "3.10" - major_dot_minor: "3.11" - major_dot_minor: "3.12" + - major_dot_minor: "3.13" exclude: - os: matrix: windows diff --git a/.github/workflows/test-install-scripts.yml b/.github/workflows/test-install-scripts.yml index 05f153362203..ab4bfab3a80d 100644 --- a/.github/workflows/test-install-scripts.yml +++ b/.github/workflows/test-install-scripts.yml @@ -206,7 +206,7 @@ jobs: # The behavior we follow in install.sh is unique with Arch in that # we leave it to the user to install the appropriate version of python, # so we need to install python here in order for the test to succeed. - pacman --noconfirm -U --needed https://archive.archlinux.org/packages/p/python/python-3.12.7-1-x86_64.pkg.tar.zst + pacman --noconfirm -U --needed https://archive.archlinux.org/packages/p/python/python-3.13.5-1-x86_64.pkg.tar.zst - name: Prepare Debian if: ${{ matrix.distribution.type == 'debian' }} diff --git a/.github/workflows/test-single.yml b/.github/workflows/test-single.yml index fc18c48dbfc7..b19f59145bf1 100644 --- a/.github/workflows/test-single.yml +++ b/.github/workflows/test-single.yml @@ -105,6 +105,15 @@ jobs: exclude_from: limited: True main: True + - name: "3.13" + file_name: "3.13" + action: "3.13" + apt: "3.13" + install_sh: "3.13" + matrix: "3.13" + exclude_from: + limited: True + main: True exclude: - arch: matrix: arm diff --git a/.github/workflows/upload-pypi-source.yml b/.github/workflows/upload-pypi-source.yml index 76314e035a3b..f029005cd4d5 100644 --- a/.github/workflows/upload-pypi-source.yml +++ b/.github/workflows/upload-pypi-source.yml @@ -62,6 +62,7 @@ jobs: - major_dot_minor: "3.10" - major_dot_minor: "3.11" - major_dot_minor: "3.12" + - major_dot_minor: "3.13" check: - name: mypy command: | From 238ae01ae54c3e473884d585b34862c55cde4d46 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 2 Sep 2025 11:23:06 -0400 Subject: [PATCH 5/8] fixup --- chia/server/chia_policy.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/chia/server/chia_policy.py b/chia/server/chia_policy.py index 36ed1c0cd0c1..c0b8a5c2e126 100644 --- a/chia/server/chia_policy.py +++ b/chia/server/chia_policy.py @@ -132,20 +132,22 @@ def __init__( max_concurrent_connections if max_concurrent_connections is not None else global_max_concurrent_connections ) - def _attach(self) -> None: - super()._attach() - logging.getLogger(__name__).debug(f"New connection. Total connections: {self._active_count}") - if not self._paused and self._active_count >= self.max_concurrent_connections: + def _attach(self, *args: object, **kwargs: object) -> None: + super()._attach(*args, **kwargs) + active_connections = self._chia_active_connections() + logging.getLogger(__name__).debug(f"New connection. Total connections: {active_connections}") + if not self._paused and active_connections >= self.max_concurrent_connections: self._chia_pause() - def _detach(self) -> None: - super()._detach() - logging.getLogger(__name__).debug(f"Connection lost. Total connections: {self._active_count}") + def _detach(self, *args: object, **kwargs: object) -> None: + super()._detach(*args, **kwargs) + active_connections = self._chia_active_connections() + logging.getLogger(__name__).debug(f"Connection lost. Total connections: {active_connections}") if ( - self._active_count > 0 + active_connections > 0 and self._sockets is not None and self._paused - and self._active_count < self.max_concurrent_connections + and active_connections < self.max_concurrent_connections ): self._chia_resume() @@ -180,6 +182,12 @@ def _chia_resume(self) -> None: ) logging.getLogger(__name__).debug("Resumed accepting connections.") + def _chia_active_connections(self) -> int: + if sys.version_info >= (3, 13): + return len(self._clients) + else: + return self._active_count + async def _chia_create_server( cls: Any, From f8d4f7d93e8136d236410e89262e4510543d161a Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 2 Sep 2025 11:51:12 -0400 Subject: [PATCH 6/8] fixup --- chia/server/chia_policy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/chia/server/chia_policy.py b/chia/server/chia_policy.py index c0b8a5c2e126..8596dc1b9fe3 100644 --- a/chia/server/chia_policy.py +++ b/chia/server/chia_policy.py @@ -6,6 +6,7 @@ import ssl import struct import sys +import weakref if sys.platform == "win32": import _overlapped # type: ignore[import-not-found] @@ -57,7 +58,11 @@ class BaseEventsServer(asyncio.base_events.Server): else: _loop: EventsAbstractEventLoop _sockets: Iterable[socket.socket] - _active_count: int + if sys.version_info >= (3, 13): + # https://github.com/python/cpython/blob/v3.13.7/Lib/asyncio/base_events.py#L283 + _clients: weakref.WeakSet[object] + else: + _active_count: int _protocol_factory: _ProtocolFactory _backlog: int _ssl_context: _SSLContext From 828e413dc177ce5aef11fde46ac309b89145401a Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 2 Sep 2025 17:55:45 -0400 Subject: [PATCH 7/8] update expected signature in 3.13 --- chia/_tests/core/server/test_event_loop.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chia/_tests/core/server/test_event_loop.py b/chia/_tests/core/server/test_event_loop.py index 19af2456c631..91716c20dd6e 100644 --- a/chia/_tests/core/server/test_event_loop.py +++ b/chia/_tests/core/server/test_event_loop.py @@ -30,7 +30,9 @@ def test_base_event_loop_has_methods() -> None: assert hasattr(base_selector_event_loop, "create_server") method = getattr(base_selector_event_loop, "create_server") assert inspect.ismethod(method) - if sys.version_info >= (3, 11): + if sys.version_info >= (3, 13): + expected_signature = "(protocol_factory, host=None, port=None, *, family=, flags=, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, keep_alive=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)" # noqa: E501 + elif sys.version_info >= (3, 11): expected_signature = "(protocol_factory, host=None, port=None, *, family=, flags=, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, ssl_shutdown_timeout=None, start_serving=True)" # noqa: E501 else: expected_signature = "(protocol_factory, host=None, port=None, *, family=, flags=, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)" # noqa: E501 From f395ca98c0a6719ca01658f9d4154f51ff2542e5 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Thu, 11 Sep 2025 11:51:59 -0400 Subject: [PATCH 8/8] fixup _attach/_detach hinting and testing --- chia/_tests/core/server/test_event_loop.py | 10 ++++++++-- chia/server/chia_policy.py | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/chia/_tests/core/server/test_event_loop.py b/chia/_tests/core/server/test_event_loop.py index 91716c20dd6e..51e7168e1b15 100644 --- a/chia/_tests/core/server/test_event_loop.py +++ b/chia/_tests/core/server/test_event_loop.py @@ -105,7 +105,13 @@ async def main() -> None: for func in ("_attach", "_detach"): assert hasattr(base_server, func) - method = getattr(base_server, func) - assert str(inspect.signature(method)) == "()" + if sys.version_info >= (3, 13): + # https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Lib/asyncio/base_events.py#L296 + method = getattr(base_server, func) + assert str(inspect.signature(method)) == "(transport)" + else: + method = getattr(base_server, func) + assert str(inspect.signature(method)) == "()" + finally: selector_event_loop.close() diff --git a/chia/server/chia_policy.py b/chia/server/chia_policy.py index 8596dc1b9fe3..fec3242936bf 100644 --- a/chia/server/chia_policy.py +++ b/chia/server/chia_policy.py @@ -68,9 +68,16 @@ class BaseEventsServer(asyncio.base_events.Server): _ssl_context: _SSLContext _ssl_handshake_timeout: Optional[float] - def _attach(self) -> None: ... + if sys.version_info >= (3, 13): + # https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Lib/asyncio/base_events.py#L296 + def _attach(self, transport: object) -> None: ... + + def _detach(self, transport: object) -> None: ... + else: + + def _attach(self) -> None: ... - def _detach(self) -> None: ... + def _detach(self) -> None: ... def _start_serving(self) -> None: ...