Skip to content

Commit

Permalink
adding commentmixin to remaining entities (#416)
Browse files Browse the repository at this point in the history
* adding commentmixin to remaining entities
* additional tests
* type hints
* additional entities
* additional tests
* additional tests
* projects cleanup
  • Loading branch information
sonaalthaker authored Mar 6, 2024
1 parent 02e9842 commit 0cd94ee
Show file tree
Hide file tree
Showing 19 changed files with 183 additions and 48 deletions.
4 changes: 2 additions & 2 deletions rubicon_ml/client/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
import fsspec

from rubicon_ml.client.base import Base
from rubicon_ml.client.mixin import TagMixin
from rubicon_ml.client.mixin import CommentMixin, TagMixin
from rubicon_ml.client.utils.exception_handling import failsafe

if TYPE_CHECKING:
from rubicon_ml.client import Project
from rubicon_ml.domain import Artifact as ArtifactDomain


class Artifact(Base, TagMixin):
class Artifact(Base, TagMixin, CommentMixin):
"""A client artifact.
An `artifact` is a catch-all for any other type of
Expand Down
4 changes: 2 additions & 2 deletions rubicon_ml/client/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import TYPE_CHECKING, Callable, Literal, Optional, Union

from rubicon_ml.client import Base, TagMixin
from rubicon_ml.client import Base, CommentMixin, TagMixin
from rubicon_ml.client.utils.exception_handling import failsafe
from rubicon_ml.exceptions import RubiconException

Expand All @@ -11,7 +11,7 @@
from rubicon_ml.domain import Dataframe as DataframeDomain


class Dataframe(Base, TagMixin):
class Dataframe(Base, TagMixin, CommentMixin):
"""A client dataframe.
A `dataframe` is a two-dimensional, tabular dataset with
Expand Down
67 changes: 61 additions & 6 deletions rubicon_ml/client/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,15 @@ def _get_identifiers(self):
return self.project.name, self.id

@failsafe
def log_metric(self, name, value, directionality="score", description=None, tags=[]):
def log_metric(
self,
name: str,
value: float,
directionality: str = "score",
description: str = None,
tags: list[str] = [],
comments: list[str] = [],
) -> Metric:
"""Create a metric under the experiment.
Parameters
Expand All @@ -76,6 +84,9 @@ def log_metric(self, name, value, directionality="score", description=None, tags
tags : list of str, optional
Values to tag the experiment with. Use tags to organize and
filter your metrics.
comments : list of str, optional
Values to comment the experiment with. Use comments to organize and
filter your metrics.
Returns
-------
Expand All @@ -85,8 +96,18 @@ def log_metric(self, name, value, directionality="score", description=None, tags
if not isinstance(tags, list) or not all([isinstance(tag, str) for tag in tags]):
raise ValueError("`tags` must be `list` of type `str`")

if not isinstance(comments, list) or not all(
[isinstance(comment, str) for comment in comments]
):
raise ValueError("`comments` must be `list` of type `str`")

metric = domain.Metric(
name, value, directionality=directionality, description=description, tags=tags
name,
value,
directionality=directionality,
description=description,
tags=tags,
comments=comments,
)
for repo in self.repositories:
repo.create_metric(metric, self.project.name, self.id)
Expand Down Expand Up @@ -161,7 +182,14 @@ def metric(self, name=None, id=None):
return [m for m in self.metrics() if m.id == id][0]

@failsafe
def log_feature(self, name, description=None, importance=None, tags=[]):
def log_feature(
self,
name: str,
description: str = None,
importance: float = None,
tags: list[str] = [],
comments: list[str] = [],
) -> Feature:
"""Create a feature under the experiment.
Parameters
Expand All @@ -176,6 +204,9 @@ def log_feature(self, name, description=None, importance=None, tags=[]):
tags : list of str, optional
Values to tag the experiment with. Use tags to organize and
filter your features.
comments : list of str, optional
Values to comment the experiment with. Use comments to organize and
filter your features.
Returns
-------
Expand All @@ -185,7 +216,14 @@ def log_feature(self, name, description=None, importance=None, tags=[]):
if not isinstance(tags, list) or not all([isinstance(tag, str) for tag in tags]):
raise ValueError("`tags` must be `list` of type `str`")

feature = domain.Feature(name, description=description, importance=importance, tags=tags)
if not isinstance(comments, list) or not all(
[isinstance(comment, str) for comment in comments]
):
raise ValueError("`comments` must be `list` of type `str`")

feature = domain.Feature(
name, description=description, importance=importance, tags=tags, comments=comments
)

for repo in self.repositories:
repo.create_feature(feature, self.project.name, self.id)
Expand Down Expand Up @@ -260,7 +298,14 @@ def feature(self, name=None, id=None):
return [f for f in self.features() if f.id == id][0]

@failsafe
def log_parameter(self, name, value=None, description=None, tags=[]):
def log_parameter(
self,
name: str,
value: object = None,
description: str = None,
tags: list[str] = [],
comments: list[str] = [],
) -> Parameter:
"""Create a parameter under the experiment.
Parameters
Expand All @@ -277,6 +322,9 @@ def log_parameter(self, name, value=None, description=None, tags=[]):
tags : list of str, optional
Values to tag the parameter with. Use tags to organize and
filter your parameters.
comments : list of str, optional
Values to comment the experiment with. Use comments to organize and
filter your features.
Returns
-------
Expand All @@ -286,7 +334,14 @@ def log_parameter(self, name, value=None, description=None, tags=[]):
if not isinstance(tags, list) or not all([isinstance(tag, str) for tag in tags]):
raise ValueError("`tags` must be `list` of type `str`")

parameter = domain.Parameter(name, value=value, description=description, tags=tags)
if not isinstance(comments, list) or not all(
[isinstance(comment, str) for comment in comments]
):
raise ValueError("`comments` must be `list` of type `str`")

parameter = domain.Parameter(
name, value=value, description=description, tags=tags, comments=comments
)

for repo in self.repositories:
repo.create_parameter(parameter, self.project.name, self.id)
Expand Down
4 changes: 2 additions & 2 deletions rubicon_ml/client/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from datetime import datetime
from typing import TYPE_CHECKING, Optional

from rubicon_ml.client import Base, TagMixin
from rubicon_ml.client import Base, CommentMixin, TagMixin

if TYPE_CHECKING:
from rubicon_ml.client import Experiment
from rubicon_ml.domain import Feature as FeatureDomain


class Feature(Base, TagMixin):
class Feature(Base, TagMixin, CommentMixin):
"""A client feature.
A `feature` is an input to an `experiment` (model run)
Expand Down
4 changes: 2 additions & 2 deletions rubicon_ml/client/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from datetime import datetime
from typing import TYPE_CHECKING, Optional

from rubicon_ml.client import Base, TagMixin
from rubicon_ml.client import Base, CommentMixin, TagMixin

if TYPE_CHECKING:
from rubicon_ml.client import Experiment
from rubicon_ml.domain import Metric as MetricDomain


class Metric(Base, TagMixin):
class Metric(Base, TagMixin, CommentMixin):
"""A client metric.
A `metric` is a single-value output of an `experiment` that
Expand Down
23 changes: 23 additions & 0 deletions rubicon_ml/client/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def log_artifact(
name: Optional[str] = None,
description: Optional[str] = None,
tags: Optional[List[str]] = None,
comments: Optional[List[str]] = None,
) -> Artifact:
"""Log an artifact to this client object.
Expand All @@ -93,6 +94,9 @@ def log_artifact(
tags : list of str, optional
Values to tag the experiment with. Use tags to organize and
filter your artifacts.
comments : list of str, optional
Values to comment the experiment with. Use comments to organize and
filter your artifacts.
Notes
-----
Expand Down Expand Up @@ -128,13 +132,21 @@ def log_artifact(
if not isinstance(tags, list) or not all([isinstance(tag, str) for tag in tags]):
raise ValueError("`tags` must be `list` of type `str`")

if comments is None:
comments = []
if not isinstance(comments, list) or not all(
[isinstance(comment, str) for comment in comments]
):
raise ValueError("`comments` must be `list` of type `str`")

data_bytes, name = self._validate_data(data_bytes, data_file, data_object, data_path, name)

artifact = domain.Artifact(
name=name,
description=description,
parent_id=self._domain.id,
tags=tags,
comments=comments,
)

project_name, experiment_id = self._get_identifiers()
Expand Down Expand Up @@ -413,6 +425,7 @@ def log_dataframe(
description: Optional[str] = None,
name: Optional[str] = None,
tags: Optional[List[str]] = None,
comments: Optional[List[str]] = None,
) -> Dataframe:
"""Log a dataframe to this client object.
Expand All @@ -425,6 +438,8 @@ def log_dataframe(
additional context.
tags : list of str
The values to tag the dataframe with.
comments: list of str
The values to comment the dataframe with.
Returns
-------
Expand All @@ -436,11 +451,19 @@ def log_dataframe(
if not isinstance(tags, list) or not all([isinstance(tag, str) for tag in tags]):
raise ValueError("`tags` must be `list` of type `str`")

if comments is None:
comments = []
if not isinstance(comments, list) or not all(
[isinstance(comment, str) for comment in comments]
):
raise ValueError("`comments` must be `list` of type `str`")

dataframe = domain.Dataframe(
parent_id=self._domain.id,
description=description,
name=name,
tags=tags,
comments=comments,
)

project_name, experiment_id = self._get_identifiers()
Expand Down
4 changes: 2 additions & 2 deletions rubicon_ml/client/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from datetime import datetime
from typing import TYPE_CHECKING, Optional, Union

from rubicon_ml.client import Base, TagMixin
from rubicon_ml.client import Base, CommentMixin, TagMixin

if TYPE_CHECKING:
from rubicon_ml.client import Experiment
from rubicon_ml.domain import Parameter as ParameterDomain


class Parameter(Base, TagMixin):
class Parameter(Base, TagMixin, CommentMixin):
"""A client parameter.
A `parameter` is an input to an `experiment` (model run)
Expand Down
5 changes: 3 additions & 2 deletions rubicon_ml/domain/artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
from datetime import datetime
from typing import List, Optional

from rubicon_ml.domain.mixin import TagMixin
from rubicon_ml.domain.mixin import CommentMixin, TagMixin
from rubicon_ml.domain.utils import uuid


@dataclass
class Artifact(TagMixin):
class Artifact(TagMixin, CommentMixin):
name: str

id: str = field(default_factory=uuid.uuid4)
description: Optional[str] = None
created_at: datetime = field(default_factory=datetime.utcnow)
tags: List[str] = field(default_factory=list)
comments: List[str] = field(default_factory=list)

parent_id: Optional[str] = None
5 changes: 3 additions & 2 deletions rubicon_ml/domain/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
from datetime import datetime
from typing import List, Optional

from rubicon_ml.domain.mixin import TagMixin
from rubicon_ml.domain.mixin import CommentMixin, TagMixin
from rubicon_ml.domain.utils import uuid


@dataclass
class Dataframe(TagMixin):
class Dataframe(TagMixin, CommentMixin):
id: str = field(default_factory=uuid.uuid4)
name: Optional[str] = None
description: Optional[str] = None
tags: List[str] = field(default_factory=list)
comments: List[str] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.utcnow)

parent_id: Optional[str] = None
5 changes: 3 additions & 2 deletions rubicon_ml/domain/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
from datetime import datetime
from typing import List, Optional

from rubicon_ml.domain.mixin import TagMixin
from rubicon_ml.domain.mixin import CommentMixin, TagMixin
from rubicon_ml.domain.utils import uuid


@dataclass
class Feature(TagMixin):
class Feature(TagMixin, CommentMixin):
name: str

id: str = field(default_factory=uuid.uuid4)
description: Optional[str] = None
importance: Optional[float] = None
tags: List[str] = field(default_factory=list)
comments: List[str] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.utcnow)
5 changes: 3 additions & 2 deletions rubicon_ml/domain/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
from datetime import datetime
from typing import List, Optional

from rubicon_ml.domain.mixin import TagMixin
from rubicon_ml.domain.mixin import CommentMixin, TagMixin
from rubicon_ml.domain.utils import uuid

DIRECTIONALITY_VALUES = ["score", "loss"]


@dataclass
class Metric(TagMixin):
class Metric(TagMixin, CommentMixin):
name: str
value: float

Expand All @@ -18,6 +18,7 @@ class Metric(TagMixin):
directionality: str = "score"
created_at: datetime = field(default_factory=datetime.utcnow)
tags: List[str] = field(default_factory=list)
comments: List[str] = field(default_factory=list)

def __post_init__(self):
if self.directionality not in DIRECTIONALITY_VALUES:
Expand Down
Loading

0 comments on commit 0cd94ee

Please sign in to comment.