halib 0.2.31__py3-none-any.whl → 0.2.33__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.
halib/common/common.py CHANGED
@@ -1,3 +1,4 @@
1
+ from fiftyone.brain.internal.core.lancedb import pa
1
2
  import os
2
3
  import sys
3
4
  import re
@@ -280,6 +281,9 @@ def log_func(
280
281
  func_name = getattr(func, "__name__", "Unknown_Func")
281
282
  skip_list = skip_idxs or []
282
283
 
284
+ SUMMARY_WIDTH = 80
285
+ SUB_SUMMARY_WIDTH = 50
286
+
283
287
  with ConsoleLog(func_name):
284
288
  start = time.perf_counter()
285
289
  try:
@@ -288,22 +292,24 @@ def log_func(
288
292
  end = time.perf_counter()
289
293
 
290
294
  if log_time or log_args:
291
- console.print(pad_string(f"Func <{func_name}> summary", 80))
295
+ console.print(
296
+ pad_string(f"Func <{func_name}> summary", SUMMARY_WIDTH)
297
+ )
292
298
 
293
299
  if log_args:
294
- console.print(f"--- Arguments for {func_name} ---")
300
+ console.print(pad_string(f"Args Summary", SUMMARY_WIDTH))
295
301
  # Log Positional Args line-by-line
296
302
  for i, val in enumerate(args):
297
- if i in skip_list:
298
- console.print(f" arg[{i}]: <SKIPPED>")
299
- continue
300
- pprint(f" arg[{i}]: \n {val}")
301
-
303
+ val = "SKIPPED" if i in skip_list else val
304
+ console.print(pad_string(f"arg[{i}]", SUB_SUMMARY_WIDTH))
305
+ pprint(val)
302
306
  # Log Keyword Args line-by-line
303
307
  for k, v in kwargs.items():
304
- pprint(f" {k}: \n {v}")
308
+ console.print(pad_string(f"{k}", SUB_SUMMARY_WIDTH))
309
+ pprint(v)
305
310
 
306
311
  if log_time:
312
+ console.print(pad_string(f"Time Summary", SUMMARY_WIDTH))
307
313
  console.print(f"{func_name} took {end - start:.6f} seconds")
308
314
 
309
315
  return result
@@ -0,0 +1,140 @@
1
+ import glob
2
+ import wandb
3
+ import subprocess
4
+ from pathlib import Path
5
+ from typing import Optional, Literal
6
+
7
+ from tap import Tap
8
+ from tqdm import tqdm
9
+
10
+ from rich.console import Console
11
+ import yaml
12
+
13
+ wandb_console = Console()
14
+
15
+
16
+ # --- Argument Parser ---
17
+ class WandbArgs(Tap):
18
+ # --- Auth ---
19
+ api_key_yaml: Path = Path(
20
+ "E:/Dev/__halib/.env.yaml"
21
+ ) # Path to YAML file containing W&B API key
22
+
23
+ # --- Operations ---
24
+ op: Literal["sync", "delete"] = "delete" # Operation to perform
25
+
26
+ # --- Project & Filtering ---
27
+ project: str = "paper2_main" # W&B project name
28
+ pattern: Optional[str] = None # Run name pattern to match for deletion
29
+
30
+ # --- Paths ---
31
+ outdir: Path = Path("./zout/zruns") # Directory containing runs to sync
32
+
33
+ def configure(self):
34
+ self.add_argument("-prj", "--project")
35
+ self.add_argument("-pt", "--pattern")
36
+ self.add_argument("-o", "--outdir")
37
+ self.add_argument("-k", "--api_key_yaml")
38
+
39
+ def validate(self):
40
+ if self.op == "sync" and not self.outdir.exists():
41
+ raise ValueError(f"Output directory {self.outdir} does not exist.")
42
+ if self.op == "delete" and not self.project.strip():
43
+ raise ValueError("Project name must be a non-empty string.")
44
+
45
+
46
+ def login_wandb(api_key: Optional[str]):
47
+ """Handles authentication with Weights & Biases."""
48
+ try:
49
+ if api_key:
50
+ # Explicit login with key
51
+ wandb.login(key=api_key)
52
+ wandb_console.print(
53
+ "[green]Successfully logged into W&B using provided API key.[/green]"
54
+ )
55
+ else:
56
+ # Attempts to find key in environment variables or netrc file
57
+ if wandb.login():
58
+ wandb_console.print(
59
+ "[blue]Logged into W&B using existing credentials.[/blue]"
60
+ )
61
+ else:
62
+ wandb_console.print(
63
+ "[red]Authentication failed. Please provide an API key with -k.[/red]"
64
+ )
65
+ exit(1)
66
+ except Exception as e:
67
+ wandb_console.print(f"[bold red]Login Error:[/bold red] {e}")
68
+ exit(1)
69
+
70
+
71
+ # --- Logic Functions ---
72
+
73
+
74
+ def sync_runs(outdir: Path):
75
+ outdir_path = outdir.absolute()
76
+ sub_dirs = [d for d in outdir_path.iterdir() if d.is_dir()]
77
+
78
+ if not sub_dirs:
79
+ wandb_console.print(f"[red]No subdirectories found in {outdir_path}.[/red]")
80
+ return
81
+
82
+ wandb_console.rule(f"Syncing from {outdir_path}")
83
+
84
+ wandb_dirs = []
85
+ for exp_dir in sub_dirs:
86
+ wandb_dirs.extend(glob.glob(str(exp_dir / "wandb" / "*run-*")))
87
+
88
+ if not wandb_dirs:
89
+ wandb_console.print("No wandb runs found.")
90
+ return
91
+
92
+ for i, wandb_dir in enumerate(wandb_dirs):
93
+ wandb_console.print(f"[{i+1}/{len(wandb_dirs)}] Syncing: {wandb_dir}")
94
+
95
+ # Note: 'wandb sync' command uses the credentials from wandb.login()
96
+ process = subprocess.Popen(
97
+ ["wandb", "sync", wandb_dir],
98
+ stdout=subprocess.PIPE,
99
+ stderr=subprocess.STDOUT,
100
+ text=True,
101
+ )
102
+ for line in process.stdout: # ty:ignore[not-iterable]
103
+ if "ERROR" in line:
104
+ wandb_console.print(f"[red]{line.strip()}[/red]")
105
+ process.wait()
106
+
107
+
108
+ def delete_runs(project: str, pattern: Optional[str]):
109
+ api = wandb.Api()
110
+ runs = api.runs(project)
111
+
112
+ deleted = 0
113
+ for run in tqdm(runs, desc="Processing runs"):
114
+ if pattern is None or pattern in run.name:
115
+ run.delete()
116
+ deleted += 1
117
+ wandb_console.print(f"[green]Total runs deleted: {deleted}[/green]")
118
+
119
+
120
+ def main():
121
+ args = WandbArgs().parse_args()
122
+ cfg_dict = {}
123
+ with open(args.api_key_yaml, "r") as f:
124
+ cfg_dict = yaml.safe_load(f)
125
+ wandb_api_key = cfg_dict.get("WANDB_API_KEY")
126
+ assert (
127
+ wandb_api_key is not None
128
+ ), "W&B API key not found in the specified YAML file."
129
+ # 1. Login first
130
+ login_wandb(wandb_api_key)
131
+
132
+ # 2. Execute operation
133
+ if args.op == "sync":
134
+ sync_runs(args.outdir)
135
+ elif args.op == "delete":
136
+ delete_runs(args.project, args.pattern)
137
+
138
+
139
+ if __name__ == "__main__":
140
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: halib
3
- Version: 0.2.31
3
+ Version: 0.2.33
4
4
  Summary: Small library for common tasks
5
5
  Author: Hoang Van Ha
6
6
  Author-email: hoangvanhauit@gmail.com
@@ -57,7 +57,10 @@ Dynamic: summary
57
57
 
58
58
  ## v0.2.x (Experiment & Core Updates)
59
59
 
60
- ### **v0.2.31**
60
+ ### **v0.2.33**
61
+
62
+ - 🚀 **Improvement:**: move `wandb_op.py` to `utils` and add `scripts` folder
63
+
61
64
 
62
65
  - ✨ **New Feature:**: add `common.common.log_func` as decorator to log function entry, exit, with execution time and arguments.
63
66
 
@@ -17,7 +17,7 @@ halib/textfile.py,sha256=EhVFrit-nRBJx18e6rtIqcE1cSbgsLnMXe_kdhi1EPI,399
17
17
  halib/torchloader.py,sha256=-q9YE-AoHZE1xQX2dgNxdqtucEXYs4sQ22WXdl6EGfI,6500
18
18
  halib/videofile.py,sha256=NTLTZ-j6YD47duw2LN2p-lDQDglYFP1LpEU_0gzHLdI,4737
19
19
  halib/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- halib/common/common.py,sha256=C8oyWPn5PWwHqu2HyKEiyk0yhPC58fLZGPx70ogAUMM,10213
20
+ halib/common/common.py,sha256=sGfL03cg3lsp6rfpWSltpfDWV7vNI_0lh6pMFmAli4I,10516
21
21
  halib/common/rich_color.py,sha256=tyK5fl3Dtv1tKsfFzt_5Rco4Fj72QliA-w5aGXaVuqQ,6392
22
22
  halib/exp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  halib/exp/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -103,8 +103,9 @@ halib/utils/listop.py,sha256=Vpa8_2fI0wySpB2-8sfTBkyi_A4FhoFVVvFiuvW8N64,339
103
103
  halib/utils/slack.py,sha256=2ugWE_eJ0s479ObACJbx7iEu3kjMPD4Rt2hEwuMpuNQ,3099
104
104
  halib/utils/tele_noti.py,sha256=-4WXZelCA4W9BroapkRyIdUu9cUVrcJJhegnMs_WpGU,5928
105
105
  halib/utils/video.py,sha256=zLoj5EHk4SmP9OnoHjO8mLbzPdtq6gQPzTQisOEDdO8,3261
106
- halib-0.2.31.dist-info/licenses/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
107
- halib-0.2.31.dist-info/METADATA,sha256=wOgFsTwJbBmOXLmPZP_8dDsjrfMjE-X_F1GngNqOO9s,8183
108
- halib-0.2.31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
109
- halib-0.2.31.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
110
- halib-0.2.31.dist-info/RECORD,,
106
+ halib/utils/wandb_op.py,sha256=qqDdTMW4J07bzuJTTg2HoLAPs21nVEbwt2-Aa5ZKiVk,4336
107
+ halib-0.2.33.dist-info/licenses/LICENSE.txt,sha256=qZssdna4aETiR8znYsShUjidu-U4jUT9Q-EWNlZ9yBQ,1100
108
+ halib-0.2.33.dist-info/METADATA,sha256=-lEH1imwexo2Ig9i47CgkHkxHwsok4l4D3z-cUzmFM0,8268
109
+ halib-0.2.33.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
+ halib-0.2.33.dist-info/top_level.txt,sha256=7AD6PLaQTreE0Fn44mdZsoHBe_Zdd7GUmjsWPyQ7I-k,6
111
+ halib-0.2.33.dist-info/RECORD,,
File without changes