Skip to content

Commit

Permalink
Update license, plugin interface, dataset interface (#28)
Browse files Browse the repository at this point in the history
* Update all configurations

* Set up data format and validation (#2)

* Implement library config

* Isort docs/conf.py

* Improve configuration

* Add logging

* Add .print to logger

* Set up way of updating things on config changes

* Simplify and use get_config()

* Tidy multi-line logger messages

* Add logger.raise_ convenience method

* Move logging into a package

* Add diagnose, backtrace as configurable options

* Make default config be defined in yaml file only

* Add validator design

* Add extra config test

* Define global data settings

* Clean up validator

* Use builtin types in DataSettings

* Minor refactor validator

* Set up DataRequirements

* Set up validation implementation

* Decouple tests, tidy imports

* Imports to Google style where possible

* Implement some data validators (root_validate)

* Use decorator in val. impl. method registry

* Improve exception logging

* Update some validation_implementation methods

* Reorganize dir structure

* Clean up tests

* Allow for inheritance in val. impl.

* Add validator > df tests

* Separate out SupportsContainer interface

* Shorten package names

* Factor out SupportsImplementations

* Factor out RegisterMethodDecorator

* Add dispatch_to_implementation()

* Separate out interface

* Set up framework for *Samples objects

* Add data utils

* Implement as_array for TimeSeriesSamples

* Introduce data container def.

* Update data container defs, separate out tests

* Set up default container flavor mechanism

* Add check_untyped_defs = True in mypy.ini

* Implement EventSamples

* Implement as_array for EventSamples

* Update setup requirements

* Set up docs (#4)

* Remove unneeded BAK file

* Small additions to README

* Update image display

* Major update README

* Table width

* Change image align

* Prepare README for docs

* Add logo

* Update docs

* Fix issue in README

* Dr shushen/model setup (#23)

* Remove unneeded BAK file

* Change abc import to be Google code format style

* Introduce TemporBaseModel

* Introduce fit()

* Bugfix, add typing overloads for fit()

* Add core requirements

* Introduce RequirementCategory

* Set up requirement validator concept

* Reorganize data/

* Introduce DataBundle

* Add DataBundle requirements

* Set up from_data_containers static method

* Update install_requires

* Introduce RequirementsConfig

* Reorganize packages to improve naming

* Develop RequirementsConfig further

* Improve RequirementsConfig repr

* Deal with _validate_method_config

* Minor bugfixes

* Add some int. tests for base model fit config

* Add _fit_called flag

* Introduce transform method

* Tidy imports

* Update LICENSE (#24)

* [Feat] Basic plugin interface and loader (#27)

* Rename model dir to plugins

* Set up plugins/core dir

* Simplify estimator, transformer

* Add predictor

* Fix circular import

* Add core plugin methods like name()

* Implement a Plugin interface

* Factorize out test utility "patch_module"

* Add test for plugin infrastructure

* Add test for loaded plugins

* add fit_{predict,transform} methods

* Add hyperparameter methods

* Add Base* to indicate base models

* Keep only estimator init with params as kwargs

* Rename test file

* Add parent constructor calls for clarity

* Set up Dataset (#36)

* Remove old data format

* Initial interface for Dataset

* Remove unnecessary decorator

* Add StaticSamples validation and tests

* Add TimeSeriesSamples validation

* Add EventSamples validation

* Add tests for samples basics

* Test EventSamples.split method

* Add  time/sample_index helper methods

* Add @validate_arguments and some note comments

* Add repr's

* Implement from_numpy for {Static,Event}Samples

* Implement .numpy for {Static,Event}Samples

* Add utils for array/df manipulation

* Implement TimeSeriesSamples .numpy()

* Fix some typing definitions

* Write utils for array -> TS df conversion

* Check in register_plugin if re-imported (no exc.)

* Add docstrings in utils

* Add pydantic.validate_arguments in data utils

* Implement TimeSeriesSamples from_numpy()

* Update docstring in TimeSeriesSamples.__init__

* Add unit tests for Dataset

* Set default debug level to INFO

* Update tests

* Add data format tutorial notebook

* Add reprs

* Simplify _check_same_class

* Add docstring to Dataset classes
  • Loading branch information
DrShushen authored Mar 3, 2023
1 parent 3b11933 commit 46896a5
Show file tree
Hide file tree
Showing 67 changed files with 5,959 additions and 2,377 deletions.
822 changes: 201 additions & 621 deletions LICENSE.txt

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ name = temporai
description = TemporAI: ML-centric Toolkit for Medical Time Series
author = Evgeny Saveliev
author_email = [email protected]
license = GPL-3.0-or-later
license = Apache-2.0 license
license_files = LICENSE.txt
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8; variant=GFM
Expand Down Expand Up @@ -55,6 +55,7 @@ install_requires =
pandas >=1
pandera >=0.13
pydantic >=1, <2
rich


[options.packages.find]
Expand All @@ -74,9 +75,11 @@ tempor =

# Add here test requirements (semicolon/line-separated)
testing =
setuptools
jupyter
notebook
pytest
pytest-cov
setuptools

[options.entry_points]
# Add here console scripts like:
Expand Down Expand Up @@ -118,6 +121,7 @@ exclude =
max-line-length = 120
disable = R, C
generated-members = torch.*
extension-pkg-whitelist = pydantic

[pylint.messages_control]
disable = C0330, C0326, fixme, c-extension-no-member
Expand Down
2 changes: 1 addition & 1 deletion src/tempor/config/conf/tempor/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
logging:
mode: LIBRARY # {LIBRARY, SCRIPT}
level: DEBUG
level: INFO
diagnose: false
backtrace: true
file_log: true
Expand Down
2 changes: 1 addition & 1 deletion src/tempor/core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import _supports_impl as supports_impl
from . import supports_impl
from ._register_method_decorator import RegisterMethodDecorator

__all__ = [
Expand Down
8 changes: 4 additions & 4 deletions src/tempor/core/_supports_impl.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from abc import ABC, abstractmethod
import abc
from typing import Dict, Generic, Tuple, TypeVar

SupportsT = TypeVar("SupportsT")
ImplementationT = TypeVar("ImplementationT")


class SupportsImplementations(Generic[SupportsT, ImplementationT], ABC):
class SupportsImplementations(Generic[SupportsT, ImplementationT], abc.ABC):
def __init__(self) -> None:
super().__init__()
self._implementations: Dict[SupportsT, ImplementationT] = self._register_implementations()
Expand All @@ -26,11 +26,11 @@ def dispatch_to_implementation(self, key: SupportsT) -> ImplementationT:
return self._implementations[key]

@property
@abstractmethod
@abc.abstractmethod
def supports_implementations_for(self) -> Tuple[SupportsT, ...]: # pragma: no cover
...

@abstractmethod
@abc.abstractmethod
def _register_implementations(self) -> Dict[SupportsT, ImplementationT]: # pragma: no cover
...

Expand Down
16 changes: 16 additions & 0 deletions src/tempor/core/pydantic_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from typing import Dict, Optional


def exclusive_args(
values: Dict,
arg1: str,
arg2: str,
arg1_friendly_name: Optional[str] = None,
arg2_friendly_name: Optional[str] = None,
) -> None:
arg1_value = values.get(arg1, None)
arg2_value = values.get(arg2, None)
arg1_name = arg1_friendly_name if arg1_friendly_name else f"`{arg1}`"
arg2_name = arg2_friendly_name if arg2_friendly_name else f"`{arg2}`"
if arg1_value is not None and arg2_value is not None:
raise ValueError(f"Must provide either {arg1_name} or {arg2_name} but not both")
59 changes: 59 additions & 0 deletions src/tempor/core/requirements.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import abc
import enum
from typing import Any, ClassVar, Sequence, get_type_hints

import pydantic
import rich.pretty


class RequirementCategory(enum.Enum):
DATA_CONTAINER = enum.auto()
DATA_BUNDLE = enum.auto()
MODEL = enum.auto()


class Requirement(abc.ABC):
definition: Any

name: ClassVar[str] = None # type: ignore
validator_methods: ClassVar[Sequence[Any]] = tuple()

def __init__(self, definition) -> None:
validator = pydantic.create_model(
f"{self.__class__.__name__}Validator",
__validators__={clsmtd.__func__.__name__: clsmtd for clsmtd in self.validator_methods}, # type: ignore
name=(str, ...),
definition=(get_type_hints(self)["definition"], ...),
)
validator(name=self.name, definition=definition)
self.definition = definition

@property
@abc.abstractmethod
def requirement_category(self) -> RequirementCategory: # pragma: no cover
...

def __rich_repr__(self):
yield "definition", self.definition

def __repr__(self) -> str:
return rich.pretty.pretty_repr(self)


class RequirementValidator(abc.ABC):
@property
@abc.abstractmethod
def supported_requirement_category(self) -> RequirementCategory: # pragma: no cover
...

def validate(self, target: Any, *, requirements: Sequence[Requirement], **kwargs): # pragma: no cover
for r in requirements:
if r.requirement_category != self.supported_requirement_category:
raise ValueError(
f"{self.__class__.__name__} does not support requirement category {r.requirement_category}"
)
self._validate(target=target, requirements=requirements, **kwargs)

@abc.abstractmethod
def _validate(self, *args, **kwargs): # pragma: no cover
...
1 change: 1 addition & 0 deletions src/tempor/core/supports_impl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from ._supports_impl import * # noqa # pylint: disable=W
22 changes: 22 additions & 0 deletions src/tempor/core/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import enum


def get_class_full_name(o: object):
# See: https://stackoverflow.com/a/2020083
class_ = o.__class__
module = class_.__module__
if module == "builtins":
return class_.__qualname__ # avoid outputs like "builtins.str"
return module + "." + class_.__qualname__


def get_enum_name(enum_: enum.Enum) -> str:
return enum_.name.lower()


class RichReprStrPassthrough:
def __init__(self, string: str) -> None:
self.string = string

def __repr__(self) -> str:
return self.string
34 changes: 0 additions & 34 deletions src/tempor/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,34 +0,0 @@
from ._check_data_container_def import CheckDataContainerDefinition
from ._settings import (
CONTAINER_CLASS_TO_CONTAINER_FLAVORS,
DATA_CATEGORY_TO_CONTAINER_FLAVORS,
DATA_SETTINGS,
DEFAULT_CONTAINER_FLAVOR,
DataSettings,
)
from ._supports_container import (
DataContainerDef,
EventSupportsContainer,
StaticSupportsContainer,
SupportsContainer,
TimeSeriesSupportsContainer,
)
from ._types import ContainerFlavor, DataCategory, DataContainer, Dtype

__all__ = [
"CheckDataContainerDefinition",
"CONTAINER_CLASS_TO_CONTAINER_FLAVORS",
"ContainerFlavor",
"DEFAULT_CONTAINER_FLAVOR",
"DATA_CATEGORY_TO_CONTAINER_FLAVORS",
"DATA_SETTINGS",
"DataCategory",
"DataContainer",
"DataContainerDef",
"DataSettings",
"Dtype",
"EventSupportsContainer",
"StaticSupportsContainer",
"SupportsContainer",
"TimeSeriesSupportsContainer",
]
48 changes: 0 additions & 48 deletions src/tempor/data/_check_data_container_def.py

This file was deleted.

48 changes: 0 additions & 48 deletions src/tempor/data/_settings.py

This file was deleted.

65 changes: 0 additions & 65 deletions src/tempor/data/_supports_container.py

This file was deleted.

Loading

0 comments on commit 46896a5

Please sign in to comment.