Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Handle exceptions in Vardef client #75

Merged
merged 34 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a079340
add create draft exception example
tilen1976 Dec 6, 2024
7e8abba
Add test invalid unit types - correct unittypes happy path
tilen1976 Dec 6, 2024
e29b083
change exception
tilen1976 Dec 6, 2024
0bf1efc
add test exception message
tilen1976 Dec 6, 2024
d7adca5
assert 404 not working correctly
tilen1976 Dec 6, 2024
981b682
add new open api file
tilen1976 Dec 7, 2024
9eef1d6
specify exception
tilen1976 Dec 9, 2024
7391582
linting
tilen1976 Dec 9, 2024
dff02c4
update short name
tilen1976 Dec 9, 2024
ad7d303
Remove bad request example - add not found variable definition exampl…
tilen1976 Dec 9, 2024
6d2c333
last edition not found
tilen1976 Dec 9, 2024
07144c2
remove fixture
tilen1976 Dec 9, 2024
dfcd030
updated open api spec
tilen1976 Dec 10, 2024
63a93ad
Test custom exception message
tilen1976 Dec 10, 2024
62e52f9
handle constraint violations
tilen1976 Dec 10, 2024
f002d13
update open api file
tilen1976 Dec 10, 2024
f0a26a3
update open api file
tilen1976 Dec 11, 2024
01462a4
add tests for constraint violations
tilen1976 Dec 11, 2024
1c32418
add tests for missing elements
tilen1976 Dec 11, 2024
65424a5
update open api file with new excptions
tilen1976 Dec 11, 2024
ba6e735
update tests with new exception structure
tilen1976 Dec 11, 2024
3908cc3
start of decorator for vardef client exception handling
tilen1976 Dec 12, 2024
ffa4018
Merge branch 'main' into feat/vardef-client-add-tests-exceptions
tilen1976 Dec 12, 2024
6045bb8
decorator ok
tilen1976 Dec 12, 2024
1504eee
set temp type ignore
tilen1976 Dec 12, 2024
180984a
rename test
tilen1976 Dec 12, 2024
dc0c42d
Remove local testcontainer path
tilen1976 Dec 12, 2024
4e5cf3f
Update src/dapla_metadata/variable_definitions/exceptions.py
tilen1976 Dec 12, 2024
56d527c
Update src/dapla_metadata/variable_definitions/exceptions.py
tilen1976 Dec 12, 2024
dc21337
Move testcontainer dependency to dev
tilen1976 Dec 12, 2024
9f22080
Merge branch 'feat/vardef-client-add-tests-exceptions' of github.com:…
tilen1976 Dec 12, 2024
2bd4547
format violations inline to add default messages - remove formatting …
tilen1976 Dec 12, 2024
790b241
delete unnecessary tests
tilen1976 Dec 13, 2024
48efec1
Merge branch 'main' into feat/vardef-client-add-tests-exceptions
tilen1976 Dec 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions src/dapla_metadata/variable_definitions/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Vardef client exceptions."""

import json
from functools import wraps

from dapla_metadata.variable_definitions.generated.vardef_client.exceptions import (
OpenApiException,
)


class VardefClientException(OpenApiException):
"""Custom exception to represent errors encountered in the Vardef client.

This exception extracts and formats error details from a JSON response body
provided by the Vardef API, enabling more descriptive error messages.
If the response body cannot be parsed as JSON or lacks expected keys,
default values are used to provide meaningful feedback.
"""

def __init__(self, response_body: str) -> None:
"""Initialize the exception with a JSON-formatted response body.

Args:
response_body (str): The JSON string containing error details
from the Vardef API response.

