bear-utils 0.7.23__py3-none-any.whl → 0.7.24__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/extras/responses/function_response.py +73 -38
- bear_utils/files/file_handlers/_base_file_handler.py +3 -9
- bear_utils/files/file_handlers/json_file_handler.py +2 -2
- bear_utils/files/file_handlers/log_file_handler.py +2 -2
- bear_utils/files/file_handlers/toml_file_handler.py +1 -1
- bear_utils/files/file_handlers/txt_file_handler.py +2 -2
- bear_utils/files/file_handlers/yaml_file_handler.py +1 -0
- {bear_utils-0.7.23.dist-info → bear_utils-0.7.24.dist-info}/METADATA +2 -2
- {bear_utils-0.7.23.dist-info → bear_utils-0.7.24.dist-info}/RECORD +10 -10
- {bear_utils-0.7.23.dist-info → bear_utils-0.7.24.dist-info}/WHEEL +0 -0
@@ -5,12 +5,11 @@ from __future__ import annotations
|
|
5
5
|
from io import StringIO
|
6
6
|
import json
|
7
7
|
from subprocess import CompletedProcess
|
8
|
-
from typing import
|
8
|
+
from typing import Any, Literal, Self, overload
|
9
9
|
|
10
10
|
from pydantic import BaseModel, Field, field_validator
|
11
11
|
|
12
|
-
|
13
|
-
from bear_utils.constants.logger_protocol import LoggerProtocol
|
12
|
+
from bear_utils.constants.logger_protocol import LoggerProtocol # noqa: TC001 # DO NOT PUT INTO A TYPE_CHECKING BLOCK
|
14
13
|
|
15
14
|
SUCCESS: list[str] = ["name", "success"]
|
16
15
|
FAILURE: list[str] = ["name"]
|
@@ -130,6 +129,25 @@ class FunctionResponse(BaseModel):
|
|
130
129
|
"""Check if the response indicates success."""
|
131
130
|
return self.returncode == 0
|
132
131
|
|
132
|
+
def sub_task(
|
133
|
+
self,
|
134
|
+
name: str = "",
|
135
|
+
content: str | list[str] = "",
|
136
|
+
error: str | list[str] = "",
|
137
|
+
extra: dict[str, Any] | None = None,
|
138
|
+
returncode: int | None = None,
|
139
|
+
log_output: bool = False,
|
140
|
+
) -> None:
|
141
|
+
"""Add a sub-task response to the FunctionResponse."""
|
142
|
+
func_response: FunctionResponse = FunctionResponse(name=name, logger=self.logger).add(
|
143
|
+
content=content,
|
144
|
+
error=error,
|
145
|
+
returncode=returncode or self.returncode,
|
146
|
+
log_output=log_output,
|
147
|
+
extra=extra,
|
148
|
+
)
|
149
|
+
self.add(content=func_response)
|
150
|
+
|
133
151
|
def successful(
|
134
152
|
self,
|
135
153
|
content: str | list[str] | CompletedProcess,
|
@@ -184,6 +202,19 @@ class FunctionResponse(BaseModel):
|
|
184
202
|
except Exception as e:
|
185
203
|
raise ValueError(f"Failed to add content: {e!s}") from e
|
186
204
|
|
205
|
+
def _handle_function_response(self, func_response: FunctionResponse) -> None:
|
206
|
+
"""Handle a FunctionResponse object and update the current response."""
|
207
|
+
if func_response.extra:
|
208
|
+
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)
|
211
|
+
|
212
|
+
def _handle_completed_process(self, result: CompletedProcess[str]) -> None:
|
213
|
+
"""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 "")
|
216
|
+
self.returncode = result.returncode
|
217
|
+
|
187
218
|
def add(
|
188
219
|
self,
|
189
220
|
content: list[str] | str | FunctionResponse | CompletedProcess | None = None,
|
@@ -205,45 +236,49 @@ class FunctionResponse(BaseModel):
|
|
205
236
|
Self: The updated FunctionResponse instance.
|
206
237
|
"""
|
207
238
|
try:
|
208
|
-
|
209
|
-
|
210
|
-
self.
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
if
|
224
|
-
|
225
|
-
if
|
226
|
-
self.
|
227
|
-
if extra is not None and isinstance(extra, dict):
|
228
|
-
self.extra.update(extra)
|
229
|
-
if log_output and self.logger is not None:
|
230
|
-
if content is not None and error is None:
|
231
|
-
if isinstance(content, list):
|
232
|
-
for item in content:
|
233
|
-
self.logger.info(message=f"{self.name}: {item}" if self.name else item)
|
234
|
-
elif isinstance(content, str):
|
235
|
-
self.logger.info(message=f"{self.name}: {content}" if self.name else content)
|
236
|
-
elif error is not None and content is None:
|
237
|
-
if isinstance(error, list):
|
238
|
-
for err in error:
|
239
|
-
self.logger.error(message=f"{self.name}: {err}" if self.name else err)
|
240
|
-
elif isinstance(error, str):
|
241
|
-
self.logger.error(message=f"{self.name}: {error}" if self.name else error)
|
242
|
-
|
239
|
+
match content:
|
240
|
+
case FunctionResponse():
|
241
|
+
self._handle_function_response(func_response=content)
|
242
|
+
self.number_of_tasks += 1
|
243
|
+
case CompletedProcess():
|
244
|
+
self._handle_completed_process(result=content)
|
245
|
+
self.number_of_tasks += 1
|
246
|
+
case str() | list() if content:
|
247
|
+
self._add_to_content(content=content)
|
248
|
+
self.number_of_tasks += 1
|
249
|
+
case None:
|
250
|
+
content = None
|
251
|
+
case _:
|
252
|
+
content = None
|
253
|
+
self._add_to_error(error=error) if isinstance(error, (str | list)) else None
|
254
|
+
self.returncode = returncode if returncode is not None else self.returncode
|
255
|
+
self.extra.update(extra) if isinstance(extra, dict) else None
|
256
|
+
if log_output and self.logger is not None and (content is not None or error is not None):
|
257
|
+
self._log_handling(content=content, error=error, logger=self.logger)
|
243
258
|
except Exception as e:
|
244
259
|
raise ValueError(f"Failed to add content: {e!s}") from e
|
245
260
|
return self
|
246
261
|
|
262
|
+
def _log_handling(
|
263
|
+
self,
|
264
|
+
content: list[str] | str | FunctionResponse | CompletedProcess | None,
|
265
|
+
error: str | list[str] | None,
|
266
|
+
logger: LoggerProtocol,
|
267
|
+
) -> None:
|
268
|
+
"""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(message=f"{self.name}: {item}" if self.name else item)
|
273
|
+
elif isinstance(content, str):
|
274
|
+
logger.info(message=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(message=f"{self.name}: {err}" if self.name else err)
|
279
|
+
elif isinstance(error, str):
|
280
|
+
logger.error(message=f"{self.name}: {error}" if self.name else error)
|
281
|
+
|
247
282
|
@overload
|
248
283
|
def done(self, to_dict: Literal[True], suppress: list[str] | None = None) -> dict[str, Any]: ...
|
249
284
|
|
@@ -8,12 +8,6 @@ P = ParamSpec("P")
|
|
8
8
|
R = TypeVar("R")
|
9
9
|
|
10
10
|
|
11
|
-
def check_data_type(data: dict[str, Any] | str, valid_types: tuple[type, ...]) -> None:
|
12
|
-
"""Check if the data is of a valid type for text files."""
|
13
|
-
if not isinstance(data, valid_types):
|
14
|
-
raise TypeError(f"Data must be one of {valid_types}, got {type(data)}")
|
15
|
-
|
16
|
-
|
17
11
|
class FileHandler(ABC):
|
18
12
|
"""Abstract class for file handling with read, write, and present methods
|
19
13
|
|
@@ -40,7 +34,7 @@ class FileHandler(ABC):
|
|
40
34
|
return file_path.suffix.lstrip(".") in cls.valid_extensions
|
41
35
|
|
42
36
|
@classmethod
|
43
|
-
def check_data_type(cls, data: Any) ->
|
37
|
+
def check_data_type(cls, data: dict[str, Any] | str, valid_types: tuple[type, ...]) -> None:
|
44
38
|
"""Check if the data is of the correct type.
|
45
39
|
|
46
40
|
Args:
|
@@ -49,8 +43,8 @@ class FileHandler(ABC):
|
|
49
43
|
Returns:
|
50
44
|
bool: True if the data is of the correct type, False otherwise
|
51
45
|
"""
|
52
|
-
if not isinstance(data,
|
53
|
-
raise TypeError(f"Data must be one of {
|
46
|
+
if not isinstance(data, valid_types):
|
47
|
+
raise TypeError(f"Data must be one of {valid_types}, got {type(data)}")
|
54
48
|
|
55
49
|
@classmethod
|
56
50
|
def ValidateFileType(cls, method: Callable[P, R]) -> Callable[P, R]: # noqa: N802 disable=invalid-name
|
@@ -4,7 +4,7 @@ import json
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, ClassVar, overload
|
6
6
|
|
7
|
-
from ._base_file_handler import FileHandler
|
7
|
+
from ._base_file_handler import FileHandler
|
8
8
|
|
9
9
|
|
10
10
|
class JsonFileHandler(FileHandler):
|
@@ -44,7 +44,7 @@ class JsonFileHandler(FileHandler):
|
|
44
44
|
"""Write data to a JSON file."""
|
45
45
|
try:
|
46
46
|
super().write_file(file_path=file_path, data=data)
|
47
|
-
check_data_type(data=data, valid_types=self.valid_types)
|
47
|
+
self.check_data_type(data=data, valid_types=self.valid_types)
|
48
48
|
data = self.present_file(data, indent=indent, sort_keys=sort_keys)
|
49
49
|
file_path.write_text(data=data, encoding="utf-8")
|
50
50
|
except Exception as e:
|
@@ -3,7 +3,7 @@
|
|
3
3
|
from pathlib import Path
|
4
4
|
from typing import Any, ClassVar, cast
|
5
5
|
|
6
|
-
from ._base_file_handler import FileHandler
|
6
|
+
from ._base_file_handler import FileHandler
|
7
7
|
|
8
8
|
|
9
9
|
class LogFileHandler(FileHandler):
|
@@ -27,7 +27,7 @@ class LogFileHandler(FileHandler):
|
|
27
27
|
"""Write data to a log file."""
|
28
28
|
try:
|
29
29
|
super().write_file(file_path=file_path, data=data)
|
30
|
-
check_data_type(data=data, valid_types=self.valid_types)
|
30
|
+
self.check_data_type(data=data, valid_types=self.valid_types)
|
31
31
|
with open(file_path, "w", encoding="utf-8") as file:
|
32
32
|
file.write(cast("str", data))
|
33
33
|
except Exception as e:
|
@@ -30,7 +30,7 @@ class TomlFileHandler(FileHandler):
|
|
30
30
|
"""Write data to a TOML file."""
|
31
31
|
try:
|
32
32
|
super().write_file(file_path=file_path, data=data)
|
33
|
-
|
33
|
+
self.check_data_type(data=data, valid_types=self.valid_types)
|
34
34
|
with open(file_path, "w", encoding="utf-8") as file:
|
35
35
|
if isinstance(data, dict):
|
36
36
|
toml.dump(data, file, **kwargs)
|
@@ -4,7 +4,7 @@ import json
|
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import Any, ClassVar, overload
|
6
6
|
|
7
|
-
from ._base_file_handler import FileHandler
|
7
|
+
from ._base_file_handler import FileHandler
|
8
8
|
|
9
9
|
|
10
10
|
class TextFileHandler(FileHandler):
|
@@ -44,7 +44,7 @@ class TextFileHandler(FileHandler):
|
|
44
44
|
"""Write data to a text file."""
|
45
45
|
try:
|
46
46
|
super().write_file(file_path=file_path, data=data)
|
47
|
-
check_data_type(data, self.valid_types)
|
47
|
+
self.check_data_type(data=data, valid_types=self.valid_types)
|
48
48
|
if isinstance(data, dict):
|
49
49
|
data = json.dumps(data, indent=indent, sort_keys=sort_keys)
|
50
50
|
elif isinstance(data, list):
|
@@ -50,6 +50,7 @@ class YamlFileHandler(FileHandler):
|
|
50
50
|
"""Write data to a YAML file."""
|
51
51
|
try:
|
52
52
|
super().write_file(file_path=file_path, data=data)
|
53
|
+
self.check_data_type(data=data, valid_types=self.valid_types)
|
53
54
|
with open(file=file_path, mode="w", encoding="utf-8") as file:
|
54
55
|
yaml.dump(data, stream=file, default_flow_style=False, sort_keys=False, **kwargs)
|
55
56
|
except Exception as e:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bear-utils
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.24
|
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.7.
|
23
|
+
# Bear Utils v# Bear Utils v0.7.24
|
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
|
|
@@ -33,19 +33,19 @@ bear_utils/extras/_async_helpers.py,sha256=cxq5d24NHkECmZqTVXEazv6K-XUa7skFnX6KQ
|
|
33
33
|
bear_utils/extras/_tools.py,sha256=OYzGEEp7F6H6qr1t1QlnHTnAb4JaH6p9_maSXeDGFFM,7681
|
34
34
|
bear_utils/extras/platform_utils.py,sha256=Ai7ow7S-_cKb5zFwFh8dkC8xmbMJFy-0_-w3NCERdEw,1362
|
35
35
|
bear_utils/extras/responses/__init__.py,sha256=U5InC9ec9OI-f_eCi78z8UJsqtgEA5PGBvu94yvgjnA,89
|
36
|
-
bear_utils/extras/responses/function_response.py,sha256=
|
36
|
+
bear_utils/extras/responses/function_response.py,sha256=Zis2uIpGp3Mqbpc0RszyNt2JSsLAiGmWKhgezLjzUTM,14153
|
37
37
|
bear_utils/extras/wrappers/__init__.py,sha256=crh4sKOLvuhNMVX5bJYjCFWtXtH7G47UgNPOHq3HXTk,43
|
38
38
|
bear_utils/extras/wrappers/add_methods.py,sha256=z2XZG2ZoYOB1MaGiLli4NRyyTeRgBy7tuYsiy8mTa9s,4422
|
39
39
|
bear_utils/files/__init__.py,sha256=mIdnFSXoDE64ElM43bN2m6KuafURnN82ki0pdqN8q2o,201
|
40
40
|
bear_utils/files/ignore_parser.py,sha256=ipBqUH5ndipPSq27TEsGDa7Sqq53KrczGLZcnNbW9F0,10951
|
41
41
|
bear_utils/files/file_handlers/__init__.py,sha256=VF2IlWNr3UqeSvsbh3YCbLw9cLmlyf64mfeOKuhBdvk,136
|
42
|
-
bear_utils/files/file_handlers/_base_file_handler.py,sha256=
|
42
|
+
bear_utils/files/file_handlers/_base_file_handler.py,sha256=Fl45rAuKSY-fVYBP-7o7op6thXlX8FLQbgwXEt4gDLQ,3726
|
43
43
|
bear_utils/files/file_handlers/file_handler_factory.py,sha256=fDo2UcWp5-pOMtVWKCTuz-Fw4qSIB9fg5FgNRoYR6g4,9931
|
44
|
-
bear_utils/files/file_handlers/json_file_handler.py,sha256=
|
45
|
-
bear_utils/files/file_handlers/log_file_handler.py,sha256=
|
46
|
-
bear_utils/files/file_handlers/toml_file_handler.py,sha256=
|
47
|
-
bear_utils/files/file_handlers/txt_file_handler.py,sha256=
|
48
|
-
bear_utils/files/file_handlers/yaml_file_handler.py,sha256=
|
44
|
+
bear_utils/files/file_handlers/json_file_handler.py,sha256=0kqsG5QErFc3TVbK1I1l4cdzSxT6mYCmNuaW7hpFkYo,2656
|
45
|
+
bear_utils/files/file_handlers/log_file_handler.py,sha256=RDPOqNE_ujL_IIjfqi89LXNd4jntQ0bYTGqRVKiC_CU,1530
|
46
|
+
bear_utils/files/file_handlers/toml_file_handler.py,sha256=YPC9Y8DEURS9v3lV_iEng6URP0q97oDD74qdN870rhg,2699
|
47
|
+
bear_utils/files/file_handlers/txt_file_handler.py,sha256=Et_AxKEb3_XpVfJYIIsrHqvmDNXzzrBjmn2Ost3bPPA,2762
|
48
|
+
bear_utils/files/file_handlers/yaml_file_handler.py,sha256=iUFAJle2t67SX6uvPiutjdO8gSU1q_rXrZXH9MnJygg,2536
|
49
49
|
bear_utils/graphics/__init__.py,sha256=uR_NFKfskJGDPT0PGiw38rRniV945H67fvDALxUTnVw,268
|
50
50
|
bear_utils/graphics/bear_gradient.py,sha256=36B9hjU_qDjdgZaVcRl4jE3uQyU8k8G_MiORFzaendE,5272
|
51
51
|
bear_utils/graphics/image_helpers.py,sha256=AaDQm6uunIdVkcMSXmoiaNQ68zRQQJ6bbhoApk6GSKU,1649
|
@@ -78,6 +78,6 @@ bear_utils/monitoring/__init__.py,sha256=9DKNIWTp_voLnaWgiP-wJ-o_N0hYixo-MzjUmg8
|
|
78
78
|
bear_utils/monitoring/_common.py,sha256=LYQFxgTP9fk0cH71IQTuGwBYYPWCqHP_mMRNecoD76M,657
|
79
79
|
bear_utils/monitoring/host_monitor.py,sha256=iawDGJWvByUnTanJvgiZMlqSJr3JpEWJdgA99A-fol0,13214
|
80
80
|
bear_utils/time/__init__.py,sha256=d9Ovv-Dlx5NWgnOl1hY-evznVm9hboS6ypNp1wDFxQQ,934
|
81
|
-
bear_utils-0.7.
|
82
|
-
bear_utils-0.7.
|
83
|
-
bear_utils-0.7.
|
81
|
+
bear_utils-0.7.24.dist-info/METADATA,sha256=UMrwess6tydfPIEh_rszg6XqQ_YyF9VYHgyVpRAn864,8629
|
82
|
+
bear_utils-0.7.24.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
83
|
+
bear_utils-0.7.24.dist-info/RECORD,,
|
File without changes
|