Skip to content

Commit 751cd4c

Browse files
committed
[ci skip] WIP - Add docstr
1 parent 0ca228e commit 751cd4c

19 files changed

+663
-139
lines changed

skore-remote-project/pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ parallel = true
6969
omit = ["src/*", "tests/*"]
7070
show_missing = true
7171
exclude_also = [
72-
'raise NotImplementedError',
73-
'if __name__ == .__main__.:',
74-
'if TYPE_CHECKING:',
72+
"raise NotImplementedError",
73+
"if __name__ == .__main__.:",
74+
"if TYPE_CHECKING:",
7575
]
7676

7777
[tool.ruff]

skore-remote-project/src/skore_remote_project/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Package that provides APIs to communicate between ``skore`` and ``skore hub``."""
2+
13
from rich.console import Console
24
from rich.theme import Theme
35

skore-remote-project/src/skore_remote_project/item/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""
2+
Module definition of the ``Item`` classes.
3+
4+
``Item`` is an internal concept that is used as a DTO (Data Transfer Object) to exchange
5+
python objects between ``skore`` and ``skore hub``.
6+
"""
7+
18
from __future__ import annotations
29

310
from contextlib import suppress
@@ -22,6 +29,7 @@
2229

2330

2431
def object_to_item(object: Any, /) -> Item:
32+
"""Serialize any python object into an ``Item``."""
2533
for cls in (
2634
# Lexicographically sorted, the order of execution doesn't matter
2735
AltairChartItem,

skore-remote-project/src/skore_remote_project/item/altair_chart_item.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""
2+
AltairChartItem.
3+
4+
This module defines the ``AltairChartItem`` class used to serialize instances of
5+
``altair`` charts, using the ``JSON`` format.
6+
"""
7+
18
from __future__ import annotations
29

310
from json import loads
@@ -10,17 +17,29 @@
1017

1118

1219
class AltairChartItem(Item):
20+
"""Serialize instances of ``altair`` charts, using the ``JSON`` format."""
21+
1322
def __init__(self, chart_json_str: str):
23+
"""
24+
Initialize a ``AltairChartItem``.
25+
26+
Parameters
27+
----------
28+
chart_json_str : str
29+
The ``altair`` chart serialized in a str in the ``JSON`` format.
30+
"""
1431
self.chart_json_str = chart_json_str
1532

1633
@property
1734
def __raw__(self) -> AltairChart:
35+
"""Get the value from the ``AltairChartItem`` instance."""
1836
import altair
1937

2038
return altair.Chart.from_json(self.chart_json_str)
2139

2240
@property
2341
def __representation__(self) -> dict:
42+
"""Get the representation of the ``AltairChartItem`` instance."""
2443
return {
2544
"representation": {
2645
"media_type": "application/vnd.vega.v5+json",
@@ -29,8 +48,28 @@ def __representation__(self) -> dict:
2948
}
3049

3150
@classmethod
32-
def factory(cls, chart: AltairChart, /, **kwargs) -> AltairChartItem:
33-
if not lazy_is_instance(chart, "altair.vegalite.v5.schema.core.TopLevelSpec"):
34-
raise ItemTypeError(f"Type '{chart.__class__}' is not supported.")
51+
def factory(cls, value: AltairChart, /) -> AltairChartItem:
52+
"""
53+
Create a new ``AltairChartItem`` from an instance of ``altair`` chart.
54+
55+
It uses the ``JSON`` format.
56+
57+
Parameters
58+
----------
59+
value: ``altair`` chart.
60+
The value to serialize.
61+
62+
Returns
63+
-------
64+
AltairChartItem
65+
A new ``AltairChartItem`` instance.
66+
67+
Raises
68+
------
69+
ItemTypeError
70+
If ``value`` is not an instance of ``altair`` chart.
71+
"""
72+
if not lazy_is_instance(value, "altair.vegalite.v5.schema.core.TopLevelSpec"):
73+
raise ItemTypeError(f"Type '{value.__class__}' is not supported.")
3574

36-
return cls(chart.to_json(), **kwargs)
75+
return cls(value.to_json())
Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Abstract base class for all items in the ``skore`` remote project."""
2+
13
from __future__ import annotations
24

35
from abc import ABC, abstractmethod
@@ -7,30 +9,50 @@
79

810

911
def lazy_is_instance(value: Any, cls_fullname: str) -> bool:
10-
"""Return True if value is an instance of `cls_fullname`."""
12+
"""Return True if value is an instance of ``cls_fullname``."""
1113
return cls_fullname in {
1214
f"{cls.__module__}.{cls.__name__}" for cls in value.__class__.__mro__
1315
}
1416

1517

1618
def bytes_to_b64_str(literal: bytes) -> str:
17-
"""Encode the bytes-like object `literal` in a Base64 str."""
19+
"""Encode the bytes-like object ``literal`` in a Base64 str."""
1820
return b64encode(literal).decode("utf-8")
1921

2022

2123
def b64_str_to_bytes(literal: str) -> bytes:
22-
"""Decode the Base64 str object `literal` in a bytes."""
24+
"""Decode the Base64 str object ``literal`` in a bytes."""
2325
return b64decode(literal.encode("utf-8"))
2426

2527

2628
class ItemTypeError(Exception):
27-
""""""
29+
"""
30+
Item type exception.
31+
32+
Exception raised when an attempt is made to convert an object to an ``Item`` with an
33+
unsupported type.
34+
"""
2835

2936

3037
class Item(ABC):
38+
"""
39+
Abstract base class for all items in the ``skore`` remote project.
40+
41+
This class provides a common interface for all items, including the serialization of
42+
the parameters needed to recreate the instance from the remote project.
43+
44+
``Item`` is an internal concept that is used as a DTO (Data Transfer Object) to
45+
exchange python objects between ``skore`` and ``skore hub``.
46+
"""
47+
3148
@property
3249
def __parameters__(self) -> dict[str, dict[str, Any]]:
33-
""""""
50+
"""
51+
Get the parameters of the ``Item`` instance.
52+
53+
These parameters must be sufficient to recreate the instance.
54+
They are persisted in the ``skore`` remote project and retrieved as needed.
55+
"""
3456
cls = self.__class__
3557
cls_name = cls.__name__
3658
cls_parameters = inspect_signature(cls).parameters
@@ -44,19 +66,20 @@ def __parameters__(self) -> dict[str, dict[str, Any]]:
4466

4567
@property
4668
def __metadata__(self) -> dict[str, Any]:
69+
"""Get the metadata of the ``Item`` instance."""
4770
return dict()
4871

4972
@property
5073
@abstractmethod
5174
def __raw__(self) -> Any:
52-
""""""
75+
"""Get the raw python object from the ``Item`` instance."""
5376

5477
@property
5578
@abstractmethod
5679
def __representation__(self) -> dict[str, Any]:
57-
""""""
80+
"""Get the representation of the ``Item`` instance."""
5881

5982
@classmethod
6083
@abstractmethod
6184
def factory(cls, *args, **kwargs) -> Item:
62-
""""""
85+
"""Create and return a new instance of ``Item``."""

skore-remote-project/src/skore_remote_project/item/jsonable_item.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""
2+
JSONableItem.
3+
4+
This module defines the ``JSONableItem`` class used to serialize objects using the
5+
``JSON`` format.
6+
"""
7+
18
from __future__ import annotations
29

310
from json import dumps, loads
@@ -7,15 +14,27 @@
714

815

916
class JSONableItem(Item):
17+
"""Serialize objects using the ``JSON`` format."""
18+
1019
def __init__(self, value: Any):
20+
"""
21+
Initialize a ``JSONableItem``.
22+
23+
Parameters
24+
----------
25+
value : Any
26+
The value.
27+
"""
1128
self.value = value
1229

1330
@property
1431
def __raw__(self):
32+
"""Get the value from the ``JSONableItem`` instance."""
1533
return self.value
1634

1735
@property
1836
def __representation__(self) -> dict:
37+
"""Get the representation of the ``JSONableItem`` instance."""
1938
return {
2039
"representation": {
2140
"media_type": "application/json",
@@ -24,10 +43,28 @@ def __representation__(self) -> dict:
2443
}
2544

2645
@classmethod
27-
def factory(cls, value: Any, /, **kwargs) -> JSONableItem:
46+
def factory(cls, value: Any, /) -> JSONableItem:
47+
"""
48+
Create a new ``JSONableItem`` from ``value`` using the ``JSON`` format.
49+
50+
Parameters
51+
----------
52+
value: Any
53+
The value to serialize.
54+
55+
Returns
56+
-------
57+
JSONableItem
58+
A new ``JSONableItem`` instance.
59+
60+
Raises
61+
------
62+
ItemTypeError
63+
If ``value`` cannot be serialized using the ``JSON`` format.
64+
"""
2865
try:
2966
value = loads(dumps(value))
3067
except TypeError:
3168
raise ItemTypeError(f"Type '{value.__class__}' is not supported.") from None
3269

33-
return cls(value, **kwargs)
70+
return cls(value)

skore-remote-project/src/skore_remote_project/item/pandas_dataframe_item.py

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,51 @@
1+
"""
2+
PandasDataFrameItem.
3+
4+
This module defines the ``PandasDataFrameItem`` class used to serialize instances of
5+
``pandas.DataFrame``, using the ``JSON`` format.
6+
"""
7+
18
from __future__ import annotations
29

310
from functools import cached_property
411
from typing import TYPE_CHECKING, Literal
512

6-
from .item import Item, ItemTypeError
13+
from .item import Item, ItemTypeError, lazy_is_instance
714

815
if TYPE_CHECKING:
916
import pandas
1017

1118

1219
class PandasDataFrameItem(Item):
20+
"""Serialize instances of ``pandas.DataFrame``, using the ``JSON`` format."""
21+
1322
ORIENT: Literal["split"] = "split"
1423

1524
def __init__(self, index_json_str: str, dataframe_json_str: str):
25+
"""
26+
Initialize a ``PandasDataFrameItem``.
27+
28+
Parameters
29+
----------
30+
index_json_str : str
31+
The index of the ``pandas.DataFrame`` serialized in a str in the ``JSON``
32+
format.
33+
dataframe_json_str : str
34+
The ``pandas.DataFrame`` serialized in a str in the ``JSON`` format, without
35+
its index.
36+
"""
1637
self.index_json_str = index_json_str
1738
self.dataframe_json_str = dataframe_json_str
1839

1940
@cached_property
2041
def __raw__(self) -> pandas.DataFrame:
2142
"""
22-
The pandas DataFrame from the persistence.
43+
Get the value from the ``PandasDataFrameItem``.
2344
24-
Its content can differ from the original dataframe because it has been
25-
serialized using pandas' `to_json` function and not pickled, in order to be
45+
Notes
46+
-----
47+
Its content can slightly differ from the original because it has been serialized
48+
using ``pandas.to_json`` function and not pickled, in order to be
2649
environment-independent.
2750
"""
2851
import io
@@ -42,6 +65,7 @@ def __raw__(self) -> pandas.DataFrame:
4265

4366
@property
4467
def __representation__(self) -> dict:
68+
"""Get the representation of the ``PandasDataFrameItem`` instance."""
4569
return {
4670
"representation": {
4771
"media_type": "application/vnd.dataframe",
@@ -50,28 +74,33 @@ def __representation__(self) -> dict:
5074
}
5175

5276
@classmethod
53-
def factory(cls, dataframe: pandas.DataFrame, /) -> PandasDataFrameItem:
77+
def factory(cls, value: pandas.DataFrame, /) -> PandasDataFrameItem:
5478
"""
55-
Create a new PandasDataFrameItem instance from a pandas DataFrame.
79+
Create a new ``PandasDataFrameItem`` from an instance of ``pandas.DataFrame``.
80+
81+
It uses the ``JSON`` format.
5682
5783
Parameters
5884
----------
59-
dataframe : pd.DataFrame
60-
The pandas DataFrame to store.
85+
value : ``pandas.DataFrame``
86+
The value to serialize.
6187
6288
Returns
6389
-------
6490
PandasDataFrameItem
65-
A new PandasDataFrameItem instance.
91+
A new ``PandasDataFrameItem`` instance.
92+
93+
Raises
94+
------
95+
ItemTypeError
96+
If ``value`` is not an instance of ``pandas.DataFrame``.
6697
6798
Notes
6899
-----
69100
The dataframe must be JSON serializable.
70101
"""
71-
import pandas
72-
73-
if not isinstance(dataframe, pandas.DataFrame):
74-
raise ItemTypeError(f"Type '{dataframe.__class__}' is not supported.")
102+
if not lazy_is_instance(value, "pandas.core.frame.DataFrame"):
103+
raise ItemTypeError(f"Type '{value.__class__}' is not supported.")
75104

76105
# Two native methods are available to serialize dataframe with multi-index,
77106
# while keeping the index names:
@@ -95,13 +124,13 @@ def factory(cls, dataframe: pandas.DataFrame, /) -> PandasDataFrameItem:
95124
#
96125
# None of those methods being compatible, we decide to store indexes separately.
97126

98-
index = dataframe.index.to_frame(index=False)
99-
dataframe_without_index = dataframe.reset_index(drop=True)
127+
index = value.index.to_frame(index=False)
128+
dataframe_without_index = value.reset_index(drop=True)
100129

101130
instance = cls(
102131
index.to_json(orient=PandasDataFrameItem.ORIENT),
103132
dataframe_without_index.to_json(orient=PandasDataFrameItem.ORIENT),
104133
)
105-
instance.__raw__ = dataframe
134+
instance.__raw__ = value
106135

107136
return instance

0 commit comments

Comments
 (0)