From acb08e263d9d13cdd6b86059e6c79782ab3e6372 Mon Sep 17 00:00:00 2001 From: sophia Date: Mon, 9 Dec 2024 10:07:20 -0800 Subject: [PATCH 1/6] Fix pydantic deprecation warnings --- .../_internal/environment.py | 2 +- .../plugins/lock/conda_lock/conda_lock.py | 2 +- .../conda_store_server/_internal/schema.py | 8 +- .../_internal/server/views/api.py | 6 +- .../_internal/worker/build.py | 12 +- conda-store-server/conda_store_server/app.py | 6 +- .../conda_store_server/server/auth.py | 2 +- .../tests/_internal/action/test_actions.py | 2 +- .../tests/_internal/server/views/test_api.py | 140 +++++++++--------- .../tests/_internal/test_schema.py | 2 +- conda-store-server/tests/conftest.py | 4 +- tests/test_api.py | 140 +++++++++--------- 12 files changed, 163 insertions(+), 163 deletions(-) diff --git a/conda-store-server/conda_store_server/_internal/environment.py b/conda-store-server/conda_store_server/_internal/environment.py index 0b2df2b55..9c7cc1da3 100644 --- a/conda-store-server/conda_store_server/_internal/environment.py +++ b/conda-store-server/conda_store_server/_internal/environment.py @@ -14,7 +14,7 @@ def validate_environment(specification): try: - specification = schema.CondaSpecification.parse_obj(specification) + specification = schema.CondaSpecification.model_validate(specification) return True except pydantic.ValidationError: return False diff --git a/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py b/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py index 85399d4f6..2e78eb32d 100644 --- a/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py +++ b/conda-store-server/conda_store_server/_internal/plugins/lock/conda_lock/conda_lock.py @@ -40,7 +40,7 @@ def lock_environment( lockfile_filename = pathlib.Path.cwd() / "conda-lock.yaml" with environment_filename.open("w") as f: - json.dump(spec.dict(), f) + json.dump(spec.model_dump(), f) context.log.info( "Note that the output of `conda config --show` displayed below only reflects " diff --git a/conda-store-server/conda_store_server/_internal/schema.py b/conda-store-server/conda_store_server/_internal/schema.py index ed04523bf..3a638619d 100644 --- a/conda-store-server/conda_store_server/_internal/schema.py +++ b/conda-store-server/conda_store_server/_internal/schema.py @@ -372,9 +372,9 @@ class CondaSpecification(BaseModel): variables: Optional[Dict[str, Union[str, int]]] = None @classmethod - def parse_obj(cls, specification): + def model_validate(cls, specification): try: - return super().parse_obj(specification) + return super().model_validate(specification) except ValidationError as e: # there can be multiple errors. Let's build a comprehensive summary # to return to the end user. @@ -414,7 +414,7 @@ class LockfileSpecification(BaseModel): lockfile: Lockfile @classmethod - def parse_obj(cls, specification): + def model_validate(cls, specification): # To show a human-readable error if no data is provided specification = {} if specification is None else specification # This uses pop because the version field must not be part of Lockfile @@ -429,7 +429,7 @@ def parse_obj(cls, specification): "Expected lockfile to have no version field, or version=1", ) - return super().parse_obj(specification) + return super().model_validate(specification) def model_dump(self): res = super().model_dump() diff --git a/conda-store-server/conda_store_server/_internal/server/views/api.py b/conda-store-server/conda_store_server/_internal/server/views/api.py index fe95c9a39..a3116d480 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/api.py +++ b/conda-store-server/conda_store_server/_internal/server/views/api.py @@ -682,7 +682,7 @@ async def api_list_environments( if jwt: # Fetch the environments visible to the supplied token role_bindings = auth.entity_bindings( - AuthenticationToken.parse_obj(auth.authentication.decrypt_token(jwt)) + AuthenticationToken.model_validate(auth.authentication.decrypt_token(jwt)) ) else: role_bindings = None @@ -887,9 +887,9 @@ async def api_post_specification( "description": environment_description, "lockfile": specification, } - specification = schema.LockfileSpecification.parse_obj(lockfile_spec) + specification = schema.LockfileSpecification.model_validate(lockfile_spec) else: - specification = schema.CondaSpecification.parse_obj(specification) + specification = schema.CondaSpecification.model_validate(specification) except yaml.error.YAMLError: raise HTTPException(status_code=400, detail="Unable to parse. Invalid YAML") except utils.CondaStoreError as e: diff --git a/conda-store-server/conda_store_server/_internal/worker/build.py b/conda-store-server/conda_store_server/_internal/worker/build.py index 42a51575e..c9f649521 100644 --- a/conda-store-server/conda_store_server/_internal/worker/build.py +++ b/conda-store-server/conda_store_server/_internal/worker/build.py @@ -213,7 +213,7 @@ def build_conda_environment(db: Session, conda_store, build): with utils.timer(conda_store.log, f"building conda_prefix={conda_prefix}"): if is_lockfile: context = action.action_save_lockfile( - specification=schema.LockfileSpecification.parse_obj( + specification=schema.LockfileSpecification.model_validate( build.specification.spec ), stdout=LoggedStream( @@ -227,7 +227,7 @@ def build_conda_environment(db: Session, conda_store, build): else: lock_backend, locker = conda_store.lock_plugin() conda_lock_spec = locker.lock_environment( - spec=schema.CondaSpecification.parse_obj(build.specification.spec), + spec=schema.CondaSpecification.model_validate(build.specification.spec), platforms=settings.conda_solve_platforms, context=plugin_context.PluginContext( conda_store=conda_store, @@ -341,7 +341,7 @@ def solve_conda_environment(db: Session, conda_store, solve: orm.Solve): _, locker = conda_store.lock_plugin() conda_lock_spec = locker.lock_environment( context=plugin_context.PluginContext(conda_store=conda_store), - spec=schema.CondaSpecification.parse_obj(solve.specification.spec), + spec=schema.CondaSpecification.model_validate(solve.specification.spec), platforms=[conda_utils.conda_platform()], ) @@ -440,7 +440,7 @@ def build_constructor_installer(db: Session, conda_store, build: orm.Build): is_lockfile = build.specification.is_lockfile if is_lockfile: - specification = schema.LockfileSpecification.parse_obj( + specification = schema.LockfileSpecification.model_validate( build.specification.spec ) else: @@ -449,7 +449,7 @@ def build_constructor_installer(db: Session, conda_store, build: orm.Build): # pinned dependencies. This code is wrapped into try/except # because the lockfile lookup might fail if the file is not # in external storage or on disk, or if parsing fails - specification = schema.LockfileSpecification.parse_obj( + specification = schema.LockfileSpecification.model_validate( { "name": build.specification.name, "lockfile": json.loads( @@ -463,7 +463,7 @@ def build_constructor_installer(db: Session, conda_store, build: orm.Build): "Exception while obtaining lockfile, using specification", exc_info=e, ) - specification = schema.CondaSpecification.parse_obj( + specification = schema.CondaSpecification.model_validate( build.specification.spec ) diff --git a/conda-store-server/conda_store_server/app.py b/conda-store-server/conda_store_server/app.py index c3dd307d2..983859b23 100644 --- a/conda-store-server/conda_store_server/app.py +++ b/conda-store-server/conda_store_server/app.py @@ -130,7 +130,7 @@ def _check_build_key_version(self, proposal): conda_solve_platforms = List( [conda_utils.conda_platform()], - description="Conda platforms to solve environments for via conda-lock. Must include current platform.", + help="Conda platforms to solve environments for via conda-lock. Must include current platform.", config=True, ) @@ -651,7 +651,7 @@ def register_environment( db=db, conda_store=self, namespace=namespace.name, - specification=schema.CondaSpecification.parse_obj(specification), + specification=schema.CondaSpecification.model_validate(specification), ) spec_sha256 = utils.datastructure_hash(specification_model.model_dump()) @@ -817,7 +817,7 @@ def delete_namespace(self, db: Session, namespace: str): if namespace is None: raise utils.CondaStoreError(f"namespace={namespace} does not exist") - utcnow = datetime.datetime.utcnow() + utcnow = datetime.datetime.now(datetime.UTC) namespace.deleted_on = utcnow for environment_orm in namespace.environments: environment_orm.deleted_on = utcnow diff --git a/conda-store-server/conda_store_server/server/auth.py b/conda-store-server/conda_store_server/server/auth.py index 80b5ba27f..a6ae44909 100644 --- a/conda-store-server/conda_store_server/server/auth.py +++ b/conda-store-server/conda_store_server/server/auth.py @@ -68,7 +68,7 @@ def authenticate(self, token): authentication_token = self.predefined_tokens[token] else: authentication_token = self.decrypt_token(token) - return schema.AuthenticationToken.parse_obj(authentication_token) + return schema.AuthenticationToken.model_validate(authentication_token) except Exception: return None diff --git a/conda-store-server/tests/_internal/action/test_actions.py b/conda-store-server/tests/_internal/action/test_actions.py index 76b958e94..9ae4ea484 100644 --- a/conda-store-server/tests/_internal/action/test_actions.py +++ b/conda-store-server/tests/_internal/action/test_actions.py @@ -189,7 +189,7 @@ def test_generate_conda_export(conda_store, conda_prefix): # an environment is in an envs dir. See the discussion on PR #549. context.result["name"] = "test-prefix" - schema.CondaSpecification.parse_obj(context.result) + schema.CondaSpecification.model_validate(context.result) @pytest.mark.long_running_test diff --git a/conda-store-server/tests/_internal/server/views/test_api.py b/conda-store-server/tests/_internal/server/views/test_api.py index 73695aec3..dd46ad6a5 100644 --- a/conda-store-server/tests/_internal/server/views/test_api.py +++ b/conda-store-server/tests/_internal/server/views/test_api.py @@ -47,7 +47,7 @@ def test_api_version_unauth(testclient): response = testclient.get("/api/v1/") response.raise_for_status() - r = schema.APIGetStatus.parse_obj(response.json()) + r = schema.APIGetStatus.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.version == __version__ @@ -56,7 +56,7 @@ def test_api_permissions_unauth(testclient): response = testclient.get("api/v1/permission/") response.raise_for_status() - r = schema.APIGetPermission.parse_obj(response.json()) + r = schema.APIGetPermission.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.authenticated is False assert r.data.primary_namespace == "default" @@ -75,7 +75,7 @@ def test_api_permissions_auth(testclient, authenticate): response = testclient.get("api/v1/permission/") response.raise_for_status() - r = schema.APIGetPermission.parse_obj(response.json()) + r = schema.APIGetPermission.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.authenticated is True assert r.data.primary_namespace == "username" @@ -122,7 +122,7 @@ def test_get_usage_unauth(testclient): response = testclient.get("/api/v1/usage/") response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -130,7 +130,7 @@ def test_get_usage_auth(testclient, authenticate): response = testclient.get("/api/v1/usage/") response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -138,7 +138,7 @@ def test_api_list_namespace_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/namespace") response.raise_for_status() - r = schema.APIListNamespace.parse_obj(response.json()) + r = schema.APIListNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK # by default unauth only has access to the default namespace assert len(r.data) == 1 @@ -149,7 +149,7 @@ def test_api_list_namespace_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/namespace") response.raise_for_status() - r = schema.APIListNamespace.parse_obj(response.json()) + r = schema.APIListNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert sorted([_.name for _ in r.data]) == ["default", "namespace1", "namespace2"] @@ -158,7 +158,7 @@ def test_api_get_namespace_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/namespace/default") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == "default" @@ -167,7 +167,7 @@ def test_api_get_namespace_unauth_no_exist(testclient, seed_conda_store): response = testclient.get("api/v1/namespace/namespace1") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -175,7 +175,7 @@ def test_api_get_namespace_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/namespace/namespace1") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == "namespace1" @@ -184,7 +184,7 @@ def test_api_get_namespace_auth_no_exist(testclient, seed_conda_store, authentic response = testclient.get("api/v1/namespace/wrong") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -192,7 +192,7 @@ def test_api_list_environments_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/environment") response.raise_for_status() - r = schema.APIListEnvironment.parse_obj(response.json()) + r = schema.APIListEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert sorted([_.name for _ in r.data]) == ["name1", "name2"] @@ -201,7 +201,7 @@ def test_api_list_environments_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/environment") response.raise_for_status() - r = schema.APIListEnvironment.parse_obj(response.json()) + r = schema.APIListEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert sorted([_.name for _ in r.data]) == ["name1", "name2", "name3", "name4"] @@ -295,7 +295,7 @@ def test_api_list_environments_jwt( response.raise_for_status() - r = schema.APIListEnvironment.parse_obj(response.json()) + r = schema.APIListEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK # The environments returned by `/environment/` should only be the ones @@ -309,7 +309,7 @@ def test_api_get_environment_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/environment/namespace1/name3") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -317,7 +317,7 @@ def test_api_get_environment_auth_existing(testclient, seed_conda_store, authent response = testclient.get("api/v1/environment/namespace1/name3") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.namespace.name == "namespace1" assert r.data.name == "name3" @@ -329,7 +329,7 @@ def test_api_get_environment_auth_not_existing( response = testclient.get("api/v1/environment/namespace1/wrong") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -337,7 +337,7 @@ def test_api_list_builds_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/build") response.raise_for_status() - r = schema.APIListBuild.parse_obj(response.json()) + r = schema.APIListBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) == 2 @@ -346,7 +346,7 @@ def test_api_list_builds_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/build") response.raise_for_status() - r = schema.APIListBuild.parse_obj(response.json()) + r = schema.APIListBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) == 4 @@ -355,7 +355,7 @@ def test_api_get_build_one_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/build/3") # namespace1/name3 assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -363,7 +363,7 @@ def test_api_get_build_one_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/build/3") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.id == 3 assert r.data.specification.name == "name3" @@ -374,7 +374,7 @@ def test_api_get_build_one_unauth_packages(testclient, seed_conda_store): response = testclient.get("api/v1/build/3/packages") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -382,7 +382,7 @@ def test_api_get_build_one_auth_packages(testclient, seed_conda_store, authentic response = testclient.get("api/v1/build/3/packages") response.raise_for_status() - r = schema.APIListCondaPackage.parse_obj(response.json()) + r = schema.APIListCondaPackage.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) == 1 @@ -393,7 +393,7 @@ def test_api_get_build_auth_packages_no_exist( response = testclient.get("api/v1/build/101010101/packages") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -401,7 +401,7 @@ def test_api_get_build_one_unauth_logs(testclient, seed_conda_store): response = testclient.get("api/v1/build/3/logs") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -435,7 +435,7 @@ def test_api_get_build_two_auth(testclient, seed_conda_store, authenticate): response = testclient.get("api/v1/build/1010101010101") response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -443,7 +443,7 @@ def test_api_list_conda_channels_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/channel") response.raise_for_status() - r = schema.APIListCondaChannel.parse_obj(response.json()) + r = schema.APIListCondaChannel.model_validate(response.json()) assert r.status == schema.APIStatus.OK api_channels = set(_.name for _ in r.data) assert api_channels == { @@ -455,7 +455,7 @@ def test_api_list_conda_packages_unauth(testclient, seed_conda_store): response = testclient.get("api/v1/package") response.raise_for_status() - r = schema.APIListCondaPackage.parse_obj(response.json()) + r = schema.APIListCondaPackage.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) == 4 @@ -476,7 +476,7 @@ def test_create_specification_unauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -508,7 +508,7 @@ def test_create_specification_auth_env_name_too_long( ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK build_id = r.data.build_id @@ -521,7 +521,7 @@ def test_create_specification_auth_env_name_too_long( response = testclient.get(f"api/v1/build/{build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name if r.data.status == "QUEUED": @@ -580,7 +580,7 @@ def test_create_specification_auth_extended_prefix( ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK build_id = r.data.build_id @@ -593,7 +593,7 @@ def test_create_specification_auth_extended_prefix( response = testclient.get(f"api/v1/build/{build_id}", timeout=30) response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name if r.data.status in ("QUEUED", "BUILDING"): @@ -630,14 +630,14 @@ def test_create_specification_auth(testclient, celery_worker, authenticate): ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK # check for the given build response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name @@ -645,7 +645,7 @@ def test_create_specification_auth(testclient, celery_worker, authenticate): response = testclient.get(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.data.namespace.name == namespace @@ -661,14 +661,14 @@ def test_create_specification_auth_no_namespace_specified( ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK # check for the given build response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name @@ -676,7 +676,7 @@ def test_create_specification_auth_no_namespace_specified( response = testclient.get(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.data.namespace.name == namespace @@ -686,7 +686,7 @@ def test_put_build_trigger_build_noauth(testclient, seed_conda_store): response = testclient.put(f"api/v1/build/{build_id}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -696,13 +696,13 @@ def test_put_build_trigger_build_auth( build_id = 1 response = testclient.put(f"api/v1/build/{build_id}") - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -712,7 +712,7 @@ def test_create_namespace_noauth(testclient): response = testclient.post(f"api/v1/namespace/{namespace}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -722,13 +722,13 @@ def test_create_namespace_auth(testclient, authenticate): response = testclient.post(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == namespace @@ -739,26 +739,26 @@ def test_create_get_delete_namespace_auth(testclient, celery_worker, authenticat response = testclient.post(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == namespace response = testclient.delete(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -772,7 +772,7 @@ def test_update_environment_build_unauth(testclient, seed_conda_store): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -788,13 +788,13 @@ def test_update_environment_build_auth( ) response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/environment/{namespace}/{name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.current_build_id == 4 @@ -806,7 +806,7 @@ def test_delete_environment_unauth(testclient, seed_conda_store): response = testclient.delete(f"api/v1/environment/{namespace}/{name}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -825,13 +825,13 @@ def test_delete_environment_auth( ) response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.delete(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -841,7 +841,7 @@ def test_delete_build_unauth(testclient, seed_conda_store): response = testclient.delete(f"api/v1/build/{build_id}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -849,7 +849,7 @@ def test_delete_build_auth(testclient, seed_conda_store, authenticate, celery_wo build_id = 4 response = testclient.put(f"api/v1/build/{build_id}") - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK new_build_id = r.data.build_id @@ -857,7 +857,7 @@ def test_delete_build_auth(testclient, seed_conda_store, authenticate, celery_wo response = testclient.get(f"api/v1/build/{new_build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK # currently you cannot delete a build before it succeeds or fails @@ -865,13 +865,13 @@ def test_delete_build_auth(testclient, seed_conda_store, authenticate, celery_wo response = testclient.delete(f"api/v1/build/{new_build_id}") assert response.status_code == 400 - # r = schema.APIAckResponse.parse_obj(response.json()) + # r = schema.APIAckResponse.model_validate(response.json()) # assert r.status == schema.APIStatus.OK # response = testclient.get(f'api/v1/build/{new_build_id}') # assert response.status_code == 404 - # r = schema.APIResponse.parse_obj(response.json()) + # r = schema.APIResponse.model_validate(response.json()) # assert r.status == schema.APIStatus.ERROR @@ -887,7 +887,7 @@ def test_get_settings_unauth(testclient, route): response = testclient.get(route) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -903,7 +903,7 @@ def test_put_settings_unauth(testclient, route): response = testclient.put(route, json={"conda_included_packages": ["numpy"]}) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -919,7 +919,7 @@ def test_get_settings_auth(testclient, authenticate, route): response = testclient.get(route) assert response.status_code == 200 - r = schema.APIGetSetting.parse_obj(response.json()) + r = schema.APIGetSetting.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert { "default_namespace", @@ -961,12 +961,12 @@ def test_put_global_settings_auth(testclient, authenticate, route): ) response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(route) response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.data["conda_max_solve_time"] == 60 * 60 @@ -984,12 +984,12 @@ def test_put_environment_settings_auth(testclient, authenticate, route): ) response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(route) response.raise_for_status() - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.data["conda_included_packages"] == ["numpy", "ipykernel"] @@ -1005,7 +1005,7 @@ def test_put_environment_settings_auth_invliad_type(testclient, authenticate, ro response = testclient.put(route, json={"conda_included_packages": 1}) assert response.status_code == 400 - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR assert "Invalid parsing" in r.message @@ -1029,7 +1029,7 @@ def test_put_settings_auth_invalid_keys(testclient, authenticate, route): ) assert response.status_code == 400 - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR assert "Invalid setting keys" in r.message @@ -1055,7 +1055,7 @@ def test_put_global_settings_auth_in_namespace_environment( ) assert response.status_code == 400 - r = schema.APIPutSetting.parse_obj(response.json()) + r = schema.APIPutSetting.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR assert "global setting" in r.message diff --git a/conda-store-server/tests/_internal/test_schema.py b/conda-store-server/tests/_internal/test_schema.py index 8bf70a816..92067d3aa 100644 --- a/conda-store-server/tests/_internal/test_schema.py +++ b/conda-store-server/tests/_internal/test_schema.py @@ -60,5 +60,5 @@ def test_parse_lockfile_obj(test_lockfile): # against the original dict "lockfile": test_lockfile.copy(), } - specification = schema.LockfileSpecification.parse_obj(lockfile_spec) + specification = schema.LockfileSpecification.model_validate(lockfile_spec) assert specification.model_dump()["lockfile"] == test_lockfile diff --git a/conda-store-server/tests/conftest.py b/conda-store-server/tests/conftest.py index 75bbded91..f1cebe23b 100644 --- a/conda-store-server/tests/conftest.py +++ b/conda-store-server/tests/conftest.py @@ -235,7 +235,7 @@ def simple_conda_lock_with_pip(): @pytest.fixture def simple_lockfile_specification(simple_conda_lock): - return schema.LockfileSpecification.parse_obj( + return schema.LockfileSpecification.model_validate( { "name": "test", "description": "simple lockfile specification", @@ -246,7 +246,7 @@ def simple_lockfile_specification(simple_conda_lock): @pytest.fixture def simple_lockfile_specification_with_pip(simple_conda_lock_with_pip): - return schema.LockfileSpecification.parse_obj( + return schema.LockfileSpecification.model_validate( { "name": "test", "description": "simple lockfile specification with pip", diff --git a/tests/test_api.py b/tests/test_api.py index 3e8554702..5c19f4649 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -75,7 +75,7 @@ def test_api_status_unauth(testclient): response = testclient.get("api/v1/") response.raise_for_status() - r = schema.APIGetStatus.parse_obj(response.json()) + r = schema.APIGetStatus.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.version == conda_store_server.__version__ @@ -84,7 +84,7 @@ def test_api_permissions_unauth(testclient): response = testclient.get("api/v1/permission/") response.raise_for_status() - r = schema.APIGetPermission.parse_obj(response.json()) + r = schema.APIGetPermission.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.authenticated is False assert r.data.primary_namespace == "default" @@ -104,7 +104,7 @@ def test_api_permissions_auth(testclient): response = testclient.get("api/v1/permission/") response.raise_for_status() - r = schema.APIGetPermission.parse_obj(response.json()) + r = schema.APIGetPermission.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.authenticated is True assert r.data.primary_namespace == "username" @@ -151,7 +151,7 @@ def test_api_list_namespace_unauth(testclient): response = testclient.get("api/v1/namespace") response.raise_for_status() - r = schema.APIListNamespace.parse_obj(response.json()) + r = schema.APIListNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK # by default unauth only has access to the default namespace assert len(r.data) == 1 @@ -162,7 +162,7 @@ def test_api_list_namespace_auth(testclient): response = testclient.get("api/v1/namespace") response.raise_for_status() - r = schema.APIListNamespace.parse_obj(response.json()) + r = schema.APIListNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK # by default auth has at least two environments created # `default` and `filesystem` @@ -173,7 +173,7 @@ def test_api_get_namespace_unauth(testclient): response = testclient.get("api/v1/namespace/default") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == "default" @@ -182,7 +182,7 @@ def test_api_get_namespace_unauth_no_exist(testclient): response = testclient.get("api/v1/namespace/wrong") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -191,7 +191,7 @@ def test_api_get_namespace_auth(testclient): response = testclient.get("api/v1/namespace/filesystem") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == "filesystem" @@ -201,7 +201,7 @@ def test_api_get_namespace_auth_no_exist(testclient): response = testclient.get("api/v1/namespace/wrong") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -209,7 +209,7 @@ def test_api_list_environments_unauth(testclient): response = testclient.get("api/v1/environment") response.raise_for_status() - r = schema.APIListEnvironment.parse_obj(response.json()) + r = schema.APIListEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -218,7 +218,7 @@ def test_api_list_environments_auth(testclient): response = testclient.get("api/v1/environment") response.raise_for_status() - r = schema.APIListEnvironment.parse_obj(response.json()) + r = schema.APIListEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) >= 1 @@ -227,7 +227,7 @@ def test_api_get_environment_unauth(testclient): response = testclient.get("api/v1/environment/filesystem/python-flask-env") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -236,7 +236,7 @@ def test_api_get_environment_auth_existing(testclient): response = testclient.get("api/v1/environment/filesystem/python-flask-env") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.namespace.name == "filesystem" assert r.data.name == "python-flask-env" @@ -247,7 +247,7 @@ def test_api_get_environment_auth_not_existing(testclient): response = testclient.get("api/v1/environment/filesystem/wrong") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -255,7 +255,7 @@ def test_api_list_builds_unauth(testclient): response = testclient.get("api/v1/build") response.raise_for_status() - r = schema.APIListBuild.parse_obj(response.json()) + r = schema.APIListBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -264,7 +264,7 @@ def test_api_list_builds_auth(testclient): response = testclient.get("api/v1/build") response.raise_for_status() - r = schema.APIListBuild.parse_obj(response.json()) + r = schema.APIListBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) >= 1 @@ -273,7 +273,7 @@ def test_api_get_build_one_unauth(testclient): response = testclient.get("api/v1/build/1") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -284,7 +284,7 @@ def test_api_get_build_one_auth(testclient): response = testclient.get("api/v1/build/1") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.id == 1 assert r.data.specification.name == "python-flask-env" @@ -304,7 +304,7 @@ def test_api_get_build_one_unauth_packages(testclient): response = testclient.get("api/v1/build/1/packages") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -315,7 +315,7 @@ def test_api_get_build_one_auth_packages(testclient): response = testclient.get("api/v1/build/1/packages?size=5") response.raise_for_status() - r = schema.APIListCondaPackage.parse_obj(response.json()) + r = schema.APIListCondaPackage.model_validate(response.json()) assert r.status == schema.APIStatus.OK if len(r.data) == 0: time.sleep(10) @@ -331,7 +331,7 @@ def test_api_get_build_auth_packages_no_exist(testclient): response = testclient.get("api/v1/build/101010101/packages") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -339,7 +339,7 @@ def test_api_get_build_one_unauth_logs(testclient): response = testclient.get("api/v1/build/1/logs") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -417,7 +417,7 @@ def test_api_get_build_two_auth(testclient): response = testclient.get("api/v1/build/1010101010101") response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -425,7 +425,7 @@ def test_api_list_conda_channels_unauth(testclient): response = testclient.get("api/v1/channel") response.raise_for_status() - r = schema.APIListCondaChannel.parse_obj(response.json()) + r = schema.APIListCondaChannel.model_validate(response.json()) assert r.status == schema.APIStatus.OK api_channels = set(_.name for _ in r.data) assert api_channels == { @@ -439,7 +439,7 @@ def test_api_list_conda_packages_unauth(testclient): response = testclient.get("api/v1/package?size=15") response.raise_for_status() - r = schema.APIListCondaPackage.parse_obj(response.json()) + r = schema.APIListCondaPackage.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert len(r.data) == 15 @@ -460,7 +460,7 @@ def test_create_specification_uauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -478,14 +478,14 @@ def test_create_specification_auth(testclient): ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK # check for the given build response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name @@ -493,7 +493,7 @@ def test_create_specification_auth(testclient): response = testclient.get(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.data.namespace.name == namespace @@ -536,7 +536,7 @@ def test_create_specification_parallel_auth(testclient): timeout=10, ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK build_ids.append(r.data.build_id) @@ -579,7 +579,7 @@ def test_create_specification_parallel_auth(testclient): # Checks the status response = testclient.get(f"api/v1/build/{build_id}", timeout=10) response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name @@ -701,7 +701,7 @@ def test_create_specification_auth_env_name_too_long(testclient, size): return # error, nothing to do response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK build_id = r.data.build_id @@ -714,7 +714,7 @@ def test_create_specification_auth_env_name_too_long(testclient, size): response = testclient.get(f"api/v1/build/{build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name if r.data.status == "QUEUED": @@ -740,14 +740,14 @@ def test_create_specification_auth_no_namespace_specified(testclient): ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK # check for the given build response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.specification.name == environment_name @@ -755,7 +755,7 @@ def test_create_specification_auth_no_namespace_specified(testclient): response = testclient.get(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.data.namespace.name == namespace @@ -765,7 +765,7 @@ def test_put_build_trigger_build_noauth(testclient): response = testclient.put(f"api/v1/build/{build_id}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -774,13 +774,13 @@ def test_put_build_trigger_build_auth(testclient): testclient.login() response = testclient.put(f"api/v1/build/{build_id}") - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/build/{r.data.build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -790,7 +790,7 @@ def test_create_namespace_noauth(testclient): response = testclient.post(f"api/v1/namespace/{namespace}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -801,13 +801,13 @@ def test_create_namespace_auth(testclient): response = testclient.post(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == namespace @@ -831,7 +831,7 @@ def test_update_namespace_noauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR # Updates the role mappings only @@ -840,7 +840,7 @@ def test_update_namespace_noauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR # Updates both the metadata and the role mappings @@ -853,7 +853,7 @@ def test_update_namespace_noauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -884,7 +884,7 @@ def test_update_namespace_auth(testclient, editor_role): }, ) - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK # Updates the metadata only @@ -896,7 +896,7 @@ def test_update_namespace_auth(testclient, editor_role): ) response.raise_for_status() - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK # Updates the role mappings only @@ -904,7 +904,7 @@ def test_update_namespace_auth(testclient, editor_role): f"api/v1/namespace/{namespace}", json={"role_mappings": test_role_mappings} ) - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -915,26 +915,26 @@ def test_create_get_delete_namespace_auth(testclient): response = testclient.post(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIGetNamespace.parse_obj(response.json()) + r = schema.APIGetNamespace.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.name == namespace response = testclient.delete(f"api/v1/namespace/{namespace}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/namespace/{namespace}") assert response.status_code == 404 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -956,7 +956,7 @@ def _crud_common( else: assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) if auth: assert r.status == schema.APIStatus.OK if data_pred is None: @@ -1074,7 +1074,7 @@ def test_update_environment_build_unauth(testclient): ) assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -1089,13 +1089,13 @@ def test_update_environment_build_auth(testclient): ) response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.get(f"api/v1/environment/{namespace}/{name}") response.raise_for_status() - r = schema.APIGetEnvironment.parse_obj(response.json()) + r = schema.APIGetEnvironment.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.current_build_id == 1 @@ -1107,7 +1107,7 @@ def test_delete_environment_unauth(testclient): response = testclient.delete(f"api/v1/environment/{namespace}/{name}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -1125,13 +1125,13 @@ def test_delete_environment_auth(testclient): ) response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK response = testclient.delete(f"api/v1/environment/{namespace}/{environment_name}") response.raise_for_status() - r = schema.APIAckResponse.parse_obj(response.json()) + r = schema.APIAckResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK @@ -1141,7 +1141,7 @@ def test_delete_build_unauth(testclient): response = testclient.delete(f"api/v1/build/{build_id}") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -1150,7 +1150,7 @@ def test_delete_build_auth(testclient): testclient.login() response = testclient.put(f"api/v1/build/{build_id}") - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK new_build_id = r.data.build_id @@ -1158,7 +1158,7 @@ def test_delete_build_auth(testclient): response = testclient.get(f"api/v1/build/{new_build_id}") response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK # currently you cannot delete a build before it succeeds or fails @@ -1166,13 +1166,13 @@ def test_delete_build_auth(testclient): response = testclient.delete(f"api/v1/build/{new_build_id}") assert response.status_code == 400 - # r = schema.APIAckResponse.parse_obj(response.json()) + # r = schema.APIAckResponse.model_validate(response.json()) # assert r.status == schema.APIStatus.OK # response = testclient.get(f'api/v1/build/{new_build_id}') # assert response.status_code == 404 - # r = schema.APIResponse.parse_obj(response.json()) + # r = schema.APIResponse.model_validate(response.json()) # assert r.status == schema.APIStatus.ERROR @@ -1182,7 +1182,7 @@ def test_api_cancel_build_unauth(testclient): response = testclient.put(f"api/v1/build/{build_id}/cancel") assert response.status_code == 403 - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.ERROR @@ -1191,7 +1191,7 @@ def test_api_cancel_build_auth(testclient): testclient.login() response = testclient.put(f"api/v1/build/{build_id}") - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK new_build_id = r.data.build_id @@ -1208,7 +1208,7 @@ def test_api_cancel_build_auth(testclient): continue response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK if r.data.status == schema.BuildStatus.BUILDING.value: building = True @@ -1221,7 +1221,7 @@ def test_api_cancel_build_auth(testclient): response = testclient.put(f"api/v1/build/{new_build_id}/cancel") response.raise_for_status() - r = schema.APIResponse.parse_obj(response.json()) + r = schema.APIResponse.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.message == f"build {new_build_id} canceled" @@ -1238,7 +1238,7 @@ def test_api_cancel_build_auth(testclient): continue response.raise_for_status() - r = schema.APIGetBuild.parse_obj(response.json()) + r = schema.APIGetBuild.model_validate(response.json()) assert r.status == schema.APIStatus.OK assert r.data.id == new_build_id if r.data.status == schema.BuildStatus.CANCELED.value: @@ -1272,7 +1272,7 @@ def post_specification( }, ) response.raise_for_status() - r = schema.APIPostSpecification.parse_obj(response.json()) + r = schema.APIPostSpecification.model_validate(response.json()) assert r.status == schema.APIStatus.OK return r.data.build_id From 95026dbb917f11a79f3595c5f3dfc15551228ee3 Mon Sep 17 00:00:00 2001 From: sophia Date: Mon, 9 Dec 2024 10:36:34 -0800 Subject: [PATCH 2/6] Fix template response deprecation warning --- .../_internal/server/views/conda_store_ui.py | 2 +- .../_internal/server/views/ui.py | 19 +++++++++++-------- .../conda_store_server/server/auth.py | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/conda-store-server/conda_store_server/_internal/server/views/conda_store_ui.py b/conda-store-server/conda_store_server/_internal/server/views/conda_store_ui.py index bd60c14ce..bbda62534 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/conda_store_ui.py +++ b/conda-store-server/conda_store_server/_internal/server/views/conda_store_ui.py @@ -32,7 +32,7 @@ async def get_conda_store_ui( "url_prefix": url_prefix, "ui_prefix": router_conda_store_ui.prefix, } - response = templates.TemplateResponse("conda-store-ui.html", context) + response = templates.TemplateResponse(request, "conda-store-ui.html", context) if path.endswith("not-found"): response.status_code = 404 return response diff --git a/conda-store-server/conda_store_server/_internal/server/views/ui.py b/conda-store-server/conda_store_server/_internal/server/views/ui.py index d4a51c509..42bfd095d 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/ui.py +++ b/conda-store-server/conda_store_server/_internal/server/views/ui.py @@ -47,7 +47,7 @@ def sort_namespace(n): "entity": entity, } - return templates.TemplateResponse("create.html", context) + return templates.TemplateResponse(request, "create.html", context) @router_ui.get("/") @@ -74,7 +74,7 @@ async def ui_list_environments( "platform": get_installer_platform(), } - return templates.TemplateResponse("home.html", context) + return templates.TemplateResponse(request, "home.html", context) @router_ui.get("/namespace/") @@ -96,7 +96,7 @@ async def ui_list_namespaces( "entity": entity, } - return templates.TemplateResponse("namespace.html", context) + return templates.TemplateResponse(request, "namespace.html", context) @router_ui.get("/environment/{namespace}/{environment_name}/") @@ -122,6 +122,7 @@ async def ui_get_environment( ) if environment is None: return templates.TemplateResponse( + request, "404.html", { "request": request, @@ -145,7 +146,7 @@ async def ui_get_environment( "spec": yaml.dump(spec), } - return templates.TemplateResponse("environment.html", context) + return templates.TemplateResponse(request, "environment.html", context) @router_ui.get("/environment/{namespace}/{environment_name}/edit/") @@ -171,6 +172,7 @@ async def ui_edit_environment( ) if environment is None: return templates.TemplateResponse( + request, "404.html", { "request": request, @@ -198,7 +200,7 @@ async def ui_edit_environment( "namespaces": [environment.namespace], } - return templates.TemplateResponse("create.html", context) + return templates.TemplateResponse(request, "create.html", context) @router_ui.get("/build/{build_id}/") @@ -215,6 +217,7 @@ async def ui_get_build( build = api.get_build(db, build_id) if build is None: return templates.TemplateResponse( + request, "404.html", { "request": request, @@ -239,7 +242,7 @@ async def ui_get_build( "platform": get_installer_platform(), } - return templates.TemplateResponse("build.html", context) + return templates.TemplateResponse(request, "build.html", context) @router_ui.get("/user/") @@ -276,7 +279,7 @@ async def ui_get_user( "system_metrics": system_metrics, "namespace_usage_metrics": namespace_usage_metrics, } - return templates.TemplateResponse("user.html", context) + return templates.TemplateResponse(request, "user.html", context) @router_ui.get("/setting/") @@ -320,4 +323,4 @@ async def ui_get_setting( db, namespace=namespace, environment_name=environment_name ), } - return templates.TemplateResponse("setting.html", context) + return templates.TemplateResponse(request, "setting.html", context) diff --git a/conda-store-server/conda_store_server/server/auth.py b/conda-store-server/conda_store_server/server/auth.py index a6ae44909..c042f94f9 100644 --- a/conda-store-server/conda_store_server/server/auth.py +++ b/conda-store-server/conda_store_server/server/auth.py @@ -521,6 +521,7 @@ def get_login_method( ): request.session["next"] = next return templates.TemplateResponse( + request, "login.html", {"request": request, "login_html": self.get_login_html(request, templates)}, ) From e3958010899cfd589410ed96d0bfb76616e1476a Mon Sep 17 00:00:00 2001 From: sophia Date: Mon, 9 Dec 2024 10:39:25 -0800 Subject: [PATCH 3/6] Use pydantic model_dump() instead of dict() --- conda-store-server/conda_store_server/_internal/schema.py | 2 +- .../conda_store_server/_internal/server/views/api.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/conda-store-server/conda_store_server/_internal/schema.py b/conda-store-server/conda_store_server/_internal/schema.py index 3a638619d..8ad9a34ec 100644 --- a/conda-store-server/conda_store_server/_internal/schema.py +++ b/conda-store-server/conda_store_server/_internal/schema.py @@ -443,7 +443,7 @@ def model_dump(self): def __str__(self): # This makes sure the format is suitable for output if this object is # converted to a string, which can also happen implicitly - return str(self.dict()) + return str(self.model_dump()) ############################### diff --git a/conda-store-server/conda_store_server/_internal/server/views/api.py b/conda-store-server/conda_store_server/_internal/server/views/api.py index a3116d480..cbfc06407 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/api.py +++ b/conda-store-server/conda_store_server/_internal/server/views/api.py @@ -121,7 +121,7 @@ def paginated_api_response( ) return { "status": "ok", - "data": [object_schema.from_orm(_).dict(exclude=exclude) for _ in query.all()], + "data": [object_schema.from_orm(_).model_dump(exclude=exclude) for _ in query.all()], "page": (paginated_args["offset"] // paginated_args["limit"]) + 1, "size": paginated_args["limit"], "count": count, @@ -745,7 +745,7 @@ async def api_get_environment( return { "status": "ok", - "data": schema.Environment.from_orm(environment).dict( + "data": schema.Environment.from_orm(environment).model_dump( exclude={"current_build"} ), } @@ -983,7 +983,7 @@ async def api_get_build( return { "status": "ok", - "data": schema.Build.from_orm(build).dict(exclude={"packages"}), + "data": schema.Build.from_orm(build).model_dump(exclude={"packages"}), } From 2746bcfcdc7270c19ae0e77f4ec9a397a22649cb Mon Sep 17 00:00:00 2001 From: sophia Date: Mon, 9 Dec 2024 14:34:42 -0800 Subject: [PATCH 4/6] Fix from_orm deprecation warnings --- conda-store-server/conda_store_server/_internal/schema.py | 3 +++ .../conda_store_server/_internal/server/views/api.py | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/conda-store-server/conda_store_server/_internal/schema.py b/conda-store-server/conda_store_server/_internal/schema.py index 8ad9a34ec..0282a5565 100644 --- a/conda-store-server/conda_store_server/_internal/schema.py +++ b/conda-store-server/conda_store_server/_internal/schema.py @@ -357,6 +357,7 @@ class Settings(BaseModel): # Conda Environment class CondaSpecificationPip(BaseModel): + model_config = ConfigDict(from_attributes=True) pip: List[PipArg] = [] @@ -370,6 +371,7 @@ class CondaSpecification(BaseModel): name: Annotated[str, StringConstraints(pattern=f"^[{ALLOWED_CHARACTERS}]+$")] prefix: Optional[str] = None variables: Optional[Dict[str, Union[str, int]]] = None + model_config = ConfigDict(from_attributes=True) @classmethod def model_validate(cls, specification): @@ -412,6 +414,7 @@ class LockfileSpecification(BaseModel): name: Annotated[str, StringConstraints(pattern=f"^[{ALLOWED_CHARACTERS}]+$")] # noqa: F722 description: Optional[str] = "" lockfile: Lockfile + model_config = ConfigDict(from_attributes=True) @classmethod def model_validate(cls, specification): diff --git a/conda-store-server/conda_store_server/_internal/server/views/api.py b/conda-store-server/conda_store_server/_internal/server/views/api.py index cbfc06407..73a0be238 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/api.py +++ b/conda-store-server/conda_store_server/_internal/server/views/api.py @@ -121,7 +121,7 @@ def paginated_api_response( ) return { "status": "ok", - "data": [object_schema.from_orm(_).model_dump(exclude=exclude) for _ in query.all()], + "data": [object_schema.model_validate(_).model_dump(exclude=exclude) for _ in query.all()], "page": (paginated_args["offset"] // paginated_args["limit"]) + 1, "size": paginated_args["limit"], "count": count, @@ -300,7 +300,7 @@ async def api_get_namespace( return { "status": "ok", - "data": schema.Namespace.from_orm(namespace).model_dump(), + "data": schema.Namespace.model_validate(namespace).model_dump(), } @@ -745,7 +745,7 @@ async def api_get_environment( return { "status": "ok", - "data": schema.Environment.from_orm(environment).model_dump( + "data": schema.Environment.model_validate(environment).model_dump( exclude={"current_build"} ), } @@ -983,7 +983,7 @@ async def api_get_build( return { "status": "ok", - "data": schema.Build.from_orm(build).model_dump(exclude={"packages"}), + "data": schema.Build.model_validate(build).model_dump(exclude={"packages"}), } From 85f12006e8bd8960f599a428b33d2e1b7a528346 Mon Sep 17 00:00:00 2001 From: sophia Date: Mon, 9 Dec 2024 16:29:23 -0800 Subject: [PATCH 5/6] Use utcnow() --- conda-store-server/conda_store_server/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda-store-server/conda_store_server/app.py b/conda-store-server/conda_store_server/app.py index 983859b23..8150da920 100644 --- a/conda-store-server/conda_store_server/app.py +++ b/conda-store-server/conda_store_server/app.py @@ -817,7 +817,7 @@ def delete_namespace(self, db: Session, namespace: str): if namespace is None: raise utils.CondaStoreError(f"namespace={namespace} does not exist") - utcnow = datetime.datetime.now(datetime.UTC) + utcnow = datetime.datetime.utcnow() namespace.deleted_on = utcnow for environment_orm in namespace.environments: environment_orm.deleted_on = utcnow From cad48b989c3b75f8e552d9a7bd1e630e3042e37b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 00:29:41 +0000 Subject: [PATCH 6/6] [pre-commit.ci] Apply automatic pre-commit fixes --- .../_internal/server/views/api.py | 13 ++++++++++--- .../conda_store_server/_internal/server/views/ui.py | 2 +- .../conda_store_server/_internal/worker/build.py | 4 +++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/conda-store-server/conda_store_server/_internal/server/views/api.py b/conda-store-server/conda_store_server/_internal/server/views/api.py index 73a0be238..c2e718f9b 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/api.py +++ b/conda-store-server/conda_store_server/_internal/server/views/api.py @@ -121,7 +121,10 @@ def paginated_api_response( ) return { "status": "ok", - "data": [object_schema.model_validate(_).model_dump(exclude=exclude) for _ in query.all()], + "data": [ + object_schema.model_validate(_).model_dump(exclude=exclude) + for _ in query.all() + ], "page": (paginated_args["offset"] // paginated_args["limit"]) + 1, "size": paginated_args["limit"], "count": count, @@ -682,7 +685,9 @@ async def api_list_environments( if jwt: # Fetch the environments visible to the supplied token role_bindings = auth.entity_bindings( - AuthenticationToken.model_validate(auth.authentication.decrypt_token(jwt)) + AuthenticationToken.model_validate( + auth.authentication.decrypt_token(jwt) + ) ) else: role_bindings = None @@ -887,7 +892,9 @@ async def api_post_specification( "description": environment_description, "lockfile": specification, } - specification = schema.LockfileSpecification.model_validate(lockfile_spec) + specification = schema.LockfileSpecification.model_validate( + lockfile_spec + ) else: specification = schema.CondaSpecification.model_validate(specification) except yaml.error.YAMLError: diff --git a/conda-store-server/conda_store_server/_internal/server/views/ui.py b/conda-store-server/conda_store_server/_internal/server/views/ui.py index 42bfd095d..8d45c7ba2 100644 --- a/conda-store-server/conda_store_server/_internal/server/views/ui.py +++ b/conda-store-server/conda_store_server/_internal/server/views/ui.py @@ -122,7 +122,7 @@ async def ui_get_environment( ) if environment is None: return templates.TemplateResponse( - request, + request, "404.html", { "request": request, diff --git a/conda-store-server/conda_store_server/_internal/worker/build.py b/conda-store-server/conda_store_server/_internal/worker/build.py index c9f649521..0fa92a43f 100644 --- a/conda-store-server/conda_store_server/_internal/worker/build.py +++ b/conda-store-server/conda_store_server/_internal/worker/build.py @@ -227,7 +227,9 @@ def build_conda_environment(db: Session, conda_store, build): else: lock_backend, locker = conda_store.lock_plugin() conda_lock_spec = locker.lock_environment( - spec=schema.CondaSpecification.model_validate(build.specification.spec), + spec=schema.CondaSpecification.model_validate( + build.specification.spec + ), platforms=settings.conda_solve_platforms, context=plugin_context.PluginContext( conda_store=conda_store,