adding result objects, renaming components

This commit is contained in:
Florian Förster 2025-03-05 14:35:29 +01:00
parent ec63840ccc
commit c375d8e9d4
7 changed files with 73 additions and 57 deletions

View File

@ -11,11 +11,10 @@ from xgboost import XGBRegressor
from delta_barth._management import ERROR_HANDLER from delta_barth._management import ERROR_HANDLER
from delta_barth.analysis import parse from delta_barth.analysis import parse
from delta_barth.constants import COL_MAP_SALES_PROGNOSIS, FEATURES_SALES_PROGNOSIS from delta_barth.constants import COL_MAP_SALES_PROGNOSIS, FEATURES_SALES_PROGNOSIS
from delta_barth.types import CustomerDataSalesForecast, DataPipelineErrors, doptResult from delta_barth.types import CustomerDataSalesForecast, DataPipeStates, PipeResult
if TYPE_CHECKING: if TYPE_CHECKING:
from delta_barth.api.common import SalesPrognosisResponse from delta_barth.api.common import SalesPrognosisResponse
from delta_barth.types import FcResult
# TODO check pandera for DataFrame validation # TODO check pandera for DataFrame validation
@ -66,7 +65,7 @@ def sales_per_customer(
data: pd.DataFrame, data: pd.DataFrame,
customer_id: int, customer_id: int,
min_num_data_points: int = 100, min_num_data_points: int = 100,
) -> doptResult: ) -> PipeResult:
"""_summary_ """_summary_
Parameters Parameters
@ -106,7 +105,7 @@ def sales_per_customer(
# check data availability # check data availability
if len(df_cust) < min_num_data_points: if len(df_cust) < min_num_data_points:
return doptResult(resp=ERROR_HANDLER.data_pipelines.TOO_FEW_POINTS, res=None) return PipeResult(status=ERROR_HANDLER.pipe_states.TOO_FEW_POINTS, data=None)
else: else:
# Entwicklung der Umsätze: definierte Zeiträume Monat # Entwicklung der Umsätze: definierte Zeiträume Monat
df_cust["year"] = df_cust["date"].dt.year df_cust["year"] = df_cust["date"].dt.year
@ -145,4 +144,4 @@ def sales_per_customer(
test = test.reset_index(drop=True) test = test.reset_index(drop=True)
# umsetzung, prognose # umsetzung, prognose
return doptResult(resp=ERROR_HANDLER.data_pipelines.SUCCESS, res=test) return PipeResult(status=ERROR_HANDLER.pipe_states.SUCCESS, data=test)

View File

@ -14,22 +14,11 @@ from delta_barth.errors import (
UnknownApiErrorCode, UnknownApiErrorCode,
UnspecifiedRequestType, UnspecifiedRequestType,
) )
from delta_barth.types import HttpRequestTypes from delta_barth.types import DelBarApiError, HttpRequestTypes
LOGIN_ERROR_CODES_KNOWN: Final[frozenset[int]] = frozenset((400, 401, 409, 500)) LOGIN_ERROR_CODES_KNOWN: Final[frozenset[int]] = frozenset((400, 401, 409, 500))
class DelBarApiError(BaseModel):
status_code: int
message: str = ""
code: str | None = None
hints: str | None = None
type: str | None = None
title: str | None = None
errors: dict | None = None
traceId: str | None = None
def _raise_for_unknown_error( def _raise_for_unknown_error(
resp: Response, resp: Response,
) -> Never: ) -> Never:

View File

@ -5,6 +5,7 @@ from delta_barth.types import CurrentConnection, HttpContentHeaders
# ** error handling # ** error handling
DEFAULT_INTERNAL_ERR_CODE: Final[int] = 100 DEFAULT_INTERNAL_ERR_CODE: Final[int] = 100
DEFAULT_API_ERR_CODE: Final[int] = 400
HTTP_BASE_CONTENT_HEADERS: Final[HttpContentHeaders] = { HTTP_BASE_CONTENT_HEADERS: Final[HttpContentHeaders] = {
"Content-type": "application/json", "Content-type": "application/json",

View File

@ -2,11 +2,11 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Final from typing import TYPE_CHECKING, Final
from delta_barth.constants import DEFAULT_INTERNAL_ERR_CODE from delta_barth.constants import DEFAULT_API_ERR_CODE, DEFAULT_INTERNAL_ERR_CODE
from delta_barth.types import DataPipelineErrors, doptResponse from delta_barth.types import DataPipeStates, Status
if TYPE_CHECKING: if TYPE_CHECKING:
from delta_barth.types import ErrorDescription from delta_barth.types import DelBarApiError, ErrorDescription
class UnspecifiedRequestType(Exception): class UnspecifiedRequestType(Exception):
@ -26,7 +26,7 @@ class FeaturesMissingError(Exception):
## ** internal error handling ## ** internal error handling
DATA_PIPELINE_ERRORS_DESCR: Final[tuple[ErrorDescription, ...]] = ( DATA_PIPELINE_STATUS_DESCR: Final[tuple[ErrorDescription, ...]] = (
("SUCCESS", 0, "Erfolg"), ("SUCCESS", 0, "Erfolg"),
("TOO_FEW_POINTS", 1, "Datensatz besitzt nicht genügend Datenpunkte"), ("TOO_FEW_POINTS", 1, "Datensatz besitzt nicht genügend Datenpunkte"),
("BAD_QUALITY", 2, "Prognosequalität des Modells unzureichend"), ("BAD_QUALITY", 2, "Prognosequalität des Modells unzureichend"),
@ -35,33 +35,48 @@ DATA_PIPELINE_ERRORS_DESCR: Final[tuple[ErrorDescription, ...]] = (
class ErrorHandler: class ErrorHandler:
def __init__(self) -> None: def __init__(self) -> None:
self._data_pipelines: DataPipelineErrors | None = None self._pipe_states: DataPipeStates | None = None
self._parse_data_pipeline_errors() self._parse_data_pipe_states()
@property @property
def data_pipelines(self) -> DataPipelineErrors: def pipe_states(self) -> DataPipeStates:
assert self._data_pipelines is not None, ( assert self._pipe_states is not None, (
"tried to access not parsed data pipeline errors" "tried to access not parsed data pipeline errors"
) )
return self._data_pipelines return self._pipe_states
def _parse_data_pipeline_errors(self) -> None: def _parse_data_pipe_states(self) -> None:
if self._data_pipelines is not None: if self._pipe_states is not None:
return return
parsed_errors: dict[str, doptResponse] = {} parsed_errors: dict[str, Status] = {}
for err in DATA_PIPELINE_ERRORS_DESCR: for err in DATA_PIPELINE_STATUS_DESCR:
parsed_errors[err[0]] = doptResponse(status_code=err[1], description=err[2]) parsed_errors[err[0]] = Status(status_code=err[1], description=err[2])
self._data_pipelines = DataPipelineErrors(**parsed_errors) self._pipe_states = DataPipeStates(**parsed_errors)
def internal_error( def error(
self, self,
description: str, description: str,
message: str = "", message: str = "",
err_code: int = DEFAULT_INTERNAL_ERR_CODE, err_code: int = DEFAULT_INTERNAL_ERR_CODE,
) -> doptResponse: ) -> Status:
return doptResponse( return Status(
status_code=err_code, status_code=err_code,
description=description, description=description,
message=message, message=message,
) )
def api_error(
self,
error: DelBarApiError,
) -> Status:
description = "Es ist ein Fehler bei der Kommunikation mit dem API-Server aufgetreten"
message = (
"Bitte beachten Sie die zusätzliche Fehlerausgabe des Servers in dieser Antwort"
)
return Status(
status_code=DEFAULT_API_ERR_CODE,
description=description,
message=message,
api_server_error=error,
)

View File

@ -12,17 +12,29 @@ from pydantic import BaseModel, SkipValidation
ErrorDescription: TypeAlias = tuple[str, int, str] ErrorDescription: TypeAlias = tuple[str, int, str]
class doptResponse(BaseModel): class Status(BaseModel):
status_code: SkipValidation[int] status_code: SkipValidation[int]
description: SkipValidation[str] description: SkipValidation[str]
message: SkipValidation[str] = "" message: SkipValidation[str] = ""
api_server_error: SkipValidation[DelBarApiError | None] = None
class DelBarApiError(BaseModel):
status_code: int
message: str = ""
code: str | None = None
hints: str | None = None
type: str | None = None
title: str | None = None
errors: dict | None = None
traceId: str | None = None
@dataclass(slots=True) @dataclass(slots=True)
class DataPipelineErrors: class DataPipeStates:
SUCCESS: doptResponse SUCCESS: Status
TOO_FEW_POINTS: doptResponse TOO_FEW_POINTS: Status
BAD_QUALITY: doptResponse BAD_QUALITY: Status
class HttpRequestTypes(enum.StrEnum): class HttpRequestTypes(enum.StrEnum):
@ -92,6 +104,6 @@ class CustomerDataSalesForecast:
@dataclass(slots=True) @dataclass(slots=True)
class doptResult: class PipeResult:
resp: doptResponse status: Status
res: pd.DataFrame | None data: pd.DataFrame | None

View File

@ -5,18 +5,18 @@ from delta_barth.analysis import forecast as fc
def test_sales_per_customer_success(sales_data): def test_sales_per_customer_success(sales_data):
customer_id = 1133 customer_id = 1133
err, res = fc.sales_per_customer(sales_data, customer_id) res = fc.sales_per_customer(sales_data, customer_id)
assert err == 0 assert res.status.status_code == 0
assert res is not None assert res.data is not None
def test_sales_per_customer_too_few_data_points(sales_data): def test_sales_per_customer_too_few_data_points(sales_data):
customer_id = 1000 customer_id = 1000
err, res = fc.sales_per_customer(sales_data, customer_id) res = fc.sales_per_customer(sales_data, customer_id)
assert err == 1 assert res.status.status_code == 1
assert res is None assert res.data is None
def test_parse_api_resp_to_df(exmpl_api_sales_prognosis_resp): def test_parse_api_resp_to_df(exmpl_api_sales_prognosis_resp):

View File

@ -5,25 +5,25 @@ from typing import cast
import delta_barth._management import delta_barth._management
from delta_barth import errors from delta_barth import errors
from delta_barth.types import doptResponse from delta_barth.types import Status
def test_error_handler_parsing(): def test_error_handler_parsing():
predef_errs = errors.DATA_PIPELINE_ERRORS_DESCR predef_errs = errors.DATA_PIPELINE_STATUS_DESCR
err_hdlr = delta_barth._management.ErrorHandler() err_hdlr = delta_barth._management.ErrorHandler()
assert err_hdlr.data_pipelines is not None assert err_hdlr.pipe_states is not None
parsed_pipe_errs = err_hdlr.data_pipelines parsed_pipe_errs = err_hdlr.pipe_states
parsed_pipe_errs = asdict(parsed_pipe_errs) parsed_pipe_errs = asdict(parsed_pipe_errs)
for err in predef_errs: for err in predef_errs:
dopt_err = cast(doptResponse, parsed_pipe_errs[err[0]]) dopt_err = cast(Status, parsed_pipe_errs[err[0]])
assert isinstance(dopt_err, doptResponse) assert isinstance(dopt_err, Status)
assert dopt_err.status_code == err[1] assert dopt_err.status_code == err[1]
assert dopt_err.description == err[2] assert dopt_err.description == err[2]
assert dopt_err.message == "" assert dopt_err.message == ""
err_hdlr._parse_data_pipeline_errors() err_hdlr._parse_data_pipe_states()
def test_error_handler_internal(): def test_error_handler_internal():
@ -32,7 +32,7 @@ def test_error_handler_internal():
ERR_CODE = 101 ERR_CODE = 101
err_hdlr = delta_barth._management.ErrorHandler() err_hdlr = delta_barth._management.ErrorHandler()
new_err = err_hdlr.internal_error( new_err = err_hdlr.error(
description=DESCRIPTION, description=DESCRIPTION,
message=MESSAGE, message=MESSAGE,
err_code=ERR_CODE, err_code=ERR_CODE,