Python 3.12 support
qstokkink opened this issue · 1 comments
IPv8 does not work out-of-the box with Python 3.12 yet.
I'll keep track of all known issues with Python 3.12 support in this issue. The list (so far) is as follows:
-
aiohttp
fails to install using pip. Known workaround:pip install aiohttp==3.9.0b0
click me for log output
aiohttp/_websocket.c(1475): warning C4996: 'Py_OptimizeFlag': deprecated in 3.12
aiohttp/_websocket.c(3042): error C2039: 'ob_digit': is not a member of '_longobject'
C:\Python\Python312\include\cpython/longintrepr.h(87): note: see declaration of '_longobject'
aiohttp/_websocket.c(3097): error C2039: 'ob_digit': is not a member of '_longobject'
C:\Python\Python312\include\cpython/longintrepr.h(87): note: see declaration of '_longobject'
aiohttp/_websocket.c(3238): error C2039: 'ob_digit': is not a member of '_longobject'
C:\Python\Python312\include\cpython/longintrepr.h(87): note: see declaration of '_longobject'
aiohttp/_websocket.c(3293): error C2039: 'ob_digit': is not a member of '_longobject'
C:\Python\Python312\include\cpython/longintrepr.h(87): note: see declaration of '_longobject'
aiohttp/_websocket.c(3744): error C2039: 'ob_digit': is not a member of '_longobject'
C:\Python\Python312\include\cpython/longintrepr.h(87): note: see declaration of '_longobject'
error: command 'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\HostX86\x64\cl.exe' failed with exit code 2 -
object.__new__
can no longer be used, causingtype_from_format()
to crash. Known workaround:out = TypeVar.__new__(TypeVar, fmt)
click me for log output
File "C:\py-ipv8\ipv8\test\messaging\test_payload_dataclass.py", line 11, in
varlenH = type_from_format('varlenH') # noqa: N816
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\py-ipv8\ipv8\messaging\payload_dataclass.py", line 15, in type_from_format
out = object.new(TypeVar)
^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object.new(typing.TypeVar) is not safe, use typing.TypeVar.new() - When importing
apispec
, distutils is not available:ModuleNotFoundError: No module named 'distutils'
. Workaround described below. -
TestBase._callTearDown
hard locks onself._callAsync(self.tearDown)
. Known workaround:useEdit: previously stated workaround was incorrect. The actual block occurred inself._asyncioTestContext.run(self.tearDown)
instead.web.TCPSite.stop
duringwait_for
.
When the above is fixed, the unittests pass again.
It seems IPv8 itself also uses distutils.version.LooseVersion
. Additionally, inside of apispec
, I also spotted a use of LooseVersion
. Therefore, the distutils
removal is a bigger issue for IPv8 than just a one-line fix.
We can follow https://peps.python.org/pep-0632/ and switch to https://pypi.org/project/packaging/ However, for external downstream dependencies (that we obviously cannot edit directly) we should locally wrap the required distutils
functionality and load the wrapper as the distutils
module into sys.modules
(temporarily, until our dependencies update).
A quick and dirty fix would be the following (CLICK ME!)
from __future__ import annotations
import sys
import packaging.version
class LooseVersion(packaging.version.Version):
@property
def version(self):
return self.release
@property
def vstring(self):
return str(self)
def __lt__(self, other: str | "_BaseVersion") -> bool:
if isinstance(other, str):
return self < LooseVersion(other)
return super().__lt__(other)
def __le__(self, other: str | "_BaseVersion") -> bool:
if isinstance(other, str):
return self <= LooseVersion(other)
return super().__le__(other)
def __eq__(self, other: object) -> bool:
if isinstance(other, str):
return self == LooseVersion(other)
return super().__eq__(other)
def __ge__(self, other: str | "_BaseVersion") -> bool:
if isinstance(other, str):
return self >= LooseVersion(other)
return super().__ge__(other)
def __gt__(self, other: str | "_BaseVersion") -> bool:
if isinstance(other, str):
return self > LooseVersion(other)
return super().__gt__(other)
def __ne__(self, other: object) -> bool:
if isinstance(other, str):
return self != LooseVersion(other)
return super().__ne__(other)
packaging.version.LooseVersion = LooseVersion
sys.modules["distutils.version"] = packaging.version