Skip to content

Commit e8f5a17

Browse files
altendkyemloweQuexington
authored
python 3.13 support (#19123)
* python 3.13 support * some more * 3.13 for dep checks * more 3.13 *confused* * fixup * fixup * update expected signature in 3.13 * fixup _attach/_detach hinting and testing * ban freethreading * Fix trailing comma in list * replace legacy kw_only_dataclass decorator * Adjust check for python version * Remove debugging output * Use reruns for 3.13+Windows flakes only * re-lock poetry --------- Co-authored-by: Earle Lowe <[email protected]> Co-authored-by: Matt Hauff <[email protected]>
1 parent 28dbf3c commit e8f5a17

File tree

12 files changed

+99
-32
lines changed

12 files changed

+99
-32
lines changed

.github/workflows/check_wheel_availability.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
matrix: arm
4444
- name: Intel
4545
matrix: intel
46-
python-version: ["3.10", "3.11", "3.12"]
46+
python-version: ["3.10", "3.11", "3.12", "3.13"]
4747
exclude:
4848
- os:
4949
matrix: windows

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
- major_dot_minor: "3.10"
4545
- major_dot_minor: "3.11"
4646
- major_dot_minor: "3.12"
47+
- major_dot_minor: "3.13"
4748
exclude:
4849
- os:
4950
matrix: windows

.github/workflows/test-install-scripts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ jobs:
226226
# The behavior we follow in install.sh is unique with Arch in that
227227
# we leave it to the user to install the appropriate version of python,
228228
# so we need to install python here in order for the test to succeed.
229-
pacman --noconfirm -U --needed https://archive.archlinux.org/packages/p/python/python-3.12.7-1-x86_64.pkg.tar.zst
229+
pacman --noconfirm -U --needed https://archive.archlinux.org/packages/p/python/python-3.13.5-1-x86_64.pkg.tar.zst
230230
231231
- name: Prepare Debian
232232
if: ${{ matrix.distribution.type == 'debian' }}

.github/workflows/test-single.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ jobs:
9494
apt: "3.12"
9595
install_sh: "3.12"
9696
matrix: "3.12"
97+
- name: "3.13"
98+
file_name: "3.13"
99+
action: "3.13"
100+
apt: "3.13"
101+
install_sh: "3.13"
102+
matrix: "3.13"
103+
exclude_from:
104+
limited: True
105+
main: True
97106
exclude:
98107
- arch:
99108
matrix: arm
@@ -244,7 +253,13 @@ jobs:
244253
run: |
245254
mv chia/ notchia/
246255
256+
- name: Test blockchain code with pytest with windows and 3.13 and reruns
257+
if: matrix.os.name == 'windows' && matrix.python.name == '3.13'
258+
run: |
259+
pytest --reruns 1 --cov=chia --cov-config=.coveragerc --cov-report= -o 'junit_suite_name=${{ env.JOB_FILE_NAME }}' --junitxml='junit-data/junit.${{ env.JOB_FILE_NAME }}.xml' --durations=10 ${{ matrix.configuration.pytest_parallel_args[matrix.os.matrix] }} -m "not benchmark" ${{ env.ENABLE_PYTEST_MONITOR }} ${{ matrix.configuration.test_files }}
260+
247261
- name: Test blockchain code with pytest
262+
if: ${{ !(matrix.os.name == 'windows' && matrix.python.name == '3.13') }}
248263
env:
249264
ENABLE_PYTEST_MONITOR: ${{ matrix.os.matrix == 'ubuntu' && matrix.configuration.enable_pytest_monitor || '' }}
250265
run: |

.github/workflows/upload-pypi-source.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ jobs:
6262
- major_dot_minor: "3.10"
6363
- major_dot_minor: "3.11"
6464
- major_dot_minor: "3.12"
65+
- major_dot_minor: "3.13"
6566
check:
6667
- name: mypy
6768
command: |

Install.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ if ($null -eq (Get-Command py -ErrorAction SilentlyContinue))
4646
Exit 1
4747
}
4848

