Compare commits

..

3 Commits

Author SHA1 Message Date
969333998c [UPD] Exception handling 2026-02-15 20:53:32 +01:00
2a8a44e80b [WIP] Exception handling 2026-02-15 17:39:21 +01:00
7c3593d066 [UPD] Delete Library 2026-02-15 16:34:43 +01:00
19 changed files with 199 additions and 74 deletions

View File

@@ -1,10 +1,17 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import IntegrityError
from app.api.cruds.base import create, read, update, delete, read_all
from app.schema.library import Library
from ..db.config.config import get_engine_configuration
from sqlalchemy.exc import NoResultFound
from .exceptions import LibraryCreationException
from .exceptions import LibraryReadException
from .exceptions import LibraryUpdateException
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
@@ -65,21 +72,46 @@ class LibraryController:
return True
return False
#CRUDS
def create(self, library:Library):
self._library = create(self.session, library)
try:
self._library = create(self.session, library)
except IntegrityError as e:
raise LibraryCreationException(
"Cannot create library",
f"{e.orig}",
"library",
str(library)
)
return self
def read(self, _id):
self._library = read(self.session, _id, Library)
try:
self._library = read(self.session, _id, Library)
except NoResultFound as e:
raise LibraryReadException(
f"Cannot read Library with id {_id}",
f"{e}",
"library",
_id
)
return self
def read_all(self):
self._libraries = read_all(self.session, Library)
def update(self):
self.session.commit()
try:
self.session.commit()
except IntegrityError as e:
raise LibraryUpdateException(
f"Cannot update Library",
f"{e}",
"library",
None
)
def delete(self):
delete(self.session, self)
delete(self.session, self.data)
del(self)

View File

@@ -0,0 +1,5 @@
from .base import LibraryExceptionBase
from .exc_01000X_data import LibraryDataExection
from .exc_01001X_create import LibraryCreationException
from .exc_01002X_read import LibraryReadException
from .exc_01003X_update import LibraryUpdateException

View File

@@ -0,0 +1,26 @@
class LibraryExceptionBase(Exception):
def __init__(self, name, error, object_name, data, *, status_code=400):
self.code = "000000"
self.name = name
self.error = error
self.object = object_name
self.data = data
self.status_code = status_code
def to_dict(self):
return {
"status": "error",
"name": self.name,
"code": self.code,
"error": self.error,
"object": self.object,
"data": self.data,
"status_code": self.status_code
}
def __str__(self):
return f"ERROR {self.code}: {self.error}"
def __repr__(self):
return f"{self.__class__}(code={self.code!r}, error={self.error!r}), " \
f"object={self.object!r}, data={self.data!r}, status_code={self._status_code})"

View File

@@ -0,0 +1,7 @@
from .base import LibraryExceptionBase
#010010
class LibraryDataExection(LibraryExceptionBase):
def __init__(self, name, error, object_name, data, *, status_code=400):
self.code = "010000"
super().__init__(name, error, object_name, data, status_code=status_code)

View File

@@ -0,0 +1,7 @@
from .base import LibraryExceptionBase
#010010
class LibraryCreationException(LibraryExceptionBase):
def __init__(self, name, error, object_name, data, *, status_code=400):
self.code = "010010"
super().__init__(name, error, object_name, data, status_code=status_code)

View File

@@ -0,0 +1,7 @@
from .base import LibraryExceptionBase
#010030
class LibraryReadException(LibraryExceptionBase):
def __init__(self, name, error, object_name, data, status_code=404):
super().__init__(name, error, object_name, data, status_code=status_code)
self.code = "010030"

View File

@@ -0,0 +1,7 @@
from .base import LibraryExceptionBase
#010020
class LibraryUpdateException(LibraryExceptionBase):
def __init__(self, name, error, object_name, data, status_code=404):
super().__init__(name, error, object_name, data, status_code=status_code)
self.code = "010020"

View File

@@ -0,0 +1 @@
from .update_item_key import update_item_key

View File

@@ -0,0 +1,21 @@
from ..exceptions import LibraryDataExection
from ...schema.library import Base
def update_item_key(obj:Base, key, value):
if key == "id":
raise LibraryDataExection(
"id is not updatable",
"The key ID is not Updatable",
obj.__class__,
{key: value}
)
try:
obj.__getattribute__(key)
except AttributeError:
raise LibraryDataExection(
f"{key} not in {obj.__class__}",
f"The key {key} is not in {obj.__class__}",
obj.__class__,
{key: value}
)
obj.__setattr__(key, value)

View File

@@ -1 +1,40 @@
from flask import json, make_response
from werkzeug.exceptions import HTTPException
from .api import api
from ..controller.exceptions import LibraryExceptionBase
@api.errorhandler(LibraryExceptionBase)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = make_response()
# replace the body with JSON
response.data = json.dumps({
"status": "error",
"code": e.code,
"status_code": e.status_code,
"name": e.name,
"error": e.error,
"data": e.data
})
response.content_type = "application/json"
response.status_code = e.status_code
return response
@api.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"status": "error",
"code": f"000{e.code}",
"status_code": e.code,
"name": e.name,
"error": e.description,
})
response.content_type = "application/json"
return response

