Source code for exosim.utils.klass_factory
from importlib import import_module
[docs]def find_klass_in_file(python_file, baseclass):
"""
It finds in the indicated python file a class that is a sublcass of the given one.
Parameters
----------
python_file: str
python file name
baseclass: class
reference class to search for
Returns
-------
class:
class found in the python file.
"""
import importlib.util
import inspect
spec = importlib.util.spec_from_file_location("foo", python_file)
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
classes = [
m[1]
for m in inspect.getmembers(foo, inspect.isclass)
if m[1] is not baseclass and issubclass(m[1], baseclass)
]
if len(classes) == 0:
# logger = logging.getLogger(generate_logger_name(obj))
# logger.error('Could not find class of type %s in file %s',
# baseclass, python_file)
raise Exception(
f"No class inheriting from {baseclass} in " f"{python_file}"
)
return classes[0]
[docs]def load_klass(input, baseclass):
"""
It returns a class that is a subclass of the given base class.
Parameters
----------
input: str or class
if is a string, :func:`find_klass_in_file` is used to return the right class.
If is a class, it checks whether it is an eligible class or not.
baseclass: class
reference class to search for
Returns
-------
class:
subclass of baseclass
"""
if isinstance(input, str):
return find_klass_in_file(input, baseclass)
else:
raise TypeError("task model in the wrong format")
[docs]def find_task(input, baseclass):
"""
It looks for a class that is a subclass of the base class indicated.
Parameters
----------
input: str or object
can either be a string indicating a class name, a python file, or it can be a class.
baseclass: object
reference class
Returns
-------
object
"""
if isinstance(input, str):
if input == baseclass.__name__:
# import the base class
klass = baseclass
elif input.endswith(".py"):
# import from file
klass = load_klass(input, baseclass)
else:
# look for task class by name in exosim.tasks submodules
for sub in dir(import_module("exosim.tasks")):
try:
klass = getattr(
import_module("exosim.tasks.{}".format(sub)), input
)
except (ModuleNotFoundError, AttributeError):
continue
elif issubclass(input, baseclass):
klass = input
else:
raise TypeError
return klass
[docs]def find_and_run_task(parameters, key, baseclass):
"""
It looks in the input parameters for a class that is a subclass of the base class indicated, and it initialises it.
Parameters
----------
parameters: dict
input dictionaty
key: str
string indicating the keyword for the class name
baseclass: object
reference class
Returns
-------
callable
"""
try:
task = (
find_task(parameters[key], baseclass)
if key in parameters.keys()
else baseclass
)
except UnboundLocalError as exc:
raise Exception(
"unable to find and instantiate a {} class".format(baseclass)
) from exc
return task()