From 36b48fd8061e741e6cdc7151f864f0316a2da081 Mon Sep 17 00:00:00 2001 From: Nicolas Drebenstedt Date: Mon, 28 Oct 2024 14:09:39 +0100 Subject: [PATCH 1/3] update and lock --- pdm.lock | 26 +++++++++++++------------- pyproject.toml | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pdm.lock b/pdm.lock index 0b0dada7..98fa0590 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:6801a00adc35c69d0463cc12e6dde2ae49d67b4bfffc6492480972143f8d2cfb" +content_hash = "sha256:6ad2aad32dc0cdfe678313db0d437a74a64f3500cd4bef6e24604642b20c36bd" [[metadata.targets]] requires_python = "==3.11.*" @@ -545,11 +545,11 @@ files = [ [[package]] name = "mex-common" -version = "0.38.0" +version = "0.39.0" requires_python = ">=3.11,<3.13" git = "https://github.com/robert-koch-institut/mex-common.git" -ref = "0.38.0" -revision = "c428ac48a1b6ff458573ea35374cefc7ef6cf025" +ref = "0.39.0" +revision = "21e3842ac8d0230e88565301b3b75e5b36e2caa9" summary = "Common library for MEx python projects." groups = ["default"] marker = "python_version == \"3.11\"" @@ -558,24 +558,24 @@ dependencies = [ "click<9,>=8.1.7", "langdetect<2,>=1.0.9", "ldap3<3,>=2.9.1", - "mex-model @ git+https://github.com/robert-koch-institut/mex-model.git@2.5.0", - "numpy<3,>=2.0.1", - "pandas<3,>=2.2.2", + "mex-model @ git+https://github.com/robert-koch-institut/mex-model.git@3.0.0", + "numpy<3,>=2.1.2", + "pandas<3,>=2.2.3", "pyarrow<18,>=17.0.0", - "pydantic-settings<3,>=2.4.0", - "pydantic<3,>=2.8.2", + "pydantic-settings<3,>=2.5.2", + "pydantic<3,>=2.9.2", "pytz<2024.2,>=2024.1", "requests<3,>=2.32.3", ] [[package]] name = "mex-model" -version = "2.5.0" +version = "3.0.0" requires_python = "<3.13,>=3.11" git = "https://github.com/robert-koch-institut/mex-model.git" -ref = "2.5.0" -revision = "463ffde9776477b127e08b949606d6a7b32ca60b" -summary = "Conceptual and machine-readable versions of the MEx metadata model." +ref = "3.0.0" +revision = "c027f6e13b599624c085cd3d383a8ad902d8ba51" +summary = "JSON schema files defining the MEx metadata model." groups = ["default"] marker = "python_version == \"3.11\"" diff --git a/pyproject.toml b/pyproject.toml index 9db866f6..1acee213 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,13 +8,13 @@ license = { file = "LICENSE" } urls = { Repository = "https://github.com/robert-koch-institut/mex-backend" } requires-python = ">=3.11,<3.13" dependencies = [ - "fastapi>=0.114.2,<1", + "fastapi>=0.115.4,<1", "httpx>=0.27.2,<1", "jinja2>=3.1.4,<4", - "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.38.0", + "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.39.0", "neo4j>=5.24.0,<6", "pydantic>=2.9.1,<3", - "starlette>=0.38.5,<1", + "starlette>=0.41.2,<1", "uvicorn[standard]>=0.30.6,<1", ] optional-dependencies.dev = [ From 1bf382603f21cc6416b9b9388e416fd5294ffa00 Mon Sep 17 00:00:00 2001 From: Nicolas Drebenstedt Date: Mon, 28 Oct 2024 14:12:44 +0100 Subject: [PATCH 2/3] code maint and lint --- mex/backend/constants.py | 1 + mex/backend/exceptions.py | 2 +- mex/backend/graph/connector.py | 5 +++-- mex/backend/graph/models.py | 3 ++- mex/backend/graph/query.py | 2 +- mex/backend/graph/transform.py | 2 +- mex/backend/logging.py | 1 + mex/backend/main.py | 12 ++++++------ mex/backend/merged/helpers.py | 11 ++++++----- mex/backend/rules/helpers.py | 15 ++++++++++----- mex/backend/types.py | 4 ++-- mex/backend/utils.py | 5 ++--- tests/auxiliary/conftest.py | 5 +++-- tests/conftest.py | 26 +++++++++++++------------- tests/extracted/test_main.py | 5 +++-- tests/graph/test_connector.py | 6 +++--- tests/graph/test_models.py | 8 ++++---- tests/graph/test_query.py | 2 +- tests/identity/test_main.py | 11 ++++++----- tests/ingest/test_main.py | 11 ++++++----- tests/merged/test_helpers.py | 4 ++-- tests/merged/test_main.py | 5 +++-- tests/preview/test_main.py | 3 ++- tests/rules/test_main.py | 7 ++++--- tests/test_exceptions.py | 7 ++++--- tests/test_fields.py | 8 ++++---- tests/test_main.py | 10 +++++++--- tests/test_security.py | 12 ++++++++---- tests/test_utils.py | 7 ++++--- 29 files changed, 113 insertions(+), 87 deletions(-) create mode 100644 mex/backend/constants.py diff --git a/mex/backend/constants.py b/mex/backend/constants.py new file mode 100644 index 00000000..23291ec5 --- /dev/null +++ b/mex/backend/constants.py @@ -0,0 +1 @@ +NUMBER_OF_RULE_TYPES = 3 # Additive, Subtractive and Preventive diff --git a/mex/backend/exceptions.py b/mex/backend/exceptions.py index e2b0d13c..1e6358fb 100644 --- a/mex/backend/exceptions.py +++ b/mex/backend/exceptions.py @@ -59,7 +59,7 @@ def handle_uncaught_exception(request: Request, exc: Exception) -> Response: content=ErrorResponse( message=str(exc), debug=DebuggingInfo( - errors=[dict(type=type(exc).__name__)], + errors=[{"type": type(exc).__name__}], scope=DebuggingScope.model_validate(request.scope), ), ).model_dump_json(), diff --git a/mex/backend/graph/connector.py b/mex/backend/graph/connector.py index 471cf09e..59569f9d 100644 --- a/mex/backend/graph/connector.py +++ b/mex/backend/graph/connector.py @@ -92,7 +92,8 @@ def _check_connectivity_and_authentication(self) -> Result: query_builder = QueryBuilder.get() result = self.commit(query_builder.fetch_database_status()) if (status := result["currentStatus"]) != "online": - raise MExError(f"Database is {status}.") from None + msg = f"Database is {status}." + raise MExError(msg) from None return result def _seed_constraints(self) -> list[Result]: @@ -494,7 +495,7 @@ def create_rule_set( self._merge_edges( rule, stable_target_id, - extra_refs=dict(stableTargetId=stable_target_id), + extra_refs={"stableTargetId": stable_target_id}, ) def ingest(self, models: list[AnyExtractedModel]) -> list[Identifier]: diff --git a/mex/backend/graph/models.py b/mex/backend/graph/models.py index 05d8dcaf..29d20f22 100644 --- a/mex/backend/graph/models.py +++ b/mex/backend/graph/models.py @@ -5,6 +5,7 @@ from neo4j import Result as Neo4jResult from mex.backend.graph.exceptions import MultipleResultsFoundError, NoResultFoundError +from mex.backend.logging import LOGGING_LINE_LENGTH class Result: @@ -31,7 +32,7 @@ def __iter__(self) -> Iterator[dict[str, Any]]: def __repr__(self) -> str: """Return a human-readable representation of this result object.""" representation = f"Result({self.all()!r})" - if len(representation) > 90: + if len(representation) > LOGGING_LINE_LENGTH: representation = f"{representation[:40]}... ...{representation[-40:]}" return representation diff --git a/mex/backend/graph/query.py b/mex/backend/graph/query.py index 08b75a31..a72d4cc5 100644 --- a/mex/backend/graph/query.py +++ b/mex/backend/graph/query.py @@ -71,4 +71,4 @@ def __getattr__(self, name: str) -> Callable[..., str]: def close(self) -> None: """Clean up the connector.""" - pass # no clean-up needed + # no clean-up needed diff --git a/mex/backend/graph/transform.py b/mex/backend/graph/transform.py index ca6ccbbe..d2dab57e 100644 --- a/mex/backend/graph/transform.py +++ b/mex/backend/graph/transform.py @@ -16,7 +16,7 @@ def expand_references_in_search_result(item: dict[str, Any]) -> None: `_SearchResultReference`. Before parsing them into pydantic, we need to inline the references back into the `item` dictionary. """ - # XXX if we can use `apoc`, we might do this step directly in the cypher query + # TODO(ND): try to re-write directly in the cypher query, if we can use `apoc` for ref in cast(list[_SearchResultReference], item.pop("_refs")): target_list = item.setdefault(ref["label"], [None]) length_needed = 1 + ref["position"] - len(target_list) diff --git a/mex/backend/logging.py b/mex/backend/logging.py index 66e676d5..ad063eec 100644 --- a/mex/backend/logging.py +++ b/mex/backend/logging.py @@ -2,6 +2,7 @@ from mex.common.logging import logger +LOGGING_LINE_LENGTH = 90 UVICORN_LOGGING_CONFIG = DEFAULT_UVICORN_LOGGING_CONFIG.copy() UVICORN_LOGGING_CONFIG["loggers"][logger.name] = { "handlers": ["default"], diff --git a/mex/backend/main.py b/mex/backend/main.py index fd0d565d..7f318939 100644 --- a/mex/backend/main.py +++ b/mex/backend/main.py @@ -49,7 +49,7 @@ def create_openapi_schema() -> dict[str, Any]: summary=app.summary, description=app.description, routes=app.routes, - servers=[dict(url=settings.backend_api_url)], + servers=[{"url": settings.backend_api_url}], ) for identifier in chain(EXTRACTED_IDENTIFIER_CLASSES, MERGED_IDENTIFIER_CLASSES): name = identifier.__name__ @@ -78,11 +78,11 @@ async def lifespan(_: FastAPI) -> AsyncIterator[None]: "The MEx API includes endpoints for multiple use-cases, " "e.g. for extractor pipelines, the MEx editor or inter-departmental access." ), - contact=dict( - name="RKI MEx Team", - email="mex@rki.de", - url="https://github.com/robert-koch-institut/mex-backend", - ), + contact={ + "name": "RKI MEx Team", + "email": "mex@rki.de", + "url": "https://github.com/robert-koch-institut/mex-backend", + }, lifespan=lifespan, version="v0", ) diff --git a/mex/backend/merged/helpers.py b/mex/backend/merged/helpers.py index aa863391..aec920cd 100644 --- a/mex/backend/merged/helpers.py +++ b/mex/backend/merged/helpers.py @@ -2,6 +2,7 @@ from pydantic import Field, TypeAdapter, ValidationError +from mex.backend.constants import NUMBER_OF_RULE_TYPES from mex.backend.fields import MERGEABLE_FIELDS_BY_CLASS_NAME from mex.backend.graph.connector import GraphConnector from mex.backend.graph.exceptions import InconsistentGraphError @@ -109,7 +110,8 @@ def create_merged_item( elif extracted_items: entity_type = ensure_prefix(extracted_items[0].stemType, "Merged") else: - raise MExError("One of rule_set or extracted_items is required.") + msg = "One of rule_set or extracted_items is required." + raise MExError(msg) fields = MERGEABLE_FIELDS_BY_CLASS_NAME[entity_type] cls = MERGED_MODEL_CLASSES_BY_NAME[entity_type] @@ -178,14 +180,13 @@ def search_merged_items_in_graph( for component in item["components"] if component["entityType"] in RULE_MODEL_CLASSES_BY_NAME ] - if len(rules_raw) == 3: + if len(rules_raw) == NUMBER_OF_RULE_TYPES: rule_set_response = transform_raw_rules_to_rule_set_response(rules_raw) elif len(rules_raw) == 0: rule_set_response = None else: - raise MExError( - f"Unexpected number of rules found in graph: {len(rules_raw)}" - ) + msg = f"Unexpected number of rules found in graph: {len(rules_raw)}" + raise MExError(msg) items.append( create_merged_item( diff --git a/mex/backend/rules/helpers.py b/mex/backend/rules/helpers.py index f35c3136..bb67c70f 100644 --- a/mex/backend/rules/helpers.py +++ b/mex/backend/rules/helpers.py @@ -1,6 +1,7 @@ from collections.abc import Mapping from typing import Any, Final +from mex.backend.constants import NUMBER_OF_RULE_TYPES from mex.backend.graph.connector import GraphConnector from mex.common.exceptions import MExError from mex.common.models import ( @@ -31,8 +32,9 @@ def transform_raw_rules_to_rule_set_response( response: dict[str, Any] = {} model: type[AnyRuleModel] | None - if len(raw_rules) != 3: - raise MExError("inconsistent rule item count") + if len(raw_rules) != NUMBER_OF_RULE_TYPES: + msg = "inconsistent rule item count" + raise MExError(msg) for rule in raw_rules: for field_name, model_class_lookup in MODEL_CLASS_LOOKUP_BY_FIELD_NAME.items(): @@ -42,9 +44,11 @@ def transform_raw_rules_to_rule_set_response( stable_target_ids.extend(rule.pop("stableTargetId", [])) if len(set(stem_types)) != 1: - raise MExError("inconsistent rule item stem types") + msg = "inconsistent rule item stem types" + raise MExError(msg) if len(set(stable_target_ids)) != 1: - raise MExError("inconsistent rule item stableTargetIds") + msg = "inconsistent rule item stableTargetIds" + raise MExError(msg) response["stableTargetId"] = stable_target_ids[0] response_class_name = ensure_postfix(stem_types[0], "RuleSetResponse") @@ -102,5 +106,6 @@ def update_and_get_rule_set( stable_target_id, [rule_set.stemType], ): - raise MExError("no merged item found for given identifier and type") + msg = "no merged item found for given identifier and type" + raise MExError(msg) return create_and_get_rule_set(rule_set, stable_target_id) diff --git a/mex/backend/types.py b/mex/backend/types.py index 9391a4cc..22f4b7c6 100644 --- a/mex/backend/types.py +++ b/mex/backend/types.py @@ -56,8 +56,8 @@ def __new__( cls: type["DynamicStrEnum"], name: str, bases: tuple[type], dct: _EnumDict ) -> "DynamicStrEnum": """Create a new enum by adding an entry for each name in the source.""" - for name in dct.pop("__names__"): - dct[dromedary_to_snake(name).upper()] = name + for value in dct.pop("__names__"): + dct[dromedary_to_snake(value).upper()] = value return super().__new__(cls, name, bases, dct) diff --git a/mex/backend/utils.py b/mex/backend/utils.py index ec883867..02c029d0 100644 --- a/mex/backend/utils.py +++ b/mex/backend/utils.py @@ -1,3 +1,4 @@ +import contextlib from collections.abc import Callable from typing import ParamSpec, TypeVar @@ -21,10 +22,8 @@ def prune_list_in_dict(dict_: dict[str, list[T]], key: str, item: list[T] | T) - if not isinstance(item, list): item = [item] for removable in item: - try: + with contextlib.suppress(ValueError): list_.remove(removable) - except ValueError: - pass def reraising( diff --git a/tests/auxiliary/conftest.py b/tests/auxiliary/conftest.py index c7ef43bb..c765d317 100644 --- a/tests/auxiliary/conftest.py +++ b/tests/auxiliary/conftest.py @@ -6,6 +6,7 @@ import requests from pytest import MonkeyPatch from requests import Response +from starlette import status from mex.common.wikidata.connector import ( WikidataAPIConnector, @@ -15,9 +16,9 @@ TEST_DATA_DIR = Path(__file__).parent / "test_data" -@pytest.fixture() +@pytest.fixture def mocked_wikidata(monkeypatch: MonkeyPatch) -> None: - response_query = Mock(spec=Response, status_code=200) + response_query = Mock(spec=Response, status_code=status.HTTP_200_OK) session = MagicMock(spec=requests.Session) session.get = MagicMock(side_effect=[response_query]) diff --git a/tests/conftest.py b/tests/conftest.py index dbb8c747..94440648 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -49,10 +49,10 @@ def settings() -> BackendSettings: """Load the settings for this pytest session.""" settings = BackendSettings.get() settings.backend_api_key_database = APIKeyDatabase( - **{"read": "read_key", "write": "write_key"} + read="read_key", write="write_key" ) settings.backend_user_database = APIUserDatabase( - **{"read": {"Reader": "read_password"}, "write": {"Writer": "write_password"}} + read={"Reader": "read_password"}, write={"Writer": "write_password"} ) return settings @@ -62,28 +62,28 @@ def skip_integration_test_in_ci(is_integration_test: bool) -> None: """Overwrite fixture from plugin to not skip integration tests in ci.""" -@pytest.fixture() +@pytest.fixture def client() -> TestClient: """Return a fastAPI test client initialized with our app.""" with TestClient(app, raise_server_exceptions=False) as test_client: return test_client -@pytest.fixture() +@pytest.fixture def client_with_api_key_write_permission(client: TestClient) -> TestClient: """Return a fastAPI test client with write permission initialized with our app.""" client.headers.update({"X-API-Key": "write_key"}) return client -@pytest.fixture() +@pytest.fixture def client_with_api_key_read_permission(client: TestClient) -> TestClient: """Return a fastAPI test client with read permission granted by API key.""" client.headers.update({"X-API-Key": "read_key"}) return client -@pytest.fixture() +@pytest.fixture def client_with_basic_auth_read_permission(client: TestClient) -> TestClient: """Return a fastAPI test client with read permission granted by basic auth.""" client.headers.update( @@ -92,7 +92,7 @@ def client_with_basic_auth_read_permission(client: TestClient) -> TestClient: return client -@pytest.fixture() +@pytest.fixture def client_with_basic_auth_write_permission(client: TestClient) -> TestClient: """Return a fastAPI test client with write permission granted by basic auth.""" client.headers.update( @@ -127,7 +127,7 @@ def call_args_list(self) -> list[Any]: return self.run.call_args_list -@pytest.fixture() +@pytest.fixture def mocked_graph(monkeypatch: MonkeyPatch) -> MockedGraph: """Mock the graph connector and return the mocked `run` for easy manipulation.""" records: list[Any] = [] @@ -189,7 +189,7 @@ def isolate_graph_database( driver.execute_query(f"DROP INDEX {row['name']};") -@pytest.fixture() +@pytest.fixture def dummy_data() -> dict[str, AnyExtractedModel]: """Create a set of interlinked dummy data.""" primary_source_1 = ExtractedPrimarySource( @@ -251,7 +251,7 @@ def dummy_data() -> dict[str, AnyExtractedModel]: } -@pytest.fixture() +@pytest.fixture def load_dummy_data( dummy_data: dict[str, AnyExtractedModel], ) -> dict[str, AnyExtractedModel]: @@ -260,7 +260,7 @@ def load_dummy_data( return dummy_data -@pytest.fixture() +@pytest.fixture def additive_organizational_unit( dummy_data: dict[str, AnyExtractedModel], ) -> AdditiveOrganizationalUnit: @@ -271,7 +271,7 @@ def additive_organizational_unit( ) -@pytest.fixture() +@pytest.fixture def organizational_unit_rule_set_request( additive_organizational_unit: AdditiveOrganizationalUnit, ) -> OrganizationalUnitRuleSetRequest: @@ -282,7 +282,7 @@ def organizational_unit_rule_set_request( ) -@pytest.fixture() +@pytest.fixture def load_dummy_rule_set( organizational_unit_rule_set_request: OrganizationalUnitRuleSetRequest, dummy_data: dict[str, AnyExtractedModel], diff --git a/tests/extracted/test_main.py b/tests/extracted/test_main.py index cfca4d7c..fd8ddf90 100644 --- a/tests/extracted/test_main.py +++ b/tests/extracted/test_main.py @@ -3,6 +3,7 @@ import pytest from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient +from starlette import status from mex.common.models import ExtractedOrganizationalUnit from tests.conftest import MockedGraph @@ -58,7 +59,7 @@ def test_search_extracted_items_mocked( ] response = client_with_api_key_read_permission.get("/v0/extracted-item") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == {"items": [jsonable_encoder(unit)], "total": 14} @@ -194,5 +195,5 @@ def test_search_extracted_items( response = client_with_api_key_read_permission.get( f"/v0/extracted-item{query_string}" ) - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected diff --git a/tests/graph/test_connector.py b/tests/graph/test_connector.py index a6f5bc2a..e1b6fcfb 100644 --- a/tests/graph/test_connector.py +++ b/tests/graph/test_connector.py @@ -20,7 +20,7 @@ from tests.conftest import MockedGraph -@pytest.fixture() +@pytest.fixture def mocked_query_builder(monkeypatch: MonkeyPatch) -> None: def __getattr__(_: QueryBuilder, query: str) -> Callable[..., str]: return lambda **parameters: format_str( @@ -367,8 +367,8 @@ def test_fetch_rule_items( { "email": [], "entityType": "AdditiveOrganizationalUnit", - "name": [dict(value="Unit 1.7", language="en")], - "website": [dict(title="Unit Homepage", url="https://unit-1-7")], + "name": [{"value": "Unit 1.7", "language": "en"}], + "website": [{"title": "Unit Homepage", "url": "https://unit-1-7"}], "parentUnit": [load_dummy_rule_set.additive.parentUnit], "stableTargetId": ["bFQoRhcVH5DHUB"], } diff --git a/tests/graph/test_models.py b/tests/graph/test_models.py index 6760c8b6..39291aa4 100644 --- a/tests/graph/test_models.py +++ b/tests/graph/test_models.py @@ -16,7 +16,7 @@ from mex.common.testing import Joker -@pytest.fixture() +@pytest.fixture def summary() -> Mock: class SummaryCounters: def __init__(self) -> None: @@ -27,7 +27,7 @@ def __init__(self) -> None: return Mock(spec=Neo4jResultSummary, counters=SummaryCounters()) -@pytest.fixture() +@pytest.fixture def multiple_results(summary: Mock) -> Mock: records = [ Mock(spec=Neo4jRecord, data=MagicMock(return_value={"num": 40})), @@ -39,14 +39,14 @@ def multiple_results(summary: Mock) -> Mock: ) -@pytest.fixture() +@pytest.fixture def no_result(summary: Mock) -> Mock: return Mock( spec=Neo4jResult, to_eager_result=MagicMock(return_value=([], summary, [])) ) -@pytest.fixture() +@pytest.fixture def single_result(summary: Mock) -> Mock: records = [ Mock( diff --git a/tests/graph/test_query.py b/tests/graph/test_query.py index c0f21cd0..670f5540 100644 --- a/tests/graph/test_query.py +++ b/tests/graph/test_query.py @@ -4,7 +4,7 @@ from mex.backend.graph.query import QueryBuilder, render_constraints -@pytest.fixture() +@pytest.fixture def query_builder() -> QueryBuilder: builder = QueryBuilder.get() builder._env.globals.update( diff --git a/tests/identity/test_main.py b/tests/identity/test_main.py index e58f67cd..f1f282f7 100644 --- a/tests/identity/test_main.py +++ b/tests/identity/test_main.py @@ -2,6 +2,7 @@ import pytest from fastapi.testclient import TestClient +from starlette import status from mex.common.models import ( MEX_PRIMARY_SOURCE_IDENTIFIER, @@ -59,7 +60,7 @@ def test_assign_identity_mocked( ) -> None: mocked_graph.return_value = mocked_return response = client_with_api_key_write_permission.post("/v0/identity", json=post_body) - assert response.status_code == 200, response.text + assert response.status_code == status, response.text assert response.json() == expected @@ -88,7 +89,7 @@ def test_assign_identity_inconsistency_mocked( "identifierInPrimarySource": "cp-2", }, ) - assert response.status_code == 500, response.text + assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR, response.text assert "MultipleResultsFoundError" in response.text @@ -142,7 +143,7 @@ def test_assign_identity( expected: dict[str, Any], ) -> None: response = client_with_api_key_write_permission.post("/v0/identity", json=post_body) - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected @@ -218,7 +219,7 @@ def test_fetch_identities_mocked( ) -> None: mocked_graph.return_value = mocked_return response = client_with_api_key_write_permission.get(f"/v0/identity{query_string}") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected @@ -269,5 +270,5 @@ def test_fetch_identities( expected: dict[str, Any], ) -> None: response = client_with_api_key_write_permission.get(f"/v0/identity{query_string}") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected diff --git a/tests/ingest/test_main.py b/tests/ingest/test_main.py index bfe23f81..9a53b23e 100644 --- a/tests/ingest/test_main.py +++ b/tests/ingest/test_main.py @@ -3,6 +3,7 @@ import pytest from fastapi.testclient import TestClient +from starlette import status from mex.backend.graph.connector import GraphConnector from mex.common.models import AnyExtractedModel @@ -11,7 +12,7 @@ Payload = dict[str, list[dict[str, Any]]] -@pytest.fixture() +@pytest.fixture def post_payload(dummy_data: dict[str, AnyExtractedModel]) -> Payload: payload = defaultdict(list) for model in dummy_data.values(): @@ -24,7 +25,7 @@ def test_bulk_insert_empty(client_with_api_key_write_permission: TestClient) -> response = client_with_api_key_write_permission.post( "/v0/ingest", json={"items": []} ) - assert response.status_code == 201, response.text + assert response.status_code == status.HTTP_201_CREATED, response.text assert response.json() == {"identifiers": []} @@ -43,7 +44,7 @@ def test_bulk_insert( ) # assert the response is the identifier of the contact point - assert response.status_code == 201, response.text + assert response.status_code == status.HTTP_201_CREATED, response.text assert sorted(response.json()["identifiers"]) == expected_identifiers # verify the nodes have actually been stored in the database @@ -70,7 +71,7 @@ def test_bulk_insert_malformed( "/v0/ingest", json={"items": ["FAIL!"]}, ) - assert response.status_code == 422, response.text + assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY, response.text assert response.json() == {"detail": expected_res} @@ -84,7 +85,7 @@ def test_bulk_insert_mocked( response = client_with_api_key_write_permission.post( "/v0/ingest", json=post_payload ) - assert response.status_code == 201, response.text + assert response.status_code == status.HTTP_201_CREATED, response.text assert sorted(response.json()["identifiers"]) == sorted( d.identifier for d in dummy_data.values() ) diff --git a/tests/merged/test_helpers.py b/tests/merged/test_helpers.py index 871dce91..9d6348af 100644 --- a/tests/merged/test_helpers.py +++ b/tests/merged/test_helpers.py @@ -115,7 +115,7 @@ def test_apply_subtractive_rule() -> None: @pytest.mark.parametrize( ("extracted_items", "rule_set", "expected"), - ( + [ ( [ ExtractedPerson( @@ -226,7 +226,7 @@ def test_apply_subtractive_rule() -> None: }, ), ([], None, "One of rule_set or extracted_items is required."), - ), + ], ids=( "extracted_items_and_rule_set", "only_rule_set", diff --git a/tests/merged/test_main.py b/tests/merged/test_main.py index 76ea8fff..98e823d4 100644 --- a/tests/merged/test_main.py +++ b/tests/merged/test_main.py @@ -2,6 +2,7 @@ import pytest from fastapi.testclient import TestClient +from starlette import status from mex.common.models import ExtractedOrganizationalUnit from tests.conftest import MockedGraph @@ -66,7 +67,7 @@ def test_search_merged_items_mocked( ] response = client_with_api_key_read_permission.get("/v0/merged-item") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == { "items": [ { @@ -229,5 +230,5 @@ def test_search_merged_items( expected: dict[str, Any], ) -> None: response = client_with_api_key_read_permission.get(f"/v0/merged-item{query_string}") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected diff --git a/tests/preview/test_main.py b/tests/preview/test_main.py index 08e1161e..59d7d26f 100644 --- a/tests/preview/test_main.py +++ b/tests/preview/test_main.py @@ -2,6 +2,7 @@ import pytest from fastapi.testclient import TestClient +from starlette import status @pytest.mark.parametrize( @@ -151,6 +152,6 @@ def test_preview( response = client_with_api_key_read_permission.post( f"/v0/preview-item/{stable_target_id}", json=json_body ) - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text cleaned_response = {k: v for k, v in response.json().items() if v} assert cleaned_response == expected diff --git a/tests/rules/test_main.py b/tests/rules/test_main.py index 0794b760..fbab97b7 100644 --- a/tests/rules/test_main.py +++ b/tests/rules/test_main.py @@ -3,6 +3,7 @@ import pytest from fastapi.testclient import TestClient +from starlette import status from mex.backend.graph.connector import GraphConnector from mex.common.models import OrganizationalUnitRuleSetResponse @@ -55,7 +56,7 @@ def test_create_rule_set(client_with_api_key_write_permission: TestClient) -> No }, }, ) - assert response.status_code == 201, response.text + assert response.status_code == status.HTTP_201_CREATED, response.text assert response.json() == { "additive": { "contact": [], @@ -213,7 +214,7 @@ def test_get_rule_set( response = client_with_api_key_write_permission.get( f"/v0/rule-set/{load_dummy_rule_set.stableTargetId}" ) - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == { "additive": { "parentUnit": None, @@ -288,7 +289,7 @@ def test_update_rule_set( }, }, ) - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == { "additive": { "parentUnit": None, diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 0a605683..7f16f518 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -5,6 +5,7 @@ import pydantic_core import pytest from pydantic import ValidationError +from starlette import status from mex.backend.exceptions import handle_uncaught_exception, handle_validation_error from mex.common.exceptions import MExError @@ -31,7 +32,7 @@ }, "message": "foo", }, - 500, + status.HTTP_500_INTERNAL_SERVER_ERROR, ), ( MExError("bar"), @@ -42,7 +43,7 @@ "scope": MOCK_REQUEST_SCOPE, }, }, - 500, + status.HTTP_500_INTERNAL_SERVER_ERROR, ), ], ids=["TypeError", "MExError"], @@ -71,7 +72,7 @@ def test_handle_validation_error() -> None: ], ) response = handle_validation_error(request, exception) - assert response.status_code == 400, response.body + assert response.status_code == status.HTTP_400_BAD_REQUEST, response.body assert json.loads(response.body) == { "debug": { "errors": [ diff --git a/tests/test_fields.py b/tests/test_fields.py index fe26376a..c9984465 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -16,14 +16,14 @@ @pytest.mark.parametrize( ("annotation", "expected_types"), - ( + [ (str, [str]), (str | None, [str]), (str | int, [str, int]), (list[str | int | list[str]], [str, int, str]), (Annotated[list[str | int], "some-annotation"], [str, int]), (None, []), - ), + ], ids=[ "simple annotation", "optional type", @@ -39,7 +39,7 @@ def test_get_inner_types(annotation: Any, expected_types: list[type]) -> None: @pytest.mark.parametrize( ("annotation", "types", "expected"), - ( + [ (None, [str], False), (str, [str], True), (str, [Identifier], False), @@ -47,7 +47,7 @@ def test_get_inner_types(annotation: Any, expected_types: list[type]) -> None: (list[str | int | list[str]], [str, float], False), (list[str | int | list[str]], [int, str], True), (MergedPersonIdentifier | None, MERGED_IDENTIFIER_CLASSES, True), - ), + ], ids=[ "static None", "simple str", diff --git a/tests/test_main.py b/tests/test_main.py index 6d217d5d..776ad4fb 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,6 +1,7 @@ import pytest from fastapi.testclient import TestClient from neo4j import GraphDatabase +from starlette import status from mex.backend.main import app from mex.backend.settings import BackendSettings @@ -8,7 +9,7 @@ def test_openapi_schema(client: TestClient) -> None: response = client.get("/openapi.json") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text schema = response.json() assert schema["info"]["title"] == "mex-backend" @@ -26,7 +27,7 @@ def test_openapi_schema(client: TestClient) -> None: def test_health_check(client: TestClient) -> None: response = client.get("/v0/_system/check") - assert response.status_code == 200, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == {"status": "ok"} @@ -42,7 +43,10 @@ def test_all_endpoints_require_authorization(client: TestClient) -> None: if route.path not in excluded_routes: for method in route.methods: client_method = getattr(client, method.lower()) - assert client_method(route.path).status_code == 401 + assert ( + client_method(route.path).status_code + == status.HTTP_401_UNAUTHORIZED + ) @pytest.mark.integration diff --git a/tests/test_security.py b/tests/test_security.py index 15cd7e80..11a0125b 100644 --- a/tests/test_security.py +++ b/tests/test_security.py @@ -5,16 +5,20 @@ from mex.backend.security import has_read_access, has_write_access read_credentials = HTTPBasicCredentials( - **{"username": "Reader", "password": "read_password"} + username="Reader", + password="read_password", # noqa: S106 ) write_credentials = HTTPBasicCredentials( - **{"username": "Writer", "password": "write_password"} + username="Writer", + password="write_password", # noqa: S106 ) missing_user = HTTPBasicCredentials( - **{"username": "Missing", "password": "no_password"} + username="Missing", + password="no_password", # noqa: S106 ) user_wrong_pw = HTTPBasicCredentials( - **{"username": "Writer", "password": "wrong_password"} + username="Writer", + password="wrong_password", # noqa: S106 ) diff --git a/tests/test_utils.py b/tests/test_utils.py index 858bc37e..03f37521 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -44,14 +44,14 @@ def add(a: int, b: int) -> int: return a + b result = reraising(ValueError, RuntimeError, add, 1, 2) - assert result == 3 + assert result == 1 + 2 def test_reraising_with_caught_exception() -> None: def divide(a: int, b: int) -> float: return a / b - with pytest.raises(ValueError) as exc_info: + with pytest.raises(ValueError, match="division by zero") as exc_info: reraising(ZeroDivisionError, ValueError, divide, 1, 0) assert isinstance(exc_info.value, ValueError) @@ -61,7 +61,8 @@ def divide(a: int, b: int) -> float: def test_reraising_propagates_other_exceptions() -> None: def raise_type_error() -> None: - raise TypeError("This is a TypeError") + msg = "This is a TypeError" + raise TypeError(msg) with pytest.raises(TypeError) as exc_info: reraising(ValueError, RuntimeError, raise_type_error) From ab3fa4f624311e8e56a5390e329cde3182882a44 Mon Sep 17 00:00:00 2001 From: Nicolas Drebenstedt Date: Mon, 28 Oct 2024 16:48:35 +0100 Subject: [PATCH 3/3] update and fix tests --- CHANGELOG.md | 3 + pdm.lock | 16 +++--- pyproject.toml | 2 +- tests/conftest.py | 2 +- tests/graph/test_connector.py | 102 +++++++++------------------------- tests/graph/test_transform.py | 4 +- tests/identity/test_main.py | 2 +- tests/ingest/test_main.py | 8 +-- tests/preview/test_main.py | 4 +- tests/test_utils.py | 9 ++- 10 files changed, 53 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3901db7..b48ef9c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changes +- upgrade mex-common and mex-model dependencies to metadata model v3 +- apply additional linters in prep for `all` ruff linters + ### Deprecated ### Removed diff --git a/pdm.lock b/pdm.lock index 98fa0590..17066934 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:6ad2aad32dc0cdfe678313db0d437a74a64f3500cd4bef6e24604642b20c36bd" +content_hash = "sha256:955352b2e90470cfd0c69cc2077533d857fc618f58ad1e959359943e1d0a0801" [[metadata.targets]] requires_python = "==3.11.*" @@ -545,11 +545,11 @@ files = [ [[package]] name = "mex-common" -version = "0.39.0" +version = "0.40.0" requires_python = ">=3.11,<3.13" git = "https://github.com/robert-koch-institut/mex-common.git" -ref = "0.39.0" -revision = "21e3842ac8d0230e88565301b3b75e5b36e2caa9" +ref = "0.40.0" +revision = "402bfd513270659047bc8364179d7ed759685c93" summary = "Common library for MEx python projects." groups = ["default"] marker = "python_version == \"3.11\"" @@ -558,7 +558,7 @@ dependencies = [ "click<9,>=8.1.7", "langdetect<2,>=1.0.9", "ldap3<3,>=2.9.1", - "mex-model @ git+https://github.com/robert-koch-institut/mex-model.git@3.0.0", + "mex-model @ git+https://github.com/robert-koch-institut/mex-model.git@3.1.0", "numpy<3,>=2.1.2", "pandas<3,>=2.2.3", "pyarrow<18,>=17.0.0", @@ -570,11 +570,11 @@ dependencies = [ [[package]] name = "mex-model" -version = "3.0.0" +version = "3.1.0" requires_python = "<3.13,>=3.11" git = "https://github.com/robert-koch-institut/mex-model.git" -ref = "3.0.0" -revision = "c027f6e13b599624c085cd3d383a8ad902d8ba51" +ref = "3.1.0" +revision = "61283bbb386573e18db79ec86dbc03363b4348ce" summary = "JSON schema files defining the MEx metadata model." groups = ["default"] marker = "python_version == \"3.11\"" diff --git a/pyproject.toml b/pyproject.toml index 1acee213..1a01b27a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ dependencies = [ "fastapi>=0.115.4,<1", "httpx>=0.27.2,<1", "jinja2>=3.1.4,<4", - "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.39.0", + "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.40.0", "neo4j>=5.24.0,<6", "pydantic>=2.9.1,<3", "starlette>=0.41.2,<1", diff --git a/tests/conftest.py b/tests/conftest.py index 94440648..c813b068 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -236,7 +236,7 @@ def dummy_data() -> dict[str, AnyExtractedModel]: identifierInPrimarySource="a-1", responsibleUnit=[organizational_unit_1.stableTargetId], start=[YearMonthDay("2014-08-24")], - theme=[Theme["DIGITAL_PUBLIC_HEALTH"]], + theme=[Theme["INFECTIOUS_DISEASES_AND_EPIDEMIOLOGY"]], title=[Text(value="Aktivität 1", language=TextLanguage.DE)], website=[Link(title="Activity Homepage", url="https://activity-1")], ) diff --git a/tests/graph/test_connector.py b/tests/graph/test_connector.py index e1b6fcfb..2a23098f 100644 --- a/tests/graph/test_connector.py +++ b/tests/graph/test_connector.py @@ -1,4 +1,5 @@ from collections.abc import Callable +from unittest.mock import Mock import pytest from black import Mode, format_str @@ -194,7 +195,7 @@ def test_mocked_graph_fetch_extracted_items(mocked_graph: MockedGraph) -> None: result = graph.fetch_extracted_items( query_string="my-query", stable_target_id=Identifier.generate(99), - entity_type=[], + entity_type=["ExtractedFoo", "ExtractedBar", "ExtractedBatz"], skip=10, limit=100, ) @@ -206,17 +207,9 @@ def test_mocked_graph_fetch_extracted_items(mocked_graph: MockedGraph) -> None: )""", { "labels": [ - "ExtractedAccessPlatform", - "ExtractedActivity", - "ExtractedContactPoint", - "ExtractedDistribution", - "ExtractedOrganization", - "ExtractedOrganizationalUnit", - "ExtractedPerson", - "ExtractedPrimarySource", - "ExtractedResource", - "ExtractedVariable", - "ExtractedVariableGroup", + "ExtractedFoo", + "ExtractedBar", + "ExtractedBatz", ], "limit": 100, "query_string": "my-query", @@ -288,7 +281,7 @@ def test_mocked_graph_fetch_rule_items(mocked_graph: MockedGraph) -> None: result = graph.fetch_rule_items( query_string="my-query", stable_target_id=Identifier.generate(99), - entity_type=[], + entity_type=["AdditiveFoo", "SubtractiveBar", "PreventiveBatz"], skip=10, limit=100, ) @@ -300,39 +293,9 @@ def test_mocked_graph_fetch_rule_items(mocked_graph: MockedGraph) -> None: )""", { "labels": [ - "AdditiveAccessPlatform", - "AdditiveActivity", - "AdditiveContactPoint", - "AdditiveDistribution", - "AdditiveOrganization", - "AdditiveOrganizationalUnit", - "AdditivePerson", - "AdditivePrimarySource", - "AdditiveResource", - "AdditiveVariable", - "AdditiveVariableGroup", - "SubtractiveAccessPlatform", - "SubtractiveActivity", - "SubtractiveContactPoint", - "SubtractiveDistribution", - "SubtractiveOrganization", - "SubtractiveOrganizationalUnit", - "SubtractivePerson", - "SubtractivePrimarySource", - "SubtractiveResource", - "SubtractiveVariable", - "SubtractiveVariableGroup", - "PreventiveAccessPlatform", - "PreventiveActivity", - "PreventiveContactPoint", - "PreventiveDistribution", - "PreventiveOrganization", - "PreventiveOrganizationalUnit", - "PreventivePerson", - "PreventivePrimarySource", - "PreventiveResource", - "PreventiveVariable", - "PreventiveVariableGroup", + "AdditiveFoo", + "SubtractiveBar", + "PreventiveBatz", ], "limit": 100, "query_string": "my-query", @@ -431,7 +394,7 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: result = graph.fetch_merged_items( query_string="my-query", stable_target_id=Identifier.generate(99), - entity_type=[], + entity_type=["MergedFoo", "MergedBar", "MergedBatz"], skip=10, limit=100, ) @@ -443,17 +406,9 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: )""", { "labels": [ - "MergedAccessPlatform", - "MergedActivity", - "MergedContactPoint", - "MergedDistribution", - "MergedOrganization", - "MergedOrganizationalUnit", - "MergedPerson", - "MergedPrimarySource", - "MergedResource", - "MergedVariable", - "MergedVariableGroup", + "MergedFoo", + "MergedBar", + "MergedBatz", ], "limit": 100, "query_string": "my-query", @@ -601,18 +556,25 @@ def test_mocked_graph_fetch_identities(mocked_graph: MockedGraph) -> None: @pytest.mark.usefixtures("mocked_query_builder") -def test_mocked_graph_exists_merged_item(mocked_graph: MockedGraph) -> None: +def test_mocked_graph_exists_merged_item( + mocked_graph: MockedGraph, monkeypatch: MonkeyPatch +) -> None: + monkeypatch.setattr( + connector_module, + "MERGED_MODEL_CLASSES_BY_NAME", + {"MergedFoo": Mock(), "MergedBar": Mock(), "MergedBatz": Mock()}, + ) mocked_graph.return_value = [{"exists": True}] graph = GraphConnector.get() graph.exists_merged_item( stable_target_id=Identifier.generate(99), - stem_types=["Person", "ContactPoint"], + stem_types=["Foo", "Bar"], ) assert mocked_graph.call_args_list[-1].args == ( """\ -exists_merged_item(node_labels=["MergedPerson", "MergedContactPoint"])""", +exists_merged_item(node_labels=["MergedFoo", "MergedBar"])""", {"identifier": Identifier.generate(99)}, ) @@ -622,21 +584,7 @@ def test_mocked_graph_exists_merged_item(mocked_graph: MockedGraph) -> None: assert mocked_graph.call_args_list[-1].args == ( """\ -exists_merged_item( - node_labels=[ - "MergedAccessPlatform", - "MergedActivity", - "MergedContactPoint", - "MergedDistribution", - "MergedOrganization", - "MergedOrganizationalUnit", - "MergedPerson", - "MergedPrimarySource", - "MergedResource", - "MergedVariable", - "MergedVariableGroup", - ] -)""", +exists_merged_item(node_labels=["MergedFoo", "MergedBar", "MergedBatz"])""", {"identifier": Identifier.generate(99)}, ) @@ -779,6 +727,6 @@ def test_mocked_graph_creates_rule_set( @pytest.mark.usefixtures("mocked_graph") def test_mocked_graph_ingests_models(dummy_data: dict[str, AnyExtractedModel]) -> None: graph = GraphConnector.get() - identifiers = graph.ingest(dummy_data.values()) + identifiers = graph.ingest(list(dummy_data.values())) assert identifiers == [d.identifier for d in dummy_data.values()] diff --git a/tests/graph/test_transform.py b/tests/graph/test_transform.py index 315ae191..9cfbc4a8 100644 --- a/tests/graph/test_transform.py +++ b/tests/graph/test_transform.py @@ -38,7 +38,7 @@ def test_expand_references_in_search_result() -> None: "identifier": "bFQoRhcVH5DHUA", "identifierInPrimarySource": "a-1", "start": [], - "theme": ["https://mex.rki.de/item/theme-3"], + "theme": ["https://mex.rki.de/item/theme-11"], } expand_references_in_search_result(node_dict) @@ -51,7 +51,7 @@ def test_expand_references_in_search_result() -> None: "identifier": "bFQoRhcVH5DHUA", "identifierInPrimarySource": "a-1", "start": [], - "theme": ["https://mex.rki.de/item/theme-3"], + "theme": ["https://mex.rki.de/item/theme-11"], "responsibleUnit": ["bFQoRhcVH5DHUz"], "contact": ["bFQoRhcVH5DHUv", "bFQoRhcVH5DHUx", "bFQoRhcVH5DHUz"], "hadPrimarySource": ["bFQoRhcVH5DHUr"], diff --git a/tests/identity/test_main.py b/tests/identity/test_main.py index f1f282f7..2fcf10a0 100644 --- a/tests/identity/test_main.py +++ b/tests/identity/test_main.py @@ -60,7 +60,7 @@ def test_assign_identity_mocked( ) -> None: mocked_graph.return_value = mocked_return response = client_with_api_key_write_permission.post("/v0/identity", json=post_body) - assert response.status_code == status, response.text + assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == expected diff --git a/tests/ingest/test_main.py b/tests/ingest/test_main.py index 9a53b23e..acb28aa7 100644 --- a/tests/ingest/test_main.py +++ b/tests/ingest/test_main.py @@ -6,7 +6,7 @@ from starlette import status from mex.backend.graph.connector import GraphConnector -from mex.common.models import AnyExtractedModel +from mex.common.models import EXTRACTED_MODEL_CLASSES, AnyExtractedModel from tests.conftest import MockedGraph Payload = dict[str, list[dict[str, Any]]] @@ -56,7 +56,7 @@ def test_bulk_insert( def test_bulk_insert_malformed( client_with_api_key_write_permission: TestClient, ) -> None: - expected_res = [] + expected_response = [] exp_err = { "ctx": {"error": {}}, "input": "FAIL!", @@ -65,14 +65,14 @@ def test_bulk_insert_malformed( "other types is not supported for models with computed fields.", "type": "assertion_error", } - expected_res += [exp_err] * 11 + expected_response += [exp_err] * len(EXTRACTED_MODEL_CLASSES) response = client_with_api_key_write_permission.post( "/v0/ingest", json={"items": ["FAIL!"]}, ) assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY, response.text - assert response.json() == {"detail": expected_res} + assert response.json() == {"detail": expected_response} def test_bulk_insert_mocked( diff --git a/tests/preview/test_main.py b/tests/preview/test_main.py index 59d7d26f..81d19b72 100644 --- a/tests/preview/test_main.py +++ b/tests/preview/test_main.py @@ -33,7 +33,7 @@ ], "start": ["2014-08-24"], "end": ["2025"], - "theme": ["https://mex.rki.de/item/theme-3"], + "theme": ["https://mex.rki.de/item/theme-11"], "website": [ { "language": None, @@ -69,7 +69,7 @@ "abstract": [ {"value": "An active activity.", "language": "en"}, ], - "theme": ["https://mex.rki.de/item/theme-3"], + "theme": ["https://mex.rki.de/item/theme-11"], "website": [ { "language": None, diff --git a/tests/test_utils.py b/tests/test_utils.py index 03f37521..cb69964f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -48,13 +48,16 @@ def add(a: int, b: int) -> int: def test_reraising_with_caught_exception() -> None: + class CustomDivisionError(Exception): + pass + def divide(a: int, b: int) -> float: return a / b - with pytest.raises(ValueError, match="division by zero") as exc_info: - reraising(ZeroDivisionError, ValueError, divide, 1, 0) + with pytest.raises(CustomDivisionError) as exc_info: + reraising(ZeroDivisionError, CustomDivisionError, divide, 1, 0) - assert isinstance(exc_info.value, ValueError) + assert isinstance(exc_info.value, CustomDivisionError) assert exc_info.value.__cause__ is not None assert isinstance(exc_info.value.__cause__, ZeroDivisionError)