From ce2e99e42b3a6aac8dc22f0e1fccfea44d843bf5 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:10:31 +0100 Subject: [PATCH 01/14] reference_files - use release URL to download files --- acacore/reference_files/ref_files.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/acacore/reference_files/ref_files.py b/acacore/reference_files/ref_files.py index a7369ca..421351e 100644 --- a/acacore/reference_files/ref_files.py +++ b/acacore/reference_files/ref_files.py @@ -10,15 +10,14 @@ from acacore.models.reference_files import Action from acacore.models.reference_files import CustomSignature -actions_url: str = "https://raw.githubusercontent.com/aarhusstadsarkiv/reference-files/main/fileformats.yml" -custom_signatures_url: str = ( - "https://raw.githubusercontent.com/aarhusstadsarkiv/reference-files/main/custom_signatures.json" -) +download_url: str = "https://github.com/aarhusstadsarkiv/reference-files/releases/latest/download/" +actions_file: str = "fileformats.yml" +custom_signatures_file: str = "custom_signatures.json" @lru_cache def _get_actions() -> dict[str, Action]: - response: HTTPResponse = request.urlopen(actions_url) + response: HTTPResponse = request.urlopen(f"{download_url.rstrip('/')}/{actions_file.lstrip('/')}") if response.getcode() != 200: raise HTTPException(response.getcode()) @@ -27,7 +26,7 @@ def _get_actions() -> dict[str, Action]: @lru_cache def _get_custom_signatures() -> list[CustomSignature]: - response: HTTPResponse = request.urlopen(custom_signatures_url) + response: HTTPResponse = request.urlopen(f"{download_url.rstrip('/')}/{custom_signatures_file.lstrip('/')}") if response.getcode() != 200: raise HTTPException(response.getcode()) From 36de32bdfc6c45823df634f52267c2ee8a0cf21f Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:11:08 +0100 Subject: [PATCH 02/14] reference_files - rename ref_files.py to get.py --- acacore/reference_files/__init__.py | 4 ++-- acacore/reference_files/{ref_files.py => get.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename acacore/reference_files/{ref_files.py => get.py} (100%) diff --git a/acacore/reference_files/__init__.py b/acacore/reference_files/__init__.py index dd220e2..094ed1e 100644 --- a/acacore/reference_files/__init__.py +++ b/acacore/reference_files/__init__.py @@ -1,2 +1,2 @@ -from .ref_files import get_actions -from .ref_files import get_custom_signatures +from .get import get_actions +from .get import get_custom_signatures diff --git a/acacore/reference_files/ref_files.py b/acacore/reference_files/get.py similarity index 100% rename from acacore/reference_files/ref_files.py rename to acacore/reference_files/get.py From 0062ba2befc221489c6c269985ffde82cb19af94 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:21:57 +0100 Subject: [PATCH 03/14] reference_files - cached download functions get URL from parameters Avoids cache overriding changes to the URL --- acacore/reference_files/get.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/acacore/reference_files/get.py b/acacore/reference_files/get.py index 421351e..4246be4 100644 --- a/acacore/reference_files/get.py +++ b/acacore/reference_files/get.py @@ -16,8 +16,8 @@ @lru_cache -def _get_actions() -> dict[str, Action]: - response: HTTPResponse = request.urlopen(f"{download_url.rstrip('/')}/{actions_file.lstrip('/')}") +def _get_actions(url: str) -> dict[str, Action]: + response: HTTPResponse = request.urlopen(url) if response.getcode() != 200: raise HTTPException(response.getcode()) @@ -25,8 +25,8 @@ def _get_actions() -> dict[str, Action]: @lru_cache -def _get_custom_signatures() -> list[CustomSignature]: - response: HTTPResponse = request.urlopen(f"{download_url.rstrip('/')}/{custom_signatures_file.lstrip('/')}") +def _get_custom_signatures(url: str) -> list[CustomSignature]: + response: HTTPResponse = request.urlopen(url) if response.getcode() != 200: raise HTTPException(response.getcode()) @@ -48,7 +48,11 @@ def get_actions(use_cache: bool = True) -> dict[str, Action]: See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/actions.yml """ - return _get_actions() if use_cache else _get_actions.__wrapped__() + return ( + _get_actions(f"{download_url.rstrip('/')}/{actions_file.lstrip('/')}") + if use_cache + else _get_actions.__wrapped__() + ) def get_custom_signatures(use_cache: bool = True) -> list[CustomSignature]: @@ -66,4 +70,8 @@ def get_custom_signatures(use_cache: bool = True) -> list[CustomSignature]: See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/custom_signatures.json """ - return _get_custom_signatures() if use_cache else _get_custom_signatures.__wrapped__() + return ( + _get_custom_signatures(f"{download_url.rstrip('/')}/{custom_signatures_file.lstrip('/')}") + if use_cache + else _get_custom_signatures.__wrapped__() + ) From 61e8141eb7308a82463aca4cc55c3e76e90249b1 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:23:46 +0100 Subject: [PATCH 04/14] reference_files - raise HTTPError instead of HTTPException Consistent with built-in behaviour of urlopen, which raises HTTPError automatically on 404 responses. --- acacore/reference_files/get.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acacore/reference_files/get.py b/acacore/reference_files/get.py index 4246be4..ca8b50b 100644 --- a/acacore/reference_files/get.py +++ b/acacore/reference_files/get.py @@ -1,7 +1,7 @@ from functools import lru_cache -from http.client import HTTPException from http.client import HTTPResponse from urllib import request +from urllib.error import HTTPError from pydantic import TypeAdapter from yaml import load @@ -19,7 +19,7 @@ def _get_actions(url: str) -> dict[str, Action]: response: HTTPResponse = request.urlopen(url) if response.getcode() != 200: - raise HTTPException(response.getcode()) + raise HTTPError(url, response.getcode(), "", response.headers, response) return TypeAdapter(dict[str, Action]).validate_python(load(response.read(), Loader)) @@ -28,7 +28,7 @@ def _get_actions(url: str) -> dict[str, Action]: def _get_custom_signatures(url: str) -> list[CustomSignature]: response: HTTPResponse = request.urlopen(url) if response.getcode() != 200: - raise HTTPException(response.getcode()) + raise HTTPError(url, response.getcode(), "", response.headers, response) return TypeAdapter(list[CustomSignature]).validate_json(response.read()) From 5f4455b8b880d081651183d4b81f20fbe8558d57 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:25:05 +0100 Subject: [PATCH 05/14] reference_files - update docstrings with Raises --- acacore/reference_files/get.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/acacore/reference_files/get.py b/acacore/reference_files/get.py index ca8b50b..af2f252 100644 --- a/acacore/reference_files/get.py +++ b/acacore/reference_files/get.py @@ -45,6 +45,9 @@ def get_actions(use_cache: bool = True) -> dict[str, Action]: Returns: dict[str, Action]: A dictionary with PUID keys and Action values. + Raises: + urllib.error.HTTPError: If there is an issue with the request. + See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/actions.yml """ @@ -65,7 +68,10 @@ def get_custom_signatures(use_cache: bool = True) -> list[CustomSignature]: use_cache (bool): Use cached data if True, otherwise fetch data regardless of cache status Returns: - list[CustomSignature]: A list of CustomSignature objects + list[CustomSignature]: A list of CustomSignature objects. + + Raises: + urllib.error.HTTPError: If there is an issue with the request. See Also: https://github.com/aarhusstadsarkiv/reference-files/blob/main/custom_signatures.json From 0eb9d3ed930dd146434bc5bcae90cdabf776444d Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:25:34 +0100 Subject: [PATCH 06/14] reference_files - import urlopen directly --- acacore/reference_files/get.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acacore/reference_files/get.py b/acacore/reference_files/get.py index af2f252..c3a4d48 100644 --- a/acacore/reference_files/get.py +++ b/acacore/reference_files/get.py @@ -1,7 +1,7 @@ from functools import lru_cache from http.client import HTTPResponse -from urllib import request from urllib.error import HTTPError +from urllib.request import urlopen from pydantic import TypeAdapter from yaml import load @@ -17,7 +17,7 @@ @lru_cache def _get_actions(url: str) -> dict[str, Action]: - response: HTTPResponse = request.urlopen(url) + response: HTTPResponse = urlopen(url) if response.getcode() != 200: raise HTTPError(url, response.getcode(), "", response.headers, response) @@ -26,7 +26,7 @@ def _get_actions(url: str) -> dict[str, Action]: @lru_cache def _get_custom_signatures(url: str) -> list[CustomSignature]: - response: HTTPResponse = request.urlopen(url) + response: HTTPResponse = urlopen(url) if response.getcode() != 200: raise HTTPError(url, response.getcode(), "", response.headers, response) From 953ee98e509e8f13d6ca054ed08566ce5d44aa54 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 10:26:42 +0100 Subject: [PATCH 07/14] tests:reference_files - test error --- tests/test_reference_files.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/test_reference_files.py b/tests/test_reference_files.py index e21cc9e..6cdbf1a 100644 --- a/tests/test_reference_files.py +++ b/tests/test_reference_files.py @@ -1,10 +1,21 @@ -from acacore.reference_files import get_actions -from acacore.reference_files import get_custom_signatures +from urllib.error import HTTPError + +import pytest + +import acacore.reference_files as reference_files def test_actions(): - assert get_actions() + assert reference_files.get_actions() + with pytest.raises(HTTPError) as error: + reference_files.get.actions_file = f"wrong/path/{reference_files.get.actions_file}" + reference_files.get_actions() + assert error.value.code == 404 def test_custom_signatures(): - assert get_custom_signatures() + assert reference_files.get_custom_signatures() + with pytest.raises(HTTPError) as error: + reference_files.get.custom_signatures_file = f"wrong/path/{reference_files.get.actions_file}" + reference_files.get_custom_signatures() + assert error.value.code == 404 From 66f526f8add8a6f097d849eeef8a3f5bb23d2449 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:32:04 +0100 Subject: [PATCH 08/14] utils:helpers - let ExceptionManager raise specific exceptions --- acacore/utils/helpers.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/acacore/utils/helpers.py b/acacore/utils/helpers.py index 8044693..9287919 100644 --- a/acacore/utils/helpers.py +++ b/acacore/utils/helpers.py @@ -1,5 +1,6 @@ from types import TracebackType from typing import Optional +from typing import Sequence from typing import Type @@ -14,14 +15,16 @@ class ExceptionManager: exception (Optional[BaseException]): The exception that was raised within the context, if any. traceback (Optional[TracebackType]): The traceback associated with the exception, if any. catch (tuple[Type[BaseException], ...]): Tuple of exceptions that should be caught instead of letting them rise. + allow (tuple[Type[BaseException], ...]): Tuple of exceptions that should be allowed to rise. """ - __slots__ = ("exception", "traceback", "catch") + __slots__ = ("exception", "traceback", "catch", "allow") - def __init__(self, *catch: Type[BaseException]) -> None: + def __init__(self, *catch: Type[BaseException], allow: Optional[Sequence[Type[BaseException]]] = None) -> None: self.exception: Optional[BaseException] = None self.traceback: Optional[TracebackType] = None self.catch: tuple[Type[BaseException], ...] = catch + self.allow: tuple[Type[BaseException], ...] = tuple(allow or []) def __enter__(self) -> "ExceptionManager": return self @@ -34,4 +37,8 @@ def __exit__( ) -> bool: self.exception = exc_val self.traceback = exc_tb - return any(issubclass(exc_type, e) for e in self.catch) if exc_type else False + + if not exc_type: + return False + + return any(issubclass(exc_type, e) for e in self.catch) and not any(issubclass(exc_type, e) for e in self.allow) From fa89e5d382517dc531e3cc0b32b6ed91902a3946 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:32:21 +0100 Subject: [PATCH 09/14] tests:utils - test allow argument of ExceptionManager --- tests/test_utils.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 7446b6c..a5083fc 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -49,13 +49,25 @@ def test_helpers(): assert context.exception.code == 3 assert context.traceback is not None - with pytest.raises(KeyboardInterrupt) as raises, ExceptionManager(Exception) as context: + with ( + pytest.raises(KeyboardInterrupt) as raises, + ExceptionManager(Exception) as context, + ): raise KeyboardInterrupt assert isinstance(raises.value, KeyboardInterrupt) assert isinstance(context.exception, KeyboardInterrupt) assert context.traceback is not None + with ( + pytest.raises(OSError) as raises, # noqa: PT011 + ExceptionManager(BaseException, allow=[OSError]) as context, + ): + raise FileNotFoundError + + assert isinstance(raises.value, FileNotFoundError) + assert isinstance(context.exception, FileNotFoundError) + with ExceptionManager() as context: pass From 011c096e9604bdb55890d7e41180165894e29d5e Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:38:11 +0100 Subject: [PATCH 10/14] utils:helpers - ExceptionManager always catches explicitly declared exceptions --- acacore/utils/helpers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acacore/utils/helpers.py b/acacore/utils/helpers.py index 9287919..24cb50f 100644 --- a/acacore/utils/helpers.py +++ b/acacore/utils/helpers.py @@ -41,4 +41,6 @@ def __exit__( if not exc_type: return False - return any(issubclass(exc_type, e) for e in self.catch) and not any(issubclass(exc_type, e) for e in self.allow) + return any(issubclass(exc_type, e) for e in self.catch) and ( + exc_type in self.catch or not any(issubclass(exc_type, e) for e in self.allow) + ) From cf672689cd5549dc166ed82adb2f4962cd1cb947 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:38:24 +0100 Subject: [PATCH 11/14] tests:utils - update ExceptionManager tests --- tests/test_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_utils.py b/tests/test_utils.py index a5083fc..7efd780 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -68,6 +68,11 @@ def test_helpers(): assert isinstance(raises.value, FileNotFoundError) assert isinstance(context.exception, FileNotFoundError) + with ExceptionManager(BaseException, FileNotFoundError, allow=[OSError]) as context: + raise FileNotFoundError + + assert isinstance(context.exception, FileNotFoundError) + with ExceptionManager() as context: pass From db1cdc89994cf3b11fed25f9753fc46209b5d6ef Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:50:19 +0100 Subject: [PATCH 12/14] utils:helpers - update ExceptionManager docstring Describe behaviour of exceptions whose class is declared in `catch` but whose subclass(es) is in `allow`. --- acacore/utils/helpers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/acacore/utils/helpers.py b/acacore/utils/helpers.py index 24cb50f..e3429c1 100644 --- a/acacore/utils/helpers.py +++ b/acacore/utils/helpers.py @@ -8,6 +8,9 @@ class ExceptionManager: """ A context manager class that catches specified exceptions and stores the exception and traceback for later use. + Exceptions whose class is explicitly declared in the 'catch' argument are always caught, + even if they subclass from classes passed int the 'allow' argument. + Args: *catch (Type[BaseException]): Exception types that should be caught and not allowed to rise. From 53db8a729c7253e8c689a54c576981804094f3fd Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:51:24 +0100 Subject: [PATCH 13/14] version - patch 1.1.1 > 1.1.2 --- acacore/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acacore/__version__.py b/acacore/__version__.py index a82b376..72f26f5 100644 --- a/acacore/__version__.py +++ b/acacore/__version__.py @@ -1 +1 @@ -__version__ = "1.1.1" +__version__ = "1.1.2" From 4de5e0d89d31b4c9debd2ebe49fd326a1af33907 Mon Sep 17 00:00:00 2001 From: Matteo Campinoti Date: Tue, 21 Nov 2023 12:51:25 +0100 Subject: [PATCH 14/14] poetry - version patch 1.1.1 > 1.1.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 557275f..4d87632 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "acacore" -version = "1.1.1" +version = "1.1.2" description = "" authors = ["Matteo Campinoti "] license = "GPL-3.0"