Skip to content

Commit

Permalink
Create wrapper function for common class functionality (orest-d#15)
Browse files Browse the repository at this point in the history
* Implement wrapper functions for plot and read
* Implement wrapper for conversion routines
  • Loading branch information
martin-schlipf authored Aug 14, 2020
1 parent 25a4f40 commit 394caff
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
32 changes: 31 additions & 1 deletion src/py4vasp/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from .trajectory import Trajectory
from .viewer3d import Viewer3d
from .structure import Structure
from py4vasp.exceptions import NotImplementException

import plotly.io as pio
import cufflinks as cf
Expand All @@ -37,4 +38,33 @@
cf.set_config_file(theme="ggplot")

_this_mod = sys.modules[__name__]
__all__ = [name for name, _ in inspect.getmembers(_this_mod, inspect.isclass)]
_class_names = [name for name, _ in inspect.getmembers(_this_mod, inspect.isclass)]
_classes = [value for _, value in inspect.getmembers(_this_mod, inspect.isclass)]
_functions = set(("read", "plot"))
for c in _classes:
for name, _ in inspect.getmembers(c, inspect.isfunction):
if "to_" in name:
_functions.add(name)
__all__ = _class_names + list(_functions)


def get_function_if_possible(obj, name):
try:
return getattr(obj, name)
except AttributeError as err:
class_ = obj.__class__.__name__
msg = "For the {} no {} function is implemented.".format(class_, name)
raise NotImplementException(msg) from err


def _wrapper_factory(module, name):
def wrapper(cls, *args, **kwargs):
with cls.from_file() as obj:
function = get_function_if_possible(obj, name)
return function(*args, **kwargs)

setattr(module, name, wrapper)


for function in _functions:
_wrapper_factory(_this_mod, function)
4 changes: 4 additions & 0 deletions src/py4vasp/exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ class RefinementException(Py4VaspException):

class UsageException(Py4VaspException):
"""The user provided input is not suitable for processing"""


class NotImplementException(Py4VaspException):
"""Exception raised when a function is called that is not implemented."""
60 changes: 60 additions & 0 deletions tests/data/test_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from py4vasp.data import plot, read, to_dict
from py4vasp.exceptions import NotImplementException
from unittest.mock import MagicMock
from contextlib import contextmanager
import pytest


def test_plot():
plotable = MagicMock()
context = plotable.from_file.return_value
obj = context.__enter__.return_value
# without arguments
res = plot(plotable)
plotable.from_file.assert_called_once()
context.__enter__.assert_called_once()
obj.plot.assert_called_once()
assert res == obj.plot.return_value
# with arguments
res = plot(plotable, "arguments")
obj.plot.assert_called_with("arguments")


def test_plot():
readable = MagicMock()
context = readable.from_file.return_value
obj = context.__enter__.return_value
# without arguments
res = read(readable)
readable.from_file.assert_called_once()
context.__enter__.assert_called_once()
obj.read.assert_called_once()
assert res == obj.read.return_value
# with arguments
res = read(readable, "arguments")
obj.read.assert_called_with("arguments")


def test_conversion():
convertible = MagicMock()
context = convertible.from_file.return_value
obj = context.__enter__.return_value
# without arguments
res = to_dict(convertible) # we test to_dict as generic for conversion
convertible.from_file.assert_called_once()
context.__enter__.assert_called_once()
obj.to_dict.assert_called_once()
assert res == obj.to_dict.return_value
# with arguments
res = to_dict(convertible, "arguments")
obj.to_dict.assert_called_with("arguments")


def test_exception():
class NoReadDefined:
@contextmanager
def from_file():
yield NoReadDefined()

with pytest.raises(NotImplementException):
read(NoReadDefined)

0 comments on commit 394caff

Please sign in to comment.