zrb 1.5.10__py3-none-any.whl → 1.5.11__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.
- zrb/builtin/llm/tool/file.py +22 -88
- zrb/task/cmd_task.py +2 -2
- {zrb-1.5.10.dist-info → zrb-1.5.11.dist-info}/METADATA +1 -1
- {zrb-1.5.10.dist-info → zrb-1.5.11.dist-info}/RECORD +6 -7
- zrb/task/base/dependencies.py +0 -57
- {zrb-1.5.10.dist-info → zrb-1.5.11.dist-info}/WHEEL +0 -0
- {zrb-1.5.10.dist-info → zrb-1.5.11.dist-info}/entry_points.txt +0 -0
zrb/builtin/llm/tool/file.py
CHANGED
@@ -92,6 +92,10 @@ def list_files(
|
|
92
92
|
"""
|
93
93
|
all_files: list[str] = []
|
94
94
|
abs_path = os.path.abspath(os.path.expanduser(path))
|
95
|
+
# Explicitly check if path exists before proceeding
|
96
|
+
if not os.path.exists(abs_path):
|
97
|
+
# Raise FileNotFoundError, which is a subclass of OSError
|
98
|
+
raise FileNotFoundError(f"Path does not exist: {path}")
|
95
99
|
# Determine effective exclusion patterns
|
96
100
|
patterns_to_exclude = (
|
97
101
|
excluded_patterns
|
@@ -150,14 +154,17 @@ def list_files(
|
|
150
154
|
|
151
155
|
def _is_hidden(path: str) -> bool:
|
152
156
|
"""
|
153
|
-
Check if path is hidden (starts with '.').
|
157
|
+
Check if path is hidden (starts with '.') but ignore '.' and '..'.
|
154
158
|
Args:
|
155
159
|
path: File or directory path to check
|
156
160
|
Returns:
|
157
161
|
True if the path is hidden, False otherwise
|
158
162
|
"""
|
159
|
-
|
160
|
-
|
163
|
+
basename = os.path.basename(path)
|
164
|
+
# Ignore '.' and '..' as they are not typically considered hidden in listings
|
165
|
+
if basename == "." or basename == "..":
|
166
|
+
return False
|
167
|
+
return basename.startswith(".")
|
161
168
|
|
162
169
|
|
163
170
|
def _is_excluded(name: str, patterns: list[str]) -> bool:
|
@@ -373,41 +380,27 @@ def _get_file_matches(
|
|
373
380
|
|
374
381
|
def apply_diff(
|
375
382
|
path: str,
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
replace_marker: str = ">>>>>> REPLACE",
|
383
|
+
start_line: int,
|
384
|
+
end_line: int,
|
385
|
+
search_content: str,
|
386
|
+
replace_content: str,
|
381
387
|
) -> str:
|
382
|
-
"""Apply a precise search/replace
|
388
|
+
"""Apply a precise search/replace to a file based on line numbers and content.
|
383
389
|
Args:
|
384
390
|
path (str): Path to modify. Pass exactly as provided, including '~'.
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
SEARCH block should NOT contains line numbers
|
393
|
-
Format example:
|
394
|
-
[Search Marker, e.g., <<<<<< SEARCH]
|
395
|
-
:start_line:10
|
396
|
-
:end_line:15
|
397
|
-
[Meta Marker, e.g., ------]
|
398
|
-
[exact content to find including whitespace]
|
399
|
-
[Separator, e.g., ======]
|
400
|
-
[new content to replace with]
|
401
|
-
[Replace Marker, e.g., >>>>>> REPLACE]
|
391
|
+
start_line (int): The 1-based starting line number of the content to replace.
|
392
|
+
end_line (int): The 1-based ending line number (inclusive) of the content to replace.
|
393
|
+
search_content (str): The exact content expected to be found in the specified
|
394
|
+
line range. Must exactly match file content including whitespace/indentation,
|
395
|
+
excluding line numbers.
|
396
|
+
replace_content (str): The new content to replace the search_content with.
|
397
|
+
Excluding line numbers.
|
402
398
|
Returns:
|
403
399
|
str: JSON: {"success": true, "path": "f.py"} or {"success": false, "error": "..."}
|
404
400
|
Raises:
|
405
401
|
Exception: If an error occurs.
|
406
402
|
"""
|
407
403
|
try:
|
408
|
-
start_line, end_line, search_content, replace_content = _parse_diff(
|
409
|
-
diff, search_marker, meta_marker, separator, replace_marker
|
410
|
-
)
|
411
404
|
abs_path = os.path.abspath(os.path.expanduser(path))
|
412
405
|
if not os.path.exists(abs_path):
|
413
406
|
return json.dumps(
|
@@ -451,62 +444,3 @@ def apply_diff(
|
|
451
444
|
raise OSError(f"Error applying diff to {path}: {e}")
|
452
445
|
except Exception as e:
|
453
446
|
raise RuntimeError(f"Unexpected error applying diff to {path}: {e}")
|
454
|
-
|
455
|
-
|
456
|
-
def _parse_diff(
|
457
|
-
diff: str,
|
458
|
-
search_marker: str,
|
459
|
-
meta_marker: str,
|
460
|
-
separator: str,
|
461
|
-
replace_marker: str,
|
462
|
-
) -> tuple[int, int, str, str]:
|
463
|
-
"""
|
464
|
-
Parse diff content into components.
|
465
|
-
Args:
|
466
|
-
diff: The diff content to parse
|
467
|
-
search_marker: Marker indicating the start of the search block
|
468
|
-
meta_marker: Marker indicating the start of the content to search for
|
469
|
-
separator: Marker separating search content from replacement content
|
470
|
-
replace_marker: Marker indicating the end of the replacement block
|
471
|
-
Returns:
|
472
|
-
Tuple of (start_line, end_line, search_content, replace_content)
|
473
|
-
Raises:
|
474
|
-
ValueError: If diff format is invalid or missing required markers
|
475
|
-
ValueError: If start_line or end_line cannot be parsed
|
476
|
-
"""
|
477
|
-
# Find all marker positions
|
478
|
-
search_start_idx = diff.find(search_marker)
|
479
|
-
meta_start_idx = diff.find(meta_marker)
|
480
|
-
separator_idx = diff.find(separator)
|
481
|
-
replace_end_idx = diff.find(replace_marker)
|
482
|
-
# Validate all markers are present
|
483
|
-
missing_markers = []
|
484
|
-
if search_start_idx == -1:
|
485
|
-
missing_markers.append("search marker")
|
486
|
-
if meta_start_idx == -1:
|
487
|
-
missing_markers.append("meta marker")
|
488
|
-
if separator_idx == -1:
|
489
|
-
missing_markers.append("separator")
|
490
|
-
if replace_end_idx == -1:
|
491
|
-
missing_markers.append("replace marker")
|
492
|
-
if missing_markers:
|
493
|
-
raise ValueError(f"Invalid diff format - missing: {', '.join(missing_markers)}")
|
494
|
-
# Extract metadata
|
495
|
-
meta_content = diff[search_start_idx + len(search_marker) : meta_start_idx].strip()
|
496
|
-
# Parse line numbers
|
497
|
-
start_line_match = re.search(r":start_line:(\d+)", meta_content)
|
498
|
-
end_line_match = re.search(r":end_line:(\d+)", meta_content)
|
499
|
-
if not start_line_match:
|
500
|
-
raise ValueError("Missing start_line in diff metadata")
|
501
|
-
if not end_line_match:
|
502
|
-
raise ValueError("Missing end_line in diff metadata")
|
503
|
-
start_line = int(start_line_match.group(1))
|
504
|
-
end_line = int(end_line_match.group(1))
|
505
|
-
# Extract content sections
|
506
|
-
search_content = diff[meta_start_idx + len(meta_marker) : separator_idx].strip(
|
507
|
-
"\r\n"
|
508
|
-
)
|
509
|
-
replace_content = diff[separator_idx + len(separator) : replace_end_idx].strip(
|
510
|
-
"\r\n"
|
511
|
-
)
|
512
|
-
return start_line, end_line, search_content, replace_content
|
zrb/task/cmd_task.py
CHANGED
@@ -255,14 +255,14 @@ class CmdTask(BaseTask):
|
|
255
255
|
def __render_single_cmd_val(
|
256
256
|
self, ctx: AnyContext, single_cmd_val: SingleCmdVal
|
257
257
|
) -> str | None:
|
258
|
+
if isinstance(single_cmd_val, AnyCmdVal):
|
259
|
+
return single_cmd_val.to_str(ctx)
|
258
260
|
if callable(single_cmd_val):
|
259
261
|
return single_cmd_val(ctx)
|
260
262
|
if isinstance(single_cmd_val, str):
|
261
263
|
if self._render_cmd:
|
262
264
|
return ctx.render(single_cmd_val)
|
263
265
|
return single_cmd_val
|
264
|
-
if isinstance(single_cmd_val, AnyCmdVal):
|
265
|
-
return single_cmd_val.to_str(ctx)
|
266
266
|
return None
|
267
267
|
|
268
268
|
def __get_multiline_repr(self, text: str) -> str:
|
@@ -13,7 +13,7 @@ zrb/builtin/llm/llm_chat.py,sha256=XL5HK_o1EejkYS0fJIBI39vApuqYYsGHFSigvXfS7CI,4
|
|
13
13
|
zrb/builtin/llm/previous-session.js,sha256=xMKZvJoAbrwiyHS0OoPrWuaKxWYLoyR5sguePIoCjTY,816
|
14
14
|
zrb/builtin/llm/tool/api.py,sha256=yR9I0ZsI96OeQl9pgwORMASVuXsAL0a89D_iPS4C8Dc,1699
|
15
15
|
zrb/builtin/llm/tool/cli.py,sha256=_CNEmEc6K2Z0i9ppYeM7jGpqaEdT3uxaWQatmxP3jKE,858
|
16
|
-
zrb/builtin/llm/tool/file.py,sha256=
|
16
|
+
zrb/builtin/llm/tool/file.py,sha256=ig4tZGYnGjE96U9KgOpbANmyAgFmTcQzym1wVAsZYRM,16620
|
17
17
|
zrb/builtin/llm/tool/rag.py,sha256=45t0o88l7F62oq2P61NnC1hsZJ4h72dZsVQfcsOIUc8,7521
|
18
18
|
zrb/builtin/llm/tool/web.py,sha256=4qzom9xX-JxztIaTWneNfyTRlgweHIxzC1uSEAxJ00A,5507
|
19
19
|
zrb/builtin/md5.py,sha256=0pNlrfZA0wlZlHvFHLgyqN0JZJWGKQIF5oXxO44_OJk,949
|
@@ -300,14 +300,13 @@ zrb/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
300
300
|
zrb/task/any_task.py,sha256=zklUjkLRQ62TEvfnOUUYfXChj8Zk4igee3w8V3_rN08,5846
|
301
301
|
zrb/task/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
302
302
|
zrb/task/base/context.py,sha256=73k3fKwup0AJwTTLpay0f_-axJextaxgbTem4w4Bmas,3670
|
303
|
-
zrb/task/base/dependencies.py,sha256=Kcxhn7z4OU9Fc_y-cD1Sc96wgNXs0VDoi8r5cJMu0oY,1952
|
304
303
|
zrb/task/base/execution.py,sha256=lB6cfivk-EM6sZSaPjYs_ufb7jb-A2jLJNhBupwBFgI,11101
|
305
304
|
zrb/task/base/lifecycle.py,sha256=YIugyqRmEKMnc9MTCDEZr9jVhie3Kwt7LTMtAVAN9Ks,7278
|
306
305
|
zrb/task/base/monitoring.py,sha256=UAOEcPiYNtZR4FFxzWCosuOEFE_P3c4GT5vAhQmohqI,5663
|
307
306
|
zrb/task/base/operators.py,sha256=uAMFqpZJsPnCrojgOl1FUDXTS15mtOa_IqiAXltyYRU,1576
|
308
307
|
zrb/task/base_task.py,sha256=3MLPYDzNgjIJiQTxSyKLmvG_FspOl61htuRZG7l34QA,8915
|
309
308
|
zrb/task/base_trigger.py,sha256=jC722rDvodaBLeNaFghkTyv1u0QXrK6BLZUUqcmBJ7Q,4581
|
310
|
-
zrb/task/cmd_task.py,sha256=
|
309
|
+
zrb/task/cmd_task.py,sha256=xFAdOvLDK9Qaye40T_lG3K6AIKgbPAMHk_3GIAYeJAM,10750
|
311
310
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
312
311
|
zrb/task/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
313
312
|
zrb/task/llm/agent.py,sha256=2u1zlX41oBzMKozXWXD3gDEOzOsHNsFpedRcJXbUNHI,5105
|
@@ -362,7 +361,7 @@ zrb/util/string/name.py,sha256=8picJfUBXNpdh64GNaHv3om23QHhUZux7DguFLrXHp8,1163
|
|
362
361
|
zrb/util/todo.py,sha256=1nDdwPc22oFoK_1ZTXyf3638Bg6sqE2yp_U4_-frHoc,16015
|
363
362
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
364
363
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
365
|
-
zrb-1.5.
|
366
|
-
zrb-1.5.
|
367
|
-
zrb-1.5.
|
368
|
-
zrb-1.5.
|
364
|
+
zrb-1.5.11.dist-info/METADATA,sha256=TAOvXdXnUwI1_y0VSDOLxYElSCv441WHSRogvF5EUYU,8469
|
365
|
+
zrb-1.5.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
366
|
+
zrb-1.5.11.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
367
|
+
zrb-1.5.11.dist-info/RECORD,,
|
zrb/task/base/dependencies.py
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
from typing import TypeVar
|
2
|
-
|
3
|
-
from zrb.task.any_task import AnyTask
|
4
|
-
|
5
|
-
T = TypeVar("T", bound="AnyTask")
|
6
|
-
|
7
|
-
|
8
|
-
def get_dependency_list(task: AnyTask, attr_name: str) -> list[AnyTask]:
|
9
|
-
"""
|
10
|
-
Safely retrieves a list of dependencies (upstreams, fallbacks, etc.)
|
11
|
-
from a task attribute, handling None or single-task values.
|
12
|
-
"""
|
13
|
-
dependencies = getattr(task, attr_name, None)
|
14
|
-
if dependencies is None:
|
15
|
-
return []
|
16
|
-
elif isinstance(dependencies, list):
|
17
|
-
# Ensure all elements are AnyTask (or compatible) if needed,
|
18
|
-
# but for now, assume the list contains tasks.
|
19
|
-
return dependencies
|
20
|
-
# Assume it's a single AnyTask instance
|
21
|
-
return [dependencies]
|
22
|
-
|
23
|
-
|
24
|
-
def append_dependency(
|
25
|
-
task: T, attr_name: str, dependencies_to_add: AnyTask | list[AnyTask]
|
26
|
-
) -> None:
|
27
|
-
"""
|
28
|
-
Appends one or more dependencies to the specified attribute list of a task,
|
29
|
-
ensuring the attribute becomes a list and avoiding duplicates.
|
30
|
-
|
31
|
-
Modifies the attribute on the task object directly.
|
32
|
-
"""
|
33
|
-
# Retrieve the current list, handling None or single item cases
|
34
|
-
current_deps_list = getattr(task, attr_name, None)
|
35
|
-
if current_deps_list is None:
|
36
|
-
current_deps_list = []
|
37
|
-
elif not isinstance(current_deps_list, list):
|
38
|
-
current_deps_list = [current_deps_list]
|
39
|
-
else:
|
40
|
-
# Create a copy to avoid modifying the original list if no changes occur
|
41
|
-
current_deps_list = list(current_deps_list)
|
42
|
-
|
43
|
-
if isinstance(dependencies_to_add, list):
|
44
|
-
new_deps = dependencies_to_add
|
45
|
-
else:
|
46
|
-
new_deps = [dependencies_to_add] # Ensure it's always a list
|
47
|
-
|
48
|
-
added = False
|
49
|
-
for dep in new_deps:
|
50
|
-
# Check for existence before appending
|
51
|
-
if dep not in current_deps_list:
|
52
|
-
current_deps_list.append(dep)
|
53
|
-
added = True
|
54
|
-
|
55
|
-
# Update the attribute on the task object only if changes were made
|
56
|
-
if added:
|
57
|
-
setattr(task, attr_name, current_deps_list)
|
File without changes
|
File without changes
|