49-
$supportedPythonVersions = "3.12", "3.11", "3.10"
49+
$supportedPythonVersions = "3.13", "3.12", "3.11", "3.10"
5050
if ("$env:INSTALL_PYTHON_VERSION" -ne "")
5151
{
5252
$pythonVersion = $env:INSTALL_PYTHON_VERSION

chia/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import importlib.metadata
4+
import sys
45

56
__version__: str
67
try:
@@ -15,3 +16,6 @@
1516
pass
1617
else:
1718
raise Exception("asserts are not working and _must_ be enabled, do not run with an optimized build of python")
19+
20+
if not getattr(sys, "_is_gil_enabled", lambda: True)():
21+
raise Exception("freethreading is not supported, do not run with a freethreaded build of python")

chia/_tests/core/server/test_event_loop.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ def test_base_event_loop_has_methods() -> None:
3030
assert hasattr(base_selector_event_loop, "create_server")
3131
method = getattr(base_selector_event_loop, "create_server")
3232
assert inspect.ismethod(method)
33-
if sys.version_info >= (3, 11):
33+
if sys.version_info >= (3, 13):
34+
expected_signature = "(protocol_factory, host=None, port=None, *, family=<AddressFamily.AF_UNSPEC: 0>, flags=<AddressInfo.AI_PASSIVE: 1>, 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
35+
elif sys.version_info >= (3, 11):
3436
expected_signature = "(protocol_factory, host=None, port=None, *, family=<AddressFamily.AF_UNSPEC: 0>, flags=<AddressInfo.AI_PASSIVE: 1>, 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
3537
else:
3638
expected_signature = "(protocol_factory, host=None, port=None, *, family=<AddressFamily.AF_UNSPEC: 0>, flags=<AddressInfo.AI_PASSIVE: 1>, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None, ssl_handshake_timeout=None, start_serving=True)" # noqa: E501
@@ -103,7 +105,13 @@ async def main() -> None:
103105

104106
for func in ("_attach", "_detach"):
105107
assert hasattr(base_server, func)
106-
method = getattr(base_server, func)
107-
assert str(inspect.signature(method)) == "()"
108+
if sys.version_info >= (3, 13):
109+
# https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Lib/asyncio/base_events.py#L296
110+
method = getattr(base_server, func)
111+
assert str(inspect.signature(method)) == "(transport)"
112+
else:
113+
method = getattr(base_server, func)
114+
assert str(inspect.signature(method)) == "()"
115+
108116
finally:
109117
selector_event_loop.close()

chia/server/chia_policy.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ssl
77
import struct
88
import sys
9+
import weakref
910

1011
if sys.platform == "win32":
1112
import _overlapped # type: ignore[import-not-found]
@@ -57,15 +58,26 @@ class BaseEventsServer(asyncio.base_events.Server):
5758
else:
5859
_loop: EventsAbstractEventLoop
5960
_sockets: Iterable[socket.socket]
60-
_active_count: int
61+
if sys.version_info >= (3, 13):
62+
# https://github.com/python/cpython/blob/v3.13.7/Lib/asyncio/base_events.py#L283
63+
_clients: weakref.WeakSet[object]
64+
else:
65+
_active_count: int
6166
_protocol_factory: _ProtocolFactory
6267
_backlog: int
6368
_ssl_context: _SSLContext
6469
_ssl_handshake_timeout: Optional[float]
6570

66-
def _attach(self) -> None: ...
71+
if sys.version_info >= (3, 13):
72+
# https://github.com/python/cpython/blob/bcee1c322115c581da27600f2ae55e5439c027eb/Lib/asyncio/base_events.py#L296
73+
def _attach(self, transport: object) -> None: ...
74+
75+
def _detach(self, transport: object) -> None: ...
76+
else:
77+
78+
def _attach(self) -> None: ...
6779

68-
def _detach(self) -> None: ...
80+
def _detach(self) -> None: ...
6981

7082
def _start_serving(self) -> None: ...
7183

@@ -132,20 +144,22 @@ def __init__(
132144
max_concurrent_connections if max_concurrent_connections is not None else global_max_concurrent_connections
133145
)
134146

135-
def _attach(self) -> None:
136-
super()._attach()
137-
logging.getLogger(__name__).debug(f"New connection. Total connections: {self._active_count}")
138-
if not self._paused and self._active_count >= self.max_concurrent_connections:
147+
def _attach(self, *args: object, **kwargs: object) -> None:
148+
super()._attach(*args, **kwargs)
149+
active_connections = self._chia_active_connections()
150+
logging.getLogger(__name__).debug(f"New connection. Total connections: {active_connections}")
151+
if not self._paused and active_connections >= self.max_concurrent_connections:
139152
self._chia_pause()
140153

141-
def _detach(self) -> None:
142-
super()._detach()
143-
logging.getLogger(__name__).debug(f"Connection lost. Total connections: {self._active_count}")
154+
def _detach(self, *args: object, **kwargs: object) -> None:
155+
super()._detach(*args, **kwargs)
156+
active_connections = self._chia_active_connections()
157+
logging.getLogger(__name__).debug(f"Connection lost. Total connections: {active_connections}")
144158
if (
145-
self._active_count > 0
159+
active_connections > 0
146160
and self._sockets is not None
147161
and self._paused
148-
and self._active_count < self.max_concurrent_connections
162+
and active_connections < self.max_concurrent_connections
149163
):
150164
self._chia_resume()
151165

@@ -180,6 +194,12 @@ def _chia_resume(self) -> None:
180194
)
181195
logging.getLogger(__name__).debug("Resumed accepting connections.")
182196

197+
def _chia_active_connections(self) -> int:
198+
if sys.version_info >= (3, 13):
199+
return len(self._clients)
200+
else:
201+
return self._active_count
202+
183203

184204
async def _chia_create_server(
185205
cls: Any,

install.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ OPENSSL_VERSION_INT=
7171
find_python() {
7272
set +e
7373
unset BEST_VERSION
74-
for V in 312 3.12 311 3.11 310 3.10 3; do
74+
for V in 313 3.13 312 3.12 311 3.11 310 3.10 3; do
7575
if command -v python$V >/dev/null; then
7676
if [ "$BEST_VERSION" = "" ]; then
7777
BEST_VERSION=$V
@@ -134,8 +134,8 @@ if ! command -v "$INSTALL_PYTHON_PATH" >/dev/null; then
134134
exit 1
135135
fi
136136

137-
if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "7" ] || [ "$PYTHON_MINOR_VER" -ge "13" ]; then
138-
echo "Chia requires Python version >= 3.10 and < 3.13.0" >&2
137+
if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "10" ] || [ "$PYTHON_MINOR_VER" -ge "14" ]; then
138+
echo "Chia requires Python version >= 3.10 and < 3.14.0" >&2
139139
echo "Current Python version = $INSTALL_PYTHON_VERSION" >&2
140140
# If Arch, direct to Arch Wiki
141141
if type pacman >/dev/null 2>&1 && [ -f "/etc/arch-release" ]; then

0 commit comments

Comments
 (0)