Skip to content

Commit

Permalink
updated with remarks from pull request #45, #46
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoHuebner authored and pmayd committed Sep 4, 2022
1 parent 5bee232 commit b1824b2
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 39 deletions.
20 changes: 12 additions & 8 deletions src/pygenesis/cache.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Module provides functions/decorators to cache downloaded data."""
"""Module provides functions/decorators to cache downloaded data as well as remove cached data."""
import logging
import shutil
from datetime import date
Expand Down Expand Up @@ -31,9 +31,13 @@ def wrapper_func(**kwargs):
cache_dir,
)

# TODO: Is "name" generally in all subsequent methods
# (e.g. beyond get_data - or is only data meaningful to cache)?
name = kwargs["name"]
# get name specified, if None given do not cache data
name = kwargs.get("name", None)

if name is None:
data: pd.DateFrame = func(**kwargs)
return data

data_dir = cache_dir / name
if data_dir.exists():
# TODO: Implement solution for updated data.
Expand Down Expand Up @@ -76,9 +80,7 @@ def clean_cache(file: Optional[str] = None) -> None:

# remove specified file (directory) from the data cache
# or clear complete cache (remove childs, preserve base)
file_paths = (
[cache_dir / file] if file is not None else list(cache_dir.iterdir())
)
file_paths = [cache_dir / file] if file is not None else cache_dir.iterdir()

for file_path in file_paths:
# delete if file or symlink, otherwise remove complete tree
Expand All @@ -88,4 +90,6 @@ def clean_cache(file: Optional[str] = None) -> None:
elif file_path.is_dir():
shutil.rmtree(file_path)
except (OSError, ValueError, FileNotFoundError) as e:
print(f"Failed to delete {file_path}. Reason: {e}")
logger.warning(f"Failed to delete {file_path}. Reason: {e}")

logger.info(f"Removed files: {file_paths}")
7 changes: 7 additions & 0 deletions src/pygenesis/custom_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Define custom "speaking" Exception and Error classes."""


class DestatisStatusError(ValueError):
"""Raised when Destatis status code indicates an error ("Fehler")"""

pass
28 changes: 13 additions & 15 deletions src/pygenesis/http_helper.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
"""Wrapper module for the data endpoint."""
import json
import warnings
import logging

import requests

from pygenesis.config import load_config
from pygenesis.custom_exceptions import DestatisStatusError

config = load_config()
logger = logging.getLogger(__name__)


def get_response_from_endpoint(
Expand Down Expand Up @@ -51,11 +53,8 @@ def _check_invalid_status_code(status_code: int) -> None:
Raises:
AssertionError: Assert that status is not 4xx or 5xx
"""
if status_code // 100 in [
4,
5,
]:
raise AssertionError(
if status_code // 100 in [4, 5]:
raise requests.exceptions.HTTPError(
f"Error {status_code}: The server returned a {status_code} status code"
)

Expand Down Expand Up @@ -97,36 +96,35 @@ def _check_destatis_status(destatis_status: dict) -> None:
destatis_status (dict): Status response dict from Destatis
Raises:
# TODO: Is this a Value or KeyError?
ValueError: If the status code or type displays an error (caused by the user inputs)
DestatisStatusError: If the status code or type displays an error (caused by the user inputs)
"""
# -1 status code for unexpected errors and if no status code is given (faulty response)
destatis_status_code = int(destatis_status.get("Code", -1))
destatis_status_type = str(destatis_status.get("Type", "Information"))
destatis_status_content = str(destatis_status.get("Content"))
destatis_status_code = destatis_status.get("Code", -1)
destatis_status_type = destatis_status.get("Type", "Information")
destatis_status_content = destatis_status.get("Content")

# define status types
error_en_de = ["Error", "Fehler"]
warning_en_de = ["Warning", "Warnung"]

# check for generic/ system error
if destatis_status_code == -1:
raise ValueError(
raise DestatisStatusError(
"Error: There is a system error.\
Please check your query parameters."
)

# check for destatis/ query errors
elif (destatis_status_code == 104) or (destatis_status_type in error_en_de):
raise ValueError(destatis_status_content)
raise DestatisStatusError(destatis_status_content)

# output warnings to user
elif (destatis_status_code == 22) or (
destatis_status_type in warning_en_de
):
warnings.warn(destatis_status_content, UserWarning, stacklevel=2)
logger.warning(destatis_status_content)

# output information to user
# TODO: Would logger.info (with forced visibility) be the better option?
elif destatis_status_type.lower() == "information":
print(f"Code {destatis_status_code}: {destatis_status_content}")
logger.info(f"Code {destatis_status_code}: {destatis_status_content}")
44 changes: 28 additions & 16 deletions tests/unit_tests/test_http_helper.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
import logging

import pytest
import requests

from src.pygenesis.http_helper import (
from pygenesis.custom_exceptions import DestatisStatusError
from pygenesis.http_helper import (
_check_invalid_destatis_status_code,
_check_invalid_status_code,
)
Expand All @@ -18,7 +20,7 @@ def test__check_invalid_status_code_with_error():
for _handle_status_code method.
"""
for status_code in [400, 500]:
with pytest.raises(AssertionError) as e:
with pytest.raises(requests.exceptions.HTTPError) as e:
_check_invalid_status_code(status_code)
assert (
str(e.value)
Expand Down Expand Up @@ -95,36 +97,46 @@ def test__check_invalid_destatis_status_code_with_error():
# extract status content which is raised
status_content = status.json().get("Status").get("Content")

with pytest.raises(ValueError) as e:
with pytest.raises(DestatisStatusError) as e:
_check_invalid_destatis_status_code(status)
assert str(e.value) == status_content


def test__check_invalid_destatis_status_code_with_warning():
def test__check_invalid_destatis_status_code_with_warning(caplog):
"""
Basic tests to check a warning status code as defined in the
documentation via code (e.g. 22) or type ('Warning', 'Warnung').
"""
caplog.set_level(logging.WARNING)

for status in [
_generic_request_status(code=22),
_generic_request_status(status_type="Warnung"),
_generic_request_status(status_type="Warning"),
]:
# TODO: Is this the best/ most specific way to capture the warning?
with pytest.warns(UserWarning):
_check_invalid_destatis_status_code(status)
# extract status content which is contained in warning
status_content = status.json().get("Status").get("Content")

_check_invalid_destatis_status_code(status)

assert status_content in caplog.text

def test__check_invalid_destatis_status_code_without_error():

def test__check_invalid_destatis_status_code_without_error(caplog):
"""
Basic tests to check the successful status code 0 or only text response as defined in the documentation.
"""
for status in [
_generic_request_status(),
_generic_request_status(status_response=False),
]:
try:
_check_invalid_destatis_status_code(status)
except Exception:
assert False
# JSON response with status code
caplog.set_level(logging.INFO)
status = _generic_request_status()
status_content = status.json().get("Status").get("Content")
_check_invalid_destatis_status_code(status)

assert status_content in caplog.text

# text only response
status_text = _generic_request_status(status_response=False)
try:
_check_invalid_destatis_status_code(status_text)
except Exception:
assert False

0 comments on commit b1824b2

Please sign in to comment.