bear-utils 0.8.21__tar.gz → 0.8.22__tar.gz
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-0.8.21 → bear_utils-0.8.22}/.bumpversion.cfg +1 -1
- {bear_utils-0.8.21 → bear_utils-0.8.22}/PKG-INFO +2 -2
- {bear_utils-0.8.21 → bear_utils-0.8.22}/README.md +1 -1
- {bear_utils-0.8.21 → bear_utils-0.8.22}/pyproject.toml +1 -1
- bear_utils-0.8.22/src/bear_utils/extras/_async_helpers.py +67 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/responses/function_response.py +58 -29
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/qt_app.py +1 -1
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_function_response.py +17 -2
- bear_utils-0.8.21/src/bear_utils/extras/_async_helpers.py +0 -38
- {bear_utils-0.8.21 → bear_utils-0.8.22}/.gitignore +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/.python-version +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/AGENTS.md +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/coverage.ini +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/default.toml +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/git-changelog.toml +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/pytest.ini +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/ruff.toml +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/vscode/launch.json +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/vscode/settings.json +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/config/vscode/tasks.json +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/directory_structure.txt +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/directory_structure.xml +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/maskfile.md +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/noxfile.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/__main__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/_internal/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/_internal/cli.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/_internal/debug.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/ai_helpers/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/ai_helpers/_common.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/ai_helpers/_config.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/ai_helpers/_parsers.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/ai/ai_helpers/_types.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cache/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/commands.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/prompt_helpers.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/shell/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/shell/_base_command.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/shell/_base_shell.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/cli/shell/_common.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/config/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/config/config_manager.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/config/dir_manager.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/config/settings_manager.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/_exceptions.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/_lazy_typing.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/date_related.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/server.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/constants/time_related.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/database/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/database/_db_manager.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/events/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/events/events_class.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/events/events_module.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/_tools.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/platform_utils.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/responses/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/wrappers/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/wrappers/add_methods.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/_base_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/file_handler_factory.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/json_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/log_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/toml_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/txt_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/yaml_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/ignore_parser.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/graphics/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/graphics/bear_gradient.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/graphics/image_helpers.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/_settings.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/_types.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/qt_color_picker.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/qt_file_handler.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/gui/gui_tools/qt_input_dialog.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/_common.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/_console_junk.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/_log_level.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/_styles.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/logger_protocol.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/_level_sin.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/base_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/base_logger.pyi +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/basic_logger/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/basic_logger/logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/basic_logger/logger.pyi +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/buffer_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/console_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/console_logger.pyi +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/fastapi_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/file_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/simple_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/sub_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/sub_logger.pyi +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/monitoring/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/monitoring/_common.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/monitoring/host_monitor.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/time/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/__init__.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_add_ord_suffix.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_clipboard.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_database_manager.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_default_shell.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_gradient.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_logger.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_platform_utils.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/tests/test_prompt_helpers.py +0 -0
- {bear_utils-0.8.21 → bear_utils-0.8.22}/uv.lock +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bear-utils
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.22
|
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
|
@@ -24,7 +24,7 @@ Provides-Extra: gui
|
|
24
24
|
Requires-Dist: pyqt6>=6.9.0; extra == 'gui'
|
25
25
|
Description-Content-Type: text/markdown
|
26
26
|
|
27
|
-
# Bear Utils v# Bear Utils v0.8.
|
27
|
+
# Bear Utils v# Bear Utils v0.8.22
|
28
28
|
|
29
29
|
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.
|
30
30
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Bear Utils v# Bear Utils v0.8.
|
1
|
+
# Bear Utils v# Bear Utils v0.8.22
|
2
2
|
|
3
3
|
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.
|
4
4
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "bear-utils"
|
3
|
-
version = "0.8.
|
3
|
+
version = "0.8.22"
|
4
4
|
description = "Various utilities for Bear programmers, including a rich logging utility, a disk cache, and a SQLite database wrapper amongst other things."
|
5
5
|
authors = [{ name = "chaz", email = "bright.lid5647@fastmail.com" }]
|
6
6
|
readme = "README.md"
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import asyncio
|
2
|
+
from asyncio import AbstractEventLoop, Task
|
3
|
+
from collections.abc import Callable
|
4
|
+
from contextlib import suppress
|
5
|
+
import inspect
|
6
|
+
|
7
|
+
from pydantic import BaseModel, Field
|
8
|
+
|
9
|
+
|
10
|
+
class AsyncResponseModel(BaseModel):
|
11
|
+
"""A model to handle asynchronous operations with a function and its arguments."""
|
12
|
+
|
13
|
+
loop: AbstractEventLoop | None = Field(default=None, description="The event loop to run the function in.")
|
14
|
+
task: Task | None = Field(default=None, description="The task created for the asynchronous function.")
|
15
|
+
before_loop: bool = Field(default=False, description="If the function was called from a running loop.")
|
16
|
+
|
17
|
+
model_config = {"arbitrary_types_allowed": True}
|
18
|
+
|
19
|
+
def conditional_run(self) -> None:
|
20
|
+
"""Run the event loop until the task is complete if not in a running loop."""
|
21
|
+
if self.loop and self.task and not self.before_loop:
|
22
|
+
self.loop.run_until_complete(self.task)
|
23
|
+
|
24
|
+
|
25
|
+
def is_async_function(func: Callable) -> bool:
|
26
|
+
"""Check if a function is asynchronous.
|
27
|
+
|
28
|
+
Args:
|
29
|
+
func (Callable): The function/method to check.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
bool: True if the function is asynchronous, False otherwise.
|
33
|
+
"""
|
34
|
+
return inspect.iscoroutinefunction(func) or inspect.isasyncgenfunction(func) or inspect.isasyncgen(func)
|
35
|
+
|
36
|
+
|
37
|
+
def in_async_loop() -> bool:
|
38
|
+
"""Check if the current context is already in an async loop.
|
39
|
+
|
40
|
+
Returns:
|
41
|
+
bool: True if an async loop is running, False otherwise.
|
42
|
+
"""
|
43
|
+
loop: AbstractEventLoop | None = None
|
44
|
+
with suppress(RuntimeError):
|
45
|
+
loop = asyncio.get_running_loop()
|
46
|
+
return loop.is_running() if loop else False
|
47
|
+
|
48
|
+
|
49
|
+
def gimmie_async_loop() -> AbstractEventLoop:
|
50
|
+
"""Get the current event loop, creating one if it doesn't exist."""
|
51
|
+
if in_async_loop():
|
52
|
+
return asyncio.get_event_loop()
|
53
|
+
loop: AbstractEventLoop = asyncio.new_event_loop()
|
54
|
+
asyncio.set_event_loop(loop)
|
55
|
+
return loop
|
56
|
+
|
57
|
+
|
58
|
+
def create_async_task(
|
59
|
+
func: Callable,
|
60
|
+
*args,
|
61
|
+
**kwargs,
|
62
|
+
) -> AsyncResponseModel:
|
63
|
+
"""Create an asyncio task for a given function."""
|
64
|
+
before_loop: bool = in_async_loop()
|
65
|
+
loop: AbstractEventLoop = gimmie_async_loop()
|
66
|
+
task = loop.create_task(func(*args, **kwargs))
|
67
|
+
return AsyncResponseModel(loop=loop, task=task, before_loop=before_loop)
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/extras/responses/function_response.py
RENAMED
@@ -2,23 +2,24 @@
|
|
2
2
|
|
3
3
|
from __future__ import annotations
|
4
4
|
|
5
|
-
from collections.abc import Callable
|
6
5
|
import json
|
7
6
|
from subprocess import CompletedProcess
|
8
7
|
from types import SimpleNamespace as Namespace
|
9
|
-
from typing import Any, Literal, Self, overload
|
8
|
+
from typing import TYPE_CHECKING, Any, Literal, Self, overload
|
10
9
|
|
11
10
|
from pydantic import BaseModel, Field, field_validator
|
12
11
|
|
13
|
-
from bear_utils.extras._async_helpers import
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
)
|
12
|
+
from bear_utils.extras._async_helpers import AsyncResponseModel, create_async_task, is_async_function
|
13
|
+
|
14
|
+
# Pydantic will yell if we put this into a TYPE_CHECKING block.
|
15
|
+
from bear_utils.logger_manager import AsyncLoggerProtocol, LoggerProtocol # noqa: TC001
|
18
16
|
|
19
17
|
SUCCESS: list[str] = ["name", "success"]
|
20
18
|
FAILURE: list[str] = ["name"]
|
21
19
|
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from collections.abc import Callable
|
22
|
+
|
22
23
|
|
23
24
|
class FunctionResponse(BaseModel):
|
24
25
|
"""A class to represent the response of a function call, including success status, content, and error messages."""
|
@@ -240,6 +241,19 @@ class FunctionResponse(BaseModel):
|
|
240
241
|
self._add_error(error=result.stderr.strip() if result.stderr else "")
|
241
242
|
self.returncode = result.returncode
|
242
243
|
|
244
|
+
def _handle_content(self, content: list[str] | str | FunctionResponse | CompletedProcess | Any) -> None:
|
245
|
+
"""Handle different types of content and update the FunctionResponse."""
|
246
|
+
if isinstance(content, FunctionResponse):
|
247
|
+
self._handle_function_response(func_response=content)
|
248
|
+
elif isinstance(content, CompletedProcess):
|
249
|
+
self._handle_completed_process(result=content)
|
250
|
+
elif isinstance(content, (str | list)):
|
251
|
+
self._add_content(content=content)
|
252
|
+
else:
|
253
|
+
return
|
254
|
+
self.number_of_tasks += 1
|
255
|
+
|
256
|
+
@overload
|
243
257
|
def add(
|
244
258
|
self,
|
245
259
|
content: list[str] | str | FunctionResponse | CompletedProcess | None = None,
|
@@ -247,19 +261,36 @@ class FunctionResponse(BaseModel):
|
|
247
261
|
returncode: int | None = None,
|
248
262
|
log_output: bool = False,
|
249
263
|
extra: dict[str, Any] | None = None,
|
250
|
-
|
264
|
+
*,
|
265
|
+
to_dict: Literal[True],
|
266
|
+
) -> dict[str, Any]: ...
|
267
|
+
|
268
|
+
@overload
|
269
|
+
def add(
|
270
|
+
self,
|
271
|
+
content: list[str] | str | FunctionResponse | CompletedProcess | None = None,
|
272
|
+
error: str | list[str] | None = None,
|
273
|
+
returncode: int | None = None,
|
274
|
+
log_output: bool = False,
|
275
|
+
extra: dict[str, Any] | None = None,
|
276
|
+
*,
|
277
|
+
to_dict: Literal[False] = False,
|
278
|
+
) -> Self: ...
|
279
|
+
|
280
|
+
def add(
|
281
|
+
self,
|
282
|
+
content: list[str] | str | FunctionResponse | CompletedProcess | None = None,
|
283
|
+
error: str | list[str] | None = None,
|
284
|
+
returncode: int | None = None,
|
285
|
+
log_output: bool = False,
|
286
|
+
extra: dict[str, Any] | None = None,
|
287
|
+
*,
|
288
|
+
to_dict: bool = False,
|
289
|
+
) -> Self | dict[str, Any]:
|
251
290
|
"""Append additional content to the existing content."""
|
252
291
|
try:
|
253
292
|
if content is not None:
|
254
|
-
|
255
|
-
self._handle_function_response(func_response=content)
|
256
|
-
self.number_of_tasks += 1
|
257
|
-
elif isinstance(content, CompletedProcess):
|
258
|
-
self._handle_completed_process(result=content)
|
259
|
-
self.number_of_tasks += 1
|
260
|
-
elif isinstance(content, (str | list)) and content:
|
261
|
-
self._add_content(content=content)
|
262
|
-
self.number_of_tasks += 1
|
293
|
+
self._handle_content(content=content)
|
263
294
|
if error is not None and isinstance(error, (str | list)):
|
264
295
|
self._add_error(error=error)
|
265
296
|
if isinstance(returncode, int):
|
@@ -270,6 +301,8 @@ class FunctionResponse(BaseModel):
|
|
270
301
|
self._log_handling(content=content, error=error, logger=self.logger)
|
271
302
|
except Exception as e:
|
272
303
|
raise ValueError(f"Failed to add content: {e!s}") from e
|
304
|
+
if to_dict:
|
305
|
+
return self.done(to_dict=True)
|
273
306
|
return self
|
274
307
|
|
275
308
|
def _log_handling(
|
@@ -308,18 +341,14 @@ class FunctionResponse(BaseModel):
|
|
308
341
|
if not content and not error:
|
309
342
|
return
|
310
343
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
info_func=logger.info,
|
318
|
-
error_func=logger.error,
|
319
|
-
)
|
344
|
+
res: AsyncResponseModel = create_async_task(
|
345
|
+
_log_messages,
|
346
|
+
content=content,
|
347
|
+
error=error,
|
348
|
+
info_func=logger.info,
|
349
|
+
error_func=logger.error,
|
320
350
|
)
|
321
|
-
|
322
|
-
loop.run_until_complete(task)
|
351
|
+
res.conditional_run()
|
323
352
|
|
324
353
|
@overload
|
325
354
|
def done(self, to_dict: Literal[True], suppress: list[str] | None = None) -> dict[str, Any]: ...
|
@@ -352,7 +381,7 @@ class FunctionResponse(BaseModel):
|
|
352
381
|
add("name", self.name, bool(self.name))
|
353
382
|
add("success", self.success)
|
354
383
|
add("returncode", self.returncode, self.returncode > 0)
|
355
|
-
add("number_of_tasks", self.number_of_tasks, self.number_of_tasks > 0)
|
384
|
+
add("number_of_tasks", self.number_of_tasks, (self.number_of_tasks > 0 and not self.success))
|
356
385
|
add("content", self.content, bool(self.content))
|
357
386
|
add("error", self.error, bool(self.error))
|
358
387
|
result.update(self.extra)
|
@@ -36,7 +36,7 @@ class QTApplication(QObject):
|
|
36
36
|
self.app.setOrganizationDomain(org_domain)
|
37
37
|
else:
|
38
38
|
self.app = QApplication.instance()
|
39
|
-
self.console = ConsoleLogger.get_instance(init=True, name=app_name, level=VERBOSE)
|
39
|
+
self.console: ConsoleLogger = ConsoleLogger.get_instance(init=True, name=app_name, level=VERBOSE)
|
40
40
|
atexit.register(self.cleanup)
|
41
41
|
|
42
42
|
def _default_exit_shortcuts(self) -> None:
|
@@ -635,15 +635,30 @@ class TestComplexScenarios:
|
|
635
635
|
response.successful("Cleared 5 completed tasks")
|
636
636
|
response.add(content="Operation summary generated")
|
637
637
|
|
638
|
-
# Get dict format suitable for MCP
|
639
638
|
result = response.done(to_dict=True, suppress=SUCCESS)
|
640
639
|
|
641
640
|
# SUCCESS suppresses "name" and "success", so check what actually remains
|
642
641
|
assert "content" in result
|
643
|
-
assert "number_of_tasks" in result
|
642
|
+
assert "number_of_tasks" not in result # This will only be here in failures
|
644
643
|
assert "name" not in result
|
645
644
|
assert "success" not in result
|
646
645
|
|
646
|
+
def test_mcp_server_response_format_error(self):
|
647
|
+
"""Test formatting response for MCP server consumption."""
|
648
|
+
response = FunctionResponse(name="clear_tasks_error")
|
649
|
+
|
650
|
+
# Add some successful operations
|
651
|
+
response.fail("Failed to clear tasks")
|
652
|
+
response.add(content="Error summary generated")
|
653
|
+
|
654
|
+
result = response.done(to_dict=True, suppress=FAILURE)
|
655
|
+
|
656
|
+
# SUCCESS suppresses "name" and "success", so check what actually remains
|
657
|
+
assert "content" in result
|
658
|
+
assert "number_of_tasks" in result
|
659
|
+
assert "name" not in result
|
660
|
+
assert "success" in result
|
661
|
+
|
647
662
|
def test_error_handling_in_add_method(self):
|
648
663
|
"""Test error handling within add method."""
|
649
664
|
response = FunctionResponse()
|
@@ -1,38 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from asyncio import AbstractEventLoop
|
3
|
-
from collections.abc import Callable
|
4
|
-
from contextlib import suppress
|
5
|
-
import inspect
|
6
|
-
|
7
|
-
|
8
|
-
def is_async_function(func: Callable) -> bool:
|
9
|
-
"""Check if a function is asynchronous.
|
10
|
-
|
11
|
-
Args:
|
12
|
-
func (Callable): The function/method to check.
|
13
|
-
|
14
|
-
Returns:
|
15
|
-
bool: True if the function is asynchronous, False otherwise.
|
16
|
-
"""
|
17
|
-
return inspect.iscoroutinefunction(func) or inspect.isasyncgenfunction(func) or inspect.isasyncgen(func)
|
18
|
-
|
19
|
-
|
20
|
-
def in_async_loop() -> bool:
|
21
|
-
"""Check if the current context is already in an async loop.
|
22
|
-
|
23
|
-
Returns:
|
24
|
-
bool: True if an async loop is running, False otherwise.
|
25
|
-
"""
|
26
|
-
loop: AbstractEventLoop | None = None
|
27
|
-
with suppress(RuntimeError):
|
28
|
-
loop = asyncio.get_running_loop()
|
29
|
-
return loop.is_running() if loop else False
|
30
|
-
|
31
|
-
|
32
|
-
def gimmie_async_loop() -> AbstractEventLoop:
|
33
|
-
"""Get the current event loop, creating one if it doesn't exist."""
|
34
|
-
if in_async_loop():
|
35
|
-
return asyncio.get_event_loop()
|
36
|
-
loop: AbstractEventLoop = asyncio.new_event_loop()
|
37
|
-
asyncio.set_event_loop(loop)
|
38
|
-
return loop
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/_base_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/file_handler_factory.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/json_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/log_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/toml_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/txt_file_handler.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/files/file_handlers/yaml_file_handler.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/base_logger.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/base_logger.pyi
RENAMED
File without changes
|
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/basic_logger/logger.py
RENAMED
File without changes
|
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/buffer_logger.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/console_logger.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/console_logger.pyi
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/fastapi_logger.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/file_logger.py
RENAMED
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/simple_logger.py
RENAMED
File without changes
|
File without changes
|
{bear_utils-0.8.21 → bear_utils-0.8.22}/src/bear_utils/logger_manager/loggers/sub_logger.pyi
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|