lionagi 0.7.0__py3-none-any.whl → 0.7.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|