lionagi 0.12.4__py3-none-any.whl → 0.12.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lionagi/protocols/generic/pile.py +76 -29
- lionagi/protocols/graph/node.py +25 -19
- lionagi/version.py +1 -1
- {lionagi-0.12.4.dist-info → lionagi-0.12.5.dist-info}/METADATA +2 -3
- {lionagi-0.12.4.dist-info → lionagi-0.12.5.dist-info}/RECORD +7 -17
- lionagi/adapters/__init__.py +0 -1
- lionagi/adapters/adapter.py +0 -120
- lionagi/adapters/json_adapter.py +0 -181
- lionagi/adapters/pandas_/__init__.py +0 -0
- lionagi/adapters/pandas_/csv_adapter.py +0 -94
- lionagi/adapters/pandas_/excel_adapter.py +0 -94
- lionagi/adapters/pandas_/pd_dataframe_adapter.py +0 -81
- lionagi/adapters/pandas_/pd_series_adapter.py +0 -57
- lionagi/adapters/toml_adapter.py +0 -204
- lionagi/adapters/types.py +0 -21
- {lionagi-0.12.4.dist-info → lionagi-0.12.5.dist-info}/WHEEL +0 -0
- {lionagi-0.12.4.dist-info → lionagi-0.12.5.dist-info}/licenses/LICENSE +0 -0
@@ -5,6 +5,7 @@
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
7
|
import asyncio
|
8
|
+
import json
|
8
9
|
import threading
|
9
10
|
from collections import deque
|
10
11
|
from collections.abc import (
|
@@ -21,18 +22,13 @@ from typing import Any, ClassVar, Generic, TypeVar
|
|
21
22
|
import pandas as pd
|
22
23
|
from pydantic import Field
|
23
24
|
from pydantic.fields import FieldInfo
|
25
|
+
from pydapter import Adapter, AdapterRegistry
|
26
|
+
from pydapter.adapters import CsvAdapter, JsonAdapter
|
27
|
+
from pydapter.extras.excel_ import ExcelAdapter
|
28
|
+
from pydapter.extras.pandas_ import DataFrameAdapter
|
24
29
|
from typing_extensions import Self, override
|
25
30
|
|
26
31
|
from lionagi._errors import ItemExistsError, ItemNotFoundError
|
27
|
-
from lionagi.adapters.types import (
|
28
|
-
Adapter,
|
29
|
-
AdapterRegistry,
|
30
|
-
CSVFileAdapter,
|
31
|
-
ExcelFileAdapter,
|
32
|
-
JsonAdapter,
|
33
|
-
JsonFileAdapter,
|
34
|
-
PandasDataFrameAdapter,
|
35
|
-
)
|
36
32
|
from lionagi.utils import UNDEFINED, is_same_dtype, to_list
|
37
33
|
|
38
34
|
from .._concepts import Observable
|
@@ -45,10 +41,9 @@ T = TypeVar("T", bound=E)
|
|
45
41
|
|
46
42
|
PILE_DEFAULT_ADAPTERS = (
|
47
43
|
JsonAdapter,
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
PandasDataFrameAdapter,
|
44
|
+
CsvAdapter,
|
45
|
+
ExcelAdapter,
|
46
|
+
DataFrameAdapter,
|
52
47
|
)
|
53
48
|
|
54
49
|
|
@@ -56,8 +51,9 @@ class PileAdapterRegistry(AdapterRegistry):
|
|
56
51
|
pass
|
57
52
|
|
58
53
|
|
54
|
+
pile_adapter_registry = PileAdapterRegistry()
|
59
55
|
for i in PILE_DEFAULT_ADAPTERS:
|
60
|
-
|
56
|
+
pile_adapter_registry.register(i)
|
61
57
|
|
62
58
|
|
63
59
|
__all__ = (
|
@@ -117,7 +113,7 @@ class Pile(Element, Collective[E], Generic[E]):
|
|
117
113
|
frozen=True,
|
118
114
|
)
|
119
115
|
|
120
|
-
_adapter_registry: ClassVar[AdapterRegistry] =
|
116
|
+
_adapter_registry: ClassVar[AdapterRegistry] = pile_adapter_registry
|
121
117
|
|
122
118
|
def __pydantic_extra__(self) -> dict[str, FieldInfo]:
|
123
119
|
return {
|
@@ -966,12 +962,25 @@ class Pile(Element, Collective[E], Generic[E]):
|
|
966
962
|
|
967
963
|
def adapt_to(self, obj_key: str, /, **kwargs: Any) -> Any:
|
968
964
|
"""Convert to another format."""
|
969
|
-
|
965
|
+
# For JSON adapter, we need to pass the dict representation
|
966
|
+
if obj_key in ["json", "csv", "toml"]:
|
967
|
+
data = self.to_dict()
|
970
968
|
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
969
|
+
# Create a simple object that has model_dump method
|
970
|
+
class _Wrapper:
|
971
|
+
def __init__(self, data):
|
972
|
+
self._data = data
|
973
|
+
|
974
|
+
def model_dump(self):
|
975
|
+
return self._data
|
976
|
+
|
977
|
+
wrapper = _Wrapper(data)
|
978
|
+
return self._get_adapter_registry().adapt_to(
|
979
|
+
wrapper, obj_key=obj_key, **kwargs
|
980
|
+
)
|
981
|
+
return self._get_adapter_registry().adapt_to(
|
982
|
+
self, obj_key=obj_key, **kwargs
|
983
|
+
)
|
975
984
|
|
976
985
|
@classmethod
|
977
986
|
def register_adapter(cls, adapter: type[Adapter]):
|
@@ -988,7 +997,7 @@ class Pile(Element, Collective[E], Generic[E]):
|
|
988
997
|
def adapt_from(cls, obj: Any, obj_key: str, /, **kwargs: Any):
|
989
998
|
"""Create from another format."""
|
990
999
|
dict_ = cls._get_adapter_registry().adapt_from(
|
991
|
-
cls, obj, obj_key, **kwargs
|
1000
|
+
cls, obj, obj_key=obj_key, **kwargs
|
992
1001
|
)
|
993
1002
|
if isinstance(dict_, list):
|
994
1003
|
dict_ = {"collections": dict_}
|
@@ -1000,11 +1009,31 @@ class Pile(Element, Collective[E], Generic[E]):
|
|
1000
1009
|
**kwargs: Any,
|
1001
1010
|
) -> pd.DataFrame:
|
1002
1011
|
"""Convert to DataFrame."""
|
1003
|
-
|
1012
|
+
# For DataFrame, we need to pass a list of dicts
|
1013
|
+
data = [item.to_dict() for item in self.collections.values()]
|
1014
|
+
|
1015
|
+
# Create wrapper objects for each item
|
1016
|
+
class _ItemWrapper:
|
1017
|
+
def __init__(self, data):
|
1018
|
+
self._data = data
|
1019
|
+
|
1020
|
+
def model_dump(self):
|
1021
|
+
return self._data
|
1022
|
+
|
1023
|
+
wrappers = [_ItemWrapper(d) for d in data]
|
1024
|
+
df = self._get_adapter_registry().adapt_to(
|
1025
|
+
wrappers, obj_key="pd.DataFrame", many=True, **kwargs
|
1026
|
+
)
|
1027
|
+
|
1028
|
+
if columns:
|
1029
|
+
return df[columns]
|
1030
|
+
return df
|
1004
1031
|
|
1005
1032
|
def to_csv_file(self, fp: str | Path, **kwargs: Any) -> None:
|
1006
1033
|
"""Save to CSV file."""
|
1007
|
-
|
1034
|
+
# Convert to DataFrame first, then save as CSV
|
1035
|
+
df = self.to_df()
|
1036
|
+
df.to_csv(fp, index=False, **kwargs)
|
1008
1037
|
|
1009
1038
|
def to_json_file(
|
1010
1039
|
self,
|
@@ -1025,8 +1054,14 @@ class Pile(Element, Collective[E], Generic[E]):
|
|
1025
1054
|
**kwargs: Additional arguments for json.dump() or DataFrame.to_json().
|
1026
1055
|
"""
|
1027
1056
|
if use_pd:
|
1028
|
-
return self.to_df().to_json(mode=mode, **kwargs)
|
1029
|
-
|
1057
|
+
return self.to_df().to_json(path_or_buf, mode=mode, **kwargs)
|
1058
|
+
|
1059
|
+
# Get JSON string from adapter
|
1060
|
+
json_str = self.adapt_to("json", many=many, **kwargs)
|
1061
|
+
|
1062
|
+
# Write to file
|
1063
|
+
with open(path_or_buf, mode, encoding="utf-8") as f:
|
1064
|
+
f.write(json_str)
|
1030
1065
|
|
1031
1066
|
|
1032
1067
|
def pile(
|
@@ -1052,16 +1087,28 @@ def pile(
|
|
1052
1087
|
"""
|
1053
1088
|
|
1054
1089
|
if df:
|
1055
|
-
return Pile.adapt_from(df, "
|
1090
|
+
return Pile.adapt_from(df, "pd.DataFrame", **kwargs)
|
1056
1091
|
|
1057
1092
|
if fp:
|
1058
1093
|
fp = Path(fp)
|
1059
1094
|
if fp.suffix == ".csv":
|
1060
|
-
|
1095
|
+
# Read CSV to DataFrame first
|
1096
|
+
df = pd.read_csv(fp, **kwargs)
|
1097
|
+
return Pile.adapt_from(df, "pd.DataFrame")
|
1061
1098
|
if fp.suffix == ".xlsx":
|
1062
|
-
|
1099
|
+
# Read Excel to DataFrame first
|
1100
|
+
df = pd.read_excel(fp, **kwargs)
|
1101
|
+
return Pile.adapt_from(df, "pd.DataFrame")
|
1063
1102
|
if fp.suffix in [".json", ".jsonl"]:
|
1064
|
-
|
1103
|
+
# Read JSON file
|
1104
|
+
with open(fp, encoding="utf-8") as f:
|
1105
|
+
data = json.load(f)
|
1106
|
+
if isinstance(data, dict):
|
1107
|
+
return Pile.from_dict(data)
|
1108
|
+
elif isinstance(data, list):
|
1109
|
+
return Pile.from_dict({"collections": data})
|
1110
|
+
else:
|
1111
|
+
raise ValueError(f"Invalid JSON data structure in {fp}")
|
1065
1112
|
|
1066
1113
|
return Pile(
|
1067
1114
|
collections,
|
lionagi/protocols/graph/node.py
CHANGED
@@ -6,26 +6,19 @@ import json
|
|
6
6
|
from typing import Any, ClassVar
|
7
7
|
|
8
8
|
from pydantic import field_validator
|
9
|
+
from pydapter import AdapterRegistry
|
10
|
+
from pydapter.adapters import JsonAdapter, TomlAdapter
|
11
|
+
from pydapter.extras.pandas_ import SeriesAdapter
|
9
12
|
|
10
13
|
from lionagi._class_registry import LION_CLASS_REGISTRY
|
11
|
-
from lionagi.adapters.types import (
|
12
|
-
AdapterRegistry,
|
13
|
-
JsonAdapter,
|
14
|
-
JsonFileAdapter,
|
15
|
-
PandasSeriesAdapter,
|
16
|
-
TomlAdapter,
|
17
|
-
TomlFileAdapter,
|
18
|
-
)
|
19
14
|
|
20
15
|
from .._concepts import Relational
|
21
16
|
from ..generic.element import Element
|
22
17
|
|
23
18
|
NODE_DEFAULT_ADAPTERS = (
|
24
19
|
JsonAdapter,
|
25
|
-
|
26
|
-
PandasSeriesAdapter,
|
20
|
+
SeriesAdapter,
|
27
21
|
TomlAdapter,
|
28
|
-
TomlFileAdapter,
|
29
22
|
)
|
30
23
|
|
31
24
|
|
@@ -33,8 +26,9 @@ class NodeAdapterRegistry(AdapterRegistry):
|
|
33
26
|
pass
|
34
27
|
|
35
28
|
|
29
|
+
node_adapter_registry = NodeAdapterRegistry()
|
36
30
|
for i in NODE_DEFAULT_ADAPTERS:
|
37
|
-
|
31
|
+
node_adapter_registry.register(i)
|
38
32
|
|
39
33
|
__all__ = ("Node",)
|
40
34
|
|
@@ -48,7 +42,7 @@ class Node(Element, Relational):
|
|
48
42
|
- Automatic subclass registration
|
49
43
|
"""
|
50
44
|
|
51
|
-
_adapter_registry: ClassVar[AdapterRegistry] =
|
45
|
+
_adapter_registry: ClassVar[AdapterRegistry] = node_adapter_registry
|
52
46
|
|
53
47
|
content: Any = None
|
54
48
|
embedding: list[float] | None = None
|
@@ -88,8 +82,24 @@ class Node(Element, Relational):
|
|
88
82
|
"""
|
89
83
|
Convert this Node to another format using a registered adapter.
|
90
84
|
"""
|
85
|
+
# For JSON/TOML adapters, we need to pass the dict representation
|
86
|
+
if obj_key in ["json", "toml"]:
|
87
|
+
data = self.to_dict()
|
88
|
+
|
89
|
+
# Create a simple object that has model_dump method
|
90
|
+
class _Wrapper:
|
91
|
+
def __init__(self, data):
|
92
|
+
self._data = data
|
93
|
+
|
94
|
+
def model_dump(self):
|
95
|
+
return self._data
|
96
|
+
|
97
|
+
wrapper = _Wrapper(data)
|
98
|
+
return self._get_adapter_registry().adapt_to(
|
99
|
+
wrapper, obj_key=obj_key, many=many, **kwargs
|
100
|
+
)
|
91
101
|
return self._get_adapter_registry().adapt_to(
|
92
|
-
self, obj_key, many=many, **kwargs
|
102
|
+
self, obj_key=obj_key, many=many, **kwargs
|
93
103
|
)
|
94
104
|
|
95
105
|
@classmethod
|
@@ -107,7 +117,7 @@ class Node(Element, Relational):
|
|
107
117
|
auto-delegate to the correct subclass via from_dict.
|
108
118
|
"""
|
109
119
|
result = cls._get_adapter_registry().adapt_from(
|
110
|
-
cls, obj, obj_key, many=many, **kwargs
|
120
|
+
cls, obj, obj_key=obj_key, many=many, **kwargs
|
111
121
|
)
|
112
122
|
# If adapter returned multiple items, choose the first or handle as needed.
|
113
123
|
if isinstance(result, list):
|
@@ -124,9 +134,5 @@ class Node(Element, Relational):
|
|
124
134
|
def register_adapter(cls, adapter: Any) -> None:
|
125
135
|
cls._get_adapter_registry().register(adapter)
|
126
136
|
|
127
|
-
@classmethod
|
128
|
-
def list_adapters(cls) -> list[str]:
|
129
|
-
return cls._get_adapter_registry().list_adapters()
|
130
|
-
|
131
137
|
|
132
138
|
# File: lionagi/protocols/graph/node.py
|
lionagi/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.12.
|
1
|
+
__version__ = "0.12.5"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lionagi
|
3
|
-
Version: 0.12.
|
3
|
+
Version: 0.12.5
|
4
4
|
Summary: An Intelligence Operating System.
|
5
5
|
Author-email: HaiyangLi <quantocean.li@gmail.com>, Liangbingyan Luo <llby_luo@outlook.com>
|
6
6
|
License: Apache License
|
@@ -223,10 +223,9 @@ Requires-Dist: aiocache>=0.12.0
|
|
223
223
|
Requires-Dist: aiohttp>=3.12.0
|
224
224
|
Requires-Dist: backoff>=2.2.1
|
225
225
|
Requires-Dist: jinja2>=3.1.0
|
226
|
-
Requires-Dist: pandas>=2.0.0
|
227
226
|
Requires-Dist: pillow>=11.0.0
|
228
227
|
Requires-Dist: pydantic-settings>=2.8.0
|
229
|
-
Requires-Dist:
|
228
|
+
Requires-Dist: pydapter[pandas]>=0.3.0
|
230
229
|
Requires-Dist: python-dotenv>=1.1.0
|
231
230
|
Requires-Dist: tiktoken>=0.8.0
|
232
231
|
Requires-Dist: toml>=0.9.0
|
@@ -6,17 +6,7 @@ lionagi/config.py,sha256=dAhDFKtaaSfn6WT9dwX9Vd4TWWs6-Su1FgYIrFgYcgc,3709
|
|
6
6
|
lionagi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
lionagi/settings.py,sha256=W52mM34E6jXF3GyqCFzVREKZrmnUqtZm_BVDsUiDI_s,1627
|
8
8
|
lionagi/utils.py,sha256=uLTJKl7aTnFXV6ehA6zwiwEB7G2nQYKsO2pZ6mqFzUk,78908
|
9
|
-
lionagi/version.py,sha256=
|
10
|
-
lionagi/adapters/__init__.py,sha256=FJBV1Fb7GR9mcRApEB9bNP3IRMQ9Qjg5aVTouZFyTBU,45
|
11
|
-
lionagi/adapters/adapter.py,sha256=aW7s1OKAdxHd8HBv2UcThn-r2Q08EyArssNyFobMLuA,3357
|
12
|
-
lionagi/adapters/json_adapter.py,sha256=EJj0Jev46ZhU3ZMnlYwyzN2rLxjLCVrMDpHkEuggBvk,4561
|
13
|
-
lionagi/adapters/toml_adapter.py,sha256=XOx0Q41g9FoNVuGrce96ck3gxPo4G-3mwqSin5kGq9s,5441
|
14
|
-
lionagi/adapters/types.py,sha256=CHfB39BSeyU11SDkXXkU_vzqy4v7kaR-2r0y6DYkhXc,660
|
15
|
-
lionagi/adapters/pandas_/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
lionagi/adapters/pandas_/csv_adapter.py,sha256=HWie6Jlt8nR-EVJC_zmCFilaWszLNuk7EWUp8Xvr-H8,2358
|
17
|
-
lionagi/adapters/pandas_/excel_adapter.py,sha256=ZqRT2xF93NLKNyMp16ePNzwUN3ntNkUy1dO3nbsrfak,2287
|
18
|
-
lionagi/adapters/pandas_/pd_dataframe_adapter.py,sha256=ULGZVhK5aaOuTrmFq4x5SiuDScYetyYYUHeL8Hh13Eg,2279
|
19
|
-
lionagi/adapters/pandas_/pd_series_adapter.py,sha256=TX3cqFtgEip8JqVqkjdJYOu4PQGpW1yYU6POhvz8Jeg,1388
|
9
|
+
lionagi/version.py,sha256=QFQfu3CUVe9Ncr8kv3aaBY3oWrZmv8xboen_Uwy7eXU,23
|
20
10
|
lionagi/fields/__init__.py,sha256=8oU7Vfk-fKiULFKqhM6VpJMqdZcVXPTM7twVfNDN_SQ,603
|
21
11
|
lionagi/fields/action.py,sha256=iWSApCM77jS0Oc28lb7G601Etkp-yjx5U1hfI_FQgfA,5792
|
22
12
|
lionagi/fields/base.py,sha256=5CJc7j8kTTWzXwpYzkSAFzx4BglABfx3AElIATKB7bg,3857
|
@@ -140,13 +130,13 @@ lionagi/protocols/generic/__init__.py,sha256=5y5joOZzfFWERl75auAcNcKC3lImVJ5ZZGv
|
|
140
130
|
lionagi/protocols/generic/element.py,sha256=Eaij2YpTWsGk28Tqjazmjmc_tOnalH7_iGFZrL6QJb4,14420
|
141
131
|
lionagi/protocols/generic/event.py,sha256=InjBd2K9aSYxgai1c20d4jaJOkEx5VGFfb7iZbiMiNA,5200
|
142
132
|
lionagi/protocols/generic/log.py,sha256=vepclOaY3fdR1QgFDj9usOffsx9T-9PbgwXjTvm6twQ,7441
|
143
|
-
lionagi/protocols/generic/pile.py,sha256=
|
133
|
+
lionagi/protocols/generic/pile.py,sha256=L965LgVKhaxpEe_5dOwjYFZ1UAGeWmUtZ4Tf0MRznHw,33562
|
144
134
|
lionagi/protocols/generic/processor.py,sha256=LTF9Enb-9jj5Wuy_jLanAhiesc5-Gm6WiSntZoAAm8w,10382
|
145
135
|
lionagi/protocols/generic/progression.py,sha256=qlITq1qzV119iR5qR__fBAzV489S7d4t20E8uDRicEw,15189
|
146
136
|
lionagi/protocols/graph/__init__.py,sha256=5y5joOZzfFWERl75auAcNcKC3lImVJ5ZZGvvHZUFCJM,112
|
147
137
|
lionagi/protocols/graph/edge.py,sha256=lgxeceoazM4Jl2Un_owLpJOanqw2m4XPk3-dXGp1u8g,5229
|
148
138
|
lionagi/protocols/graph/graph.py,sha256=ks3zJWdwycUW_3Q4dz3f_ZLYhOALpg76t5J3HEzDcy4,10237
|
149
|
-
lionagi/protocols/graph/node.py,sha256=
|
139
|
+
lionagi/protocols/graph/node.py,sha256=_bQ9h_s_X6dVyV4pueEfiKiFapOkDL-HuH2MboUekYI,4250
|
150
140
|
lionagi/protocols/mail/__init__.py,sha256=5y5joOZzfFWERl75auAcNcKC3lImVJ5ZZGvvHZUFCJM,112
|
151
141
|
lionagi/protocols/mail/exchange.py,sha256=P1PcrFylIBeiQa8kox9H1qyJ4kjhUlbLiTUT8rs1OXg,7041
|
152
142
|
lionagi/protocols/mail/mail.py,sha256=RB5CUft_4J85H9nM9g6aRXomTaqKwF5xVjJacPAhoa8,1356
|
@@ -207,7 +197,7 @@ lionagi/tools/types.py,sha256=XtJLY0m-Yi_ZLWhm0KycayvqMCZd--HxfQ0x9vFUYDE,230
|
|
207
197
|
lionagi/tools/file/__init__.py,sha256=5y5joOZzfFWERl75auAcNcKC3lImVJ5ZZGvvHZUFCJM,112
|
208
198
|
lionagi/tools/file/reader.py,sha256=0TdnfVGVCKuM58MmGM-NyVjhU9BFoitkNYEepdc0z_Y,9529
|
209
199
|
lionagi/tools/memory/tools.py,sha256=zTGBenVsF8Wuh303kWntmQSGlAFKonHNdh5ePuQ26KE,15948
|
210
|
-
lionagi-0.12.
|
211
|
-
lionagi-0.12.
|
212
|
-
lionagi-0.12.
|
213
|
-
lionagi-0.12.
|
200
|
+
lionagi-0.12.5.dist-info/METADATA,sha256=0vHIkYR3nyKPKxuivRY8XjNiVBk0UP0KvEbY2cxscEY,18960
|
201
|
+
lionagi-0.12.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
202
|
+
lionagi-0.12.5.dist-info/licenses/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
|
203
|
+
lionagi-0.12.5.dist-info/RECORD,,
|
lionagi/adapters/__init__.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
"""deprecated, will be removed in v0.13.0"""
|
lionagi/adapters/adapter.py
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
# Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
|
5
|
-
"""
|
6
|
-
Defines the `Adapter` protocol (a formal interface), along with the
|
7
|
-
`AdapterRegistry` that maps string/file extensions or object keys to
|
8
|
-
specific adapter implementations.
|
9
|
-
"""
|
10
|
-
|
11
|
-
import logging
|
12
|
-
from typing import Any, Protocol, TypeVar, runtime_checkable
|
13
|
-
|
14
|
-
from typing_extensions import get_protocol_members
|
15
|
-
|
16
|
-
T = TypeVar("T")
|
17
|
-
|
18
|
-
__all__ = (
|
19
|
-
"Adapter",
|
20
|
-
"ADAPTER_MEMBERS",
|
21
|
-
"AdapterRegistry",
|
22
|
-
)
|
23
|
-
|
24
|
-
|
25
|
-
@runtime_checkable
|
26
|
-
class Adapter(Protocol):
|
27
|
-
"""
|
28
|
-
Describes a two-way converter that knows how to transform an object
|
29
|
-
from an external representation to an internal format, and vice versa.
|
30
|
-
|
31
|
-
Attributes
|
32
|
-
----------
|
33
|
-
obj_key : str
|
34
|
-
A unique key or extension that identifies what format this
|
35
|
-
adapter supports (e.g. ".csv", "json", "pd_dataframe").
|
36
|
-
|
37
|
-
Methods
|
38
|
-
-------
|
39
|
-
from_obj(subj_cls: type[T], obj: Any, /, many: bool, **kwargs) -> dict|list[dict]
|
40
|
-
Converts a raw external object (file contents, JSON string, etc.)
|
41
|
-
into a dictionary or list of dictionaries.
|
42
|
-
to_obj(subj: T, /, many: bool, **kwargs) -> Any
|
43
|
-
Converts an internal object (e.g., a Pydantic-based model)
|
44
|
-
into the target format (file, JSON, DataFrame, etc.).
|
45
|
-
"""
|
46
|
-
|
47
|
-
obj_key: str
|
48
|
-
|
49
|
-
@classmethod
|
50
|
-
def from_obj(
|
51
|
-
cls,
|
52
|
-
subj_cls: type[T],
|
53
|
-
obj: Any,
|
54
|
-
/,
|
55
|
-
*,
|
56
|
-
many: bool,
|
57
|
-
**kwargs,
|
58
|
-
) -> dict | list[dict]: ...
|
59
|
-
|
60
|
-
@classmethod
|
61
|
-
def to_obj(
|
62
|
-
cls,
|
63
|
-
subj: T,
|
64
|
-
/,
|
65
|
-
*,
|
66
|
-
many: bool,
|
67
|
-
**kwargs,
|
68
|
-
) -> Any: ...
|
69
|
-
|
70
|
-
|
71
|
-
ADAPTER_MEMBERS = get_protocol_members(Adapter) # duck typing
|
72
|
-
|
73
|
-
|
74
|
-
class AdapterRegistry:
|
75
|
-
|
76
|
-
_adapters: dict[str, Adapter] = {}
|
77
|
-
|
78
|
-
@classmethod
|
79
|
-
def list_adapters(cls) -> list[tuple[str | type, ...]]:
|
80
|
-
return list(cls._adapters.keys())
|
81
|
-
|
82
|
-
@classmethod
|
83
|
-
def register(cls, adapter: type[Adapter]) -> None:
|
84
|
-
for member in ADAPTER_MEMBERS:
|
85
|
-
if not hasattr(adapter, member):
|
86
|
-
_str = getattr(adapter, "obj_key", None) or repr(adapter)
|
87
|
-
_str = _str[:50] if len(_str) > 50 else _str
|
88
|
-
raise AttributeError(
|
89
|
-
f"Adapter {_str} missing required methods."
|
90
|
-
)
|
91
|
-
|
92
|
-
if isinstance(adapter, type):
|
93
|
-
cls._adapters[adapter.obj_key] = adapter()
|
94
|
-
else:
|
95
|
-
cls._adapters[adapter.obj_key] = adapter
|
96
|
-
|
97
|
-
@classmethod
|
98
|
-
def get(cls, obj_key: type | str) -> Adapter:
|
99
|
-
try:
|
100
|
-
return cls._adapters[obj_key]
|
101
|
-
except Exception as e:
|
102
|
-
logging.error(f"Error getting adapter for {obj_key}. Error: {e}")
|
103
|
-
|
104
|
-
@classmethod
|
105
|
-
def adapt_from(
|
106
|
-
cls, subj_cls: type[T], obj: Any, obj_key: type | str, **kwargs
|
107
|
-
) -> dict | list[dict]:
|
108
|
-
try:
|
109
|
-
return cls.get(obj_key).from_obj(subj_cls, obj, **kwargs)
|
110
|
-
except Exception as e:
|
111
|
-
logging.error(f"Error adapting data from {obj_key}. Error: {e}")
|
112
|
-
raise e
|
113
|
-
|
114
|
-
@classmethod
|
115
|
-
def adapt_to(cls, subj: T, obj_key: type | str, **kwargs) -> Any:
|
116
|
-
try:
|
117
|
-
return cls.get(obj_key).to_obj(subj, **kwargs)
|
118
|
-
except Exception as e:
|
119
|
-
logging.error(f"Error adapting data to {obj_key}. Error: {e}")
|
120
|
-
raise e
|
lionagi/adapters/json_adapter.py
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Implements two adapters:
|
3
|
-
- `JsonAdapter` for in-memory JSON strings
|
4
|
-
- `JsonFileAdapter` for reading/writing JSON files
|
5
|
-
"""
|
6
|
-
|
7
|
-
import json
|
8
|
-
import logging
|
9
|
-
from pathlib import Path
|
10
|
-
|
11
|
-
from lionagi.protocols._concepts import Collective
|
12
|
-
|
13
|
-
from .adapter import Adapter, T
|
14
|
-
|
15
|
-
|
16
|
-
class JsonAdapter(Adapter):
|
17
|
-
"""
|
18
|
-
Adapter that converts to/from JSON **strings** in memory.
|
19
|
-
Example usage: taking a Python dictionary and making JSON,
|
20
|
-
or parsing JSON string to a dict.
|
21
|
-
"""
|
22
|
-
|
23
|
-
obj_key = "json"
|
24
|
-
|
25
|
-
@classmethod
|
26
|
-
def from_obj(
|
27
|
-
cls,
|
28
|
-
subj_cls: type[T],
|
29
|
-
obj: str,
|
30
|
-
/,
|
31
|
-
*,
|
32
|
-
many: bool = False,
|
33
|
-
**kwargs,
|
34
|
-
) -> dict | list[dict]:
|
35
|
-
"""
|
36
|
-
Convert a JSON string into a dict or list of dicts.
|
37
|
-
|
38
|
-
Parameters
|
39
|
-
----------
|
40
|
-
subj_cls : type[T]
|
41
|
-
The target class for context (not always used).
|
42
|
-
obj : str
|
43
|
-
The JSON string.
|
44
|
-
many : bool, optional
|
45
|
-
If True, expects a JSON array (returns list[dict]).
|
46
|
-
Otherwise returns a single dict or the first element.
|
47
|
-
**kwargs
|
48
|
-
Extra arguments for json.loads().
|
49
|
-
|
50
|
-
Returns
|
51
|
-
-------
|
52
|
-
dict | list[dict]
|
53
|
-
The loaded JSON data.
|
54
|
-
"""
|
55
|
-
result = json.loads(obj, **kwargs)
|
56
|
-
if many:
|
57
|
-
return result if isinstance(result, list) else [result]
|
58
|
-
if isinstance(result, list) and len(result) > 0:
|
59
|
-
return result[0]
|
60
|
-
return result
|
61
|
-
|
62
|
-
@classmethod
|
63
|
-
def to_obj(
|
64
|
-
cls,
|
65
|
-
subj: T,
|
66
|
-
*,
|
67
|
-
many: bool = False,
|
68
|
-
**kwargs,
|
69
|
-
) -> str:
|
70
|
-
"""
|
71
|
-
Convert an object (or collection) to a JSON string.
|
72
|
-
|
73
|
-
Parameters
|
74
|
-
----------
|
75
|
-
subj : T
|
76
|
-
The object to serialize.
|
77
|
-
many : bool, optional
|
78
|
-
If True, convert multiple items to a JSON array.
|
79
|
-
**kwargs
|
80
|
-
Extra arguments for json.dumps().
|
81
|
-
|
82
|
-
Returns
|
83
|
-
-------
|
84
|
-
str
|
85
|
-
The resulting JSON string.
|
86
|
-
"""
|
87
|
-
if many:
|
88
|
-
if isinstance(subj, Collective):
|
89
|
-
data = [i.to_dict() for i in subj]
|
90
|
-
else:
|
91
|
-
data = [subj.to_dict()]
|
92
|
-
return json.dumps(data, **kwargs)
|
93
|
-
return json.dumps(subj.to_dict(), **kwargs)
|
94
|
-
|
95
|
-
|
96
|
-
class JsonFileAdapter(Adapter):
|
97
|
-
"""
|
98
|
-
Adapter that reads/writes JSON data to/from a file on disk.
|
99
|
-
The file extension key is ".json".
|
100
|
-
"""
|
101
|
-
|
102
|
-
obj_key = ".json"
|
103
|
-
|
104
|
-
@classmethod
|
105
|
-
def from_obj(
|
106
|
-
cls,
|
107
|
-
subj_cls: type[T],
|
108
|
-
obj: str | Path,
|
109
|
-
/,
|
110
|
-
*,
|
111
|
-
many: bool = False,
|
112
|
-
**kwargs,
|
113
|
-
) -> dict | list[dict]:
|
114
|
-
"""
|
115
|
-
Read a JSON file from disk and return a dict or list of dicts.
|
116
|
-
|
117
|
-
Parameters
|
118
|
-
----------
|
119
|
-
subj_cls : type[T]
|
120
|
-
The target class for context.
|
121
|
-
obj : str | Path
|
122
|
-
The JSON file path.
|
123
|
-
many : bool
|
124
|
-
If True, expects a list. Otherwise single dict or first element.
|
125
|
-
**kwargs
|
126
|
-
Extra arguments for json.load().
|
127
|
-
|
128
|
-
Returns
|
129
|
-
-------
|
130
|
-
dict | list[dict]
|
131
|
-
The loaded data from file.
|
132
|
-
"""
|
133
|
-
with open(obj, encoding="utf-8") as f:
|
134
|
-
result = json.load(f, **kwargs)
|
135
|
-
if many:
|
136
|
-
return result if isinstance(result, list) else [result]
|
137
|
-
if isinstance(result, list) and len(result) > 0:
|
138
|
-
return result[0]
|
139
|
-
return result
|
140
|
-
|
141
|
-
@classmethod
|
142
|
-
def to_obj(
|
143
|
-
cls,
|
144
|
-
subj: T,
|
145
|
-
/,
|
146
|
-
*,
|
147
|
-
fp: str | Path,
|
148
|
-
many: bool = False,
|
149
|
-
mode: str = "w",
|
150
|
-
**kwargs,
|
151
|
-
) -> None:
|
152
|
-
"""
|
153
|
-
Write a dict (or list) to a JSON file.
|
154
|
-
|
155
|
-
Parameters
|
156
|
-
----------
|
157
|
-
subj : T
|
158
|
-
The object/collection to serialize.
|
159
|
-
fp : str | Path
|
160
|
-
The file path to write.
|
161
|
-
many : bool
|
162
|
-
If True, write as a JSON array of multiple items.
|
163
|
-
**kwargs
|
164
|
-
Extra arguments for json.dump().
|
165
|
-
|
166
|
-
Returns
|
167
|
-
-------
|
168
|
-
None
|
169
|
-
"""
|
170
|
-
with open(fp, mode, encoding="utf-8") as f:
|
171
|
-
if many:
|
172
|
-
if isinstance(subj, Collective):
|
173
|
-
json.dump([i.to_dict() for i in subj], f, **kwargs)
|
174
|
-
else:
|
175
|
-
json.dump([subj.to_dict()], f, **kwargs)
|
176
|
-
else:
|
177
|
-
json.dump(subj.to_dict(), f, **kwargs)
|
178
|
-
logging.info(f"JSON data saved to {fp}")
|
179
|
-
|
180
|
-
|
181
|
-
# File: lionagi/protocols/adapters/json_adapter.py
|
File without changes
|
@@ -1,94 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from pathlib import Path
|
3
|
-
|
4
|
-
import pandas as pd
|
5
|
-
|
6
|
-
from lionagi.protocols._concepts import Collective
|
7
|
-
|
8
|
-
from ..adapter import Adapter, T
|
9
|
-
|
10
|
-
|
11
|
-
class CSVFileAdapter(Adapter):
|
12
|
-
"""
|
13
|
-
Reads/writes CSV files to a list of dicts or vice versa,
|
14
|
-
using `pandas`.
|
15
|
-
"""
|
16
|
-
|
17
|
-
obj_key = ".csv"
|
18
|
-
|
19
|
-
@classmethod
|
20
|
-
def from_obj(
|
21
|
-
cls,
|
22
|
-
subj_cls: type[T],
|
23
|
-
obj: str | Path,
|
24
|
-
/,
|
25
|
-
*,
|
26
|
-
many: bool = False,
|
27
|
-
**kwargs,
|
28
|
-
) -> list[dict]:
|
29
|
-
"""
|
30
|
-
Read a CSV file into a list of dictionaries.
|
31
|
-
|
32
|
-
Parameters
|
33
|
-
----------
|
34
|
-
subj_cls : type[T]
|
35
|
-
The target class for context (not used).
|
36
|
-
obj : str | Path
|
37
|
-
The CSV file path.
|
38
|
-
many : bool, optional
|
39
|
-
If True, returns list[dict]; if False, returns only
|
40
|
-
the first dict.
|
41
|
-
**kwargs
|
42
|
-
Additional options for `pd.read_csv`.
|
43
|
-
|
44
|
-
Returns
|
45
|
-
-------
|
46
|
-
list[dict]
|
47
|
-
The parsed CSV data as a list of row dictionaries.
|
48
|
-
"""
|
49
|
-
df: pd.DataFrame = pd.read_csv(obj, **kwargs)
|
50
|
-
dicts_ = df.to_dict(orient="records")
|
51
|
-
if many:
|
52
|
-
return dicts_
|
53
|
-
return dicts_[0] if len(dicts_) > 0 else {}
|
54
|
-
|
55
|
-
@classmethod
|
56
|
-
def to_obj(
|
57
|
-
cls,
|
58
|
-
subj: T,
|
59
|
-
/,
|
60
|
-
*,
|
61
|
-
fp: str | Path,
|
62
|
-
many: bool = False,
|
63
|
-
**kwargs,
|
64
|
-
) -> None:
|
65
|
-
"""
|
66
|
-
Write an object's data to a CSV file.
|
67
|
-
|
68
|
-
Parameters
|
69
|
-
----------
|
70
|
-
subj : T
|
71
|
-
The item(s) to convert. If `many=True`, can be a Collective.
|
72
|
-
fp : str | Path
|
73
|
-
File path to write the CSV.
|
74
|
-
many : bool
|
75
|
-
If True, we assume a collection of items, else a single item.
|
76
|
-
**kwargs
|
77
|
-
Extra params for `DataFrame.to_csv`.
|
78
|
-
|
79
|
-
Returns
|
80
|
-
-------
|
81
|
-
None
|
82
|
-
"""
|
83
|
-
kwargs["index"] = False # By default, do not save index
|
84
|
-
if many:
|
85
|
-
if isinstance(subj, Collective):
|
86
|
-
pd.DataFrame([i.to_dict() for i in subj]).to_csv(fp, **kwargs)
|
87
|
-
else:
|
88
|
-
pd.DataFrame([subj.to_dict()]).to_csv(fp, **kwargs)
|
89
|
-
else:
|
90
|
-
pd.DataFrame([subj.to_dict()]).to_csv(fp, **kwargs)
|
91
|
-
logging.info(f"CSV data saved to {fp}")
|
92
|
-
|
93
|
-
|
94
|
-
# File: lionagi/protocols/adapters/pandas_/csv_adapter.py
|
@@ -1,94 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Provides an ExcelFileAdapter for reading/writing Excel (.xlsx) files
|
3
|
-
via pandas.
|
4
|
-
"""
|
5
|
-
|
6
|
-
import logging
|
7
|
-
from pathlib import Path
|
8
|
-
|
9
|
-
import pandas as pd
|
10
|
-
|
11
|
-
from lionagi.protocols._concepts import Collective
|
12
|
-
|
13
|
-
from ..adapter import Adapter, T
|
14
|
-
|
15
|
-
|
16
|
-
class ExcelFileAdapter(Adapter):
|
17
|
-
"""
|
18
|
-
Reads/writes Excel (XLSX) files, using `pandas`.
|
19
|
-
"""
|
20
|
-
|
21
|
-
obj_key = ".xlsx"
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
def from_obj(
|
25
|
-
cls,
|
26
|
-
subj_cls: type[T],
|
27
|
-
obj: str | Path,
|
28
|
-
/,
|
29
|
-
*,
|
30
|
-
many: bool = False,
|
31
|
-
**kwargs,
|
32
|
-
) -> list[dict]:
|
33
|
-
"""
|
34
|
-
Read an Excel file into a list of dictionaries.
|
35
|
-
|
36
|
-
Parameters
|
37
|
-
----------
|
38
|
-
subj_cls : type[T]
|
39
|
-
Target class for context.
|
40
|
-
obj : str | Path
|
41
|
-
The Excel file path.
|
42
|
-
many : bool, optional
|
43
|
-
If True, returns list[dict]. If False, returns single dict or first element.
|
44
|
-
**kwargs
|
45
|
-
Additional options for `pd.read_excel`.
|
46
|
-
|
47
|
-
Returns
|
48
|
-
-------
|
49
|
-
list[dict]
|
50
|
-
"""
|
51
|
-
df: pd.DataFrame = pd.read_excel(obj, **kwargs)
|
52
|
-
dicts_ = df.to_dict(orient="records")
|
53
|
-
if many:
|
54
|
-
return dicts_
|
55
|
-
return dicts_[0] if len(dicts_) > 0 else {}
|
56
|
-
|
57
|
-
@classmethod
|
58
|
-
def to_obj(
|
59
|
-
cls,
|
60
|
-
subj: T,
|
61
|
-
/,
|
62
|
-
*,
|
63
|
-
fp: str | Path,
|
64
|
-
many: bool = False,
|
65
|
-
**kwargs,
|
66
|
-
) -> None:
|
67
|
-
"""
|
68
|
-
Write data to an Excel file.
|
69
|
-
|
70
|
-
Parameters
|
71
|
-
----------
|
72
|
-
subj : T
|
73
|
-
The object(s) to convert to Excel rows.
|
74
|
-
fp : str | Path
|
75
|
-
Path to save the XLSX file.
|
76
|
-
many : bool
|
77
|
-
If True, writes multiple items (e.g., a Collective).
|
78
|
-
**kwargs
|
79
|
-
Extra parameters for `DataFrame.to_excel`.
|
80
|
-
"""
|
81
|
-
kwargs["index"] = False
|
82
|
-
if many:
|
83
|
-
if isinstance(subj, Collective):
|
84
|
-
pd.DataFrame([i.to_dict() for i in subj]).to_excel(
|
85
|
-
fp, **kwargs
|
86
|
-
)
|
87
|
-
else:
|
88
|
-
pd.DataFrame([subj.to_dict()]).to_excel(fp, **kwargs)
|
89
|
-
else:
|
90
|
-
pd.DataFrame([subj.to_dict()]).to_excel(fp, **kwargs)
|
91
|
-
logging.info(f"Excel data saved to {fp}")
|
92
|
-
|
93
|
-
|
94
|
-
# File: lionagi/protocols/adapters/pandas_/excel_adapter.py
|
@@ -1,81 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Defines a `PandasDataFrameAdapter` that converts between
|
3
|
-
a DataFrame and a list of dictionary-based elements.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from datetime import datetime
|
7
|
-
|
8
|
-
import pandas as pd
|
9
|
-
|
10
|
-
from ..adapter import Adapter, T
|
11
|
-
|
12
|
-
|
13
|
-
class PandasDataFrameAdapter(Adapter):
|
14
|
-
"""
|
15
|
-
Converts a set of objects to a single `pd.DataFrame`, or
|
16
|
-
a DataFrame to a list of dictionaries. Typically used in memory,
|
17
|
-
not for saving to file.
|
18
|
-
"""
|
19
|
-
|
20
|
-
obj_key = "pd_dataframe"
|
21
|
-
alias = ("pandas_dataframe", "pd.DataFrame", "pd_dataframe")
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
def from_obj(
|
25
|
-
cls, subj_cls: type[T], obj: pd.DataFrame, /, **kwargs
|
26
|
-
) -> list[dict]:
|
27
|
-
"""
|
28
|
-
Convert an existing DataFrame into a list of dicts.
|
29
|
-
|
30
|
-
Parameters
|
31
|
-
----------
|
32
|
-
subj_cls : type[T]
|
33
|
-
The internal class to which we might parse.
|
34
|
-
obj : pd.DataFrame
|
35
|
-
The DataFrame to convert.
|
36
|
-
**kwargs
|
37
|
-
Additional args for DataFrame.to_dict (like `orient`).
|
38
|
-
|
39
|
-
Returns
|
40
|
-
-------
|
41
|
-
list[dict]
|
42
|
-
Each row as a dictionary.
|
43
|
-
"""
|
44
|
-
return obj.to_dict(orient="records", **kwargs)
|
45
|
-
|
46
|
-
@classmethod
|
47
|
-
def to_obj(cls, subj: list[T], /, **kwargs) -> pd.DataFrame:
|
48
|
-
"""
|
49
|
-
Convert multiple items into a DataFrame, adjusting `created_at` to datetime.
|
50
|
-
|
51
|
-
Parameters
|
52
|
-
----------
|
53
|
-
subj : list[T]
|
54
|
-
The items to convert. Each item must have `to_dict()`.
|
55
|
-
**kwargs
|
56
|
-
Additional arguments for `pd.DataFrame(...)`.
|
57
|
-
|
58
|
-
Returns
|
59
|
-
-------
|
60
|
-
pd.DataFrame
|
61
|
-
The resulting DataFrame.
|
62
|
-
"""
|
63
|
-
out_ = []
|
64
|
-
for i in subj:
|
65
|
-
_dict = i.to_dict()
|
66
|
-
# Attempt to parse timestamps
|
67
|
-
if "created_at" in _dict:
|
68
|
-
try:
|
69
|
-
_dict["created_at"] = datetime.fromtimestamp(
|
70
|
-
_dict["created_at"]
|
71
|
-
)
|
72
|
-
except Exception:
|
73
|
-
pass
|
74
|
-
out_.append(_dict)
|
75
|
-
df = pd.DataFrame(out_, **kwargs)
|
76
|
-
# Convert created_at to datetime if present
|
77
|
-
if "created_at" in df.columns:
|
78
|
-
df["created_at"] = pd.to_datetime(
|
79
|
-
df["created_at"], errors="coerce"
|
80
|
-
)
|
81
|
-
return df
|
@@ -1,57 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Defines a `PandasSeriesAdapter` that converts a single object
|
3
|
-
to/from a `pd.Series`.
|
4
|
-
"""
|
5
|
-
|
6
|
-
import pandas as pd
|
7
|
-
|
8
|
-
from ..adapter import Adapter, T
|
9
|
-
|
10
|
-
|
11
|
-
class PandasSeriesAdapter(Adapter):
|
12
|
-
"""
|
13
|
-
Converts a single item to a Pandas Series and vice versa.
|
14
|
-
Great for 1-row data or simpler key-value pairs.
|
15
|
-
"""
|
16
|
-
|
17
|
-
obj_key = "pd_series"
|
18
|
-
alias = ("pandas_series", "pd.series", "pd_series")
|
19
|
-
|
20
|
-
@classmethod
|
21
|
-
def from_obj(cls, subj_cls: type[T], obj: pd.Series, /, **kwargs) -> dict:
|
22
|
-
"""
|
23
|
-
Convert a Pandas Series into a dictionary.
|
24
|
-
|
25
|
-
Parameters
|
26
|
-
----------
|
27
|
-
subj_cls : type[T]
|
28
|
-
Possibly the class we might use to rehydrate the item.
|
29
|
-
obj : pd.Series
|
30
|
-
The series to interpret.
|
31
|
-
**kwargs
|
32
|
-
Additional arguments for `Series.to_dict`.
|
33
|
-
|
34
|
-
Returns
|
35
|
-
-------
|
36
|
-
dict
|
37
|
-
The data from the Series as a dictionary.
|
38
|
-
"""
|
39
|
-
return obj.to_dict(**kwargs)
|
40
|
-
|
41
|
-
@classmethod
|
42
|
-
def to_obj(cls, subj: T, /, **kwargs) -> pd.Series:
|
43
|
-
"""
|
44
|
-
Convert a single item to a Series.
|
45
|
-
|
46
|
-
Parameters
|
47
|
-
----------
|
48
|
-
subj : T
|
49
|
-
The item, which must have `to_dict()`.
|
50
|
-
**kwargs
|
51
|
-
Extra args passed to `pd.Series`.
|
52
|
-
|
53
|
-
Returns
|
54
|
-
-------
|
55
|
-
pd.Series
|
56
|
-
"""
|
57
|
-
return pd.Series(subj.to_dict(), **kwargs)
|
lionagi/adapters/toml_adapter.py
DELETED
@@ -1,204 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Implements two adapters:
|
3
|
-
- `TomlAdapter` for in-memory TOML strings
|
4
|
-
- `TomlFileAdapter` for reading/writing TOML files
|
5
|
-
"""
|
6
|
-
|
7
|
-
import logging
|
8
|
-
from pathlib import Path
|
9
|
-
|
10
|
-
import toml
|
11
|
-
|
12
|
-
from lionagi.protocols._concepts import Collective
|
13
|
-
|
14
|
-
from .adapter import Adapter, T
|
15
|
-
|
16
|
-
|
17
|
-
class TomlAdapter(Adapter):
|
18
|
-
"""
|
19
|
-
Adapter that converts to/from TOML **strings** in memory.
|
20
|
-
Example usage: taking a Python dictionary and making TOML,
|
21
|
-
or parsing TOML string to a dict.
|
22
|
-
"""
|
23
|
-
|
24
|
-
obj_key = "toml"
|
25
|
-
|
26
|
-
@classmethod
|
27
|
-
def from_obj(
|
28
|
-
cls,
|
29
|
-
subj_cls: type[T],
|
30
|
-
obj: str,
|
31
|
-
/,
|
32
|
-
*,
|
33
|
-
many: bool = False,
|
34
|
-
**kwargs,
|
35
|
-
) -> dict | list[dict]:
|
36
|
-
"""
|
37
|
-
Convert a TOML string into a dict or list of dicts.
|
38
|
-
|
39
|
-
Parameters
|
40
|
-
----------
|
41
|
-
subj_cls : type[T]
|
42
|
-
The target class for context (not always used).
|
43
|
-
obj : str
|
44
|
-
The TOML string.
|
45
|
-
many : bool, optional
|
46
|
-
If True, expects a TOML array of tables (returns list[dict]).
|
47
|
-
Otherwise returns a single dict.
|
48
|
-
**kwargs
|
49
|
-
Extra arguments for toml.loads().
|
50
|
-
|
51
|
-
Returns
|
52
|
-
-------
|
53
|
-
dict | list[dict]
|
54
|
-
The loaded TOML data.
|
55
|
-
"""
|
56
|
-
result = toml.loads(obj, **kwargs)
|
57
|
-
|
58
|
-
# Handle array of tables in TOML for "many" case
|
59
|
-
if many:
|
60
|
-
# Check if there's a top-level array key that might hold multiple items
|
61
|
-
for key, value in result.items():
|
62
|
-
if isinstance(value, list) and all(
|
63
|
-
isinstance(item, dict) for item in value
|
64
|
-
):
|
65
|
-
return value
|
66
|
-
# If no array of tables found, wrap the result in a list
|
67
|
-
return [result]
|
68
|
-
|
69
|
-
return result
|
70
|
-
|
71
|
-
@classmethod
|
72
|
-
def to_obj(
|
73
|
-
cls,
|
74
|
-
subj: T,
|
75
|
-
*,
|
76
|
-
many: bool = False,
|
77
|
-
**kwargs,
|
78
|
-
) -> str:
|
79
|
-
"""
|
80
|
-
Convert an object (or collection) to a TOML string.
|
81
|
-
|
82
|
-
Parameters
|
83
|
-
----------
|
84
|
-
subj : T
|
85
|
-
The object to serialize.
|
86
|
-
many : bool, optional
|
87
|
-
If True, convert multiple items to a TOML array of tables.
|
88
|
-
**kwargs
|
89
|
-
Extra arguments for toml.dumps().
|
90
|
-
|
91
|
-
Returns
|
92
|
-
-------
|
93
|
-
str
|
94
|
-
The resulting TOML string.
|
95
|
-
"""
|
96
|
-
if many:
|
97
|
-
if isinstance(subj, Collective):
|
98
|
-
# For multiple items, create a wrapper dict with an array of items
|
99
|
-
data = {"items": [i.to_dict() for i in subj]}
|
100
|
-
else:
|
101
|
-
data = {"items": [subj.to_dict()]}
|
102
|
-
return toml.dumps(data, **kwargs)
|
103
|
-
|
104
|
-
return toml.dumps(subj.to_dict(), **kwargs)
|
105
|
-
|
106
|
-
|
107
|
-
class TomlFileAdapter(Adapter):
|
108
|
-
"""
|
109
|
-
Adapter that reads/writes TOML data to/from a file on disk.
|
110
|
-
The file extension key is ".toml".
|
111
|
-
"""
|
112
|
-
|
113
|
-
obj_key = ".toml"
|
114
|
-
|
115
|
-
@classmethod
|
116
|
-
def from_obj(
|
117
|
-
cls,
|
118
|
-
subj_cls: type[T],
|
119
|
-
obj: str | Path,
|
120
|
-
/,
|
121
|
-
*,
|
122
|
-
many: bool = False,
|
123
|
-
**kwargs,
|
124
|
-
) -> dict | list[dict]:
|
125
|
-
"""
|
126
|
-
Read a TOML file from disk and return a dict or list of dicts.
|
127
|
-
|
128
|
-
Parameters
|
129
|
-
----------
|
130
|
-
subj_cls : type[T]
|
131
|
-
The target class for context.
|
132
|
-
obj : str | Path
|
133
|
-
The TOML file path.
|
134
|
-
many : bool
|
135
|
-
If True, expects an array of tables. Otherwise single dict.
|
136
|
-
**kwargs
|
137
|
-
Extra arguments for toml.load().
|
138
|
-
|
139
|
-
Returns
|
140
|
-
-------
|
141
|
-
dict | list[dict]
|
142
|
-
The loaded data from file.
|
143
|
-
"""
|
144
|
-
with open(obj, encoding="utf-8") as f:
|
145
|
-
result = toml.load(f, **kwargs)
|
146
|
-
|
147
|
-
# Handle array of tables in TOML for "many" case
|
148
|
-
if many:
|
149
|
-
# Check if there's a top-level array key that might hold multiple items
|
150
|
-
for key, value in result.items():
|
151
|
-
if isinstance(value, list) and all(
|
152
|
-
isinstance(item, dict) for item in value
|
153
|
-
):
|
154
|
-
return value
|
155
|
-
# If no array of tables found, wrap the result in a list
|
156
|
-
return [result]
|
157
|
-
|
158
|
-
return result
|
159
|
-
|
160
|
-
@classmethod
|
161
|
-
def to_obj(
|
162
|
-
cls,
|
163
|
-
subj: T,
|
164
|
-
/,
|
165
|
-
*,
|
166
|
-
fp: str | Path,
|
167
|
-
many: bool = False,
|
168
|
-
mode: str = "w",
|
169
|
-
**kwargs,
|
170
|
-
) -> None:
|
171
|
-
"""
|
172
|
-
Write a dict (or list) to a TOML file.
|
173
|
-
|
174
|
-
Parameters
|
175
|
-
----------
|
176
|
-
subj : T
|
177
|
-
The object/collection to serialize.
|
178
|
-
fp : str | Path
|
179
|
-
The file path to write.
|
180
|
-
many : bool
|
181
|
-
If True, write as a TOML array of tables of multiple items.
|
182
|
-
mode : str
|
183
|
-
File open mode, defaults to write ("w").
|
184
|
-
**kwargs
|
185
|
-
Extra arguments for toml.dump().
|
186
|
-
|
187
|
-
Returns
|
188
|
-
-------
|
189
|
-
None
|
190
|
-
"""
|
191
|
-
with open(fp, mode, encoding="utf-8") as f:
|
192
|
-
if many:
|
193
|
-
if isinstance(subj, Collective):
|
194
|
-
# TOML requires arrays of tables to be in a table
|
195
|
-
data = {"items": [i.to_dict() for i in subj]}
|
196
|
-
else:
|
197
|
-
data = {"items": [subj.to_dict()]}
|
198
|
-
toml.dump(data, f, **kwargs)
|
199
|
-
else:
|
200
|
-
toml.dump(subj.to_dict(), f, **kwargs)
|
201
|
-
logging.info(f"TOML data saved to {fp}")
|
202
|
-
|
203
|
-
|
204
|
-
# File: lionagi/protocols/adapters/toml_adapter.py
|
lionagi/adapters/types.py
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
from .adapter import ADAPTER_MEMBERS, Adapter, AdapterRegistry
|
2
|
-
from .json_adapter import JsonAdapter, JsonFileAdapter
|
3
|
-
from .pandas_.csv_adapter import CSVFileAdapter
|
4
|
-
from .pandas_.excel_adapter import ExcelFileAdapter
|
5
|
-
from .pandas_.pd_dataframe_adapter import PandasDataFrameAdapter
|
6
|
-
from .pandas_.pd_series_adapter import PandasSeriesAdapter
|
7
|
-
from .toml_adapter import TomlAdapter, TomlFileAdapter
|
8
|
-
|
9
|
-
__all__ = (
|
10
|
-
"Adapter",
|
11
|
-
"AdapterRegistry",
|
12
|
-
"ADAPTER_MEMBERS",
|
13
|
-
"JsonAdapter",
|
14
|
-
"JsonFileAdapter",
|
15
|
-
"CSVFileAdapter",
|
16
|
-
"PandasSeriesAdapter",
|
17
|
-
"PandasDataFrameAdapter",
|
18
|
-
"ExcelFileAdapter",
|
19
|
-
"TomlAdapter",
|
20
|
-
"TomlFileAdapter",
|
21
|
-
)
|
File without changes
|
File without changes
|