Attributes:
status (str): The status code from the response, or "Unknown status"
if not available or the response is invalid.
detail (str || list): A detailed error message from the response, or
"No detail provided" if not provided. If "Constraint violation"
the detail is a list with field and message.
response_body (str): The raw response body string, stored for
debugging purposes.
"""
self.detail: str | list
try:
data = json.loads(response_body)
self.status = data.get("status", "Unknown status")
if data.get("title") == "Constraint Violation":
violations = data.get("violations", [])
self.detail = [
{
"field": violation.get("field", "Unknown field"),
"message": violation.get("message", "No message provided"),
}
for violation in violations
]
else:
self.detail = data.get("detail", "No detail provided")
self.response_body = response_body
except (json.JSONDecodeError, TypeError):
self.status = "Unknown"
self.detail = "Could not decode error response from API"
data = None
super().__init__(f"Status {self.status}: {self.detail}")


def vardef_exception_handler(method): # noqa: ANN201, ANN001
"""Decorator for handling exceptions in Vardef."""

@wraps(method)
def _impl(self, *method_args, **method_kwargs): # noqa: ANN001, ANN002, ANN003
try:
return method(self, *method_args, **method_kwargs)
except OpenApiException as e:
raise VardefClientException(e.body) from e

return _impl
3 changes: 3 additions & 0 deletions src/dapla_metadata/variable_definitions/vardef.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from dapla_metadata.variable_definitions import config
from dapla_metadata.variable_definitions._client import VardefClient
from dapla_metadata.variable_definitions.exceptions import vardef_exception_handler
from dapla_metadata.variable_definitions.generated.vardef_client.api.data_migration_api import (
DataMigrationApi,
)
Expand Down Expand Up @@ -113,6 +114,7 @@ def migrate_from_vardok(cls, vardok_id: str) -> VariableDefinition:
)

@classmethod
@vardef_exception_handler
def list_variable_definitions(
cls,
date_of_validity: date | None = None,
Expand Down Expand Up @@ -141,6 +143,7 @@ def list_variable_definitions(
]

@classmethod
@vardef_exception_handler
def get_variable_definition(
cls,
variable_definition_id: str,
Expand Down
78 changes: 78 additions & 0 deletions tests/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,81 @@
DAPLA_REGION = "DAPLA_REGION"
DAPLA_GROUP_CONTEXT = "DAPLA_GROUP_CONTEXT"
DAPLA_SERVICE = "DAPLA_SERVICE"
NOT_FOUND_STATUS = 404
BAD_REQUEST_STATUS = 400
CONSTRAINT_VIOLATION_BODY = """{
"cause": null,
"suppressed": [
],
"detail": null,
"instance": null,
"parameters": {
},
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Constraint Violation",
"status": 400,
"violations": [
{
"field": "updateVariableDefinitionById.updateDraft.owner.team",
"message": "Invalid Dapla team"
},
{
"field": "updateVariableDefinitionById.updateDraft.owner.team",
"message": "must not be empty"
}
]
}"""
CONSTRAINT_VIOLATION_BODY_MISSING_MESSAGES = """{
"cause": null,
"suppressed": [
],
"detail": null,
"instance": null,
"parameters": {
},
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Constraint Violation",
"status": 400,
"violations": [
{
"field": "updateVariableDefinitionById.updateDraft.owner.team"
},
{
"field": "updateVariableDefinitionById.updateDraft.owner.team"
}
]
}"""

CONSTRAINT_VIOLATION_BODY_MISSING_VIOLATIONS = """{
"cause": null,
"suppressed": [
],
"detail": null,
"instance": null,
"parameters": {
},
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Constraint Violation",
"status": 400,
"violations": []
}"""
CONSTRAINT_VIOLATION_BODY_MISSING_FIELD = """{
"cause": null,
"suppressed": [
],
"detail": null,
"instance": null,
"parameters": {
},
"type": "https://zalando.github.io/problem/constraint-violation",
"title": "Constraint Violation",
"status": 400,
"violations": [
{
"message": "Invalid Dapla team"
},
{
"message": "must not be empty"
}
]
}"""
2 changes: 1 addition & 1 deletion tests/variable_definitions/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def draft(language_string_type, contact) -> Draft:
short_name="test",
definition=language_string_type,
classification_reference="91",
unit_types=["a", "b"],
unit_types=["01"],
subject_fields=["a", "b"],
contains_sensitive_personal_information=True,
measurement_type="test",
Expand Down
13 changes: 13 additions & 0 deletions tests/variable_definitions/test_vardef.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from dapla_metadata._shared.config import DAPLA_GROUP_CONTEXT
from dapla_metadata.variable_definitions._client import VardefClient
from dapla_metadata.variable_definitions.exceptions import VardefClientException
from dapla_metadata.variable_definitions.generated.vardef_client.configuration import (
Configuration,
)
Expand All @@ -16,6 +17,7 @@
)
from dapla_metadata.variable_definitions.vardef import Vardef
from dapla_metadata.variable_definitions.variable_definition import VariableDefinition
from tests.utils.constants import NOT_FOUND_STATUS
from tests.utils.constants import VARDEF_EXAMPLE_ACTIVE_GROUP
from tests.utils.constants import VARDEF_EXAMPLE_DATE
from tests.utils.constants import VARDEF_EXAMPLE_DEFINITION_ID
Expand Down Expand Up @@ -45,6 +47,17 @@ def test_get_variable_definition(client_configuration: Configuration):
assert landbak.classification_reference == "91"


def test_get_variable_definition_invalid_id(client_configuration: Configuration):
VardefClient.set_config(client_configuration)
with pytest.raises(VardefClientException) as e:
Vardef.get_variable_definition(
variable_definition_id="invalid id",
)
assert e.value.status == NOT_FOUND_STATUS
assert e.value.detail == "Not found"
assert str(e.value) == "Status 404: Not found"


def test_list_patches(client_configuration: Configuration):
VardefClient.set_config(client_configuration)
landbak = Vardef.get_variable_definition(
Expand Down
Loading
Loading