Source code for visions.relations.relations

from typing import Any, Callable, Optional, TypeVar

import attr
from multimethod import multimethod

T = TypeVar("T")


def func_repr(func: Callable) -> str:
    return func.__name__ if hasattr(func, "__name__") else "lambda"


def identity_transform(series: Any, state: dict = dict()) -> Any:
    return series


def default_relation(series: Any, state: dict = dict()) -> bool:
    raise NotImplementedError


[docs]@attr.s(frozen=True) class TypeRelation: """Relationship encoder between implementations of :class:`visions.types.type.VisionsBaseType` Defines a one to one relationship between two :class:`visions.types.type.VisionsBaseType` implementations, A and B, with respect to an underlying data series. In order to define a relationship we need two methods: - **is_relationship**, determines whether a series of type B can be alternatively represented as type A. - **transform**, provides a mechanism to convert the series from B -> A. For example, the series `pd.Series([1.0, 2.0, 3.0])` is encoded as a sequence of floats but in reality they are all integers. Examples: >>> from visions.types import Integer, Float >>> x = pd.Series([1.0, 2.0, 3.0]) >>> state = dict() >>> relation = TypeRelation(Integer, Float) >>> relation.is_relation(x, state) True >>> relation.transform(x, state) pd.Series([1, 2, 3]) """ related_type = attr.ib() inferential: bool = attr.ib() transformer: Callable[[T, dict], T] = attr.ib( converter=multimethod, repr=func_repr # type: ignore ) relationship: Callable[[Any, dict], bool] = attr.ib( default=default_relation, converter=multimethod, repr=func_repr # type: ignore ) type = attr.ib(default=None) def is_relation(self, series: Any, state: Optional[dict] = None) -> bool: if state is None: state = {} return self.relationship(series, state) def transform(self, series: T, state: Optional[dict] = None) -> T: if state is None: state = {} return self.transformer(series, state) def __str__(self): return f"{self.related_type}->{self.type}"
[docs]@attr.s(frozen=True) class IdentityRelation(TypeRelation): relationship: Callable[[T, dict], bool] = attr.ib(repr=func_repr, default=None) transformer: Callable[[T, dict], T] = attr.ib( default=identity_transform, repr=func_repr ) inferential: bool = attr.ib(default=False)
[docs]@attr.s(frozen=True) class InferenceRelation(TypeRelation): relationship: Callable[[T, dict], bool] = attr.ib( repr=func_repr, default=default_relation ) transformer: Callable[[T, dict], T] = attr.ib( repr=func_repr, default=identity_transform ) inferential: bool = attr.ib(default=True)