waldiez 0.4.8__py3-none-any.whl → 0.4.9__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.
Potentially problematic release.
This version of waldiez might be problematic. Click here for more details.
- waldiez/_version.py +1 -1
- waldiez/cli.py +10 -54
- waldiez/exporting/agent/extras/rag/chroma_extras.py +21 -9
- waldiez/io/structured.py +21 -1
- waldiez/runner.py +7 -18
- waldiez/running/__init__.py +12 -6
- waldiez/running/post_run.py +119 -0
- waldiez/running/pre_run.py +149 -0
- waldiez/running/util.py +134 -0
- waldiez/utils/__init__.py +2 -0
- waldiez/utils/version.py +47 -0
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/METADATA +4 -4
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/RECORD +17 -14
- waldiez/running/running.py +0 -388
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/WHEEL +0 -0
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/entry_points.txt +0 -0
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/licenses/LICENSE +0 -0
- {waldiez-0.4.8.dist-info → waldiez-0.4.9.dist-info}/licenses/NOTICE.md +0 -0
waldiez/_version.py
CHANGED
waldiez/cli.py
CHANGED
|
@@ -2,43 +2,25 @@
|
|
|
2
2
|
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
3
|
# flake8: noqa: E501
|
|
4
4
|
# pylint: disable=missing-function-docstring,missing-param-doc,missing-raises-doc
|
|
5
|
+
# pylint: disable=line-too-long
|
|
5
6
|
"""Command line interface to convert or run a waldiez file."""
|
|
6
7
|
|
|
7
8
|
import json
|
|
8
9
|
import os
|
|
9
10
|
from pathlib import Path
|
|
10
|
-
from typing import
|
|
11
|
+
from typing import Any, Optional
|
|
11
12
|
|
|
12
13
|
import anyio
|
|
13
14
|
import typer
|
|
14
15
|
from dotenv import load_dotenv
|
|
15
16
|
from typing_extensions import Annotated
|
|
16
17
|
|
|
17
|
-
# pylint: disable=import-error,line-too-long
|
|
18
|
-
# pyright: reportMissingImports=false
|
|
19
|
-
try: # pragma: no cover
|
|
20
|
-
# fmt: off
|
|
21
|
-
from ._version import __version__ # type: ignore[unused-ignore, unused-import, import-not-found, import-untyped] # noqa
|
|
22
|
-
# fmt: on
|
|
23
|
-
except ImportError: # pragma: no cover
|
|
24
|
-
import warnings
|
|
25
|
-
|
|
26
|
-
warnings.warn(
|
|
27
|
-
"Importing __version__ failed. Using 'dev' as version.", stacklevel=2
|
|
28
|
-
)
|
|
29
|
-
__version__ = "dev"
|
|
30
|
-
|
|
31
|
-
|
|
32
18
|
from .exporter import WaldiezExporter
|
|
33
19
|
from .io import StructuredIOStream
|
|
34
20
|
from .logger import get_logger
|
|
35
21
|
from .models import Waldiez
|
|
36
22
|
from .runner import WaldiezRunner
|
|
37
|
-
from .utils import add_cli_extras
|
|
38
|
-
|
|
39
|
-
if TYPE_CHECKING:
|
|
40
|
-
from autogen import ChatResult # type: ignore[import-untyped]
|
|
41
|
-
|
|
23
|
+
from .utils import add_cli_extras, get_waldiez_version
|
|
42
24
|
|
|
43
25
|
load_dotenv()
|
|
44
26
|
LOG = get_logger()
|
|
@@ -71,7 +53,7 @@ def show_version(
|
|
|
71
53
|
) -> None:
|
|
72
54
|
"""Show the version of the Waldiez package and exit."""
|
|
73
55
|
if version:
|
|
74
|
-
typer.echo(f"waldiez version: {
|
|
56
|
+
typer.echo(f"waldiez version: {get_waldiez_version()}")
|
|
75
57
|
raise typer.Exit()
|
|
76
58
|
|
|
77
59
|
|
|
@@ -130,27 +112,12 @@ def run(
|
|
|
130
112
|
except json.decoder.JSONDecodeError as error:
|
|
131
113
|
typer.echo("Invalid .waldiez file. Not a valid json?")
|
|
132
114
|
raise typer.Exit(code=1) from error
|
|
133
|
-
|
|
115
|
+
_do_run(
|
|
134
116
|
data,
|
|
135
117
|
structured=structured,
|
|
136
118
|
uploads_root=uploads_root,
|
|
137
119
|
output_path=output_path,
|
|
138
120
|
)
|
|
139
|
-
if isinstance(results, list):
|
|
140
|
-
LOG.info("Results:")
|
|
141
|
-
for result in results:
|
|
142
|
-
_log_result(result)
|
|
143
|
-
sep = "-" * 80
|
|
144
|
-
print("\n" + f"{sep}" + "\n")
|
|
145
|
-
elif isinstance(results, dict):
|
|
146
|
-
LOG.info("Results:")
|
|
147
|
-
for key, result in results.items():
|
|
148
|
-
LOG.info("Order: %s", key)
|
|
149
|
-
_log_result(result)
|
|
150
|
-
sep = "-" * 80
|
|
151
|
-
print("\n" + f"{sep}" + "\n")
|
|
152
|
-
else:
|
|
153
|
-
_log_result(results)
|
|
154
121
|
|
|
155
122
|
|
|
156
123
|
@app.command()
|
|
@@ -239,7 +206,7 @@ def _do_run(
|
|
|
239
206
|
structured: bool,
|
|
240
207
|
uploads_root: Optional[Path],
|
|
241
208
|
output_path: Optional[Path],
|
|
242
|
-
) ->
|
|
209
|
+
) -> None:
|
|
243
210
|
"""Run the Waldiez flow and get the results."""
|
|
244
211
|
waldiez = Waldiez.from_dict(data)
|
|
245
212
|
if structured:
|
|
@@ -247,30 +214,29 @@ def _do_run(
|
|
|
247
214
|
with StructuredIOStream.set_default(stream):
|
|
248
215
|
runner = WaldiezRunner(waldiez)
|
|
249
216
|
if waldiez.is_async:
|
|
250
|
-
|
|
217
|
+
anyio.run(
|
|
251
218
|
runner.a_run,
|
|
252
219
|
output_path,
|
|
253
220
|
uploads_root,
|
|
254
221
|
)
|
|
255
222
|
else:
|
|
256
|
-
|
|
223
|
+
runner.run(
|
|
257
224
|
output_path=output_path,
|
|
258
225
|
uploads_root=uploads_root,
|
|
259
226
|
)
|
|
260
227
|
else:
|
|
261
228
|
runner = WaldiezRunner(waldiez)
|
|
262
229
|
if waldiez.is_async:
|
|
263
|
-
|
|
230
|
+
anyio.run(
|
|
264
231
|
runner.a_run,
|
|
265
232
|
output_path,
|
|
266
233
|
uploads_root,
|
|
267
234
|
)
|
|
268
235
|
else:
|
|
269
|
-
|
|
236
|
+
runner.run(
|
|
270
237
|
output_path=output_path,
|
|
271
238
|
uploads_root=uploads_root,
|
|
272
239
|
)
|
|
273
|
-
return results
|
|
274
240
|
|
|
275
241
|
|
|
276
242
|
def _get_output_path(output: Optional[Path], force: bool) -> Optional[Path]:
|
|
@@ -286,16 +252,6 @@ def _get_output_path(output: Optional[Path], force: bool) -> Optional[Path]:
|
|
|
286
252
|
return output
|
|
287
253
|
|
|
288
254
|
|
|
289
|
-
def _log_result(result: "ChatResult") -> None:
|
|
290
|
-
"""Log the result of the Waldiez flow."""
|
|
291
|
-
LOG.info("Chat History:\n")
|
|
292
|
-
LOG.info(result.chat_history)
|
|
293
|
-
LOG.info("Summary:\n")
|
|
294
|
-
LOG.info(result.summary)
|
|
295
|
-
LOG.info("Cost:\n")
|
|
296
|
-
LOG.info(result.cost)
|
|
297
|
-
|
|
298
|
-
|
|
299
255
|
add_cli_extras(app)
|
|
300
256
|
|
|
301
257
|
if __name__ == "__main__":
|
|
@@ -65,15 +65,13 @@ def _get_chroma_embedding_function_string(
|
|
|
65
65
|
to_import = ""
|
|
66
66
|
embedding_function_arg = ""
|
|
67
67
|
embedding_function_content = ""
|
|
68
|
-
vector_db_model = agent.retrieve_config.db_config.model
|
|
69
68
|
if not agent.retrieve_config.use_custom_embedding:
|
|
70
69
|
to_import = (
|
|
71
70
|
"from chromadb.utils.embedding_functions."
|
|
72
71
|
"sentence_transformer_embedding_function import "
|
|
73
72
|
"SentenceTransformerEmbeddingFunction"
|
|
74
73
|
)
|
|
75
|
-
embedding_function_arg = "
|
|
76
|
-
embedding_function_arg += f'model_name="{vector_db_model}")'
|
|
74
|
+
embedding_function_arg = f"{agent_name}_embedding_function"
|
|
77
75
|
else:
|
|
78
76
|
embedding_function_content, embedding_function_arg = (
|
|
79
77
|
agent.retrieve_config.get_custom_embedding_function(
|
|
@@ -124,21 +122,35 @@ def get_chroma_db_args(
|
|
|
124
122
|
# manually initializing the collection before running the flow,
|
|
125
123
|
# might be a workaround.
|
|
126
124
|
content_before = f"{agent_name}_client = {client_str}" + "\n"
|
|
125
|
+
vector_db_model = agent.retrieve_config.db_config.model
|
|
126
|
+
if not embedding_function_body:
|
|
127
|
+
content_before += (
|
|
128
|
+
f"{agent_name}_embedding_function = "
|
|
129
|
+
"SentenceTransformerEmbeddingFunction(\n"
|
|
130
|
+
f' model_name="{vector_db_model}",' + "\n"
|
|
131
|
+
")\n"
|
|
132
|
+
)
|
|
127
133
|
collection_name = agent.retrieve_config.collection_name
|
|
128
134
|
get_or_create = agent.retrieve_config.get_or_create
|
|
129
135
|
if collection_name:
|
|
130
136
|
if get_or_create:
|
|
131
137
|
content_before += (
|
|
132
|
-
f"{agent_name}_client.get_or_create_collection("
|
|
133
|
-
f'"{collection_name}"
|
|
138
|
+
f"{agent_name}_client.get_or_create_collection" + "(\n"
|
|
139
|
+
f' "{collection_name}",' + "\n"
|
|
140
|
+
f" embedding_function={embedding_function_arg}," + "\n"
|
|
141
|
+
")" + "\n"
|
|
134
142
|
)
|
|
135
143
|
else:
|
|
136
144
|
content_before += (
|
|
137
145
|
"try:\n"
|
|
138
|
-
f
|
|
139
|
-
+ "\n"
|
|
146
|
+
f" {agent_name}_client.get_collection(" + "\n"
|
|
147
|
+
f' "{collection_name}",' + "\n"
|
|
148
|
+
f" embedding_function={embedding_function_arg}," + "\n"
|
|
149
|
+
" )\n"
|
|
140
150
|
"except ValueError:\n"
|
|
141
|
-
f" {agent_name}_client.create_collection("
|
|
142
|
-
f'"{collection_name}"
|
|
151
|
+
f" {agent_name}_client.create_collection(" + "\n"
|
|
152
|
+
f' "{collection_name}",' + "\n"
|
|
153
|
+
f" embedding_function={embedding_function_arg}," + "\n"
|
|
154
|
+
" )\n"
|
|
143
155
|
)
|
|
144
156
|
return kwarg_string, to_import, embedding_function_body, content_before
|
waldiez/io/structured.py
CHANGED
|
@@ -36,9 +36,13 @@ class StructuredIOStream(IOStream):
|
|
|
36
36
|
uploads_root: Path | None = None
|
|
37
37
|
|
|
38
38
|
def __init__(
|
|
39
|
-
self,
|
|
39
|
+
self,
|
|
40
|
+
timeout: float = 120,
|
|
41
|
+
uploads_root: Path | str | None = None,
|
|
42
|
+
is_async: bool = False,
|
|
40
43
|
) -> None:
|
|
41
44
|
self.timeout = timeout
|
|
45
|
+
self.is_async = is_async
|
|
42
46
|
if uploads_root is not None:
|
|
43
47
|
self.uploads_root = Path(uploads_root).resolve()
|
|
44
48
|
if not self.uploads_root.exists():
|
|
@@ -106,6 +110,22 @@ class StructuredIOStream(IOStream):
|
|
|
106
110
|
uploads_root=self.uploads_root,
|
|
107
111
|
base_name=request_id,
|
|
108
112
|
)
|
|
113
|
+
# let's keep an eye here:
|
|
114
|
+
# https://github.com/ag2ai/ag2/blob/main/autogen/agentchat/conversable_agent.py#L2973
|
|
115
|
+
# reply = await iostream.input(prompt) ???? (await???)
|
|
116
|
+
if self.is_async:
|
|
117
|
+
# let's make a coroutine to just return the user response
|
|
118
|
+
async def async_input() -> str:
|
|
119
|
+
"""Asynchronous input method.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
str
|
|
124
|
+
The line read from the input stream.
|
|
125
|
+
"""
|
|
126
|
+
return user_response
|
|
127
|
+
|
|
128
|
+
return async_input() # type: ignore
|
|
109
129
|
return user_response
|
|
110
130
|
|
|
111
131
|
# noinspection PyMethodMayBeStatic
|
waldiez/runner.py
CHANGED
|
@@ -18,7 +18,6 @@ from pathlib import Path
|
|
|
18
18
|
from types import ModuleType, TracebackType
|
|
19
19
|
from typing import (
|
|
20
20
|
TYPE_CHECKING,
|
|
21
|
-
Callable,
|
|
22
21
|
Optional,
|
|
23
22
|
Set,
|
|
24
23
|
Type,
|
|
@@ -34,7 +33,6 @@ from .running import (
|
|
|
34
33
|
after_run,
|
|
35
34
|
before_run,
|
|
36
35
|
chdir,
|
|
37
|
-
get_printer,
|
|
38
36
|
install_requirements,
|
|
39
37
|
refresh_environment,
|
|
40
38
|
reset_env_vars,
|
|
@@ -166,25 +164,22 @@ class WaldiezRunner:
|
|
|
166
164
|
def install_requirements(self) -> None:
|
|
167
165
|
"""Install the requirements for the flow."""
|
|
168
166
|
self._called_install_requirements = True
|
|
169
|
-
printer = get_printer()
|
|
170
167
|
extra_requirements = self.gather_requirements()
|
|
171
168
|
if extra_requirements:
|
|
172
|
-
install_requirements(extra_requirements
|
|
169
|
+
install_requirements(extra_requirements)
|
|
173
170
|
|
|
174
171
|
async def a_install_requirements(self) -> None:
|
|
175
172
|
"""Install the requirements for the flow asynchronously."""
|
|
176
173
|
self._called_install_requirements = True
|
|
177
|
-
printer = get_printer()
|
|
178
174
|
extra_requirements = self.gather_requirements()
|
|
179
175
|
if extra_requirements:
|
|
180
|
-
await a_install_requirements(extra_requirements
|
|
176
|
+
await a_install_requirements(extra_requirements)
|
|
181
177
|
|
|
182
178
|
def _before_run(
|
|
183
179
|
self,
|
|
184
180
|
temp_dir: Path,
|
|
185
181
|
file_name: str,
|
|
186
182
|
module_name: str,
|
|
187
|
-
printer: Callable[..., None],
|
|
188
183
|
) -> tuple[ModuleType, dict[str, str]]:
|
|
189
184
|
self._exporter.export(Path(file_name))
|
|
190
185
|
# unique_names = self._exporter.context.get_unique_names()
|
|
@@ -197,8 +192,8 @@ class WaldiezRunner:
|
|
|
197
192
|
old_vars = set_env_vars(self.waldiez.get_flow_env_vars())
|
|
198
193
|
module = importlib.util.module_from_spec(spec)
|
|
199
194
|
spec.loader.exec_module(module)
|
|
200
|
-
|
|
201
|
-
|
|
195
|
+
print("<Waldiez> - Starting workflow...")
|
|
196
|
+
print(self.waldiez.info.model_dump_json())
|
|
202
197
|
return module, old_vars
|
|
203
198
|
|
|
204
199
|
def _run(
|
|
@@ -232,8 +227,7 @@ class WaldiezRunner:
|
|
|
232
227
|
if not self._called_install_requirements:
|
|
233
228
|
self.install_requirements()
|
|
234
229
|
refresh_environment()
|
|
235
|
-
|
|
236
|
-
printer(
|
|
230
|
+
print(
|
|
237
231
|
"Requirements installed.\n"
|
|
238
232
|
"NOTE: If new packages were added and you are using Jupyter, "
|
|
239
233
|
"you might need to restart the kernel."
|
|
@@ -246,7 +240,6 @@ class WaldiezRunner:
|
|
|
246
240
|
temp_dir=temp_dir,
|
|
247
241
|
file_name=file_name,
|
|
248
242
|
module_name=module_name,
|
|
249
|
-
printer=printer,
|
|
250
243
|
)
|
|
251
244
|
if use_structured_io:
|
|
252
245
|
stream = StructuredIOStream(
|
|
@@ -257,13 +250,12 @@ class WaldiezRunner:
|
|
|
257
250
|
results = module.main()
|
|
258
251
|
else:
|
|
259
252
|
results = module.main()
|
|
260
|
-
|
|
253
|
+
print("<Waldiez> - Workflow finished")
|
|
261
254
|
sys.path.pop(0)
|
|
262
255
|
reset_env_vars(old_vars)
|
|
263
256
|
after_run(
|
|
264
257
|
temp_dir=temp_dir,
|
|
265
258
|
output_path=output_path,
|
|
266
|
-
printer=printer,
|
|
267
259
|
flow_name=self.waldiez.name,
|
|
268
260
|
skip_mmd=skip_mmd,
|
|
269
261
|
)
|
|
@@ -285,8 +277,7 @@ class WaldiezRunner:
|
|
|
285
277
|
if not self._called_install_requirements:
|
|
286
278
|
await self.a_install_requirements()
|
|
287
279
|
refresh_environment()
|
|
288
|
-
|
|
289
|
-
printer(
|
|
280
|
+
print(
|
|
290
281
|
"Requirements installed.\n"
|
|
291
282
|
"NOTE: If new packages were added and you are using Jupyter, "
|
|
292
283
|
"you might need to restart the kernel."
|
|
@@ -299,7 +290,6 @@ class WaldiezRunner:
|
|
|
299
290
|
temp_dir=temp_dir,
|
|
300
291
|
file_name=file_name,
|
|
301
292
|
module_name=module_name,
|
|
302
|
-
printer=printer,
|
|
303
293
|
)
|
|
304
294
|
if use_structured_io:
|
|
305
295
|
stream = StructuredIOStream(
|
|
@@ -315,7 +305,6 @@ class WaldiezRunner:
|
|
|
315
305
|
after_run(
|
|
316
306
|
temp_dir=temp_dir,
|
|
317
307
|
output_path=output_path,
|
|
318
|
-
printer=printer,
|
|
319
308
|
flow_name=self.waldiez.name,
|
|
320
309
|
skip_mmd=skip_mmd,
|
|
321
310
|
)
|
waldiez/running/__init__.py
CHANGED
|
@@ -9,23 +9,29 @@ from .environment import (
|
|
|
9
9
|
reset_env_vars,
|
|
10
10
|
set_env_vars,
|
|
11
11
|
)
|
|
12
|
-
from .
|
|
13
|
-
|
|
12
|
+
from .post_run import after_run
|
|
13
|
+
from .pre_run import (
|
|
14
14
|
a_install_requirements,
|
|
15
|
-
after_run,
|
|
16
15
|
before_run,
|
|
17
|
-
chdir,
|
|
18
|
-
get_printer,
|
|
19
16
|
install_requirements,
|
|
20
17
|
)
|
|
18
|
+
from .util import (
|
|
19
|
+
a_chdir,
|
|
20
|
+
chdir,
|
|
21
|
+
create_async_subprocess,
|
|
22
|
+
create_sync_subprocess,
|
|
23
|
+
strip_ansi,
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
__all__ = [
|
|
23
27
|
"a_chdir",
|
|
24
28
|
"a_install_requirements",
|
|
25
29
|
"after_run",
|
|
26
30
|
"before_run",
|
|
31
|
+
"create_async_subprocess",
|
|
32
|
+
"create_sync_subprocess",
|
|
33
|
+
"strip_ansi",
|
|
27
34
|
"chdir",
|
|
28
|
-
"get_printer",
|
|
29
35
|
"in_virtualenv",
|
|
30
36
|
"is_root",
|
|
31
37
|
"install_requirements",
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Utilities for running code."""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
import shutil
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Optional, Union
|
|
9
|
+
|
|
10
|
+
from .gen_seq_diagram import generate_sequence_diagram
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def after_run(
|
|
14
|
+
temp_dir: Path,
|
|
15
|
+
output_path: Optional[Union[str, Path]],
|
|
16
|
+
flow_name: str,
|
|
17
|
+
skip_mmd: bool = False,
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Actions to perform after running the flow.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
temp_dir : Path
|
|
24
|
+
The temporary directory.
|
|
25
|
+
output_path : Optional[Union[str, Path]]
|
|
26
|
+
The output path.
|
|
27
|
+
flow_name : str
|
|
28
|
+
The flow name.
|
|
29
|
+
skip_mmd : bool, optional
|
|
30
|
+
Whether to skip the mermaid sequence diagram generation,
|
|
31
|
+
by default, False
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(output_path, str):
|
|
34
|
+
output_path = Path(output_path)
|
|
35
|
+
mmd_dir = output_path.parent if output_path else Path.cwd()
|
|
36
|
+
if skip_mmd is False:
|
|
37
|
+
events_csv_path = temp_dir / "logs" / "events.csv"
|
|
38
|
+
if events_csv_path.exists():
|
|
39
|
+
print("Generating mermaid sequence diagram...")
|
|
40
|
+
mmd_path = temp_dir / f"{flow_name}.mmd"
|
|
41
|
+
generate_sequence_diagram(events_csv_path, mmd_path)
|
|
42
|
+
if (
|
|
43
|
+
not output_path
|
|
44
|
+
and mmd_path.exists()
|
|
45
|
+
and mmd_path != mmd_dir / f"{flow_name}.mmd"
|
|
46
|
+
):
|
|
47
|
+
try:
|
|
48
|
+
shutil.copyfile(mmd_path, mmd_dir / f"{flow_name}.mmd")
|
|
49
|
+
except BaseException: # pylint: disable=broad-exception-caught
|
|
50
|
+
pass
|
|
51
|
+
if output_path:
|
|
52
|
+
destination_dir = output_path.parent
|
|
53
|
+
destination_dir = (
|
|
54
|
+
destination_dir
|
|
55
|
+
/ "waldiez_out"
|
|
56
|
+
/ datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
|
57
|
+
)
|
|
58
|
+
destination_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
# copy the contents of the temp dir to the destination dir
|
|
60
|
+
print(f"Copying the results to {destination_dir}")
|
|
61
|
+
copy_results(
|
|
62
|
+
temp_dir=temp_dir,
|
|
63
|
+
output_path=output_path,
|
|
64
|
+
output_dir=output_path.parent,
|
|
65
|
+
destination_dir=destination_dir,
|
|
66
|
+
)
|
|
67
|
+
shutil.rmtree(temp_dir)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def copy_results(
|
|
71
|
+
temp_dir: Path,
|
|
72
|
+
output_path: Path,
|
|
73
|
+
output_dir: Path,
|
|
74
|
+
destination_dir: Path,
|
|
75
|
+
) -> None:
|
|
76
|
+
"""Copy the results to the output directory.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
temp_dir : Path
|
|
81
|
+
The temporary directory.
|
|
82
|
+
output_path : Path
|
|
83
|
+
The output path.
|
|
84
|
+
output_dir : Path
|
|
85
|
+
The output directory.
|
|
86
|
+
destination_dir : Path
|
|
87
|
+
The destination directory.
|
|
88
|
+
"""
|
|
89
|
+
temp_dir.mkdir(parents=True, exist_ok=True)
|
|
90
|
+
for item in temp_dir.iterdir():
|
|
91
|
+
# skip cache files
|
|
92
|
+
if (
|
|
93
|
+
item.name.startswith("__pycache__")
|
|
94
|
+
or item.name.endswith(".pyc")
|
|
95
|
+
or item.name.endswith(".pyo")
|
|
96
|
+
or item.name.endswith(".pyd")
|
|
97
|
+
or item.name == ".cache"
|
|
98
|
+
):
|
|
99
|
+
continue
|
|
100
|
+
if item.is_file():
|
|
101
|
+
# let's also copy the "tree of thoughts" image
|
|
102
|
+
# to the output directory
|
|
103
|
+
if item.name.endswith("tree_of_thoughts.png") or item.name.endswith(
|
|
104
|
+
"reasoning_tree.json"
|
|
105
|
+
):
|
|
106
|
+
shutil.copy(item, output_dir / item.name)
|
|
107
|
+
shutil.copy(item, destination_dir)
|
|
108
|
+
else:
|
|
109
|
+
shutil.copytree(item, destination_dir / item.name)
|
|
110
|
+
if output_path.is_file():
|
|
111
|
+
if output_path.suffix == ".waldiez":
|
|
112
|
+
output_path = output_path.with_suffix(".py")
|
|
113
|
+
if output_path.suffix == ".py":
|
|
114
|
+
src = temp_dir / output_path.name
|
|
115
|
+
if src.exists():
|
|
116
|
+
dst = destination_dir / output_path.name
|
|
117
|
+
if dst.exists():
|
|
118
|
+
dst.unlink()
|
|
119
|
+
shutil.copyfile(src, output_dir / output_path.name)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Actions to perform before running the flow."""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import io
|
|
7
|
+
import os
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Callable, Optional, Union
|
|
13
|
+
|
|
14
|
+
from .environment import in_virtualenv, is_root
|
|
15
|
+
from .util import strip_ansi
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def before_run(
|
|
19
|
+
output_path: Optional[Union[str, Path]],
|
|
20
|
+
uploads_root: Optional[Union[str, Path]],
|
|
21
|
+
) -> str:
|
|
22
|
+
"""Actions to perform before running the flow.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
output_path : Optional[Union[str, Path]]
|
|
27
|
+
The output path.
|
|
28
|
+
uploads_root : Optional[Union[str, Path]]
|
|
29
|
+
The runtime uploads root.
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
str
|
|
34
|
+
The file name.
|
|
35
|
+
"""
|
|
36
|
+
if not uploads_root:
|
|
37
|
+
uploads_root = Path(tempfile.mkdtemp())
|
|
38
|
+
else:
|
|
39
|
+
uploads_root = Path(uploads_root)
|
|
40
|
+
if not uploads_root.exists():
|
|
41
|
+
uploads_root.mkdir(parents=True)
|
|
42
|
+
output_dir = Path.cwd()
|
|
43
|
+
if output_path and isinstance(output_path, str):
|
|
44
|
+
output_path = Path(output_path)
|
|
45
|
+
if output_path:
|
|
46
|
+
if output_path.is_dir():
|
|
47
|
+
output_dir = output_path
|
|
48
|
+
else:
|
|
49
|
+
output_dir = output_path.parent if output_path else Path.cwd()
|
|
50
|
+
if not output_dir.exists():
|
|
51
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
file_name = Path(output_path).name if output_path else "waldiez_flow.py"
|
|
53
|
+
if file_name.endswith((".json", ".waldiez")):
|
|
54
|
+
file_name = file_name.replace(".json", ".py").replace(".waldiez", ".py")
|
|
55
|
+
if not file_name.endswith(".py"):
|
|
56
|
+
file_name += ".py"
|
|
57
|
+
return file_name
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def install_requirements(
|
|
61
|
+
extra_requirements: set[str],
|
|
62
|
+
printer: Callable[..., None] = print,
|
|
63
|
+
) -> None:
|
|
64
|
+
"""Install the requirements.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
extra_requirements : set[str]
|
|
69
|
+
The extra requirements.
|
|
70
|
+
printer : Callable[..., None]
|
|
71
|
+
The printer function to use, defaults to print.
|
|
72
|
+
"""
|
|
73
|
+
requirements_string = ", ".join(extra_requirements)
|
|
74
|
+
printer(f"Installing requirements: {requirements_string}")
|
|
75
|
+
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
76
|
+
break_system_packages = ""
|
|
77
|
+
if not in_virtualenv(): # it should
|
|
78
|
+
# if not, let's try to install as user
|
|
79
|
+
# not sure if --break-system-packages is safe,
|
|
80
|
+
# but it might fail if we don't
|
|
81
|
+
break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
|
|
82
|
+
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
|
|
83
|
+
if not is_root():
|
|
84
|
+
pip_install.append("--user")
|
|
85
|
+
pip_install.extend(extra_requirements)
|
|
86
|
+
# pylint: disable=too-many-try-statements
|
|
87
|
+
try:
|
|
88
|
+
with subprocess.Popen(
|
|
89
|
+
pip_install,
|
|
90
|
+
stdout=subprocess.PIPE,
|
|
91
|
+
stderr=subprocess.PIPE,
|
|
92
|
+
) as proc:
|
|
93
|
+
if proc.stdout:
|
|
94
|
+
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
|
95
|
+
printer(strip_ansi(line.strip()))
|
|
96
|
+
if proc.stderr:
|
|
97
|
+
for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
|
|
98
|
+
printer(strip_ansi(line.strip()))
|
|
99
|
+
finally:
|
|
100
|
+
if not in_virtualenv():
|
|
101
|
+
# restore the old env var
|
|
102
|
+
if break_system_packages:
|
|
103
|
+
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
|
|
104
|
+
else:
|
|
105
|
+
del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def a_install_requirements(
|
|
109
|
+
extra_requirements: set[str],
|
|
110
|
+
printer: Callable[..., None] = print,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Install the requirements asynchronously.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
extra_requirements : set[str]
|
|
117
|
+
The extra requirements.
|
|
118
|
+
printer : Callable[..., None]
|
|
119
|
+
The printer function to use, defaults to print.
|
|
120
|
+
"""
|
|
121
|
+
requirements_string = ", ".join(extra_requirements)
|
|
122
|
+
printer(f"Installing requirements: {requirements_string}")
|
|
123
|
+
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
124
|
+
break_system_packages = ""
|
|
125
|
+
if not in_virtualenv():
|
|
126
|
+
break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
|
|
127
|
+
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
|
|
128
|
+
if not is_root():
|
|
129
|
+
pip_install.extend(["--user"])
|
|
130
|
+
pip_install.extend(extra_requirements)
|
|
131
|
+
# pylint: disable=too-many-try-statements
|
|
132
|
+
try:
|
|
133
|
+
proc = await asyncio.create_subprocess_exec(
|
|
134
|
+
*pip_install,
|
|
135
|
+
stdout=asyncio.subprocess.PIPE,
|
|
136
|
+
stderr=asyncio.subprocess.PIPE,
|
|
137
|
+
)
|
|
138
|
+
if proc.stdout:
|
|
139
|
+
async for line in proc.stdout:
|
|
140
|
+
printer(strip_ansi(line.decode().strip()))
|
|
141
|
+
if proc.stderr:
|
|
142
|
+
async for line in proc.stderr:
|
|
143
|
+
printer(strip_ansi(line.decode().strip()))
|
|
144
|
+
finally:
|
|
145
|
+
if not in_virtualenv():
|
|
146
|
+
if break_system_packages:
|
|
147
|
+
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
|
|
148
|
+
else:
|
|
149
|
+
del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
|
waldiez/running/util.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Common utilities for the waldiez runner."""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from asyncio.subprocess import Process
|
|
11
|
+
from contextlib import asynccontextmanager, contextmanager
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import AsyncIterator, Iterator, Union
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ProcessSetup:
|
|
19
|
+
"""Container for subprocess setup data."""
|
|
20
|
+
|
|
21
|
+
temp_dir: Path
|
|
22
|
+
file_path: Path
|
|
23
|
+
old_vars: dict[str, str]
|
|
24
|
+
skip_mmd: bool
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@contextmanager
|
|
28
|
+
def chdir(to: Union[str, Path]) -> Iterator[None]:
|
|
29
|
+
"""Change the current working directory in a context.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
to : Union[str, Path]
|
|
34
|
+
The directory to change to.
|
|
35
|
+
|
|
36
|
+
Yields
|
|
37
|
+
------
|
|
38
|
+
Iterator[None]
|
|
39
|
+
The context manager.
|
|
40
|
+
"""
|
|
41
|
+
old_cwd = str(os.getcwd())
|
|
42
|
+
os.chdir(to)
|
|
43
|
+
try:
|
|
44
|
+
yield
|
|
45
|
+
finally:
|
|
46
|
+
os.chdir(old_cwd)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@asynccontextmanager
|
|
50
|
+
async def a_chdir(to: Union[str, Path]) -> AsyncIterator[None]:
|
|
51
|
+
"""Asynchronously change the current working directory in a context.
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
to : Union[str, Path]
|
|
56
|
+
The directory to change to.
|
|
57
|
+
|
|
58
|
+
Yields
|
|
59
|
+
------
|
|
60
|
+
AsyncIterator[None]
|
|
61
|
+
The async context manager.
|
|
62
|
+
"""
|
|
63
|
+
old_cwd = str(os.getcwd())
|
|
64
|
+
os.chdir(to)
|
|
65
|
+
try:
|
|
66
|
+
yield
|
|
67
|
+
finally:
|
|
68
|
+
os.chdir(old_cwd)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def strip_ansi(text: str) -> str:
|
|
72
|
+
"""Remove ANSI escape sequences from text.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
text : str
|
|
77
|
+
The text to strip.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
str
|
|
82
|
+
The text without ANSI escape sequences.
|
|
83
|
+
"""
|
|
84
|
+
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m|\x1b\[.*?[@-~]")
|
|
85
|
+
return ansi_pattern.sub("", text)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def create_sync_subprocess(setup: ProcessSetup) -> subprocess.Popen[bytes]:
|
|
89
|
+
"""Create a synchronous subprocess.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
setup : ProcessSetup
|
|
94
|
+
The setup data for the subprocess.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
subprocess.Popen[bytes]
|
|
99
|
+
The created subprocess.
|
|
100
|
+
"""
|
|
101
|
+
return subprocess.Popen(
|
|
102
|
+
[sys.executable, "-u", str(setup.file_path)],
|
|
103
|
+
stdout=subprocess.PIPE,
|
|
104
|
+
stderr=subprocess.PIPE,
|
|
105
|
+
stdin=subprocess.PIPE,
|
|
106
|
+
# text=True,
|
|
107
|
+
# bufsize=1, # Line buffered for real-time output
|
|
108
|
+
# universal_newlines=True,
|
|
109
|
+
env={**os.environ},
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
async def create_async_subprocess(setup: ProcessSetup) -> Process:
|
|
114
|
+
"""Create an asynchronous subprocess.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
setup : ProcessSetup
|
|
119
|
+
The setup data for the subprocess.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
Process
|
|
124
|
+
The created asynchronous subprocess.
|
|
125
|
+
"""
|
|
126
|
+
return await asyncio.create_subprocess_exec(
|
|
127
|
+
sys.executable,
|
|
128
|
+
"-u",
|
|
129
|
+
str(setup.file_path),
|
|
130
|
+
# stdout=asyncio.subprocess.PIPE,
|
|
131
|
+
# stderr=asyncio.subprocess.PIPE,
|
|
132
|
+
# stdin=asyncio.subprocess.PIPE,
|
|
133
|
+
env={**os.environ},
|
|
134
|
+
)
|
waldiez/utils/__init__.py
CHANGED
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
from .cli_extras import add_cli_extras
|
|
6
6
|
from .conflict_checker import check_conflicts
|
|
7
7
|
from .flaml_warnings import check_flaml_warnings
|
|
8
|
+
from .version import get_waldiez_version
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
10
11
|
"check_conflicts",
|
|
11
12
|
"check_flaml_warnings",
|
|
12
13
|
"add_cli_extras",
|
|
14
|
+
"get_waldiez_version",
|
|
13
15
|
]
|
waldiez/utils/version.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
+
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
+
"""Try to get the Waldiez version."""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_waldiez_version_from_package_json() -> str | None:
|
|
10
|
+
"""Get the Waldiez version from package.json."""
|
|
11
|
+
package_json_path = Path(__file__).parent.parent.parent / "package.json"
|
|
12
|
+
if package_json_path.exists():
|
|
13
|
+
with open(package_json_path, "r", encoding="utf-8") as f:
|
|
14
|
+
package_data = json.load(f)
|
|
15
|
+
return package_data.get("version", None)
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _get_waldiez_version_from_version_py() -> str | None:
|
|
20
|
+
"""Get the Waldiez version from _version.py."""
|
|
21
|
+
version_py_path = Path(__file__).parent.parent / "_version.py"
|
|
22
|
+
if version_py_path.exists():
|
|
23
|
+
with open(version_py_path, "r", encoding="utf-8") as f:
|
|
24
|
+
for line in f:
|
|
25
|
+
if line.startswith("__version__"):
|
|
26
|
+
return line.split('"')[1]
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_waldiez_version() -> str:
|
|
31
|
+
"""Get the Waldiez version.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
str
|
|
36
|
+
The Waldiez version, or "dev" if not found.
|
|
37
|
+
"""
|
|
38
|
+
w_version = _get_waldiez_version_from_package_json()
|
|
39
|
+
if not w_version:
|
|
40
|
+
w_version = _get_waldiez_version_from_version_py()
|
|
41
|
+
if not w_version:
|
|
42
|
+
w_version = "dev"
|
|
43
|
+
return w_version
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
print(get_waldiez_version())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: waldiez
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.9
|
|
4
4
|
Dynamic: Keywords
|
|
5
5
|
Summary: Make AG2 Agents Collaborate: Drag, Drop, and Orchestrate with Waldiez.
|
|
6
6
|
Project-URL: Homepage, https://waldiez.io
|
|
@@ -157,15 +157,15 @@ Requires-Dist: natsort==8.4.0; extra == 'docs'
|
|
|
157
157
|
Provides-Extra: jupyter
|
|
158
158
|
Requires-Dist: jupyter-server==2.16.0; extra == 'jupyter'
|
|
159
159
|
Requires-Dist: jupyterlab<5.0,>=4.3.0; extra == 'jupyter'
|
|
160
|
-
Requires-Dist: waldiez-jupyter==0.4.
|
|
160
|
+
Requires-Dist: waldiez-jupyter==0.4.9; extra == 'jupyter'
|
|
161
161
|
Provides-Extra: mqtt
|
|
162
162
|
Requires-Dist: paho-mqtt<3.0,>=2.1.0; extra == 'mqtt'
|
|
163
163
|
Provides-Extra: redis
|
|
164
164
|
Requires-Dist: ag2[redis]==0.9.2; extra == 'redis'
|
|
165
165
|
Provides-Extra: runner
|
|
166
|
-
Requires-Dist: waldiez-runner==0.4.
|
|
166
|
+
Requires-Dist: waldiez-runner==0.4.9; (python_version >= '3.11') and extra == 'runner'
|
|
167
167
|
Provides-Extra: studio
|
|
168
|
-
Requires-Dist: waldiez-studio==0.4.
|
|
168
|
+
Requires-Dist: waldiez-studio==0.4.9; extra == 'studio'
|
|
169
169
|
Provides-Extra: test
|
|
170
170
|
Requires-Dist: ag2[redis]==0.9.2; extra == 'test'
|
|
171
171
|
Requires-Dist: ag2[websockets]==0.9.2; extra == 'test'
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
waldiez/__init__.py,sha256=JVVh6d5Zw3ch4GYtIwXZEBpMEyJZAc5t0mtu08tLbZs,992
|
|
2
2
|
waldiez/__main__.py,sha256=0dYzNrQbovRwQQvmZC6_1FDR1m71SUIOkTleO5tBnBw,203
|
|
3
|
-
waldiez/_version.py,sha256=
|
|
4
|
-
waldiez/cli.py,sha256=
|
|
3
|
+
waldiez/_version.py,sha256=De8aF7saKAU1lagF5W1Ha6s0ndjgEGVM1xVTicmFN_8,249
|
|
4
|
+
waldiez/cli.py,sha256=FuWHXi1NWNhuXyUHVEvSnS0450Hh0LPekfsZurML2us,7427
|
|
5
5
|
waldiez/exporter.py,sha256=Gl23KC-pF2986gnHLqGf1-7RAPfvbf2sz4VX236gXO8,6134
|
|
6
6
|
waldiez/logger.py,sha256=UFdPwS2AOl2LkFQVonDSET9Dguq5jsn2mV817iTZFJc,16375
|
|
7
7
|
waldiez/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
waldiez/runner.py,sha256=
|
|
8
|
+
waldiez/runner.py,sha256=E-e5_QPFYWvWgcY7FwOz5lso2toV1enDD2pnP_Ej1fE,13526
|
|
9
9
|
waldiez/exporting/__init__.py,sha256=xVOqb3gADkrTmp_BVrQ-dMPiySPUDU4xZmqYqhzL8BI,1026
|
|
10
10
|
waldiez/exporting/agent/__init__.py,sha256=GpNfVQLAvGoJP_U4WkMMIGpEB8k7vEV-FVR446s2zhY,260
|
|
11
11
|
waldiez/exporting/agent/code_execution.py,sha256=sxjulr2OmeSg0SrYz7rgpBgF_AfqpHfV86kmtGU49Yk,3795
|
|
@@ -28,7 +28,7 @@ waldiez/exporting/agent/extras/handoffs/condition.py,sha256=kURtSLS5B0WbXPARff3t
|
|
|
28
28
|
waldiez/exporting/agent/extras/handoffs/handoff.py,sha256=Xp0sYpXIoXQ6GbLrLPxylDpyNPiE2w1oXmQ-UqfnK7U,5918
|
|
29
29
|
waldiez/exporting/agent/extras/handoffs/target.py,sha256=R7KerfkL1kXkGMnoy1GXaOTH6DM6LSKXl7ohpTcInCE,6527
|
|
30
30
|
waldiez/exporting/agent/extras/rag/__init__.py,sha256=jkKSaHLfwA8Tj7QJH0MSdAphaP4HowuhQXDj7V122Ek,259
|
|
31
|
-
waldiez/exporting/agent/extras/rag/chroma_extras.py,sha256=
|
|
31
|
+
waldiez/exporting/agent/extras/rag/chroma_extras.py,sha256=vf4EuikCZPtqFEOCoB01YcD85Hi_SA37b1JO869DqSA,5555
|
|
32
32
|
waldiez/exporting/agent/extras/rag/mongo_extras.py,sha256=bn_5bfmyfdW5eQCOjcCRYPKLIJ7vZXKEiUsa4zPx7Sk,2822
|
|
33
33
|
waldiez/exporting/agent/extras/rag/pgvector_extras.py,sha256=Y08rU8Z3-oHUbh7huO1Jo_PZLlOW-NRa1Gz3-d9WXso,2961
|
|
34
34
|
waldiez/exporting/agent/extras/rag/qdrant_extras.py,sha256=hTzY7GUL8RBMFNEGefLDAxKFMSlD5Qmkzm3Ducgp9vU,3633
|
|
@@ -97,7 +97,7 @@ waldiez/io/__init__.py,sha256=x4-LxBgHd0ekLXyccgcgV8ERwKRENaJQxaegULkRW3g,3361
|
|
|
97
97
|
waldiez/io/_ws.py,sha256=uyuIfCrBK7LDXowTQ2fsbP4jvjUcIQZqPQefx2UXmp8,5652
|
|
98
98
|
waldiez/io/mqtt.py,sha256=T01XCGyoWYdIEhzxS5M9igbYLgZqhF-K63j3JQDmj5E,22418
|
|
99
99
|
waldiez/io/redis.py,sha256=diz0UqgcpIejBGFb9TOoT2iVzGtHWFnhg0cfEOox25Q,25523
|
|
100
|
-
waldiez/io/structured.py,sha256=
|
|
100
|
+
waldiez/io/structured.py,sha256=ZFmiaX-OOIX86SDMg3h0Gw1OwmrNgi7PgIKu9V1gUrk,14409
|
|
101
101
|
waldiez/io/utils.py,sha256=J2I0cuBMMjJadM8OjP7kiqFjoZp8hc9rXF9n5fdltEE,4488
|
|
102
102
|
waldiez/io/ws.py,sha256=aiORAYjvSA57ZqI1mXINkkHnZzqkibaICTj2bZ9Yze8,9107
|
|
103
103
|
waldiez/io/models/__init__.py,sha256=N21ET1_QEkCsJNrax8y5cDDiTrGj2rv9BfEsVvUY1m0,1240
|
|
@@ -181,20 +181,23 @@ waldiez/models/tool/extra_requirements.py,sha256=kNrmWxS96FhO93NV3B5Hr5wAJrjuUWb
|
|
|
181
181
|
waldiez/models/tool/tool.py,sha256=Mzst4x9tS-1exryTYZSAlr6B3E7ba7Q5yF9WLxXp5G8,8987
|
|
182
182
|
waldiez/models/tool/tool_data.py,sha256=lOtIetRM35tUvDCtjiHjddVSoqlwV4NFkz_496GLunA,1305
|
|
183
183
|
waldiez/models/tool/tool_type.py,sha256=VYcgnAlj1n6ZqXA8D0VdbRfZ-_U89CPSDuNgk822_UA,268
|
|
184
|
-
waldiez/running/__init__.py,sha256=
|
|
184
|
+
waldiez/running/__init__.py,sha256=Q_lhpEdJ2HoXOAISQYdCesUYMctGqq59AdYsa3Gr1yI,817
|
|
185
185
|
waldiez/running/environment.py,sha256=DxiI9GqFrFiF6p5icrpCFkbsvq6zgACoqXYyHZniffQ,3472
|
|
186
186
|
waldiez/running/gen_seq_diagram.py,sha256=wsF9b9uG0NA5iVAlW-wOtYn0w_9-bySBO9nWkUIBNUc,5943
|
|
187
|
-
waldiez/running/
|
|
188
|
-
waldiez/
|
|
187
|
+
waldiez/running/post_run.py,sha256=rxVmRndpKnoJs2uZrk0JDNrrFNihoU52rExyRxgJe0k,3891
|
|
188
|
+
waldiez/running/pre_run.py,sha256=lM5l6lLLgqlKpWS3o2Gbe_VhDvVJ6xgJZsbL8rYKJpY,5019
|
|
189
|
+
waldiez/running/util.py,sha256=7DnuL-FNkraDhu3QUV3GEZC_dNgo3IMlptBzG9tMUKA,3002
|
|
190
|
+
waldiez/utils/__init__.py,sha256=lamPdfOEeOZ9iYtDXKXEyOL2RhjZ7wpyK2W5SmVxPNc,413
|
|
189
191
|
waldiez/utils/conflict_checker.py,sha256=bskxC2KmPrAOjjYfgQhGXgNxdU5Z10ZZmx-_c0W8I7I,1493
|
|
190
192
|
waldiez/utils/flaml_warnings.py,sha256=gN1yzlAAHor04w0-_xXUK0wID6aXCizKYElaNHflkg8,630
|
|
193
|
+
waldiez/utils/version.py,sha256=pYu3CwBW5Rwv9LqWG8W5DxrvdIU1nc2MOY1RDJR8oc4,1417
|
|
191
194
|
waldiez/utils/cli_extras/__init__.py,sha256=ZvuLaN3IGuffWMh7mladTGkJxx3kn5IepUF3jk4ZAWY,684
|
|
192
195
|
waldiez/utils/cli_extras/jupyter.py,sha256=nOQraO7Xg1G8SCP93OpIVheXieXW5ireSC9Oir-dXzA,3047
|
|
193
196
|
waldiez/utils/cli_extras/runner.py,sha256=V_aoTKZsvtPgjszvWlPamKjnOG93L2aY6sBcHnIh9XI,983
|
|
194
197
|
waldiez/utils/cli_extras/studio.py,sha256=p4CMDCYW6lxrPvHvWX2kpsE1Ix7NnKZg1Jf15weWirE,984
|
|
195
|
-
waldiez-0.4.
|
|
196
|
-
waldiez-0.4.
|
|
197
|
-
waldiez-0.4.
|
|
198
|
-
waldiez-0.4.
|
|
199
|
-
waldiez-0.4.
|
|
200
|
-
waldiez-0.4.
|
|
198
|
+
waldiez-0.4.9.dist-info/METADATA,sha256=FefkfD_VJwlzOf2tuWvcPpjYvBsQ8AYlw9sOgPmzh9Y,22620
|
|
199
|
+
waldiez-0.4.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
200
|
+
waldiez-0.4.9.dist-info/entry_points.txt,sha256=9MQ8Y1rD19CU7UwjNPwoyTRpQsPs2QimjrtwTD0bD6k,44
|
|
201
|
+
waldiez-0.4.9.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
202
|
+
waldiez-0.4.9.dist-info/licenses/NOTICE.md,sha256=L7xtckFRYvYJjhjQNtFpURWCiAvEuq4ePvxJsC-XAdk,785
|
|
203
|
+
waldiez-0.4.9.dist-info/RECORD,,
|
waldiez/running/running.py
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0.
|
|
2
|
-
# Copyright (c) 2024 - 2025 Waldiez and contributors.
|
|
3
|
-
"""Utilities for running code."""
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
import datetime
|
|
7
|
-
import io
|
|
8
|
-
import os
|
|
9
|
-
import re
|
|
10
|
-
import shutil
|
|
11
|
-
import subprocess
|
|
12
|
-
import sys
|
|
13
|
-
import tempfile
|
|
14
|
-
from contextlib import asynccontextmanager, contextmanager
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import (
|
|
17
|
-
Any,
|
|
18
|
-
AsyncIterator,
|
|
19
|
-
Callable,
|
|
20
|
-
Iterator,
|
|
21
|
-
Optional,
|
|
22
|
-
Set,
|
|
23
|
-
Union,
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
from .environment import in_virtualenv, is_root
|
|
27
|
-
from .gen_seq_diagram import generate_sequence_diagram
|
|
28
|
-
|
|
29
|
-
# pylint: disable=import-outside-toplevel
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@contextmanager
|
|
33
|
-
def chdir(to: Union[str, Path]) -> Iterator[None]:
|
|
34
|
-
"""Change the current working directory in a context.
|
|
35
|
-
|
|
36
|
-
Parameters
|
|
37
|
-
----------
|
|
38
|
-
to : Union[str, Path]
|
|
39
|
-
The directory to change to.
|
|
40
|
-
|
|
41
|
-
Yields
|
|
42
|
-
------
|
|
43
|
-
Iterator[None]
|
|
44
|
-
The context manager.
|
|
45
|
-
"""
|
|
46
|
-
old_cwd = str(os.getcwd())
|
|
47
|
-
os.chdir(to)
|
|
48
|
-
try:
|
|
49
|
-
yield
|
|
50
|
-
finally:
|
|
51
|
-
os.chdir(old_cwd)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
@asynccontextmanager
|
|
55
|
-
async def a_chdir(to: Union[str, Path]) -> AsyncIterator[None]:
|
|
56
|
-
"""Asynchronously change the current working directory in a context.
|
|
57
|
-
|
|
58
|
-
Parameters
|
|
59
|
-
----------
|
|
60
|
-
to : Union[str, Path]
|
|
61
|
-
The directory to change to.
|
|
62
|
-
|
|
63
|
-
Yields
|
|
64
|
-
------
|
|
65
|
-
AsyncIterator[None]
|
|
66
|
-
The async context manager.
|
|
67
|
-
"""
|
|
68
|
-
old_cwd = str(os.getcwd())
|
|
69
|
-
os.chdir(to)
|
|
70
|
-
try:
|
|
71
|
-
yield
|
|
72
|
-
finally:
|
|
73
|
-
os.chdir(old_cwd)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def strip_ansi(text: str) -> str:
|
|
77
|
-
"""Remove ANSI escape sequences from text.
|
|
78
|
-
|
|
79
|
-
Parameters
|
|
80
|
-
----------
|
|
81
|
-
text : str
|
|
82
|
-
The text to strip.
|
|
83
|
-
|
|
84
|
-
Returns
|
|
85
|
-
-------
|
|
86
|
-
str
|
|
87
|
-
The text without ANSI escape sequences.
|
|
88
|
-
"""
|
|
89
|
-
ansi_pattern = re.compile(r"\x1b\[[0-9;]*m|\x1b\[.*?[@-~]")
|
|
90
|
-
return ansi_pattern.sub("", text)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def before_run(
|
|
94
|
-
output_path: Optional[Union[str, Path]],
|
|
95
|
-
uploads_root: Optional[Union[str, Path]],
|
|
96
|
-
) -> str:
|
|
97
|
-
"""Actions to perform before running the flow.
|
|
98
|
-
|
|
99
|
-
Parameters
|
|
100
|
-
----------
|
|
101
|
-
output_path : Optional[Union[str, Path]]
|
|
102
|
-
The output path.
|
|
103
|
-
uploads_root : Optional[Union[str, Path]]
|
|
104
|
-
The runtime uploads root.
|
|
105
|
-
|
|
106
|
-
Returns
|
|
107
|
-
-------
|
|
108
|
-
str
|
|
109
|
-
The file name.
|
|
110
|
-
"""
|
|
111
|
-
if not uploads_root:
|
|
112
|
-
uploads_root = Path(tempfile.mkdtemp())
|
|
113
|
-
else:
|
|
114
|
-
uploads_root = Path(uploads_root)
|
|
115
|
-
if not uploads_root.exists():
|
|
116
|
-
uploads_root.mkdir(parents=True)
|
|
117
|
-
file_name = "waldiez_flow.py" if not output_path else Path(output_path).name
|
|
118
|
-
if file_name.endswith((".json", ".waldiez")):
|
|
119
|
-
file_name = file_name.replace(".json", ".py").replace(".waldiez", ".py")
|
|
120
|
-
if not file_name.endswith(".py"):
|
|
121
|
-
file_name += ".py"
|
|
122
|
-
return file_name
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def install_requirements(
|
|
126
|
-
extra_requirements: Set[str], printer: Callable[..., None]
|
|
127
|
-
) -> None:
|
|
128
|
-
"""Install the requirements.
|
|
129
|
-
|
|
130
|
-
Parameters
|
|
131
|
-
----------
|
|
132
|
-
extra_requirements : Set[str]
|
|
133
|
-
The extra requirements.
|
|
134
|
-
printer : Callable[..., None]
|
|
135
|
-
The printer function.
|
|
136
|
-
"""
|
|
137
|
-
requirements_string = ", ".join(extra_requirements)
|
|
138
|
-
printer(f"Installing requirements: {requirements_string}")
|
|
139
|
-
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
140
|
-
break_system_packages = ""
|
|
141
|
-
if not in_virtualenv(): # it should
|
|
142
|
-
# if not, let's try to install as user
|
|
143
|
-
# not sure if --break-system-packages is safe,
|
|
144
|
-
# but it might fail if we don't
|
|
145
|
-
break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
|
|
146
|
-
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
|
|
147
|
-
if not is_root():
|
|
148
|
-
pip_install.append("--user")
|
|
149
|
-
pip_install.extend(extra_requirements)
|
|
150
|
-
# pylint: disable=too-many-try-statements
|
|
151
|
-
try:
|
|
152
|
-
with subprocess.Popen(
|
|
153
|
-
pip_install,
|
|
154
|
-
stdout=subprocess.PIPE,
|
|
155
|
-
stderr=subprocess.PIPE,
|
|
156
|
-
) as proc:
|
|
157
|
-
if proc.stdout:
|
|
158
|
-
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
|
|
159
|
-
printer(strip_ansi(line.strip()))
|
|
160
|
-
if proc.stderr:
|
|
161
|
-
for line in io.TextIOWrapper(proc.stderr, encoding="utf-8"):
|
|
162
|
-
printer(strip_ansi(line.strip()))
|
|
163
|
-
finally:
|
|
164
|
-
if not in_virtualenv():
|
|
165
|
-
# restore the old env var
|
|
166
|
-
if break_system_packages:
|
|
167
|
-
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
|
|
168
|
-
else:
|
|
169
|
-
del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
async def a_install_requirements(
|
|
173
|
-
extra_requirements: Set[str], printer: Callable[..., None]
|
|
174
|
-
) -> None:
|
|
175
|
-
"""Install the requirements asynchronously.
|
|
176
|
-
|
|
177
|
-
Parameters
|
|
178
|
-
----------
|
|
179
|
-
extra_requirements : Set[str]
|
|
180
|
-
The extra requirements.
|
|
181
|
-
printer : Callable[..., None]
|
|
182
|
-
The printer function.
|
|
183
|
-
"""
|
|
184
|
-
requirements_string = ", ".join(extra_requirements)
|
|
185
|
-
printer(f"Installing requirements: {requirements_string}")
|
|
186
|
-
pip_install = [sys.executable, "-m", "pip", "install"]
|
|
187
|
-
break_system_packages = ""
|
|
188
|
-
if not in_virtualenv():
|
|
189
|
-
break_system_packages = os.environ.get("PIP_BREAK_SYSTEM_PACKAGES", "")
|
|
190
|
-
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = "1"
|
|
191
|
-
if not is_root():
|
|
192
|
-
pip_install.extend(["--user"])
|
|
193
|
-
pip_install.extend(extra_requirements)
|
|
194
|
-
# pylint: disable=too-many-try-statements
|
|
195
|
-
try:
|
|
196
|
-
proc = await asyncio.create_subprocess_exec(
|
|
197
|
-
*pip_install,
|
|
198
|
-
stdout=asyncio.subprocess.PIPE,
|
|
199
|
-
stderr=asyncio.subprocess.PIPE,
|
|
200
|
-
)
|
|
201
|
-
if proc.stdout:
|
|
202
|
-
async for line in proc.stdout:
|
|
203
|
-
printer(strip_ansi(line.decode().strip()))
|
|
204
|
-
if proc.stderr:
|
|
205
|
-
async for line in proc.stderr:
|
|
206
|
-
printer(strip_ansi(line.decode().strip()))
|
|
207
|
-
finally:
|
|
208
|
-
if not in_virtualenv():
|
|
209
|
-
if break_system_packages:
|
|
210
|
-
os.environ["PIP_BREAK_SYSTEM_PACKAGES"] = break_system_packages
|
|
211
|
-
else:
|
|
212
|
-
del os.environ["PIP_BREAK_SYSTEM_PACKAGES"]
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def after_run(
|
|
216
|
-
temp_dir: Path,
|
|
217
|
-
output_path: Optional[Union[str, Path]],
|
|
218
|
-
printer: Callable[..., None],
|
|
219
|
-
flow_name: str,
|
|
220
|
-
skip_mmd: bool = False,
|
|
221
|
-
) -> None:
|
|
222
|
-
"""Actions to perform after running the flow.
|
|
223
|
-
|
|
224
|
-
Parameters
|
|
225
|
-
----------
|
|
226
|
-
temp_dir : Path
|
|
227
|
-
The temporary directory.
|
|
228
|
-
output_path : Optional[Union[str, Path]]
|
|
229
|
-
The output path.
|
|
230
|
-
printer : Callable[..., None]
|
|
231
|
-
The printer function.
|
|
232
|
-
flow_name : str
|
|
233
|
-
The flow name.
|
|
234
|
-
skip_mmd : bool, optional
|
|
235
|
-
Whether to skip the mermaid sequence diagram generation,
|
|
236
|
-
by default, False
|
|
237
|
-
"""
|
|
238
|
-
if isinstance(output_path, str):
|
|
239
|
-
output_path = Path(output_path)
|
|
240
|
-
output_dir = output_path.parent if output_path else Path.cwd()
|
|
241
|
-
if skip_mmd is False:
|
|
242
|
-
events_csv_path = temp_dir / "logs" / "events.csv"
|
|
243
|
-
if events_csv_path.exists():
|
|
244
|
-
printer("Generating mermaid sequence diagram...")
|
|
245
|
-
mmd_path = temp_dir / f"{flow_name}.mmd"
|
|
246
|
-
generate_sequence_diagram(events_csv_path, mmd_path)
|
|
247
|
-
if mmd_path.exists():
|
|
248
|
-
shutil.copyfile(mmd_path, output_dir / f"{flow_name}.mmd")
|
|
249
|
-
if output_path:
|
|
250
|
-
destination_dir = output_path.parent
|
|
251
|
-
destination_dir = (
|
|
252
|
-
destination_dir
|
|
253
|
-
/ "waldiez_out"
|
|
254
|
-
/ datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
|
255
|
-
)
|
|
256
|
-
destination_dir.mkdir(parents=True, exist_ok=True)
|
|
257
|
-
# copy the contents of the temp dir to the destination dir
|
|
258
|
-
printer(f"Copying the results to {destination_dir}")
|
|
259
|
-
copy_results(
|
|
260
|
-
temp_dir=temp_dir,
|
|
261
|
-
output_path=output_path,
|
|
262
|
-
output_dir=output_dir,
|
|
263
|
-
destination_dir=destination_dir,
|
|
264
|
-
)
|
|
265
|
-
shutil.rmtree(temp_dir)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def copy_results(
|
|
269
|
-
temp_dir: Path,
|
|
270
|
-
output_path: Path,
|
|
271
|
-
output_dir: Path,
|
|
272
|
-
destination_dir: Path,
|
|
273
|
-
) -> None:
|
|
274
|
-
"""Copy the results to the output directory.
|
|
275
|
-
|
|
276
|
-
Parameters
|
|
277
|
-
----------
|
|
278
|
-
temp_dir : Path
|
|
279
|
-
The temporary directory.
|
|
280
|
-
output_path : Path
|
|
281
|
-
The output path.
|
|
282
|
-
output_dir : Path
|
|
283
|
-
The output directory.
|
|
284
|
-
destination_dir : Path
|
|
285
|
-
The destination directory.
|
|
286
|
-
"""
|
|
287
|
-
temp_dir.mkdir(parents=True, exist_ok=True)
|
|
288
|
-
for item in temp_dir.iterdir():
|
|
289
|
-
# skip cache files
|
|
290
|
-
if (
|
|
291
|
-
item.name.startswith("__pycache__")
|
|
292
|
-
or item.name.endswith(".pyc")
|
|
293
|
-
or item.name.endswith(".pyo")
|
|
294
|
-
or item.name.endswith(".pyd")
|
|
295
|
-
or item.name == ".cache"
|
|
296
|
-
):
|
|
297
|
-
continue
|
|
298
|
-
if item.is_file():
|
|
299
|
-
# let's also copy the "tree of thoughts" image
|
|
300
|
-
# to the output directory
|
|
301
|
-
if item.name.endswith("tree_of_thoughts.png") or item.name.endswith(
|
|
302
|
-
"reasoning_tree.json"
|
|
303
|
-
):
|
|
304
|
-
shutil.copy(item, output_dir / item.name)
|
|
305
|
-
shutil.copy(item, destination_dir)
|
|
306
|
-
else:
|
|
307
|
-
shutil.copytree(item, destination_dir / item.name)
|
|
308
|
-
if output_path.is_file():
|
|
309
|
-
if output_path.suffix == ".waldiez":
|
|
310
|
-
output_path = output_path.with_suffix(".py")
|
|
311
|
-
if output_path.suffix == ".py":
|
|
312
|
-
src = temp_dir / output_path.name
|
|
313
|
-
if src.exists():
|
|
314
|
-
dst = destination_dir / output_path.name
|
|
315
|
-
if dst.exists():
|
|
316
|
-
dst.unlink()
|
|
317
|
-
shutil.copyfile(src, output_dir / output_path.name)
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
def get_printer() -> Callable[..., None]:
|
|
321
|
-
"""Get the printer function.
|
|
322
|
-
|
|
323
|
-
Returns
|
|
324
|
-
-------
|
|
325
|
-
Callable[..., None]
|
|
326
|
-
The printer function.
|
|
327
|
-
"""
|
|
328
|
-
from autogen.io import IOStream # type: ignore
|
|
329
|
-
|
|
330
|
-
# noinspection PyUnboundLocalVariable
|
|
331
|
-
printer = IOStream.get_default().print
|
|
332
|
-
|
|
333
|
-
def safe_printer(*args: Any, **kwargs: Any) -> None:
|
|
334
|
-
try:
|
|
335
|
-
printer(*args, **kwargs)
|
|
336
|
-
except UnicodeEncodeError:
|
|
337
|
-
try:
|
|
338
|
-
# Use the helper to get safely encoded message
|
|
339
|
-
safe_msg, flush = get_what_to_print(*args, **kwargs)
|
|
340
|
-
# Try printing the safe message
|
|
341
|
-
# (without end since it's already included)
|
|
342
|
-
printer(safe_msg, end="", flush=flush)
|
|
343
|
-
except UnicodeEncodeError:
|
|
344
|
-
# pylint: disable=too-many-try-statements
|
|
345
|
-
try:
|
|
346
|
-
# If that still fails, write directly to buffer
|
|
347
|
-
msg, flush = get_what_to_print(*args, **kwargs)
|
|
348
|
-
safe_msg_bytes = msg.encode("utf-8", errors="replace")
|
|
349
|
-
sys.stdout.buffer.write(safe_msg_bytes)
|
|
350
|
-
if flush:
|
|
351
|
-
sys.stdout.buffer.flush()
|
|
352
|
-
except Exception: # pylint: disable=broad-exception-caught
|
|
353
|
-
error_msg = (
|
|
354
|
-
b"Could not print message due to encoding issues.\n"
|
|
355
|
-
)
|
|
356
|
-
sys.stderr.buffer.write(error_msg)
|
|
357
|
-
sys.stderr.buffer.flush()
|
|
358
|
-
|
|
359
|
-
return safe_printer
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
def get_what_to_print(*args: object, **kwargs: object) -> tuple[str, bool]:
|
|
363
|
-
"""Get what to print.
|
|
364
|
-
|
|
365
|
-
Parameters
|
|
366
|
-
----------
|
|
367
|
-
args : object
|
|
368
|
-
The print arguments.
|
|
369
|
-
kwargs : object
|
|
370
|
-
The keyword arguments.
|
|
371
|
-
|
|
372
|
-
Returns
|
|
373
|
-
-------
|
|
374
|
-
tuple[str, bool]
|
|
375
|
-
The message and whether to flush.
|
|
376
|
-
"""
|
|
377
|
-
sep = kwargs.get("sep", " ")
|
|
378
|
-
if not isinstance(sep, str):
|
|
379
|
-
sep = " "
|
|
380
|
-
end = kwargs.get("end", "\n")
|
|
381
|
-
if not isinstance(end, str):
|
|
382
|
-
end = "\n"
|
|
383
|
-
flush = kwargs.get("flush", False)
|
|
384
|
-
if not isinstance(flush, bool):
|
|
385
|
-
flush = False
|
|
386
|
-
msg = sep.join(str(arg) for arg in args) + end
|
|
387
|
-
utf8_msg = msg.encode("utf-8", errors="replace").decode("utf-8")
|
|
388
|
-
return utf8_msg, flush
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|