diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index d1c3fe3ff..b6c5bf608 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] fail-fast: false timeout-minutes: 15 steps: diff --git a/.gitignore b/.gitignore index 2267a8c77..016f7ea70 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,6 @@ hivemind/proto/*_pb2* # libp2p-daemon binary hivemind/hivemind_cli/p2pd + +# VSCode's default venv directory +.venv \ No newline at end of file diff --git a/README.md b/README.md index 7eb599c80..6ce12cc44 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ pip install . ``` If you would like to verify that your installation is working properly, you can install with `pip install .[dev]` -instead. Then, you can run the tests with `pytest tests/`. +instead. Then, you can run the tests with `pytest tests/`. Use `pip install -e .[dev]` to make the source code editable. By default, hivemind uses the precompiled binary of the [go-libp2p-daemon](https://github.com/learning-at-home/go-libp2p-daemon) library. If you face compatibility issues diff --git a/setup.py b/setup.py index e1f90b274..f3ec53f35 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import tempfile import urllib.request -from pkg_resources import parse_requirements, parse_version +from packaging.version import parse as parse_version from setuptools import find_packages, setup from setuptools.command.build_py import build_py from setuptools.command.develop import develop @@ -141,7 +141,7 @@ def run(self): with open("requirements.txt") as requirements_file: - install_requires = list(map(str, parse_requirements(requirements_file))) + install_requires = [line.strip() for line in requirements_file if line.strip() and not line.startswith("#")] # loading version from setup.py with codecs.open(os.path.join(here, "hivemind/__init__.py"), encoding="utf-8") as init_file: @@ -151,10 +151,10 @@ def run(self): extras = {} with open("requirements-dev.txt") as dev_requirements_file: - extras["dev"] = list(map(str, parse_requirements(dev_requirements_file))) + extras["dev"] = [line.strip() for line in dev_requirements_file if line.strip() and not line.startswith("#")] with open("requirements-docs.txt") as docs_requirements_file: - extras["docs"] = list(map(str, parse_requirements(docs_requirements_file))) + extras["docs"] = [line.strip() for line in docs_requirements_file if line.strip() and not line.startswith("#")] extras["bitsandbytes"] = ["bitsandbytes~=0.45.2"] @@ -187,6 +187,7 @@ def run(self): "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Mathematics", "Topic :: Scientific/Engineering :: Artificial Intelligence", diff --git a/tests/test_auth.py b/tests/test_auth.py index 75b647995..193b780d2 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Optional import pytest @@ -31,7 +31,7 @@ async def get_token(self) -> AccessToken: token = AccessToken( username=self._username, public_key=self.local_public_key.to_bytes(), - expiration_time=str(datetime.utcnow() + timedelta(minutes=1)), + expiration_time=str(datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(minutes=1)), ) token.signature = MockAuthorizer._authority_private_key.sign(self._token_to_bytes(token)) return token @@ -52,7 +52,7 @@ def is_token_valid(self, access_token: AccessToken) -> bool: if expiration_time.tzinfo is not None: logger.exception(f"Expected to have no timezone for expiration time: {access_token.expiration_time}") return False - if expiration_time < datetime.utcnow(): + if expiration_time < datetime.now(timezone.utc).replace(tzinfo=None): logger.exception("Access token has expired") return False @@ -62,7 +62,7 @@ def is_token_valid(self, access_token: AccessToken) -> bool: def does_token_need_refreshing(self, access_token: AccessToken) -> bool: expiration_time = datetime.fromisoformat(access_token.expiration_time) - return expiration_time < datetime.utcnow() + self._MAX_LATENCY + return expiration_time < datetime.now(timezone.utc).replace(tzinfo=None) + self._MAX_LATENCY @staticmethod def _token_to_bytes(access_token: AccessToken) -> bytes: diff --git a/tests/test_utils/p2p_daemon.py b/tests/test_utils/p2p_daemon.py index db208cdd5..7f26df76c 100644 --- a/tests/test_utils/p2p_daemon.py +++ b/tests/test_utils/p2p_daemon.py @@ -5,17 +5,18 @@ import time import uuid from contextlib import asynccontextmanager, suppress +from pathlib import Path from typing import NamedTuple -from pkg_resources import resource_filename - +import hivemind from hivemind.p2p.p2p_daemon_bindings.p2pclient import Client from hivemind.utils.multiaddr import Multiaddr, protocols from test_utils.networking import get_free_port TIMEOUT_DURATION = 5 # seconds -P2PD_PATH = resource_filename("hivemind", "hivemind_cli/p2pd") +HIVEMIND_ROOT = Path(hivemind.__file__).parent +P2PD_PATH = str(HIVEMIND_ROOT / "hivemind_cli" / "p2pd") async def try_until_success(coro_func, timeout=TIMEOUT_DURATION):