Skip to content

Support Python 3.13, drop Python 3.8 #1910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
strategy:
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -78,10 +78,9 @@ jobs:
- name: Run pytest on POSIX
if: matrix.os != 'windows-latest'
# Skip Postgres tests on macos since macos runner doesn't have Docker.
# Skip Postgres tests for Python 3.8 since testcontainers<4 doesn't support asyncpg correctly.
run: |
RUNPOSTGRES=""
if [ "${{ matrix.os }}" != "macos-latest" ] && [ "${{ matrix.python-version }}" != "3.8" ]; then
if [ "${{ matrix.os }}" != "macos-latest" ]; then
RUNPOSTGRES="--runpostgres"
fi
pytest src/tests --runui $RUNPOSTGRES
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
strategy:
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -69,10 +69,9 @@ jobs:
- name: Run pytest on POSIX
if: matrix.os != 'windows-latest'
# Skip Postgres tests on macos since macos runner doesn't have Docker.
# Skip Postgres tests for Python 3.8 since testcontainers<4 doesn't support asyncpg correctly.
run: |
RUNPOSTGRES=""
if [ "${{ matrix.os }}" != "macos-latest" ] && [ "${{ matrix.python-version }}" != "3.8" ]; then
if [ "${{ matrix.os }}" != "macos-latest" ]; then
RUNPOSTGRES="--runpostgres"
fi
pytest src/tests --runui $RUNPOSTGRES
Expand Down
2 changes: 1 addition & 1 deletion ruff.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
target-version = "py38"
target-version = "py39"
line-length = 99

