Skip to content

Commit

Permalink
runtime type checking decorator implemented and tested for rdf api
Browse files Browse the repository at this point in the history
  • Loading branch information
97gamjak committed May 6, 2024
1 parent 141cbbe commit 199f8fd
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 49 deletions.
12 changes: 7 additions & 5 deletions PQAnalysis/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ def runtime_type_checking(func, *args, **kwargs):
logger.error(
_get_type_error_message(
arg_name,
arg_value,
type_hints[arg_name],
type(arg_value)
),
exception=TypeError,
)
Expand All @@ -50,8 +50,8 @@ def runtime_type_checking(func, *args, **kwargs):
logger.error(

Check warning on line 50 in PQAnalysis/type_checking.py

View check run for this annotation

Codecov / codecov/patch

PQAnalysis/type_checking.py#L47-L50

Added lines #L47 - L50 were not covered by tests
_get_type_error_message(
kwarg_name,
kwarg_value,
type_hints[kwarg_name],
type(kwarg_value)
),
exception=TypeError,
)
Expand All @@ -60,14 +60,16 @@ def runtime_type_checking(func, *args, **kwargs):
return func(*args, **kwargs)

Check warning on line 60 in PQAnalysis/type_checking.py

View check run for this annotation

Codecov / codecov/patch

PQAnalysis/type_checking.py#L60

Added line #L60 was not covered by tests


def _get_type_error_message(arg_name, expected_type, actual_type):
def _get_type_error_message(arg_name, value, expected_type):
"""
Get the error message for a type error.
"""

actual_type = type(value)

header = (
f"Argument '{arg_name}' should be of type {expected_type}, "
f"but got {actual_type}."
f"Argument '{arg_name}' with {value=} should be "
f"of type {expected_type}, but got {actual_type}."
)

if expected_type is Np1DIntArray:
Expand Down
27 changes: 18 additions & 9 deletions PQAnalysis/utils/custom_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,15 @@ def _log(self, # pylint: disable=arguments-differ
)

if level in [logging.CRITICAL, logging.ERROR]:

exception = exception or Exception

if self.isEnabledFor(logging.DEBUG):
back_tb = None

try:
if exception is not None:
raise exception

raise Exception # pylint: disable=broad-exception-raised
except Exception: # pylint: disable=broad-except
raise exception # pylint: disable=broad-exception-raised
except exception: # pylint: disable=broad-except

Check warning on line 132 in PQAnalysis/utils/custom_logging.py

View check run for this annotation

Codecov / codecov/patch

PQAnalysis/utils/custom_logging.py#L131-L132

Added lines #L131 - L132 were not covered by tests
traceback = sys.exc_info()[2]
back_frame = traceback.tb_frame.f_back

Expand All @@ -140,12 +140,21 @@ def _log(self, # pylint: disable=arguments-differ
tb_lineno=back_frame.f_lineno
)

if exception is not None:
raise Exception(msg).with_traceback(back_tb)

raise exception(msg).with_traceback(back_tb)

sys.exit(1)
class DevNull:
"""
Dummy class to redirect the sys.stderr to /dev/null.
"""

def write(self, _):
"""
Dummy write method.
"""

sys.stderr = DevNull()

raise exception(msg) # pylint: disable=raise-missing-from

def _original_log(self,
level: Any,
Expand Down
3 changes: 3 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import os

os.environ['PQANALYSIS_BEARTYPE_LEVEL'] = "RELEASE"
12 changes: 8 additions & 4 deletions tests/analysis/rdf/test_api.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import pytest

from PQAnalysis.analysis.rdf.api import rdf
from PQAnalysis.type_checking import _get_type_error_message

from .. import pytestmark # pylint: disable=unused-import
from ...conftest import assert_logging
from ...conftest import assert_logging_with_exception


class TestRDFAPI:
def test_wrong_param_types(self, caplog):
assert_logging(
assert_logging_with_exception(
caplog=caplog,
logging_name=rdf.__name__,
logging_name="TypeChecking",
logging_level="ERROR",
message_to_test="Input file must be a string",
message_to_test=_get_type_error_message(
"input_file", 1, str,
),
exception=TypeError,
function=rdf,
input_file=1,
)
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def assert_logging_with_exception(caplog, logging_name, logging_level, message_t
result = None
try:
result = function(*args, **kwargs)
except SystemExit:
except:
pass

record = caplog.records[0]
Expand Down
9 changes: 2 additions & 7 deletions tests/io/test_frameReader.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import pytest
import numpy as np

from beartype.roar import BeartypeException

from . import pytestmark

from PQAnalysis.io import FrameReader
from PQAnalysis.io.traj_file.exceptions import FrameReaderError
from PQAnalysis.core import Cell, Atom
from PQAnalysis.traj.exceptions import TrajectoryFormatError
from PQAnalysis.traj import TrajectoryFormat
from PQAnalysis.topology import Topology

from . import pytestmark


class TestFrameReader:

Expand Down Expand Up @@ -67,9 +65,6 @@ def test__read_scalar(self):
def test_read(self):
reader = FrameReader()

with pytest.raises(BeartypeException):
reader.read(["tmp"])

frame = reader.read(
"2 2.0 3.0 4.0 5.0 6.0 7.0\n\nh 1.0 2.0 3.0\no 2.0 2.0 2.0")
assert frame.n_atoms == 2
Expand Down
10 changes: 2 additions & 8 deletions tests/io/test_infoFileReader.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import pytest

from beartype.roar import BeartypeException

from . import pytestmark

from PQAnalysis.io import InfoFileReader
from PQAnalysis.traj import MDEngineFormat
from PQAnalysis.traj.exceptions import MDEngineFormatError

from . import pytestmark


@pytest.mark.parametrize("example_dir", ["readInfoFile"], indirect=False)
def test__init__(test_with_data_dir):
with pytest.raises(FileNotFoundError) as exception:
InfoFileReader("tmp")
assert str(exception.value) == "File tmp not found."

with pytest.raises(BeartypeException) as exception:
InfoFileReader(
"md-01.info", engine_format=None)

with pytest.raises(MDEngineFormatError) as exception:
InfoFileReader(
"md-01.info", engine_format="tmp")
Expand Down
18 changes: 3 additions & 15 deletions tests/physicalData/test_energy.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
import pytest
import numpy as np

from collections import defaultdict
from beartype.roar import BeartypeException

import pytest
import numpy as np

from PQAnalysis.physical_data import Energy, EnergyError


class TestEnergy:
def test__init__(self):
with pytest.raises(BeartypeException):
Energy(1)

with pytest.raises(BeartypeException):
Energy([[[1]]])

data = np.array([1, 2, 3])
energy = Energy(data)

assert np.allclose(energy.data, [data])

def test__setup_info_dictionary(self):
with pytest.raises(BeartypeException):
Energy(np.array([1]), info=1)

with pytest.raises(BeartypeException):
Energy(np.array([1]), units=1)

data = np.array([[1], [2]])
info = {1: 0, 2: 1}
units = {1: "a", 2: "b"}
Expand Down

0 comments on commit 199f8fd

Please sign in to comment.