View File

@@ -1,5 +1,4 @@
from flask import request
from sqlalchemy.exc import IntegrityError
from .blueprint import api_library
@@ -11,18 +10,10 @@ logger = logging.getLogger(__name__)
@api_library.route("/", methods=["POST"])
def create_library():
try:
data = request.json
except Exception as e:
logger.debug(f"{e}")
return { "status": "error", "error": "JSON Required" }, 415
data = request.json
with LibraryController() as controller:
try:
lib = Library(**data)
library = controller.create(lib)
except IntegrityError as e:
logger.debug(f"DB Error Creating {e}")
return { "status": "error", "error": f"{e.orig}" }, 400
else:
return { "status": "ok", "result": library.data.to_dict() }, 200
lib = Library(**data)
library = controller.create(lib)
return { "status": "ok", "result": library.data.to_dict() }, 200

View File

@@ -12,11 +12,7 @@ logger = logging.getLogger(__name__)
@api_library.route("/<_id>", methods=["DELETE"])
def delete_library(_id):
try: # TODO: function
controller = LibraryController(_id)
except NoResultFound as e:
logger.debug({e})
return { "status": "error", "error": "Library not found" }, 404
controller = LibraryController(_id)
controller.delete()

View File

@@ -17,11 +17,5 @@ def read_libraries():
@api_library.route("/<_id>", methods=["GET"])
def read_library(_id):
try:
library = LibraryController(_id)
except NoResultFound as e:
logger.debug(f"No result found for Library wid id {_id}")
logger.debug(f"Error {e}")
logger.debug(f"Error {dir(e)}")
return { "status": "error", "result": "Library not found"}, 404
library = LibraryController(_id)
return { "status": "ok", "result": library.data.to_dict() }, 200

View File

@@ -4,47 +4,24 @@ from sqlalchemy.exc import IntegrityError, NoResultFound
from .blueprint import api_library
from ....controller import LibraryController
from ....controller.functions import update_item_key
from ....schema.library.library import Library
import logging
logger = logging.getLogger(__name__)
def update_library_item(library:Library, key, value):
if key == "id":
raise AttributeError("id is not updatable")
try:
library.__getattribute__(key)
except AttributeError:
raise AttributeError(f"{key} not in library")
library.__setattr__(key, value)
@api_library.route("/<_id>", methods=["PATCH"])
def update_library(_id):
try:
data:dict = request.json
logger.debug(f"data: {data}")
except Exception as e:
logger.debug(f"{e}")
return { "status": "error", "error": "JSON Required" }, 415
try: # TODO: function
controller = LibraryController(_id)
except NoResultFound as e:
logger.debug({e})
return { "status": "error", "error": "Library not found" }, 404
data:dict = request.json
controller = LibraryController(_id)
library = controller.data
for key, value in data.items():
try:
update_library_item(library, key, value)
except AttributeError as e:
logger.debug(f"Error updating {e}")
return { "status": "error", "error": e.name }
update_item_key(library, key, value)
try:
controller.update()
except IntegrityError as e:
logger.debug(f"DB Error Creating {e}")
return { "status": "error", "error": f"{e.orig}" }, 400
else:
return { "status": "ok", "result": controller.data.to_dict() }, 200
controller.update()
return { "status": "ok", "result": controller.data.to_dict() }, 200

View File

@@ -3,5 +3,5 @@ query = sqlite:///test.db
[App]
port = 15012
debug = False
debug = True

View File

@@ -1,4 +1,4 @@
__version__ = "0.2.0.dev"
from app import app
from app.config import config

BIN
test.db

Binary file not shown.

View File

@@ -1,17 +1,19 @@
import os
import unittest
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import NoResultFound
from app.api.actions import install
from app.schema.library import Library, Tag, Book, BookTag, Path, Env
from app.controller import LibraryController
from app.controller.exceptions import LibraryReadException
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
class TestDB(unittest.TestCase):
class TestController(unittest.TestCase):
def setUp(self):
os.environ["DEV_URIA_BIBLIOGAME_CONFIG_DB"] = "sqlite:///"
@@ -137,6 +139,11 @@ class TestDB(unittest.TestCase):
self.assertNotEqual(book.name, "Test book")
self.assertEqual(book.name, "Another Book on the shelf")
def test_delete_library(self):
library = LibraryController(1, engine=self.engine)
library.delete()
self.assertRaises(LibraryReadException, LibraryController, 1, engine=self.engine)
if __name__ == "__main__":
unittest.main()

View File

@@ -2,11 +2,13 @@ import os
import unittest
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import NoResultFound
from app.api.actions import install
from app.api.cruds.base import create, read, update
from app.api.cruds.base import create, read, update, delete
from app.schema.library import Library, Path, Env, Book, Tag, BookTag
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
@@ -137,6 +139,12 @@ class TestDB(unittest.TestCase):
self.assertNotEqual(book.name, "Test book")
self.assertEqual(book.name, "Another Book on the shelf")
def test_delete_library(self):
library = read(self.session, 1, Library)
delete(self.session, library)
self.assertRaises(NoResultFound, read, self.session, 1, Library)
if __name__ == "__main__":
unittest.main()