"""Standardization for transformations between parameters and chronons
Adds classes to allow transformations in two directions:
1. Extract data (e.g. mutwo parameters) from chronons
2. Convert data (e.g. mutwo parameters) to chronons
"""
import typing
from mutwo import core_constants
from mutwo import core_converters
from mutwo import core_events
from mutwo import core_utilities
__all__ = (
"SimpleEventToAttribute",
"MutwoParameterDict",
"MutwoParameterDictToKeywordArgument",
"MutwoParameterDictToDuration",
"MutwoParameterDictToSimpleEvent",
"UnknownObjectToObject",
)
[docs]class SimpleEventToAttribute(core_converters.abc.Converter):
"""Extract from a chronon an attribute.
:param attribute_name: The name of the attribute which is fetched
from a :class:`mutwo.core_events.SimpleEvent`.
:param exception_value: This value is returned in case an `AttributeError`
raises .
"""
def __init__(self, attribute_name: str, exception_value: typing.Any):
self._attribute_name = attribute_name
self._exception_value = exception_value
[docs] def convert(self, chronon_to_convert: core_events.SimpleEvent) -> typing.Any:
"""Extract from a :class:`mutwo.core_events.SimpleEvent` an attribute.
:param chronon_to_convert: The :class:`mutwo.core_events.SimpleEvent`
from which an attribute shall be extracted.
:type chronon_to_convert: mutwo.core_events.SimpleEvent
**Example:**
>>> from mutwo import core_converters
>>> from mutwo import core_events
>>> chronon = core_events.SimpleEvent(duration=10)
>>> chronon_to_duration = core_converters.SimpleEventToAttribute(
... 'duration', 0
... )
>>> chronon_to_duration.convert(chronon)
DirectDuration(10)
>>> chronon_to_pasta = core_converters.SimpleEventToAttribute(
... 'pasta', 'spaghetti'
... )
>>> chronon_to_pasta.convert(chronon)
'spaghetti'
>>> chronon.pasta = 'tagliatelle'
>>> chronon_to_pasta.convert(chronon)
'tagliatelle'
"""
return core_utilities.call_function_except_attribute_error(
lambda chronon: getattr(chronon, self._attribute_name),
chronon_to_convert,
self._exception_value,
)
MutwoParameterDict = dict[str, core_constants.ParameterType]
[docs]class MutwoParameterDictToKeywordArgument(core_converters.abc.Converter):
"""Extract from a dict of mutwo parameters specific objects.
:param mutwo_parameter_to_search_name: The parameter name which
should be fetched from the MutwoParameterDict (if it exists).
:type mutwo_parameter_to_search_name: str
:param keyword: The keyword string to return. If no argument is given
it will use the same value as :param:`mutwo_parameter_to_search_name`.
:type keyword: typing.Optional[str]
**Example:**
>>> from mutwo import core_converters
>>> from mutwo import core_parameters
>>> mutwo_parameter_dict_to_keyword_argument = core_converters.MutwoParameterDictToKeywordArgument('duration')
>>> mutwo_parameter_dict_to_keyword_argument.convert(
... {'duration': core_parameters.DirectDuration(1)}
... )
('duration', DirectDuration(1))
"""
def __init__(
self, mutwo_parameter_to_search_name: str, keyword: typing.Optional[str] = None
):
if keyword is None:
keyword = str(mutwo_parameter_to_search_name)
self._mutwo_parameter_to_search_name = mutwo_parameter_to_search_name
self._keyword = keyword
[docs] def convert(
self, mutwo_parameter_dict_to_convert: MutwoParameterDict
) -> typing.Optional[tuple[str, core_constants.ParameterType]]:
try:
return (
self._keyword,
mutwo_parameter_dict_to_convert[self._mutwo_parameter_to_search_name],
)
except KeyError:
return None
[docs]class MutwoParameterDictToDuration(MutwoParameterDictToKeywordArgument):
"""Extract from a dict of mutwo parameters the duration.
:param duration_to_search_name: The name of the duration which shall
be searched for in the :const:`MutwoParameterDict`. If `None` the
value of the global constants
:const:`mutwo.core_converters.configurations.DEFAULT_DURATION_TO_SEARCH_NAME`
will be used. Default to `None`.
:type duration_to_search_name: typing.Optional[str]
:param duration_keyword_name: The name of the duration keyword for the
event. If `None` the value of the global constants
:const:`mutwo.core_converters.configurations.DEFAULT_DURATION_KEYWORD_NAME`
will be used. Default to `None`.
:type duration_keyword_name: typing.Optional[str]
:const:`mutwo.core_converters.configurations.DEFAULT_DURATION_KEYWORD_NAME`.
"""
def __init__(
self,
duration_to_search_name: typing.Optional[str] = None,
duration_keyword_name: typing.Optional[str] = None,
):
if duration_to_search_name is None:
duration_to_search_name = (
core_converters.configurations.DEFAULT_DURATION_TO_SEARCH_NAME
)
if duration_keyword_name is None:
duration_keyword_name = (
core_converters.configurations.DEFAULT_DURATION_KEYWORD_NAME
)
assert isinstance(duration_to_search_name, str)
assert isinstance(duration_keyword_name, str)
super().__init__(duration_to_search_name, duration_keyword_name)
[docs]class MutwoParameterDictToSimpleEvent(core_converters.abc.Converter):
"""Convert a dict of mutwo parameters to a :class:`mutwo.core_events.SimpleEvent`
:param mutwo_parameter_dict_to_keyword_argument_sequence: A sequence of
:class:`MutwoParameterDictToKeywordArgument`. If set to `None`
a sequence with :class:`MutwoParameterDictToDuration` will be created.
Default to `None`.
:type mutwo_parameter_dict_to_keyword_argument_sequence: typing.Optional[typing.Sequence[MutwoParameterDictToKeywordArgument]]
:param chronon_class: Default to :class:`mutwo.core_events.SimpleEvent`.
:type chronon_class: typing.Type[core_events.SimpleEvent]
"""
def __init__(
self,
mutwo_parameter_dict_to_keyword_argument_sequence: typing.Optional[
typing.Sequence[MutwoParameterDictToKeywordArgument]
] = None,
chronon_class: typing.Type[
core_events.SimpleEvent
] = core_events.SimpleEvent,
):
if mutwo_parameter_dict_to_keyword_argument_sequence is None:
mutwo_parameter_dict_to_keyword_argument_sequence = (
MutwoParameterDictToDuration(),
)
self._mutwo_parameter_dict_to_keyword_argument_sequence = (
mutwo_parameter_dict_to_keyword_argument_sequence
)
self._chronon_class = chronon_class
[docs] def convert(
self, mutwo_parameter_dict_to_convert: MutwoParameterDict
) -> core_events.SimpleEvent:
keyword_argument_dict = {}
for (
mutwo_parameter_dict_to_keyword_argument
) in self._mutwo_parameter_dict_to_keyword_argument_sequence:
keyword_argument_or_none = mutwo_parameter_dict_to_keyword_argument.convert(
mutwo_parameter_dict_to_convert
)
if keyword_argument_or_none:
keyword, argument = keyword_argument_or_none
keyword_argument_dict.update({keyword: argument})
return self._chronon_class(**keyword_argument_dict)
T = typing.TypeVar("T")
[docs]class UnknownObjectToObject(core_converters.abc.Converter, typing.Generic[T]):
"""Helper to simplify standardisation of syntactic sugar.
:param type_tuple_to_callable_dict: Define which types are converted by
which methods.
**Example:**
>>> from mutwo import core_converters
>>> anything_to_string = core_converters.UnknownObjectToObject[str](
... (
... ((float, int, list), str),
... ((tuple,), lambda t: str(len(t))),
... ([], lambda _: "..."),
... )
... )
>>> anything_to_string.convert(100)
'100'
>>> anything_to_string.convert(7.32)
'7.32'
>>> anything_to_string.convert((1, 2, 3))
'3'
>>> anything_to_string.convert(b'')
'...'
"""
def __init__(
self,
type_tuple_and_callable_tuple: tuple[tuple[typing.Type, ...], typing.Callable],
):
self._type_tuple_and_callable_tuple = type_tuple_and_callable_tuple
[docs] def convert(self, unknown_object_to_convert: typing.Any) -> T:
# XXX: This may break in the future, because it is an implementation
# detail.
if isinstance(unknown_object_to_convert, typing.get_args(self.__orig_class__)):
return unknown_object_to_convert
for type_tuple, callable_object in self._type_tuple_and_callable_tuple:
if type_tuple:
if isinstance(unknown_object_to_convert, type_tuple):
return callable_object(unknown_object_to_convert)
else:
return callable_object(unknown_object_to_convert)
raise NotImplementedError(
f"No conversion routine defined for object '{unknown_object_to_convert}'"
f" of type '{type(unknown_object_to_convert)}'."
)