lionagi 0.7.0__py3-none-any.whl → 0.7.2__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/operations/ReAct/ReAct.py +2 -2
- lionagi/operations/_act/act.py +10 -3
- lionagi/operations/communicate/communicate.py +0 -59
- lionagi/operations/interpret/interpret.py +1 -2
- lionagi/operations/operate/operate.py +10 -5
- lionagi/operations/parse/parse.py +0 -36
- lionagi/operations/plan/plan.py +3 -3
- lionagi/operatives/action/manager.py +105 -82
- lionagi/operatives/action/request_response_model.py +31 -0
- lionagi/operatives/action/tool.py +50 -20
- lionagi/protocols/_concepts.py +1 -1
- lionagi/protocols/adapters/adapter.py +25 -0
- lionagi/protocols/adapters/json_adapter.py +107 -27
- lionagi/protocols/adapters/pandas_/csv_adapter.py +55 -11
- lionagi/protocols/adapters/pandas_/excel_adapter.py +52 -10
- lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +54 -4
- lionagi/protocols/adapters/pandas_/pd_series_adapter.py +40 -0
- lionagi/protocols/generic/element.py +1 -1
- lionagi/protocols/generic/pile.py +5 -8
- lionagi/protocols/graph/edge.py +1 -1
- lionagi/protocols/graph/graph.py +16 -8
- lionagi/protocols/graph/node.py +1 -1
- lionagi/protocols/mail/exchange.py +126 -15
- lionagi/protocols/mail/mail.py +33 -0
- lionagi/protocols/mail/mailbox.py +62 -0
- lionagi/protocols/mail/manager.py +97 -41
- lionagi/protocols/mail/package.py +57 -3
- lionagi/protocols/messages/action_request.py +77 -26
- lionagi/protocols/messages/action_response.py +55 -26
- lionagi/protocols/messages/assistant_response.py +50 -15
- lionagi/protocols/messages/base.py +36 -0
- lionagi/protocols/messages/instruction.py +175 -145
- lionagi/protocols/messages/manager.py +152 -56
- lionagi/protocols/messages/message.py +61 -25
- lionagi/protocols/messages/system.py +54 -19
- lionagi/service/imodel.py +24 -0
- lionagi/session/branch.py +40 -32
- lionagi/utils.py +1 -0
- lionagi/version.py +1 -1
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/METADATA +1 -1
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/RECORD +43 -43
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/WHEEL +0 -0
- {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/licenses/LICENSE +0 -0
@@ -2,6 +2,12 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
+
"""
|
6
|
+
Defines the `Tool` class, which wraps a Python callable (function/method)
|
7
|
+
with optional pre/post-processing and schema auto-generation. Also includes
|
8
|
+
type aliases for function references.
|
9
|
+
"""
|
10
|
+
|
5
11
|
import inspect
|
6
12
|
from collections.abc import Callable
|
7
13
|
from typing import Any, Self, TypeAlias
|
@@ -22,10 +28,13 @@ __all__ = (
|
|
22
28
|
|
23
29
|
|
24
30
|
class Tool(Element):
|
25
|
-
"""
|
31
|
+
"""
|
32
|
+
Wraps a callable function with optional:
|
33
|
+
- Preprocessing of arguments,
|
34
|
+
- Postprocessing of results,
|
35
|
+
- Strict or partial argument matching.
|
26
36
|
|
27
|
-
|
28
|
-
schema validation, and provides utility methods for function inspection.
|
37
|
+
`tool_schema` is auto-generated from the function signature if not provided.
|
29
38
|
"""
|
30
39
|
|
31
40
|
func_callable: Callable[..., Any] = Field(
|
@@ -82,28 +91,19 @@ class Tool(Element):
|
|
82
91
|
|
83
92
|
@property
|
84
93
|
def function(self) -> str:
|
85
|
-
"""
|
86
|
-
|
87
|
-
Returns:
|
88
|
-
str: The name of the function as defined in the schema.
|
89
|
-
"""
|
94
|
+
"""Return the function name from the auto-generated schema."""
|
90
95
|
return self.tool_schema["function"]["name"]
|
91
96
|
|
92
97
|
@property
|
93
98
|
def required_fields(self) -> set[str]:
|
94
|
-
"""
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
set[str]: Set of required field names.
|
98
|
-
"""
|
99
|
+
"""Return the set of required parameter names from the schema."""
|
99
100
|
return set(self.tool_schema["function"]["parameters"]["required"])
|
100
101
|
|
101
102
|
@property
|
102
103
|
def minimum_acceptable_fields(self) -> set[str]:
|
103
|
-
"""
|
104
|
-
|
105
|
-
|
106
|
-
set[str]: Set of minimum required field names.
|
104
|
+
"""
|
105
|
+
Return the set of parameters that have no default values,
|
106
|
+
ignoring `*args` or `**kwargs`.
|
107
107
|
"""
|
108
108
|
try:
|
109
109
|
a = {
|
@@ -123,13 +123,15 @@ class Tool(Element):
|
|
123
123
|
|
124
124
|
@classmethod
|
125
125
|
def from_dict(cls, data: dict[str, Any]):
|
126
|
-
|
126
|
+
"""This is not implemented, as Tools are not typically created from arbitrary dicts."""
|
127
|
+
raise NotImplementedError("`Tool.from_dict` is not supported.")
|
127
128
|
|
128
129
|
def to_dict(self) -> dict[str, Any]:
|
129
|
-
"""
|
130
|
+
"""
|
131
|
+
Serialize the Tool to a dict, including the `function` name.
|
130
132
|
|
131
133
|
Returns:
|
132
|
-
dict[str, Any]:
|
134
|
+
dict[str, Any]: The dictionary form (excluding callables).
|
133
135
|
"""
|
134
136
|
dict_ = super().to_dict()
|
135
137
|
dict_["function"] = self.function
|
@@ -137,5 +139,33 @@ class Tool(Element):
|
|
137
139
|
|
138
140
|
|
139
141
|
FuncTool: TypeAlias = Tool | Callable[..., Any]
|
142
|
+
"""Represents either a `Tool` instance or a raw callable function."""
|
143
|
+
|
140
144
|
FuncToolRef: TypeAlias = FuncTool | str
|
145
|
+
"""
|
146
|
+
A reference to a function-based tool, by either the actual object,
|
147
|
+
the raw callable, or the function name as a string.
|
148
|
+
"""
|
149
|
+
|
141
150
|
ToolRef: TypeAlias = FuncToolRef | list[FuncToolRef] | bool
|
151
|
+
"""
|
152
|
+
Used for specifying one or more tool references, or a boolean
|
153
|
+
indicating 'all' or 'none'.
|
154
|
+
"""
|
155
|
+
|
156
|
+
|
157
|
+
def func_to_tool(func: Callable[..., Any], **kwargs) -> Tool:
|
158
|
+
"""
|
159
|
+
Convenience function that wraps a raw function in a `Tool`.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
func (Callable[..., Any]): The function to wrap.
|
163
|
+
**kwargs: Additional arguments passed to the `Tool` constructor.
|
164
|
+
|
165
|
+
Returns:
|
166
|
+
Tool: A new Tool instance wrapping `func`.
|
167
|
+
"""
|
168
|
+
return Tool(func_callable=func, **kwargs)
|
169
|
+
|
170
|
+
|
171
|
+
# File: lionagi/operatives/action/tool.py
|
lionagi/protocols/_concepts.py
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
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
|
+
|
5
11
|
import logging
|
6
12
|
from typing import Any, Protocol, TypeVar, runtime_checkable
|
7
13
|
|
@@ -18,6 +24,25 @@ __all__ = (
|
|
18
24
|
|
19
25
|
@runtime_checkable
|
20
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
|
+
"""
|
21
46
|
|
22
47
|
obj_key: str
|
23
48
|
|
@@ -1,3 +1,9 @@
|
|
1
|
+
"""
|
2
|
+
Implements two adapters:
|
3
|
+
- `JsonAdapter` for in-memory JSON strings
|
4
|
+
- `JsonFileAdapter` for reading/writing JSON files
|
5
|
+
"""
|
6
|
+
|
1
7
|
import json
|
2
8
|
import logging
|
3
9
|
from pathlib import Path
|
@@ -8,6 +14,11 @@ from .adapter import Adapter, T
|
|
8
14
|
|
9
15
|
|
10
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
|
+
"""
|
11
22
|
|
12
23
|
obj_key = "json"
|
13
24
|
|
@@ -22,16 +33,31 @@ class JsonAdapter(Adapter):
|
|
22
33
|
**kwargs,
|
23
34
|
) -> dict | list[dict]:
|
24
35
|
"""
|
25
|
-
|
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.
|
26
54
|
"""
|
27
55
|
result = json.loads(obj, **kwargs)
|
28
56
|
if many:
|
29
57
|
return result if isinstance(result, list) else [result]
|
30
|
-
|
31
|
-
result[0]
|
32
|
-
|
33
|
-
else result
|
34
|
-
)
|
58
|
+
if isinstance(result, list) and len(result) > 0:
|
59
|
+
return result[0]
|
60
|
+
return result
|
35
61
|
|
36
62
|
@classmethod
|
37
63
|
def to_obj(
|
@@ -40,18 +66,38 @@ class JsonAdapter(Adapter):
|
|
40
66
|
*,
|
41
67
|
many: bool = False,
|
42
68
|
**kwargs,
|
43
|
-
):
|
69
|
+
) -> str:
|
44
70
|
"""
|
45
|
-
|
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.
|
46
86
|
"""
|
47
87
|
if many:
|
48
88
|
if isinstance(subj, Collective):
|
49
|
-
|
50
|
-
|
89
|
+
data = [i.to_dict() for i in subj]
|
90
|
+
else:
|
91
|
+
data = [subj.to_dict()]
|
92
|
+
return json.dumps(data, **kwargs)
|
51
93
|
return json.dumps(subj.to_dict(), **kwargs)
|
52
94
|
|
53
95
|
|
54
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
|
+
"""
|
55
101
|
|
56
102
|
obj_key = ".json"
|
57
103
|
|
@@ -66,17 +112,31 @@ class JsonFileAdapter(Adapter):
|
|
66
112
|
**kwargs,
|
67
113
|
) -> dict | list[dict]:
|
68
114
|
"""
|
69
|
-
|
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.
|
70
132
|
"""
|
71
|
-
with open(obj) as f:
|
133
|
+
with open(obj, encoding="utf-8") as f:
|
72
134
|
result = json.load(f, **kwargs)
|
73
135
|
if many:
|
74
136
|
return result if isinstance(result, list) else [result]
|
75
|
-
|
76
|
-
result[0]
|
77
|
-
|
78
|
-
else result
|
79
|
-
)
|
137
|
+
if isinstance(result, list) and len(result) > 0:
|
138
|
+
return result[0]
|
139
|
+
return result
|
80
140
|
|
81
141
|
@classmethod
|
82
142
|
def to_obj(
|
@@ -86,16 +146,36 @@ class JsonFileAdapter(Adapter):
|
|
86
146
|
*,
|
87
147
|
fp: str | Path,
|
88
148
|
many: bool = False,
|
149
|
+
mode: str = "w",
|
89
150
|
**kwargs,
|
90
|
-
):
|
151
|
+
) -> None:
|
91
152
|
"""
|
92
|
-
|
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
|
93
169
|
"""
|
94
|
-
|
95
|
-
if
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
@@ -9,6 +9,11 @@ from ..adapter import Adapter, T
|
|
9
9
|
|
10
10
|
|
11
11
|
class CSVFileAdapter(Adapter):
|
12
|
+
"""
|
13
|
+
Reads/writes CSV files to a list of dicts or vice versa,
|
14
|
+
using `pandas`.
|
15
|
+
"""
|
16
|
+
|
12
17
|
obj_key = ".csv"
|
13
18
|
|
14
19
|
@classmethod
|
@@ -21,10 +26,31 @@ class CSVFileAdapter(Adapter):
|
|
21
26
|
many: bool = False,
|
22
27
|
**kwargs,
|
23
28
|
) -> list[dict]:
|
24
|
-
"""
|
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
|
+
"""
|
25
49
|
df: pd.DataFrame = pd.read_csv(obj, **kwargs)
|
26
50
|
dicts_ = df.to_dict(orient="records")
|
27
|
-
|
51
|
+
if many:
|
52
|
+
return dicts_
|
53
|
+
return dicts_[0] if len(dicts_) > 0 else {}
|
28
54
|
|
29
55
|
@classmethod
|
30
56
|
def to_obj(
|
@@ -35,16 +61,34 @@ class CSVFileAdapter(Adapter):
|
|
35
61
|
fp: str | Path,
|
36
62
|
many: bool = False,
|
37
63
|
**kwargs,
|
38
|
-
):
|
39
|
-
"""
|
40
|
-
|
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
|
41
84
|
if many:
|
42
85
|
if isinstance(subj, Collective):
|
43
86
|
pd.DataFrame([i.to_dict() for i in subj]).to_csv(fp, **kwargs)
|
44
|
-
|
45
|
-
|
87
|
+
else:
|
88
|
+
pd.DataFrame([subj.to_dict()]).to_csv(fp, **kwargs)
|
89
|
+
else:
|
46
90
|
pd.DataFrame([subj.to_dict()]).to_csv(fp, **kwargs)
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
91
|
+
logging.info(f"CSV data saved to {fp}")
|
92
|
+
|
93
|
+
|
94
|
+
# File: lionagi/protocols/adapters/pandas_/csv_adapter.py
|
@@ -1,3 +1,8 @@
|
|
1
|
+
"""
|
2
|
+
Provides an ExcelFileAdapter for reading/writing Excel (.xlsx) files
|
3
|
+
via pandas.
|
4
|
+
"""
|
5
|
+
|
1
6
|
import logging
|
2
7
|
from pathlib import Path
|
3
8
|
|
@@ -9,6 +14,10 @@ from ..adapter import Adapter, T
|
|
9
14
|
|
10
15
|
|
11
16
|
class ExcelFileAdapter(Adapter):
|
17
|
+
"""
|
18
|
+
Reads/writes Excel (XLSX) files, using `pandas`.
|
19
|
+
"""
|
20
|
+
|
12
21
|
obj_key = ".xlsx"
|
13
22
|
|
14
23
|
@classmethod
|
@@ -21,10 +30,29 @@ class ExcelFileAdapter(Adapter):
|
|
21
30
|
many: bool = False,
|
22
31
|
**kwargs,
|
23
32
|
) -> list[dict]:
|
24
|
-
"""
|
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
|
+
"""
|
25
51
|
df: pd.DataFrame = pd.read_excel(obj, **kwargs)
|
26
52
|
dicts_ = df.to_dict(orient="records")
|
27
|
-
|
53
|
+
if many:
|
54
|
+
return dicts_
|
55
|
+
return dicts_[0] if len(dicts_) > 0 else {}
|
28
56
|
|
29
57
|
@classmethod
|
30
58
|
def to_obj(
|
@@ -35,18 +63,32 @@ class ExcelFileAdapter(Adapter):
|
|
35
63
|
fp: str | Path,
|
36
64
|
many: bool = False,
|
37
65
|
**kwargs,
|
38
|
-
):
|
39
|
-
"""
|
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
|
+
"""
|
40
81
|
kwargs["index"] = False
|
41
82
|
if many:
|
42
83
|
if isinstance(subj, Collective):
|
43
84
|
pd.DataFrame([i.to_dict() for i in subj]).to_excel(
|
44
85
|
fp, **kwargs
|
45
86
|
)
|
46
|
-
|
47
|
-
|
87
|
+
else:
|
88
|
+
pd.DataFrame([subj.to_dict()]).to_excel(fp, **kwargs)
|
89
|
+
else:
|
48
90
|
pd.DataFrame([subj.to_dict()]).to_excel(fp, **kwargs)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
91
|
+
logging.info(f"Excel data saved to {fp}")
|
92
|
+
|
93
|
+
|
94
|
+
# File: lionagi/protocols/adapters/pandas_/excel_adapter.py
|
@@ -1,3 +1,8 @@
|
|
1
|
+
"""
|
2
|
+
Defines a `PandasDataFrameAdapter` that converts between
|
3
|
+
a DataFrame and a list of dictionary-based elements.
|
4
|
+
"""
|
5
|
+
|
1
6
|
from datetime import datetime
|
2
7
|
|
3
8
|
import pandas as pd
|
@@ -6,6 +11,11 @@ from ..adapter import Adapter, T
|
|
6
11
|
|
7
12
|
|
8
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
|
+
"""
|
9
19
|
|
10
20
|
obj_key = "pd_dataframe"
|
11
21
|
alias = ("pandas_dataframe", "pd.DataFrame", "pd_dataframe")
|
@@ -14,18 +24,58 @@ class PandasDataFrameAdapter(Adapter):
|
|
14
24
|
def from_obj(
|
15
25
|
cls, subj_cls: type[T], obj: pd.DataFrame, /, **kwargs
|
16
26
|
) -> list[dict]:
|
17
|
-
"""
|
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
|
+
"""
|
18
44
|
return obj.to_dict(orient="records", **kwargs)
|
19
45
|
|
20
46
|
@classmethod
|
21
47
|
def to_obj(cls, subj: list[T], /, **kwargs) -> pd.DataFrame:
|
22
|
-
"""
|
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
|
+
"""
|
23
63
|
out_ = []
|
24
64
|
for i in subj:
|
25
65
|
_dict = i.to_dict()
|
26
|
-
|
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
|
27
74
|
out_.append(_dict)
|
28
75
|
df = pd.DataFrame(out_, **kwargs)
|
76
|
+
# Convert created_at to datetime if present
|
29
77
|
if "created_at" in df.columns:
|
30
|
-
df["created_at"] = pd.to_datetime(
|
78
|
+
df["created_at"] = pd.to_datetime(
|
79
|
+
df["created_at"], errors="coerce"
|
80
|
+
)
|
31
81
|
return df
|
@@ -1,17 +1,57 @@
|
|
1
|
+
"""
|
2
|
+
Defines a `PandasSeriesAdapter` that converts a single object
|
3
|
+
to/from a `pd.Series`.
|
4
|
+
"""
|
5
|
+
|
1
6
|
import pandas as pd
|
2
7
|
|
3
8
|
from ..adapter import Adapter, T
|
4
9
|
|
5
10
|
|
6
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
|
+
"""
|
7
16
|
|
8
17
|
obj_key = "pd_series"
|
9
18
|
alias = ("pandas_series", "pd.series", "pd_series")
|
10
19
|
|
11
20
|
@classmethod
|
12
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
|
+
"""
|
13
39
|
return obj.to_dict(**kwargs)
|
14
40
|
|
15
41
|
@classmethod
|
16
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
|
+
"""
|
17
57
|
return pd.Series(subj.to_dict(), **kwargs)
|