bear-utils 0.8.6__py3-none-any.whl → 0.8.7__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.
- bear_utils/cli/prompt_helpers.py +88 -75
- bear_utils/extras/responses/function_response.py +116 -83
- {bear_utils-0.8.6.dist-info → bear_utils-0.8.7.dist-info}/METADATA +2 -2
- {bear_utils-0.8.6.dist-info → bear_utils-0.8.7.dist-info}/RECORD +5 -5
- {bear_utils-0.8.6.dist-info → bear_utils-0.8.7.dist-info}/WHEEL +0 -0
bear_utils/cli/prompt_helpers.py
CHANGED
@@ -7,37 +7,60 @@ from prompt_toolkit.completion import WordCompleter
|
|
7
7
|
from prompt_toolkit.validation import ValidationError, Validator
|
8
8
|
|
9
9
|
from bear_utils.constants._exceptions import UserCancelledError
|
10
|
-
from bear_utils.constants._lazy_typing import
|
10
|
+
from bear_utils.constants._lazy_typing import OptBool, OptFloat, OptInt, OptStr
|
11
11
|
from bear_utils.logger_manager import get_console
|
12
12
|
|
13
|
-
# TODO:
|
13
|
+
# TODO: ehhhhhhhh, it is okay
|
14
|
+
|
15
|
+
|
16
|
+
def _parse_bool(value: str) -> bool:
|
17
|
+
"""Parse a string into a boolean value."""
|
18
|
+
lower_value: str = value.lower().strip()
|
19
|
+
if lower_value in ("true", "t", "yes", "y", "1"):
|
20
|
+
return True
|
21
|
+
if lower_value in ("false", "f", "no", "n", "0"):
|
22
|
+
return False
|
23
|
+
raise ValueError(f"Cannot convert '{value}' to boolean")
|
24
|
+
|
25
|
+
|
26
|
+
def _convert_value(value: str, target_type: type) -> str | int | float | bool:
|
27
|
+
"""Convert a string value to the target type."""
|
28
|
+
if target_type is str:
|
29
|
+
return value
|
30
|
+
if target_type is int:
|
31
|
+
return int(value)
|
32
|
+
if target_type is float:
|
33
|
+
return float(value)
|
34
|
+
if target_type is bool:
|
35
|
+
return _parse_bool(value)
|
36
|
+
raise ValueError(f"Unsupported type: {target_type}")
|
14
37
|
|
15
38
|
|
16
39
|
@overload
|
17
|
-
def ask_question(question: str, expected_type:
|
40
|
+
def ask_question(question: str, expected_type: type[bool], default: OptBool = None) -> bool: ...
|
18
41
|
|
19
42
|
|
20
43
|
@overload
|
21
|
-
def ask_question(question: str, expected_type:
|
44
|
+
def ask_question(question: str, expected_type: type[int], default: OptInt = None) -> int: ...
|
22
45
|
|
23
46
|
|
24
47
|
@overload
|
25
|
-
def ask_question(question: str, expected_type:
|
48
|
+
def ask_question(question: str, expected_type: type[float], default: OptFloat = None) -> float: ...
|
26
49
|
|
27
50
|
|
28
51
|
@overload
|
29
|
-
def ask_question(question: str, expected_type:
|
52
|
+
def ask_question(question: str, expected_type: type[str], default: OptStr = None) -> str: ...
|
30
53
|
|
31
54
|
|
32
|
-
def ask_question(question: str, expected_type:
|
33
|
-
"""Ask a question and return the answer, ensuring the entered type is correct
|
55
|
+
def ask_question(question: str, expected_type: type, default: Any = None) -> Any:
|
56
|
+
"""Ask a question and return the answer, ensuring the entered type is correct.
|
34
57
|
|
35
58
|
This function will keep asking until it gets a valid response or the user cancels with Ctrl+C.
|
36
59
|
If the user cancels, a UserCancelledError is raised.
|
37
60
|
|
38
61
|
Args:
|
39
62
|
question: The prompt question to display
|
40
|
-
expected_type: The expected type
|
63
|
+
expected_type: The expected type class (int, float, str, bool)
|
41
64
|
default: Default value if no input is provided
|
42
65
|
|
43
66
|
Returns:
|
@@ -48,46 +71,29 @@ def ask_question(question: str, expected_type: Any, default: Any = None, **_) ->
|
|
48
71
|
ValueError: If an unsupported type is specified
|
49
72
|
"""
|
50
73
|
console, sub = get_console("prompt_helpers.py")
|
74
|
+
|
51
75
|
try:
|
52
76
|
while True:
|
53
77
|
console.print(question)
|
54
|
-
response
|
55
|
-
|
78
|
+
response = prompt("> ").strip()
|
79
|
+
|
80
|
+
if not response:
|
56
81
|
if default is not None:
|
57
82
|
return default
|
83
|
+
sub.error("Input required. Please enter a value.")
|
58
84
|
continue
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
sub.error("Invalid input. Please enter a valid integer.")
|
67
|
-
case "float":
|
68
|
-
try:
|
69
|
-
result = float(response)
|
70
|
-
sub.verbose("float detected")
|
71
|
-
return result
|
72
|
-
except ValueError:
|
73
|
-
sub.error("Invalid input. Please enter a valid float.")
|
74
|
-
case "str":
|
75
|
-
sub.verbose("str detected")
|
76
|
-
return response
|
77
|
-
case "bool":
|
78
|
-
lower_response = response.lower()
|
79
|
-
if lower_response in ("true", "t", "yes", "y", "1"):
|
80
|
-
return True
|
81
|
-
if lower_response in ("false", "f", "no", "n", "0"):
|
82
|
-
return False
|
83
|
-
sub.error("Invalid input. Please enter a valid boolean (true/false, yes/no, etc).")
|
84
|
-
case _:
|
85
|
-
raise ValueError(f"Unsupported type: {expected_type}")
|
85
|
+
try:
|
86
|
+
result: str | int | float | bool = _convert_value(response, expected_type)
|
87
|
+
sub.verbose(f"{expected_type.__name__} detected")
|
88
|
+
return result
|
89
|
+
except ValueError as e:
|
90
|
+
sub.error(f"Invalid input: {e}. Please enter a valid {expected_type.__name__}.")
|
91
|
+
|
86
92
|
except KeyboardInterrupt:
|
87
93
|
raise UserCancelledError("User cancelled input") from None
|
88
94
|
|
89
95
|
|
90
|
-
def ask_yes_no(question: str, default:
|
96
|
+
def ask_yes_no(question: str, default: bool | None = None) -> bool | None:
|
91
97
|
"""Ask a yes or no question and return the answer.
|
92
98
|
|
93
99
|
Args:
|
@@ -95,78 +101,85 @@ def ask_yes_no(question: str, default: None | Any = None, **kwargs) -> None | bo
|
|
95
101
|
default: Default value if no input is provided
|
96
102
|
|
97
103
|
Returns:
|
98
|
-
True for yes, False for no, or None if
|
104
|
+
True for yes, False for no, or None if user exits
|
99
105
|
"""
|
100
|
-
|
101
|
-
|
106
|
+
console, sub = get_console("prompt_helpers.py")
|
107
|
+
|
102
108
|
try:
|
103
109
|
while True:
|
104
|
-
console.
|
105
|
-
response = prompt("> ")
|
110
|
+
console.print(question)
|
111
|
+
response = prompt("> ").strip().lower()
|
106
112
|
|
107
|
-
if response
|
113
|
+
if not response:
|
108
114
|
if default is not None:
|
109
115
|
return default
|
116
|
+
sub.error("Please enter 'yes', 'no', or 'exit'.")
|
110
117
|
continue
|
111
118
|
|
112
|
-
if response
|
113
|
-
return True
|
114
|
-
if response.lower() in ["no", "n"]:
|
115
|
-
return False
|
116
|
-
if response.lower() in ["exit", "quit"]:
|
119
|
+
if response in ("exit", "quit"):
|
117
120
|
return None
|
118
|
-
|
119
|
-
|
121
|
+
try:
|
122
|
+
return _parse_bool(response)
|
123
|
+
except ValueError:
|
124
|
+
sub.error("Invalid input. Please enter 'yes', 'no', or 'exit'.")
|
120
125
|
except KeyboardInterrupt:
|
121
|
-
|
126
|
+
sub.warning("KeyboardInterrupt: Exiting the prompt.")
|
122
127
|
return None
|
123
128
|
|
124
129
|
|
125
|
-
def restricted_prompt(
|
130
|
+
def restricted_prompt(
|
131
|
+
question: str, valid_options: list[str], exit_command: str = "exit", case_sensitive: bool = False
|
132
|
+
) -> str | None:
|
126
133
|
"""Continuously prompt the user until they provide a valid response or exit.
|
127
134
|
|
128
135
|
Args:
|
129
136
|
question: The prompt question to display
|
130
137
|
valid_options: List of valid responses
|
131
138
|
exit_command: Command to exit the prompt (default: "exit")
|
139
|
+
case_sensitive: Whether options are case-sensitive (default: False)
|
132
140
|
|
133
141
|
Returns:
|
134
142
|
The user's response or None if they chose to exit
|
135
143
|
"""
|
136
|
-
|
137
|
-
|
138
|
-
completer_options: list[str] = [*valid_options, exit_command]
|
144
|
+
console, sub = get_console("prompt_helpers.py")
|
145
|
+
completer_options = [*valid_options, exit_command]
|
139
146
|
completer = WordCompleter(completer_options)
|
140
147
|
|
148
|
+
comparison_options = valid_options if case_sensitive else [opt.lower() for opt in valid_options]
|
149
|
+
comparison_exit = exit_command if case_sensitive else exit_command.lower()
|
150
|
+
|
141
151
|
class OptionValidator(Validator):
|
142
152
|
def validate(self, document: Any) -> None:
|
143
153
|
"""Validate the user's input against the valid options."""
|
144
|
-
text:
|
145
|
-
if text !=
|
154
|
+
text: Any = document.text if case_sensitive else document.text.lower()
|
155
|
+
if text and text != comparison_exit and text not in comparison_options:
|
146
156
|
raise ValidationError(
|
147
|
-
message=f"Invalid option
|
157
|
+
message=f"Invalid option. Choose from: {', '.join(valid_options)} or '{exit_command}'",
|
148
158
|
cursor_position=len(document.text),
|
149
159
|
)
|
150
160
|
|
151
161
|
try:
|
152
162
|
while True:
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
else
|
158
|
-
|
159
|
-
|
160
|
-
)
|
161
|
-
response = response.lower()
|
162
|
-
|
163
|
-
if response == exit_command:
|
164
|
-
return None
|
165
|
-
if response == "":
|
166
|
-
sub.error("No input provided. Please enter a valid option or exit.")
|
163
|
+
console.print(question)
|
164
|
+
response: str = prompt(
|
165
|
+
"> ", completer=completer, validator=OptionValidator(), complete_while_typing=True
|
166
|
+
).strip()
|
167
|
+
comparison_response: str = response if case_sensitive else response.lower()
|
168
|
+
if not response:
|
169
|
+
sub.error("Please enter a valid option or 'exit'.")
|
167
170
|
continue
|
168
|
-
if
|
171
|
+
if comparison_response == comparison_exit:
|
172
|
+
return None
|
173
|
+
if comparison_response in comparison_options:
|
174
|
+
if not case_sensitive:
|
175
|
+
idx: int = comparison_options.index(comparison_response)
|
176
|
+
return valid_options[idx]
|
169
177
|
return response
|
178
|
+
|
170
179
|
except KeyboardInterrupt:
|
171
180
|
sub.warning("KeyboardInterrupt: Exiting the prompt.")
|
172
181
|
return None
|
182
|
+
|
183
|
+
|
184
|
+
if __name__ == "__main__":
|
185
|
+
ask_question("What is your age?", int)
|
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from
|
5
|
+
from collections.abc import Callable
|
6
6
|
import json
|
7
7
|
from subprocess import CompletedProcess
|
8
|
+
from types import SimpleNamespace as Namespace
|
8
9
|
from typing import Any, Literal, Self, overload
|
9
10
|
|
10
11
|
from pydantic import BaseModel, Field, field_validator
|
@@ -23,35 +24,46 @@ class FunctionResponse(BaseModel):
|
|
23
24
|
extra: dict = Field(default_factory=dict, description="Additional metadata or information related to the response.")
|
24
25
|
content: list[str] = Field(default=[], description="Content returned by the function call")
|
25
26
|
error: list[str] = Field(default=[], description="Error message if the function call failed")
|
27
|
+
sub_tasks: list[FunctionResponse] = Field(default_factory=list, description="List of sub-tasks.")
|
26
28
|
number_of_tasks: int = Field(default=0, description="Number of tasks processed in this response.")
|
27
29
|
logger: LoggerProtocol | None = Field(default=None, description="Logger instance for logging messages.")
|
30
|
+
attrs: Namespace = Field(default_factory=Namespace, description="Storing additional attributes dynamically.")
|
28
31
|
|
29
32
|
model_config = {
|
30
33
|
"arbitrary_types_allowed": True,
|
31
34
|
}
|
32
35
|
|
36
|
+
def __getattr__(self, key: str, default: Any = None) -> Any:
|
37
|
+
if key in FunctionResponse.model_fields:
|
38
|
+
raise AttributeError(f"This should never be called, {key} is a model field.")
|
39
|
+
if hasattr(self.attrs, key):
|
40
|
+
return getattr(self.attrs, key)
|
41
|
+
return default
|
42
|
+
|
43
|
+
def __setattr__(self, key: str, value: Any) -> None:
|
44
|
+
if key in FunctionResponse.model_fields:
|
45
|
+
object.__setattr__(self, key, value)
|
46
|
+
return
|
47
|
+
setattr(self.attrs, key, value)
|
48
|
+
|
33
49
|
def __repr__(self) -> str:
|
34
50
|
"""Return a string representation of Response."""
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
result.write(")")
|
52
|
-
returned_result: str = result.getvalue().replace(", )", ")")
|
53
|
-
result.close()
|
54
|
-
return returned_result
|
51
|
+
parts: list[str] = []
|
52
|
+
|
53
|
+
def add(k: str, v: Any, _bool: bool = True, formatter: Callable | None = None) -> None:
|
54
|
+
if _bool:
|
55
|
+
formatted_value: str = formatter(v) if formatter else repr(v)
|
56
|
+
parts.append(f"{k}={formatted_value}")
|
57
|
+
|
58
|
+
add("name", self.name, bool(self.name))
|
59
|
+
add("returncode", self.returncode, self.returncode != 0)
|
60
|
+
add("success", self.success, bool(self.returncode))
|
61
|
+
add("content", ", ".join(self.content), bool(self.content))
|
62
|
+
add("error", ", ".join(self.error), bool(self.error))
|
63
|
+
add("extra", self.extra, bool(self.extra), json.dumps)
|
64
|
+
add("number_of_tasks", self.number_of_tasks, self.number_of_tasks > 0)
|
65
|
+
|
66
|
+
return f"Response({', '.join(parts)})"
|
55
67
|
|
56
68
|
def __str__(self) -> str:
|
57
69
|
"""Return a string representation of Response."""
|
@@ -124,6 +136,19 @@ class FunctionResponse(BaseModel):
|
|
124
136
|
|
125
137
|
return cls().add(returncode=returncode, content=content, error=error, **kwargs)
|
126
138
|
|
139
|
+
def from_response(self, response: FunctionResponse | Any, **kwargs) -> Self:
|
140
|
+
"""Create a FunctionResponse from another FunctionResponse object."""
|
141
|
+
if not isinstance(response, FunctionResponse):
|
142
|
+
raise TypeError("Expected a FunctionResponse instance.")
|
143
|
+
self.sub_tasks.append(response)
|
144
|
+
return self.add(
|
145
|
+
content=response.content,
|
146
|
+
error=response.error,
|
147
|
+
returncode=response.returncode,
|
148
|
+
log_output=kwargs.pop("log_output", False),
|
149
|
+
**kwargs,
|
150
|
+
)
|
151
|
+
|
127
152
|
@property
|
128
153
|
def success(self) -> bool:
|
129
154
|
"""Check if the response indicates success."""
|
@@ -137,7 +162,7 @@ class FunctionResponse(BaseModel):
|
|
137
162
|
extra: dict[str, Any] | None = None,
|
138
163
|
returncode: int | None = None,
|
139
164
|
log_output: bool = False,
|
140
|
-
) ->
|
165
|
+
) -> Self:
|
141
166
|
"""Add a sub-task response to the FunctionResponse."""
|
142
167
|
func_response: FunctionResponse = FunctionResponse(name=name, logger=self.logger).add(
|
143
168
|
content=content,
|
@@ -147,6 +172,8 @@ class FunctionResponse(BaseModel):
|
|
147
172
|
extra=extra,
|
148
173
|
)
|
149
174
|
self.add(content=func_response)
|
175
|
+
self.sub_tasks.append(func_response)
|
176
|
+
return self
|
150
177
|
|
151
178
|
def successful(
|
152
179
|
self,
|
@@ -170,49 +197,41 @@ class FunctionResponse(BaseModel):
|
|
170
197
|
self.add(content=content, error=error, returncode=returncode or 1, **kwargs)
|
171
198
|
return self
|
172
199
|
|
173
|
-
def
|
174
|
-
"""Append an
|
175
|
-
if
|
176
|
-
|
200
|
+
def _add_item(self, item: str, target_list: list[str]) -> None:
|
201
|
+
"""Append an item to the target list if not empty."""
|
202
|
+
if item != "":
|
203
|
+
target_list.append(item)
|
177
204
|
|
178
|
-
def
|
179
|
-
"""Append
|
205
|
+
def _add_to_list(self, items: str | list[str], target_list: list[str], name: str | None = None) -> None:
|
206
|
+
"""Append items to the target list with optional name prefix."""
|
180
207
|
try:
|
181
|
-
if isinstance(
|
182
|
-
for
|
183
|
-
self.
|
184
|
-
elif isinstance(
|
185
|
-
self.
|
208
|
+
if isinstance(items, list):
|
209
|
+
for item in items:
|
210
|
+
self._add_item(f"{name}: {item}" if name else item, target_list)
|
211
|
+
elif isinstance(items, str):
|
212
|
+
self._add_item(f"{name}: {items}" if name else items, target_list)
|
186
213
|
except Exception as e:
|
187
|
-
raise ValueError(f"Failed to add
|
214
|
+
raise ValueError(f"Failed to add items: {e!s}") from e
|
188
215
|
|
189
|
-
def _add_content(self, content: str) -> None:
|
216
|
+
def _add_content(self, content: str | list[str], name: str | None = None) -> None:
|
190
217
|
"""Append content to the existing content."""
|
191
|
-
|
192
|
-
self.content.append(content)
|
218
|
+
self._add_to_list(content, self.content, name)
|
193
219
|
|
194
|
-
def
|
195
|
-
"""Append
|
196
|
-
|
197
|
-
if isinstance(content, list):
|
198
|
-
for item in content:
|
199
|
-
self._add_content(content=f"{name}: {item}" if name else item)
|
200
|
-
elif isinstance(content, str):
|
201
|
-
self._add_content(content=f"{name}: {content}" if name else content)
|
202
|
-
except Exception as e:
|
203
|
-
raise ValueError(f"Failed to add content: {e!s}") from e
|
220
|
+
def _add_error(self, error: str | list[str], name: str | None = None) -> None:
|
221
|
+
"""Append error to the existing error."""
|
222
|
+
self._add_to_list(error, self.error, name)
|
204
223
|
|
205
224
|
def _handle_function_response(self, func_response: FunctionResponse) -> None:
|
206
225
|
"""Handle a FunctionResponse object and update the current response."""
|
207
226
|
if func_response.extra:
|
208
227
|
self.extra.update(func_response.extra)
|
209
|
-
self.
|
210
|
-
self.
|
228
|
+
self._add_error(error=func_response.error, name=func_response.name)
|
229
|
+
self._add_content(content=func_response.content, name=func_response.name)
|
211
230
|
|
212
231
|
def _handle_completed_process(self, result: CompletedProcess[str]) -> None:
|
213
232
|
"""Handle a CompletedProcess object and update the FunctionResponse."""
|
214
|
-
self.
|
215
|
-
self.
|
233
|
+
self._add_content(content=result.stdout.strip() if result.stdout else "")
|
234
|
+
self._add_error(error=result.stderr.strip() if result.stderr else "")
|
216
235
|
self.returncode = result.returncode
|
217
236
|
|
218
237
|
def add(
|
@@ -244,13 +263,13 @@ class FunctionResponse(BaseModel):
|
|
244
263
|
self._handle_completed_process(result=content)
|
245
264
|
self.number_of_tasks += 1
|
246
265
|
case str() | list() if content:
|
247
|
-
self.
|
266
|
+
self._add_content(content=content)
|
248
267
|
self.number_of_tasks += 1
|
249
268
|
case None:
|
250
269
|
content = None
|
251
270
|
case _:
|
252
271
|
content = None
|
253
|
-
self.
|
272
|
+
self._add_error(error=error) if isinstance(error, (str | list)) else None
|
254
273
|
self.returncode = returncode if returncode is not None else self.returncode
|
255
274
|
self.extra.update(extra) if isinstance(extra, dict) else None
|
256
275
|
if log_output and self.logger is not None and (content is not None or error is not None):
|
@@ -266,18 +285,19 @@ class FunctionResponse(BaseModel):
|
|
266
285
|
logger: LoggerProtocol,
|
267
286
|
) -> None:
|
268
287
|
"""Log the content and error messages if they exist."""
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
288
|
+
|
289
|
+
def _log_messages(messages: str | list[str], log_func: Callable) -> None:
|
290
|
+
if isinstance(messages, str):
|
291
|
+
messages = [messages]
|
292
|
+
if isinstance(messages, list):
|
293
|
+
for msg in messages:
|
294
|
+
log_func(f"{self.name}: {msg}" if self.name else msg)
|
295
|
+
|
296
|
+
if content and isinstance(content, (str | list)):
|
297
|
+
_log_messages(content, logger.info)
|
298
|
+
|
299
|
+
if error and isinstance(error, (str | list)):
|
300
|
+
_log_messages(error, logger.error)
|
281
301
|
|
282
302
|
@overload
|
283
303
|
def done(self, to_dict: Literal[True], suppress: list[str] | None = None) -> dict[str, Any]: ...
|
@@ -295,26 +315,26 @@ class FunctionResponse(BaseModel):
|
|
295
315
|
Returns:
|
296
316
|
dict[str, Any] | Self: The dictionary representation or the FunctionResponse instance.
|
297
317
|
"""
|
318
|
+
if not to_dict:
|
319
|
+
return self
|
320
|
+
|
298
321
|
if suppress is None:
|
299
322
|
suppress = []
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
if
|
305
|
-
result
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
result.update(self.extra)
|
316
|
-
return result
|
317
|
-
return self
|
323
|
+
|
324
|
+
result: dict[str, Any] = {}
|
325
|
+
|
326
|
+
def add(k: str, v: Any, _bool: bool = True) -> None:
|
327
|
+
if k not in suppress and _bool:
|
328
|
+
result[k] = v
|
329
|
+
|
330
|
+
add("name", self.name, bool(self.name))
|
331
|
+
add("success", self.success)
|
332
|
+
add("returncode", self.returncode, self.returncode > 0)
|
333
|
+
add("number_of_tasks", self.number_of_tasks, self.number_of_tasks > 0)
|
334
|
+
add("content", self.content, bool(self.content))
|
335
|
+
add("error", self.error, bool(self.error))
|
336
|
+
result.update(self.extra)
|
337
|
+
return result
|
318
338
|
|
319
339
|
|
320
340
|
def success(
|
@@ -334,3 +354,16 @@ def fail(
|
|
334
354
|
) -> FunctionResponse:
|
335
355
|
"""Create a failed FunctionResponse."""
|
336
356
|
return FunctionResponse().fail(content=content, error=error, returncode=returncode, **kwargs)
|
357
|
+
|
358
|
+
|
359
|
+
if __name__ == "__main__":
|
360
|
+
# Example usage
|
361
|
+
from rich import inspect
|
362
|
+
|
363
|
+
response = FunctionResponse(name="example_function", returncode=0, content=["Task completed successfully."])
|
364
|
+
response.task_id = 124
|
365
|
+
|
366
|
+
inspect(response)
|
367
|
+
print(response)
|
368
|
+
print(response.done(to_dict=True))
|
369
|
+
print(response.done(to_dict=False))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bear-utils
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.7
|
4
4
|
Summary: Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things.
|
5
5
|
Author-email: chaz <bright.lid5647@fastmail.com>
|
6
6
|
Requires-Python: >=3.12
|
@@ -20,7 +20,7 @@ Requires-Dist: tinydb>=4.8.2
|
|
20
20
|
Requires-Dist: toml>=0.10.2
|
21
21
|
Description-Content-Type: text/markdown
|
22
22
|
|
23
|
-
# Bear Utils v# Bear Utils v0.8.
|
23
|
+
# Bear Utils v# Bear Utils v0.8.7
|
24
24
|
|
25
25
|
Personal set of tools and utilities for Python projects, focusing on modularity and ease of use. This library includes components for caching, database management, logging, time handling, file operations, CLI prompts, image processing, clipboard interaction, gradient utilities, event systems, and async helpers.
|
26
26
|
|
@@ -12,7 +12,7 @@ bear_utils/ai/ai_helpers/_types.py,sha256=rmnl8mTlUj0LyL9USzTb-EN_31TtXY6qzhkOEu
|
|
12
12
|
bear_utils/cache/__init__.py,sha256=c9z1mLhWpZJHZdXRlviYQXl8tc9KTJCM8vin3moDO3I,4578
|
13
13
|
bear_utils/cli/__init__.py,sha256=H2QpLyHpQS_Yn3sF2px7n4KqT97LEe7Oyzafg2iHcpc,503
|
14
14
|
bear_utils/cli/commands.py,sha256=5ppEjvVV_g28WLaIFtKgz-ctzwoo-g-KpHTXNx9xBzo,3161
|
15
|
-
bear_utils/cli/prompt_helpers.py,sha256=
|
15
|
+
bear_utils/cli/prompt_helpers.py,sha256=8NmZcfnXteN-MhdE7sdH9iIu_xLi5bxArMWxX4vVWGU,6607
|
16
16
|
bear_utils/cli/shell/__init__.py,sha256=2s3oR6CqLKj1iyERy7YafWT3t3KzTr70Z1yaLKa6IiQ,42
|
17
17
|
bear_utils/cli/shell/_base_command.py,sha256=T1bwY9UX355Mv2u7JjSgI4U7VoWCTibszG8WvC3IEo4,2789
|
18
18
|
bear_utils/cli/shell/_base_shell.py,sha256=GW2kgj_KR33FtJLvV-ljSs_wzo5WQ8--H-K2hDPOblQ,16697
|
@@ -37,7 +37,7 @@ bear_utils/extras/_async_helpers.py,sha256=cxq5d24NHkECmZqTVXEazv6K-XUa7skFnX6KQ
|
|
37
37
|
bear_utils/extras/_tools.py,sha256=kxJ1jaqx3PvLpc0CZUIV8XQUwjQGrNCRLoka11aNtoc,7672
|
38
38
|
bear_utils/extras/platform_utils.py,sha256=Ai7ow7S-_cKb5zFwFh8dkC8xmbMJFy-0_-w3NCERdEw,1362
|
39
39
|
bear_utils/extras/responses/__init__.py,sha256=XbE4VKemrKRwx9E5jqy__OiM_AAjA58ebnqQ2hytnT0,225
|
40
|
-
bear_utils/extras/responses/function_response.py,sha256=
|
40
|
+
bear_utils/extras/responses/function_response.py,sha256=7MSA9UvoBwWkbjhYvn63oEyQD3p2QCQNCOihgqbU6vQ,15185
|
41
41
|
bear_utils/extras/wrappers/__init__.py,sha256=crh4sKOLvuhNMVX5bJYjCFWtXtH7G47UgNPOHq3HXTk,43
|
42
42
|
bear_utils/extras/wrappers/add_methods.py,sha256=z2XZG2ZoYOB1MaGiLli4NRyyTeRgBy7tuYsiy8mTa9s,4422
|
43
43
|
bear_utils/files/__init__.py,sha256=mIdnFSXoDE64ElM43bN2m6KuafURnN82ki0pdqN8q2o,201
|
@@ -80,6 +80,6 @@ bear_utils/monitoring/__init__.py,sha256=9DKNIWTp_voLnaWgiP-wJ-o_N0hYixo-MzjUmg8
|
|
80
80
|
bear_utils/monitoring/_common.py,sha256=LYQFxgTP9fk0cH71IQTuGwBYYPWCqHP_mMRNecoD76M,657
|
81
81
|
bear_utils/monitoring/host_monitor.py,sha256=e0TYRJw9iDj5Ga6y3ck1TBFEeH42Cax5mQYaNU8yams,13241
|
82
82
|
bear_utils/time/__init__.py,sha256=d9Ovv-Dlx5NWgnOl1hY-evznVm9hboS6ypNp1wDFxQQ,934
|
83
|
-
bear_utils-0.8.
|
84
|
-
bear_utils-0.8.
|
85
|
-
bear_utils-0.8.
|
83
|
+
bear_utils-0.8.7.dist-info/METADATA,sha256=RvbYBZNY_8VnUBwYqsR44LHhmPJJ9_-9K3hlVd4rNuk,8634
|
84
|
+
bear_utils-0.8.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
85
|
+
bear_utils-0.8.7.dist-info/RECORD,,
|
File without changes
|