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.
@@ -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
- # Extract just the basename to check if it starts with a dot
160
- return os.path.basename(path).startswith(".")
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
- diff: str,
377
- search_marker: str = "<<<<<< SEARCH",
378
- meta_marker: str = "------",
379
- separator: str = "======",
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 diff to a file.
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
- diff (str): Search/replace block defining changes (see format example below).
386
- search_marker (str): Marker for start of search block. Defaults to "<<<<<< SEARCH".
387
- meta_marker (str): Marker for start of content to search for. Defaults to "------".
388
- separator (str): Marker separating search/replace content. Defaults to "======".
389
- replace_marker (str): Marker for end of replacement block.
390
- Defaults to ">>>>>> REPLACE".
391
- SEARCH block must exactly match file content including whitespace/indentation.
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.5.10
3
+ Version: 1.5.11
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -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=e2-Mh9AeltCJGZrvhuMFMzmgQgsQbaxvSpAzcruIB9o,19222
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=f1OWajOBmdtx2QcXBr_8s6o82Fp4UTLqCXJqp2gxwzU,10750
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.10.dist-info/METADATA,sha256=ukEcYJvB_RA35-S1X5JPJT8v3qq5oN2Y2L2sYp4hiic,8469
366
- zrb-1.5.10.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
367
- zrb-1.5.10.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
368
- zrb-1.5.10.dist-info/RECORD,,
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,,
@@ -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