[lint]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def get_long_description():
description="dstack is an open-source orchestration engine for running AI workloads on any cloud or on-premises.",
long_description=get_long_description(),
long_description_content_type="text/markdown",
python_requires=">=3.8",
python_requires=">=3.9",
install_requires=BASE_DEPS,
extras_require={
"all": ALL_DEPS,
Expand Down
5 changes: 3 additions & 2 deletions src/dstack/_internal/server/services/fleets.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,9 @@ async def delete_fleets(
instances_ids = sorted([i.id for f in fleet_models for i in f.instances])
await session.commit()
logger.info("Deleting fleets: %s", [v.name for v in fleet_models])
async with get_locker().lock_ctx(FleetModel.__tablename__, fleets_ids), get_locker().lock_ctx(
InstanceModel.__tablename__, instances_ids
async with (
get_locker().lock_ctx(FleetModel.__tablename__, fleets_ids),
get_locker().lock_ctx(InstanceModel.__tablename__, instances_ids),
):
# Refetch after lock
# TODO lock instances with FOR UPDATE?
Expand Down
5 changes: 3 additions & 2 deletions src/dstack/_internal/server/services/runs.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,9 @@ async def stop_runs(
job_models = res.scalars().all()
job_ids = sorted([j.id for j in job_models])
await session.commit()
async with get_locker().lock_ctx(RunModel.__tablename__, run_ids), get_locker().lock_ctx(
JobModel.__tablename__, job_ids
async with (
get_locker().lock_ctx(RunModel.__tablename__, run_ids),
get_locker().lock_ctx(JobModel.__tablename__, job_ids),
):
for run_model in run_models:
await stop_run(session=session, run_model=run_model, abort=abort)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ async def test_provisions_gateway(self, test_db, session: AsyncSession):
project_id=project.id,
backend_id=backend.id,
)
with patch(
"dstack._internal.server.services.backends.get_project_backend_with_model_by_type_or_error"
) as m, patch(
"dstack._internal.server.services.gateways.gateway_connections_pool.get_or_add"
) as pool_add:
with (
patch(
"dstack._internal.server.services.backends.get_project_backend_with_model_by_type_or_error"
) as m,
patch(
"dstack._internal.server.services.gateways.gateway_connections_pool.get_or_add"
) as pool_add,
):
aws = Mock()
m.return_value = (backend, aws)
pool_add.return_value = MagicMock()
Expand Down Expand Up @@ -85,11 +88,14 @@ async def test_marks_gateway_as_failed_if_fails_to_connect(
project_id=project.id,
backend_id=backend.id,
)
with patch(
"dstack._internal.server.services.backends.get_project_backend_with_model_by_type_or_error"
) as m, patch(
"dstack._internal.server.services.gateways.connect_to_gateway_with_retry"
) as connect_to_gateway_with_retry_mock:
with (
patch(
"dstack._internal.server.services.backends.get_project_backend_with_model_by_type_or_error"
) as m,
patch(
"dstack._internal.server.services.gateways.connect_to_gateway_with_retry"
) as connect_to_gateway_with_retry_mock,
):
aws = Mock()
m.return_value = (backend, aws)
connect_to_gateway_with_retry_mock.return_value = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ async def test_collects_metrics(self, test_db, session: AsyncSession):
status=JobStatus.RUNNING,
job_provisioning_data=get_job_provisioning_data(),
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
):
runner_client_mock = RunnerClientMock.return_value
runner_client_mock.get_metrics.return_value = MetricsResponse(
timestamp_micro=1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ async def test_leaves_provisioning_job_unchanged_if_runner_not_alive(
submitted_at=datetime(2023, 1, 2, 5, 12, 30, 5, tzinfo=timezone.utc),
job_provisioning_data=job_provisioning_data,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock, patch(
"dstack._internal.utils.common.get_current_datetime"
) as datetime_mock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
patch("dstack._internal.utils.common.get_current_datetime") as datetime_mock,
):
datetime_mock.return_value = datetime(2023, 1, 2, 5, 12, 30, 10, tzinfo=timezone.utc)
runner_client_mock = RunnerClientMock.return_value
runner_client_mock.healthcheck = Mock()
Expand Down Expand Up @@ -123,11 +123,12 @@ async def test_runs_provisioning_job(self, test_db, session: AsyncSession):
status=JobStatus.PROVISIONING,
job_provisioning_data=job_provisioning_data,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
):
runner_client_mock = RunnerClientMock.return_value
runner_client_mock.healthcheck.return_value = HealthcheckResponse(
service="dstack-runner", version="0.0.1.dev2"
Expand Down Expand Up @@ -164,11 +165,13 @@ async def test_updates_running_job(self, test_db, session: AsyncSession, tmp_pat
status=JobStatus.RUNNING,
job_provisioning_data=job_provisioning_data,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock, patch.object(settings, "SERVER_DIR_PATH", tmp_path):
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
patch.object(settings, "SERVER_DIR_PATH", tmp_path),
):
runner_client_mock = RunnerClientMock.return_value
runner_client_mock.pull.return_value = PullResponse(
job_states=[JobStateEvent(timestamp=1, state=JobStatus.RUNNING)],
Expand All @@ -182,11 +185,12 @@ async def test_updates_running_job(self, test_db, session: AsyncSession, tmp_pat
assert job is not None
assert job.status == JobStatus.RUNNING
assert job.runner_timestamp == 1
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
):
runner_client_mock = RunnerClientMock.return_value
runner_client_mock.pull.return_value = PullResponse(
job_states=[JobStateEvent(timestamp=1, state=JobStatus.DONE)],
Expand Down Expand Up @@ -251,11 +255,10 @@ async def test_provisioning_shim_with_volumes(
status=JobStatus.PROVISIONING,
job_provisioning_data=job_provisioning_data,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.ShimClient"
) as ShimClientMock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch("dstack._internal.server.services.runner.client.ShimClient") as ShimClientMock,
):
ShimClientMock.return_value.healthcheck.return_value = HealthcheckResponse(
service="dstack-shim", version="0.0.1.dev2"
)
Expand Down Expand Up @@ -303,13 +306,13 @@ async def test_pulling_shim(self, test_db, session: AsyncSession):
status=JobStatus.PULLING,
job_provisioning_data=job_provisioning_data,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock, patch(
"dstack._internal.server.services.runner.client.ShimClient"
) as ShimClientMock:
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch(
"dstack._internal.server.services.runner.client.RunnerClient"
) as RunnerClientMock,
patch("dstack._internal.server.services.runner.client.ShimClient") as ShimClientMock,
):
RunnerClientMock.return_value.healthcheck.return_value = HealthcheckResponse(
service="dstack-runner", version="0.0.1.dev2"
)
Expand Down Expand Up @@ -355,9 +358,10 @@ async def test_pulling_shim_failed(self, test_db, session: AsyncSession):
job_provisioning_data=job_provisioning_data,
instance=instance,
)
with patch(
"dstack._internal.server.services.runner.ssh.SSHTunnel"
) as SSHTunnelMock, patch("dstack._internal.server.services.runner.ssh.time.sleep"):
with (
patch("dstack._internal.server.services.runner.ssh.SSHTunnel") as SSHTunnelMock,
patch("dstack._internal.server.services.runner.ssh.time.sleep"),
):
SSHTunnelMock.side_effect = SSHError
await process_running_jobs()
assert SSHTunnelMock.call_count == 3
Expand Down
Loading