diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e75b01876..1d61792fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 }} @@ -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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a979a5f7d..9b48b6249 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 }} @@ -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 diff --git a/ruff.toml b/ruff.toml index d6cf435a8..b61fb7d00 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,4 +1,4 @@ -target-version = "py38" +target-version = "py39" line-length = 99 [lint] diff --git a/setup.py b/setup.py index a83be3166..2d6b5c25e 100644 --- a/setup.py +++ b/setup.py @@ -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, diff --git a/src/dstack/_internal/server/services/fleets.py b/src/dstack/_internal/server/services/fleets.py index 5abfe0b6d..854fef384 100644 --- a/src/dstack/_internal/server/services/fleets.py +++ b/src/dstack/_internal/server/services/fleets.py @@ -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? diff --git a/src/dstack/_internal/server/services/runs.py b/src/dstack/_internal/server/services/runs.py index 60539b7dd..41818b532 100644 --- a/src/dstack/_internal/server/services/runs.py +++ b/src/dstack/_internal/server/services/runs.py @@ -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) diff --git a/src/tests/_internal/server/background/tasks/test_process_gateways.py b/src/tests/_internal/server/background/tasks/test_process_gateways.py index 93f2bc40b..9c4bcf029 100644 --- a/src/tests/_internal/server/background/tasks/test_process_gateways.py +++ b/src/tests/_internal/server/background/tasks/test_process_gateways.py @@ -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() @@ -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 diff --git a/src/tests/_internal/server/background/tasks/test_process_metrics.py b/src/tests/_internal/server/background/tasks/test_process_metrics.py index 5539d810b..5f0b03dda 100644 --- a/src/tests/_internal/server/background/tasks/test_process_metrics.py +++ b/src/tests/_internal/server/background/tasks/test_process_metrics.py @@ -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, diff --git a/src/tests/_internal/server/background/tasks/test_process_running_jobs.py b/src/tests/_internal/server/background/tasks/test_process_running_jobs.py index 0ec3d949e..c8c02e0c8 100644 --- a/src/tests/_internal/server/background/tasks/test_process_running_jobs.py +++ b/src/tests/_internal/server/background/tasks/test_process_running_jobs.py @@ -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() @@ -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" @@ -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)], @@ -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)], @@ -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" ) @@ -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" ) @@ -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 diff --git a/src/tests/_internal/server/routers/test_backends.py b/src/tests/_internal/server/routers/test_backends.py index 04debbbb0..31871af9d 100644 --- a/src/tests/_internal/server/routers/test_backends.py +++ b/src/tests/_internal/server/routers/test_backends.py @@ -104,11 +104,12 @@ async def test_returns_invalid_credentials( "secret_key": "1234", }, } - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ) as authenticate_mock: + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock, + ): authenticate_mock.side_effect = BackendAuthError() response = await client.post( "/api/backends/config_values", @@ -147,12 +148,12 @@ async def test_returns_config_on_valid_creds( "secret_key": "1234", }, } - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ) as authenticate_mock, patch( - "dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error" + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock, + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), ): default_creds_available_mock.return_value = True response = await client.post( @@ -239,11 +240,12 @@ async def test_returns_invalid_credentials( "client_secret": "1234", }, } - with patch( - "dstack._internal.core.backends.azure.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.azure.auth.authenticate" - ) as authenticate_mock: + with ( + patch( + "dstack._internal.core.backends.azure.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock, + ): default_creds_available_mock.return_value = False authenticate_mock.side_effect = BackendAuthError() response = await client.post( @@ -303,14 +305,15 @@ async def test_returns_config_on_valid_creds( self, test_db, session: AsyncSession, client: AsyncClient, body ): user = await create_user(session=session, global_role=GlobalRole.USER) - with patch( - "dstack._internal.core.backends.azure.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.azure.auth.authenticate" - ) as authenticate_mock, patch( - "azure.mgmt.subscription.SubscriptionClient" - ) as SubscriptionClientMock, patch( - "dstack._internal.core.backends.azure.compute.get_resource_group_network_subnet_or_error" + with ( + patch( + "dstack._internal.core.backends.azure.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock, + patch("azure.mgmt.subscription.SubscriptionClient") as SubscriptionClientMock, + patch( + "dstack._internal.core.backends.azure.compute.get_resource_group_network_subnet_or_error" + ), ): default_creds_available_mock.return_value = False authenticate_mock.return_value = None, "test_tenant" @@ -427,11 +430,12 @@ async def test_returns_invalid_credentials( "data": "1234", }, } - with patch( - "dstack._internal.core.backends.gcp.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.gcp.auth.authenticate" - ) as authenticate_mock: + with ( + patch( + "dstack._internal.core.backends.gcp.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock, + ): default_creds_available_mock.return_value = False authenticate_mock.side_effect = BackendAuthError() response = await client.post( @@ -466,13 +470,13 @@ async def test_returns_config_on_valid_creds( }, "project_id": "test_project", } - with patch( - "dstack._internal.core.backends.gcp.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.gcp.auth.authenticate" - ) as authenticate_mock, patch( - "dstack._internal.core.backends.gcp.resources.check_vpc" - ) as check_vpc_mock: + with ( + patch( + "dstack._internal.core.backends.gcp.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock, + patch("dstack._internal.core.backends.gcp.resources.check_vpc") as check_vpc_mock, + ): default_creds_available_mock.return_value = False authenticate_mock.return_value = {}, "test_project" response = await client.post( @@ -737,11 +741,14 @@ async def test_returns_config_on_valid_creds( "type": "oci", "creds": FAKE_OCI_CLIENT_CREDS, } - with patch( - "dstack._internal.core.backends.oci.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" - ) as get_regions_mock: + with ( + patch( + "dstack._internal.core.backends.oci.auth.default_creds_available" + ) as default_creds_available_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" + ) as get_regions_mock, + ): default_creds_available_mock.return_value = True get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS response = await client.post( @@ -804,11 +811,13 @@ async def test_creates_aws_backend(self, test_db, session: AsyncSession, client: }, "regions": ["us-west-1"], } - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate"), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/create", @@ -837,13 +846,13 @@ async def test_creates_gcp_backend(self, test_db, session: AsyncSession, client: "project_id": "test_project", "regions": ["us-east1"], } - with patch( - "dstack._internal.core.backends.gcp.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.gcp.auth.authenticate" - ) as authenticate_mock, patch( - "dstack._internal.core.backends.gcp.resources.check_vpc" - ) as check_vpc_mock: + with ( + patch( + "dstack._internal.core.backends.gcp.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.gcp.auth.authenticate") as authenticate_mock, + patch("dstack._internal.core.backends.gcp.resources.check_vpc") as check_vpc_mock, + ): default_creds_available_mock.return_value = False credentials_mock = Mock() authenticate_mock.return_value = credentials_mock, "test_project" @@ -899,13 +908,17 @@ async def test_creates_oci_backend(self, test_db, session: AsyncSession, client: "type": "oci", "creds": FAKE_OCI_CLIENT_CREDS, } - with patch( - "dstack._internal.core.backends.oci.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" - ) as get_regions_mock, patch( - "dstack._internal.server.services.backends.configurators.oci._create_resources" - ) as create_resources_mock: + with ( + patch( + "dstack._internal.core.backends.oci.auth.default_creds_available" + ) as default_creds_available_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" + ) as get_regions_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci._create_resources" + ) as create_resources_mock, + ): default_creds_available_mock.return_value = False get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS create_resources_mock.return_value = SAMPLE_OCI_COMPARTMENT_ID, SAMPLE_OCI_SUBNETS @@ -933,11 +946,14 @@ async def test_not_creates_oci_backend_if_regions_not_subscribed( "creds": FAKE_OCI_CLIENT_CREDS, "regions": ["me-dubai-1", "eu-frankfurt-1", "us-ashburn-1"], } - with patch( - "dstack._internal.core.backends.oci.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" - ) as get_regions_mock: + with ( + patch( + "dstack._internal.core.backends.oci.auth.default_creds_available" + ) as default_creds_available_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" + ) as get_regions_mock, + ): default_creds_available_mock.return_value = False # us-ashburn-1 not subscribed get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS @@ -970,15 +986,12 @@ async def test_create_azure_backend(self, test_db, session: AsyncSession, client "subscription_id": "test_subscription", "locations": ["eastus"], } - with patch( - "dstack._internal.core.backends.azure.auth.authenticate" - ) as authenticate_mock, patch( - "azure.mgmt.subscription.SubscriptionClient" - ) as SubscriptionClientMock, patch( - "azure.mgmt.resource.ResourceManagementClient" - ) as ResourceManagementClientMock, patch( - "azure.mgmt.network.NetworkManagementClient" - ) as NetworkManagementClientMock: + with ( + patch("dstack._internal.core.backends.azure.auth.authenticate") as authenticate_mock, + patch("azure.mgmt.subscription.SubscriptionClient") as SubscriptionClientMock, + patch("azure.mgmt.resource.ResourceManagementClient") as ResourceManagementClientMock, + patch("azure.mgmt.network.NetworkManagementClient") as NetworkManagementClientMock, + ): authenticate_mock.return_value = None, "test_tenant" subscription_client_mock = SubscriptionClientMock.return_value tenant_mock = Mock() @@ -1026,11 +1039,13 @@ async def test_returns_400_if_backend_exists( }, "regions": ["us-west-1"], } - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate"), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/create", @@ -1040,11 +1055,12 @@ async def test_returns_400_if_backend_exists( assert response.status_code == 200, response.json() res = await session.execute(select(BackendModel)) assert len(res.scalars().all()) == 1 - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ) as authenticate_mock: # noqa: F841 + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate") as authenticate_mock, # noqa: F841 + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/create", @@ -1094,11 +1110,13 @@ async def test_updates_backend(self, test_db, session: AsyncSession, client: Asy }, "regions": ["us-east-1"], } - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate"), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/update", @@ -1252,11 +1270,13 @@ async def test_creates_aws_backend(self, test_db, session: AsyncSession, client: "regions": ["us-west-1"], } body = {"config_yaml": yaml.dump(config_dict)} - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate"), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/create_yaml", @@ -1280,13 +1300,17 @@ async def test_creates_oci_backend(self, test_db, session: AsyncSession, client: "creds": FAKE_OCI_CLIENT_CREDS, } body = {"config_yaml": yaml.dump(config_dict)} - with patch( - "dstack._internal.core.backends.oci.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" - ) as get_regions_mock, patch( - "dstack._internal.server.services.backends.configurators.oci._create_resources" - ) as create_resources_mock: + with ( + patch( + "dstack._internal.core.backends.oci.auth.default_creds_available" + ) as default_creds_available_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci.get_subscribed_regions" + ) as get_regions_mock, + patch( + "dstack._internal.server.services.backends.configurators.oci._create_resources" + ) as create_resources_mock, + ): default_creds_available_mock.return_value = False get_regions_mock.return_value = SAMPLE_OCI_SUBSCRIBED_REGIONS create_resources_mock.return_value = SAMPLE_OCI_COMPARTMENT_ID, SAMPLE_OCI_SUBNETS @@ -1342,11 +1366,13 @@ async def test_updates_aws_backend(self, test_db, session: AsyncSession, client: "regions": ["us-east-1"], } body = {"config_yaml": yaml.dump(config_dict)} - with patch( - "dstack._internal.core.backends.aws.auth.default_creds_available" - ) as default_creds_available_mock, patch( - "dstack._internal.core.backends.aws.auth.authenticate" - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch( + "dstack._internal.core.backends.aws.auth.default_creds_available" + ) as default_creds_available_mock, + patch("dstack._internal.core.backends.aws.auth.authenticate"), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): default_creds_available_mock.return_value = False response = await client.post( f"/api/project/{project.name}/backends/update_yaml", diff --git a/src/tests/_internal/server/routers/test_runs.py b/src/tests/_internal/server/routers/test_runs.py index f2ee68933..ea7040f91 100644 --- a/src/tests/_internal/server/routers/test_runs.py +++ b/src/tests/_internal/server/routers/test_runs.py @@ -764,11 +764,13 @@ async def test_submits_run( if privileged is None: del run_spec["configuration"]["privileged"] body = {"run_spec": run_spec} - with patch("uuid.uuid4") as uuid_mock, patch( - "dstack._internal.utils.common.get_current_datetime" - ) as datetime_mock, patch( - "dstack._internal.server.services.backends.get_project_backends" - ) as get_project_backends_mock: + with ( + patch("uuid.uuid4") as uuid_mock, + patch("dstack._internal.utils.common.get_current_datetime") as datetime_mock, + patch( + "dstack._internal.server.services.backends.get_project_backends" + ) as get_project_backends_mock, + ): get_project_backends_mock.return_value = [Mock()] uuid_mock.return_value = run_id datetime_mock.return_value = submitted_at @@ -804,9 +806,12 @@ async def test_submits_run_without_run_name( repo_id=repo.name, ) body = {"run_spec": run_dict["run_spec"]} - with patch("uuid.uuid4") as uuid_mock, patch( - "dstack._internal.server.services.backends.get_project_backends" - ) as get_project_backends_mock: + with ( + patch("uuid.uuid4") as uuid_mock, + patch( + "dstack._internal.server.services.backends.get_project_backends" + ) as get_project_backends_mock, + ): get_project_backends_mock.return_value = [Mock()] uuid_mock.return_value = run_dict["id"] response = await client.post( @@ -849,9 +854,12 @@ async def test_returns_400_if_bad_run_name( repo_id=repo.name, ) body = {"run_spec": run_dict["run_spec"]} - with patch("uuid.uuid4") as uuid_mock, patch( - "dstack._internal.server.services.backends.get_project_backends" - ) as get_project_backends_mock: + with ( + patch("uuid.uuid4") as uuid_mock, + patch( + "dstack._internal.server.services.backends.get_project_backends" + ) as get_project_backends_mock, + ): get_project_backends_mock.return_value = [Mock()] uuid_mock.return_value = run_dict["id"] response = await client.post( @@ -1128,9 +1136,12 @@ async def test_creates_instance(self, test_db, session: AsyncSession, client: As requirements=Requirements(resources=ResourcesSpec(cpu=1)), ) instance_id = UUID("1b0e1b45-2f8c-4ab6-8010-a0d1a3e44e0e") - with patch( - "dstack._internal.server.services.offers.get_offers_by_requirements" - ) as run_plan_by_req, patch("uuid.uuid4") as uuid_mock: + with ( + patch( + "dstack._internal.server.services.offers.get_offers_by_requirements" + ) as run_plan_by_req, + patch("uuid.uuid4") as uuid_mock, + ): uuid_mock.return_value = instance_id offer = InstanceOfferWithAvailability( backend=BackendType.AWS, diff --git a/src/tests/_internal/server/services/test_config.py b/src/tests/_internal/server/services/test_config.py index 7dfd53481..0705ad251 100644 --- a/src/tests/_internal/server/services/test_config.py +++ b/src/tests/_internal/server/services/test_config.py @@ -25,13 +25,18 @@ class TestInitConfig: async def test_inits_backend(self, test_db, session: AsyncSession, tmp_path: Path): await create_project(session=session, name="main") config_filepath = tmp_path / "config.yml" - with patch.object(settings, "SERVER_CONFIG_FILE_PATH", config_filepath), patch( - "dstack._internal.server.services.backends.list_available_backend_types" - ) as list_available_backend_types_mock, patch( - "dstack._internal.server.services.backends.get_configurator" - ) as get_configurator_mock, patch( - "dstack._internal.server.services.backends.create_backend" - ) as create_backend_mock: + with ( + patch.object(settings, "SERVER_CONFIG_FILE_PATH", config_filepath), + patch( + "dstack._internal.server.services.backends.list_available_backend_types" + ) as list_available_backend_types_mock, + patch( + "dstack._internal.server.services.backends.get_configurator" + ) as get_configurator_mock, + patch( + "dstack._internal.server.services.backends.create_backend" + ) as create_backend_mock, + ): list_available_backend_types_mock.return_value = [BackendType.AZURE] default_config = AzureConfigInfoWithCreds( tenant_id="test_tenant", @@ -95,9 +100,11 @@ async def test_creates_backend(self, test_db, session: AsyncSession, tmp_path: P } with open(config_filepath, "w+") as f: yaml.dump(config, f) - with patch("boto3.session.Session"), patch.object( - settings, "SERVER_CONFIG_FILE_PATH", config_filepath - ), patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"): + with ( + patch("boto3.session.Session"), + patch.object(settings, "SERVER_CONFIG_FILE_PATH", config_filepath), + patch("dstack._internal.core.backends.aws.compute.get_vpc_id_subnet_id_or_error"), + ): manager = ServerConfigManager() manager.load_config() await manager.apply_config(session, owner)