Source code for thelper.concepts

"""Framework concepts module for high-level interface documenting.

The decorators and type checkers defined in this module help highlight the
purpose of classes and functions with respect to high-level ML tasks.
"""
import functools
import inspect
from typing import TYPE_CHECKING

if TYPE_CHECKING:  # pragma: no cover
    from typing import Any, AnyStr, Callable, Optional, Union  # noqa: F401
    from types import FunctionType  # noqa: F401

SUPPORT_PREFIX = "supports_"
"""Prefix that is applied before any 'concept' decorator."""


[docs]def apply_support(func_or_cls=None, concept=None): # type: (Optional[Union[FunctionType, Callable]], Optional[AnyStr]) -> Callable """ Utility decorator that allows marking a function or a class as *supporting* a certain ``concept``. Notes: ``concept`` support by the function or class is marked only as documentation reference, no strict validation is accomplished to ensure that further underlying requirements are met for the *concept*. .. seealso:: | :func:`thelper.concepts.classification` | :func:`thelper.concepts.detection` | :func:`thelper.concepts.segmentation` | :func:`thelper.concepts.regression` """ # actual function that applies the concept to the decorated 'thing' def apply_concept(_thing, _concept, *_args, **_kwargs): assert isinstance(_concept, str) and len(_concept) _concept = f"{SUPPORT_PREFIX}{_concept}" if not _concept.startswith(SUPPORT_PREFIX) else _concept setattr(_thing, _concept, True) return _thing # wrapper generator for class types or class instances class ApplyDecorator(object): def __new__(cls, wrapped=None, _concept=None, *args, **kwargs): cls.__wrapped__ = wrapped return apply_concept(wrapped, _concept, *args, **kwargs) # wrapper generator for functions or class methods def apply_decorator(f_or_c): if inspect.isclass(f_or_c): return ApplyDecorator(f_or_c, concept) @functools.wraps(f_or_c) # lift wrapped object definitions, so that it still looks like the original def decorate(*args, **kwargs): return apply_concept(f_or_c, concept)(*args, **kwargs) return decorate if inspect.isclass(func_or_cls): # the '_concept' input passed down here ensures that a class decorated with a predefined # shortcut decorator function called without parenthesis will still receive the wanted 'concept' # ex: # @support_classification # <== no () here # def ClassifObj(): pass return ApplyDecorator(func_or_cls, _concept=concept) elif func_or_cls: # this is in case the decorator is applied to a function instead of a class return apply_decorator(func_or_cls) return apply_decorator
[docs]def supports(thing, concept): # type: (Any, AnyStr) -> bool """Utility method to evaluate if ``thing`` *supports* a given ``concept`` as defined by decorators. Arguments: thing: any type, function, method, class or object instance to evaluate if it is marked by the concept concept: concept to check .. seealso:: | :func:`thelper.concepts.classification` | :func:`thelper.concepts.detection` | :func:`thelper.concepts.segmentation` | :func:`thelper.concepts.regression` """ if not isinstance(concept, str): return False concept = concept.lower() # in case it was capitalized return getattr(thing, f"{SUPPORT_PREFIX}{concept}", False)
[docs]def classification(func_or_cls=None): # type: (Optional[Union[FunctionType, Callable]]) -> Callable """Decorator that allows marking a function or class as *supporting* the image classification task. Example:: @thelper.concepts.classification class ClassifObject(): pass c = ClassifObject() c.supports_classification > True thelper.concepts.supports(c, "classification") > True """ return apply_support(func_or_cls, "classification")
[docs]def detection(func_or_cls=None): # type: (Optional[Union[FunctionType, Callable]]) -> Callable """Decorator that allows marking a function or class as *supporting* the object detection task. Example:: @thelper.concepts.detection class DetectObject(): pass d = DetectObject() d.supports_detection > True thelper.concepts.supports(d, "detection") > True """ return apply_support(func_or_cls, "detection")
[docs]def segmentation(func_or_cls=None): # type: (Optional[Union[FunctionType, Callable]]) -> Callable """Decorator that allows marking a function or class as *supporting* the image segmentation task. Example:: @thelper.concepts.segmentation class SegmentObject(): pass s = SegmentObject() s.supports_segmentation > True thelper.concepts.supports(s, "segmentation") > True """ return apply_support(func_or_cls, "segmentation")
[docs]def regression(func_or_cls=None): # type: (Optional[Union[FunctionType, Callable]]) -> Callable """Decorator that allows marking a function or class as *supporting* the generic regression task. Example:: @thelper.concepts.regression class RegrObject(): pass r = RegrObject() r.supports_regression > True thelper.concepts.supports(r, "regression") > True """ return apply_support(func_or_cls, "regression")