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.
Files changed (43) hide show
  1. lionagi/operations/ReAct/ReAct.py +2 -2
  2. lionagi/operations/_act/act.py +10 -3
  3. lionagi/operations/communicate/communicate.py +0 -59
  4. lionagi/operations/interpret/interpret.py +1 -2
  5. lionagi/operations/operate/operate.py +10 -5
  6. lionagi/operations/parse/parse.py +0 -36
  7. lionagi/operations/plan/plan.py +3 -3
  8. lionagi/operatives/action/manager.py +105 -82
  9. lionagi/operatives/action/request_response_model.py +31 -0
  10. lionagi/operatives/action/tool.py +50 -20
  11. lionagi/protocols/_concepts.py +1 -1
  12. lionagi/protocols/adapters/adapter.py +25 -0
  13. lionagi/protocols/adapters/json_adapter.py +107 -27
  14. lionagi/protocols/adapters/pandas_/csv_adapter.py +55 -11
  15. lionagi/protocols/adapters/pandas_/excel_adapter.py +52 -10
  16. lionagi/protocols/adapters/pandas_/pd_dataframe_adapter.py +54 -4
  17. lionagi/protocols/adapters/pandas_/pd_series_adapter.py +40 -0
  18. lionagi/protocols/generic/element.py +1 -1
  19. lionagi/protocols/generic/pile.py +5 -8
  20. lionagi/protocols/graph/edge.py +1 -1
  21. lionagi/protocols/graph/graph.py +16 -8
  22. lionagi/protocols/graph/node.py +1 -1
  23. lionagi/protocols/mail/exchange.py +126 -15
  24. lionagi/protocols/mail/mail.py +33 -0
  25. lionagi/protocols/mail/mailbox.py +62 -0
  26. lionagi/protocols/mail/manager.py +97 -41
  27. lionagi/protocols/mail/package.py +57 -3
  28. lionagi/protocols/messages/action_request.py +77 -26
  29. lionagi/protocols/messages/action_response.py +55 -26
  30. lionagi/protocols/messages/assistant_response.py +50 -15
  31. lionagi/protocols/messages/base.py +36 -0
  32. lionagi/protocols/messages/instruction.py +175 -145
  33. lionagi/protocols/messages/manager.py +152 -56
  34. lionagi/protocols/messages/message.py +61 -25
  35. lionagi/protocols/messages/system.py +54 -19
  36. lionagi/service/imodel.py +24 -0
  37. lionagi/session/branch.py +40 -32
  38. lionagi/utils.py +1 -0
  39. lionagi/version.py +1 -1
  40. {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/METADATA +1 -1
  41. {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/RECORD +43 -43
  42. {lionagi-0.7.0.dist-info → lionagi-0.7.2.dist-info}/WHEEL +0 -0
  43. {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
- """A class for handling function calls with schema validation and processing.
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
- This class wraps callable objects with optional pre and post processing,
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
- """Get the name of the function from the schema.
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
- """Get the required fields from the schema.
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
- """Get the minimum required fields from function signature.
104
-
105
- Returns:
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
- raise NotImplementedError("Tool.from_dict is not implemented.")
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
- """Convert Tool instance to dictionary.
130
+ """
131
+ Serialize the Tool to a dict, including the `function` name.
130
132
 
131
133
  Returns:
132
- dict[str, Any]: Dictionary representation of the Tool.
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
@@ -91,4 +91,4 @@ class Ordering(ABC, Generic[E]):
91
91
  pass
92
92
 
93
93
 
94
- # File: protocols/generic/concepts.py
94
+ # File: lionagi/protocols/_concepts.py
@@ -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
- kwargs for json.loads(s, **kwargs)
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
- return (
31
- result[0]
32
- if isinstance(result, list) and len(result) > 0
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
- kwargs for json.dumps(obj, **kwargs)
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
- return json.dumps([i.to_dict() for i in subj], **kwargs)
50
- return json.dumps([subj.to_dict()], **kwargs)
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
- kwargs for json.load(fp, **kwargs)
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
- return (
76
- result[0]
77
- if isinstance(result, list) and len(result) > 0
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
- kwargs for json.dump(obj, fp, **kwargs)
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
- if many:
95
- if isinstance(subj, Collective):
96
- json.dump([i.to_dict() for i in subj], fp=fp, **kwargs)
97
- return
98
- json.dump([subj.to_dict()], fp=fp, **kwargs)
99
- return
100
- json.dump(subj.to_dict(), fp=fp, **kwargs)
101
- logging.info(f"Successfully saved data to {fp}")
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
- """kwargs for pd.read_csv"""
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
- return dicts_[0] if not many else dicts_
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
- """kwargs for pd.DataFrame.to_csv"""
40
- kwargs["index"] = False
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
- logging.info(f"Successfully saved data to {fp}")
45
- return
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
- logging.info(f"Successfully saved data to {fp}")
48
- return
49
- pd.DataFrame([subj.to_dict()]).to_csv(fp, **kwargs)
50
- logging.info(f"Successfully saved data to {fp}")
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
- """kwargs for pd.read_csv"""
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
- return dicts_[0] if not many else dicts_
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
- """kwargs for pd.DataFrame.to_csv"""
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
- logging.info(f"Successfully saved data to {fp}")
47
- return
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
- logging.info(f"Successfully saved data to {fp}")
50
- return
51
- pd.DataFrame([subj.to_dict()]).to_excel(fp, **kwargs)
52
- logging.info(f"Successfully saved data to {fp}")
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
- """kwargs for pd.DataFrame.to_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
+ """
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
- """kwargs for 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
+ """
23
63
  out_ = []
24
64
  for i in subj:
25
65
  _dict = i.to_dict()
26
- _dict["created_at"] = datetime.fromtimestamp(_dict["created_at"])
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(df["created_at"])
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)
@@ -457,4 +457,4 @@ class ID(Generic[E]):
457
457
  return False
458
458
 
459
459
 
460
- # File: protocols/generic/element.py
460
+ # File: lionagi/protocols/generic/element.py