diff --git a/pyproject.toml b/pyproject.toml index a7ddf34..cc1e2a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "support_formatter" -version = "0.2.0" +version = "0.2.1" requires-python = ">= 3.10" authors = [{name = "Firq", email = "firelp42@gmail.com"}] maintainers = [{name = "Firq", email = "firelp42@gmail.com"}] diff --git a/support_formatter/logic/csv_processor.py b/support_formatter/logic/csv_processor.py index 17634f0..3a3a071 100644 --- a/support_formatter/logic/csv_processor.py +++ b/support_formatter/logic/csv_processor.py @@ -1,6 +1,9 @@ import csv import pathlib +from ..utils import convert_to_bool + + class FileTypeInvalidError(ValueError): pass @@ -30,7 +33,7 @@ def process_csv(path: pathlib.Path): entry.update({ "level": int(entry['level']), "np_level": int(entry['np_level']), - "bce": bool(entry["bce"]) + "bce": convert_to_bool(entry["bce"]) }) else: entry.update({ diff --git a/support_formatter/models/interface.py b/support_formatter/models/interface.py index 56a8e29..a75ea62 100644 --- a/support_formatter/models/interface.py +++ b/support_formatter/models/interface.py @@ -1,6 +1,8 @@ from enum import Enum + import marshmallow as ma + class HealthStatus(Enum): OK = 0 WARNING = 1 diff --git a/support_formatter/routes/interface.py b/support_formatter/routes/interface.py index e9d211e..d7e5c93 100644 --- a/support_formatter/routes/interface.py +++ b/support_formatter/routes/interface.py @@ -6,7 +6,6 @@ from flask.views import MethodView from ..app import Application from ..config import APISettings from ..models.interface import ApiVersionGet, HealthGet, HealthStatus, OpenAPIGet - from . import interface_routes as blp APP = Application.get_instance() diff --git a/support_formatter/routes/upload.py b/support_formatter/routes/upload.py index ab72d3d..6d55d24 100644 --- a/support_formatter/routes/upload.py +++ b/support_formatter/routes/upload.py @@ -1,15 +1,16 @@ import os import pathlib +import uuid from typing import List + import marshmallow as ma from flask_smorest.fields import Upload from werkzeug.datastructures import FileStorage -import uuid - from ..app import Application from ..config import APISettings -from ..logic.csv_processor import process_csv, FileTypeInvalidError +from ..logic.csv_processor import FileTypeInvalidError, process_csv +from ..utils import generate_error from . import formatter_routes as blp APP = Application.get_instance() @@ -38,28 +39,28 @@ def upload_file(form: dict[str, str], files: dict[str, FileStorage]): for name, file in files.items(): if name not in ("servantdata", "cedata"): - return { "status": 406, "message": "Invalid form sent" }, 406 + return generate_error(406, message="Invalid form sent") filepath = APISettings.FILE_SAVE_DIRECTORY / f"{uuid.uuid4()}.csv" file.save(filepath) if os.stat(filepath).st_size < 1 or not allowed_file(file.filename): - filepath.unlink() + filepath.unlink(missing_ok=True) continue filepaths.append(filepath) if len(filepaths) == 0: - return { "status": 406, "message": "No files provided" }, 406 + return generate_error(406, message="No files provided") try: for f in filepaths: result = process_csv(f) returndata = returndata | result - f.unlink() + f.unlink(missing_ok=True) except FileTypeInvalidError: for f in filepaths: - f.unlink() - return { "status": 500, "message": "Error whilst parsing uploaded file - please contact Firq on Fate/Sacc Order" }, 406 + f.unlink(missing_ok=True) + return generate_error(500, message="Error whilst parsing uploaded file - please contact Firq on Fate/Sacc Order") return returndata diff --git a/support_formatter/utils.py b/support_formatter/utils.py new file mode 100644 index 0000000..bf12636 --- /dev/null +++ b/support_formatter/utils.py @@ -0,0 +1,19 @@ +from typing import Any, Optional, Tuple, TypedDict + + +class ErrorReturn(TypedDict): + status: int + message: Optional[str] + details: Optional[dict[str, Any]] + + +def generate_error(status: int, message: Optional[str]=None, additional_data: Optional[dict[str, Any]]=None) -> Tuple[ErrorReturn, int]: + obj: ErrorReturn = { "status": status } + if message is not None: + obj |= { "message": message } + if additional_data is not None: + obj |= { "details": additional_data } + return obj, status + +def convert_to_bool(val: str) -> bool: + return bool(val) if str(val).lower() not in ("null", "none") else False