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.
@@ -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 LitBool, LitFloat, LitInt, LitStr, OptBool, OptFloat, OptInt, OptStr
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: Overhaul this trash, it is written like absolute garbage.
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: LitInt, default: OptInt = None, **kwargs) -> int: ...
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: LitFloat, default: OptFloat = None, **kwargs) -> float: ...
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: LitStr, default: OptStr = None, **kwargs) -> str: ...
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: LitBool, default: OptBool = None, **kwargs) -> bool: ...
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: Any, default: Any = None, **_) -> Any:
33
- """Ask a question and return the answer, ensuring the entered type is correct and a value is entered.
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 of the answer (int, float, str, bool)
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: str = prompt("> ")
55
- if response == "":
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
- match expected_type:
60
- case "int":
61
- try:
62
- result = int(response)
63
- sub.verbose("int detected")
64
- return result
65
- except ValueError:
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: None | Any = None, **kwargs) -> None | bool:
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 no valid response is given
104
+ True for yes, False for no, or None if user exits
99
105
  """
100
- kwargs = kwargs or {}
101
- sub, console = get_console("prompt_helpers.py")
106
+ console, sub = get_console("prompt_helpers.py")
107
+
102
108
  try:
103
109
  while True:
104
- console.info(question)
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.lower() in ["yes", "y"]:
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
- console.error("Invalid input. Please enter 'yes' or 'no' or exit.")
119
- continue
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
- console.warning("KeyboardInterrupt: Exiting the prompt.")
126
+ sub.warning("KeyboardInterrupt: Exiting the prompt.")
122
127
  return None
123
128
 
124
129
 
125
- def restricted_prompt(question: str, valid_options: list[str], exit_command: str = "exit", **kwargs) -> None | str:
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
- kwargs = kwargs or {}
137
- sub, console = get_console("prompt_helpers.py")
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: str = document.text.lower()
145
- if text != exit_command and text not in valid_options:
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: {text}. Please choose from {', '.join(valid_options)} or type '{exit_command}' to exit.",
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
- if console is not None:
154
- console.info(question)
155
- response = prompt("> ", completer=completer, validator=OptionValidator(), complete_while_typing=True)
156
- response = response.lower()
157
- else:
158
- response = prompt(
159
- question, completer=completer, validator=OptionValidator(), complete_while_typing=True
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 response in valid_options:
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 io import StringIO
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
- result = StringIO()
36
- result.write("Response(")
37
- if self.name:
38
- result.write(f"name={self.name!r}, ")
39
- if self.returncode:
40
- result.write(f"success={self.success!r}, ")
41
- if self.content:
42
- content: str = ", ".join(self.content)
43
- result.write(f"content={content!r}, ")
44
- if self.error:
45
- error: str = ", ".join(self.error)
46
- result.write(f"error={error!r}, ")
47
- if self.extra:
48
- result.write(f"extra={json.dumps(self.extra)!r}, ")
49
- if self.number_of_tasks > 0:
50
- result.write(f"number_of_tasks={self.number_of_tasks!r}, ")
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
- ) -> None:
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 _add_error(self, error: str) -> None:
174
- """Append an error message to the existing error."""
175
- if error != "":
176
- self.error.append(error)
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 _add_to_error(self, error: str | list[str], name: str | None = None) -> None:
179
- """Append additional error messages to the existing error."""
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(error, list):
182
- for err in error:
183
- self._add_error(error=f"{name}: {err}" if name else err)
184
- elif isinstance(error, str):
185
- self._add_error(error=f"{name}: {error}" if name else error)
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 error: {e!s}") from e
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
- if content != "":
192
- self.content.append(content)
218
+ self._add_to_list(content, self.content, name)
193
219
 
194
- def _add_to_content(self, content: str | list[str], name: str | None = None) -> None:
195
- """Append additional content to the existing content."""
196
- try:
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._add_to_error(error=func_response.error, name=func_response.name)
210
- self._add_to_content(content=func_response.content, name=func_response.name)
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._add_to_content(content=result.stdout.strip() if result.stdout else "")
215
- self._add_to_error(error=result.stderr.strip() if result.stderr else "")
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._add_to_content(content=content)
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._add_to_error(error=error) if isinstance(error, (str | list)) else None
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
- if content is not None and error is None:
270
- if isinstance(content, list):
271
- for item in content:
272
- logger.info(f"{self.name}: {item}" if self.name else item)
273
- elif isinstance(content, str):
274
- logger.info(f"{self.name}: {content}" if self.name else content)
275
- elif error is not None and content is None:
276
- if isinstance(error, list):
277
- for err in error:
278
- logger.error(f"{self.name}: {err}" if self.name else err)
279
- elif isinstance(error, str):
280
- logger.error(f"{self.name}: {error}" if self.name else error)
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
- if to_dict:
301
- result: dict[str, Any] = {}
302
- if self.name and "name" not in suppress:
303
- result["name"] = self.name
304
- if "success" not in suppress:
305
- result.update({"success": self.success})
306
- if self.returncode > 0 and "returncode" not in suppress:
307
- result["returncode"] = self.returncode
308
- if self.number_of_tasks > 0 and "number_of_tasks" not in suppress:
309
- result["number_of_tasks"] = self.number_of_tasks
310
- if self.content and "content" not in suppress:
311
- result["content"] = self.content
312
- if self.error and "error" not in suppress:
313
- result["error"] = self.error
314
- if self.extra:
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.6
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.6
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=DVdg1f5yZElVyFNao6RTPfrc6mKy4PoXLgY6az-ejo8,6580
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=D6123VaOaJeeSQ9Gp1gtrvCSv7HF5Iw7dZlGbxHVQDk,14121
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.6.dist-info/METADATA,sha256=QG8sOkLV4XiFr490DziS-jSq9tIaICPgMvz--TgyaZI,8634
84
- bear_utils-0.8.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
85
- bear_utils-0.8.6.dist-info/RECORD,,
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,,