dayhoff-tools 1.7.1__py3-none-any.whl → 1.7.2__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.
dayhoff_tools/cli/main.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """Entry file for the CLI, which aggregates and aliases all commands."""
2
2
 
3
3
  import sys
4
+ from importlib.metadata import PackageNotFoundError, version
4
5
 
5
6
  import typer
6
7
 
@@ -21,7 +22,20 @@ from dayhoff_tools.warehouse import (
21
22
  import_from_warehouse_typer,
22
23
  )
23
24
 
24
- app = typer.Typer()
25
+ def _get_dht_version() -> str:
26
+ try:
27
+ return version("dayhoff-tools")
28
+ except PackageNotFoundError:
29
+ # Fallback to package __version__ if running from source
30
+ try:
31
+ from dayhoff_tools import __version__ # type: ignore
32
+
33
+ return __version__
34
+ except Exception:
35
+ return "unknown"
36
+
37
+
38
+ app = typer.Typer(help=f"Dayhoff Tools (dh) v{_get_dht_version()}\n\nUse 'dh --version' to print version and exit.")
25
39
 
26
40
  # Utility commands
27
41
  app.command("clean")(delete_local_branch)
@@ -50,6 +64,22 @@ app.add_typer(engine_app, name="engine", help="Manage compute engines for develo
50
64
  app.add_typer(studio_app, name="studio", help="Manage persistent development studios.")
51
65
 
52
66
 
67
+ @app.callback()
68
+ def _version_option(
69
+ version_flag: bool = typer.Option(
70
+ False,
71
+ "--version",
72
+ "-v",
73
+ help="Print version and exit.",
74
+ is_eager=True,
75
+ )
76
+ ):
77
+ """Global options for the dh CLI (e.g., version)."""
78
+ if version_flag:
79
+ typer.echo(_get_dht_version())
80
+ raise typer.Exit()
81
+
82
+
53
83
  @app.command("wheel")
54
84
  def build_and_upload_wheel_command(
55
85
  bump: str = typer.Option(
@@ -265,42 +265,72 @@ def install_dependencies(
265
265
  help="Install the local project package itself (with 'full' extras) into the environment.",
266
266
  ),
267
267
  ):
268
- """Install dependencies based on pyproject.toml.
269
-
270
- Ensures uv.lock matches pyproject.toml and syncs the environment.
271
- When -p is used, installs the local project with its [full] optional dependencies.
268
+ """Install dependencies respecting Mac devcontainer flow and the active venv.
269
+
270
+ Behavior:
271
+ - If running on Mac devcontainer (STUDIO_PLATFORM=mac) and `pyproject.mac.toml` exists:
272
+ * Ensure `.mac_uv_project/pyproject.toml` is a copy of `pyproject.mac.toml`
273
+ * Run `uv lock` and `uv sync` in `.mac_uv_project` and always target the active venv with `--active`
274
+ * If `install_project` is true, install the project from repo root into the active env (editable, [full])
275
+ - Otherwise (default path):
276
+ * Operate in repo root, ensure lock, and `uv sync --active` so we don't create `.venv` accidentally
277
+ * If `install_project` is true, sync without `--no-install-project` (installs project)
272
278
  """
273
279
  # ANSI color codes
274
280
  BLUE = "\033[94m"
275
281
  RESET = "\033[0m"
276
282
 
277
283
  try:
278
- # Step 1: Ensure lock file matches pyproject.toml
279
- print("Ensuring lock file matches pyproject.toml...")
280
- lock_cmd = ["uv", "lock"]
281
- print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
282
- subprocess.run(lock_cmd, check=True, capture_output=True)
283
-
284
- if install_project:
285
- # Step 2a: Install the project with 'full' extras
286
- print("Installing the local project with 'full' extras...")
287
- # The .[full] syntax tells pip to install the current project ('.')
288
- # with its 'full' optional dependencies.
289
- pip_install_cmd = ["uv", "pip", "install", "-e", ".[full]"]
290
- print(f"Running command: {BLUE}{' '.join(pip_install_cmd)}{RESET}")
291
- subprocess.run(pip_install_cmd, check=True)
292
-
293
- print("Project installed with 'full' extras successfully.")
284
+ is_mac = os.environ.get("STUDIO_PLATFORM") == "mac"
285
+ mac_manifest = Path("pyproject.mac.toml")
286
+ if is_mac and mac_manifest.exists():
287
+ # Mac devcontainer flow
288
+ mac_uv_dir = Path(".mac_uv_project")
289
+ mac_uv_dir.mkdir(parents=True, exist_ok=True)
290
+ mac_pyproject = mac_uv_dir / "pyproject.toml"
291
+ mac_pyproject.write_text(mac_manifest.read_text())
292
+
293
+ # Ensure lock matches manifest (in mac temp dir)
294
+ print("Ensuring lock file matches pyproject.mac.toml (Mac devcon)…")
295
+ lock_cmd = ["uv", "lock"]
296
+ print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
297
+ subprocess.run(lock_cmd, check=True, capture_output=True, cwd=str(mac_uv_dir))
298
+
299
+ # Sync into the active environment
300
+ if install_project:
301
+ print("Syncing dependencies into ACTIVE env and installing project [full]…")
302
+ sync_cmd = ["uv", "sync", "--all-groups", "--active"]
303
+ print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
304
+ subprocess.run(sync_cmd, check=True, cwd=str(mac_uv_dir))
305
+ # Install project from repo root
306
+ pip_install_cmd = ["uv", "pip", "install", "-e", ".[full]"]
307
+ print(f"Running command: {BLUE}{' '.join(pip_install_cmd)}{RESET}")
308
+ subprocess.run(pip_install_cmd, check=True)
309
+ print("Project installed with 'full' extras successfully.")
310
+ else:
311
+ print("Syncing dependencies into ACTIVE env (project not installed)…")
312
+ sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project", "--active"]
313
+ print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
314
+ subprocess.run(sync_cmd, check=True, cwd=str(mac_uv_dir))
315
+ print("Dependencies synced successfully (project not installed).")
294
316
  else:
295
- # Original behavior: Sync environment without installing the project
296
- print(
297
- "Syncing environment with lock file (project itself will not be installed)..."
298
- )
299
- # --all-groups ensures all non-project dependencies (like dev) are installed
300
- sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project"]
301
- print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
302
- subprocess.run(sync_cmd, check=True)
303
- print("Dependencies synced successfully (project not installed).")
317
+ # Default behavior in repo root, but ensure we target the active env
318
+ print("Ensuring lock file matches pyproject.toml…")
319
+ lock_cmd = ["uv", "lock"]
320
+ print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
321
+ subprocess.run(lock_cmd, check=True, capture_output=True)
322
+
323
+ if install_project:
324
+ print("Syncing dependencies into ACTIVE env (installing project)…")
325
+ sync_cmd = ["uv", "sync", "--all-groups", "--active"]
326
+ print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
327
+ subprocess.run(sync_cmd, check=True)
328
+ else:
329
+ print("Syncing dependencies into ACTIVE env (project not installed)…")
330
+ sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project", "--active"]
331
+ print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
332
+ subprocess.run(sync_cmd, check=True)
333
+ print("Dependencies synced successfully (project not installed).")
304
334
 
305
335
  except subprocess.CalledProcessError as e:
306
336
  stderr_output = e.stderr.decode() if e.stderr else "No stderr output."
@@ -327,19 +357,27 @@ def update_dependencies(
327
357
  help="Update all dependencies instead of just dayhoff-tools.",
328
358
  ),
329
359
  ):
330
- """Update dependencies to newer versions.
331
-
332
- Default Action (no flags): Updates only 'dayhoff-tools' package to latest,
333
- updates pyproject.toml, and syncs.
334
-
335
- Flags:
336
- --all/-a: Updates all dependencies to latest compatible versions (`uv lock --upgrade`)
337
- and syncs the environment. Overrides the default.
360
+ """Update dependencies to newer versions (Mac-aware, active venv friendly).
361
+
362
+ - Default Action (no flags): Updates only 'dayhoff-tools' package to latest,
363
+ updates the manifest's version constraint, and syncs.
364
+ - Flags:
365
+ --all/-a: Updates all dependencies (uv lock --upgrade) and syncs.
366
+
367
+ Mac devcontainer behavior:
368
+ - If STUDIO_PLATFORM=mac and `pyproject.mac.toml` exists, operate in `.mac_uv_project/`:
369
+ copy `pyproject.mac.toml` to `.mac_uv_project/pyproject.toml`, run uv there, and always
370
+ use `--active` for sync so installs target the active venv.
371
+ - Update the constraint inside `pyproject.mac.toml`. If not found, try `pyproject.toml`.
372
+ Otherwise (non-Mac), operate in repo root and also target the active venv during sync.
338
373
  """
339
374
  # ANSI color codes
340
375
  BLUE = "\033[94m"
341
376
  RESET = "\033[0m"
342
377
 
378
+ is_mac = os.environ.get("STUDIO_PLATFORM") == "mac"
379
+ mac_manifest = Path("pyproject.mac.toml")
380
+ mac_uv_dir = Path(".mac_uv_project")
343
381
  lock_file_path = Path("uv.lock")
344
382
  pyproject_path = Path("pyproject.toml")
345
383
 
@@ -363,10 +401,19 @@ def update_dependencies(
363
401
  )
364
402
 
365
403
  try:
404
+ # Choose working directory for uv operations
405
+ uv_cwd = None
406
+ manifest_path_for_constraint = pyproject_path
407
+ if is_mac and mac_manifest.exists():
408
+ mac_uv_dir.mkdir(parents=True, exist_ok=True)
409
+ (mac_uv_dir / "pyproject.toml").write_text(mac_manifest.read_text())
410
+ uv_cwd = str(mac_uv_dir)
411
+ lock_file_path = mac_uv_dir / "uv.lock"
412
+ manifest_path_for_constraint = mac_manifest
366
413
  # Step 1: Run the update lock command
367
414
  print(action_description)
368
415
  print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
369
- subprocess.run(lock_cmd, check=True, capture_output=True)
416
+ subprocess.run(lock_cmd, check=True, capture_output=True, cwd=uv_cwd)
370
417
 
371
418
  # Step 2: Update pyproject.toml only if doing the dayhoff update (default)
372
419
  if run_pyproject_update:
@@ -395,9 +442,9 @@ def update_dependencies(
395
442
  return
396
443
 
397
444
  print(f"Found dayhoff-tools version {locked_version} in lock file.")
398
- print(f"Updating {pyproject_path} version constraint...")
445
+ print(f"Updating {manifest_path_for_constraint} version constraint...")
399
446
  try:
400
- content = pyproject_path.read_text()
447
+ content = manifest_path_for_constraint.read_text()
401
448
 
402
449
  package_name = "dayhoff-tools"
403
450
  package_name_esc = re.escape(package_name)
@@ -420,27 +467,41 @@ def update_dependencies(
420
467
 
421
468
  new_content, num_replacements = pattern.subn(_repl, content)
422
469
  if num_replacements > 0:
423
- pyproject_path.write_text(new_content)
470
+ manifest_path_for_constraint.write_text(new_content)
424
471
  print(
425
- f"Updated dayhoff-tools constraint in {pyproject_path} to '{new_constraint_text}'"
472
+ f"Updated dayhoff-tools constraint in {manifest_path_for_constraint} to '{new_constraint_text}'"
426
473
  )
427
474
  else:
428
- print(
429
- f"Warning: Could not find dayhoff-tools dependency line in {pyproject_path} to update constraint."
430
- )
475
+ # Fallback: try the root pyproject if we were targeting mac manifest
476
+ if manifest_path_for_constraint != pyproject_path and pyproject_path.exists():
477
+ content2 = pyproject_path.read_text()
478
+ new_content2, n2 = pattern.subn(_repl, content2)
479
+ if n2 > 0:
480
+ pyproject_path.write_text(new_content2)
481
+ print(
482
+ f"Updated dayhoff-tools constraint in {pyproject_path} to '{new_constraint_text}'"
483
+ )
484
+ else:
485
+ print(
486
+ f"Warning: Could not find dayhoff-tools dependency line in {manifest_path_for_constraint} or {pyproject_path} to update constraint."
487
+ )
488
+ else:
489
+ print(
490
+ f"Warning: Could not find dayhoff-tools dependency line in {manifest_path_for_constraint} to update constraint."
491
+ )
431
492
  except FileNotFoundError:
432
- print(f"Error: {pyproject_path} not found.")
493
+ print(f"Error: {manifest_path_for_constraint} not found.")
433
494
  return
434
495
  except Exception as e:
435
- print(f"Error updating {pyproject_path}: {e}")
496
+ print(f"Error updating {manifest_path_for_constraint}: {e}")
436
497
  print("Proceeding with sync despite pyproject.toml update error.")
437
498
 
438
499
  # Step 3: Sync environment
439
500
  print("Syncing environment with updated lock file...")
440
501
  # Always use --no-install-project for updates
441
- sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project"]
502
+ sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project", "--active"]
442
503
  print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
443
- subprocess.run(sync_cmd, check=True)
504
+ subprocess.run(sync_cmd, check=True, cwd=uv_cwd)
444
505
 
445
506
  # Final status message
446
507
  if update_all:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.7.1
3
+ Version: 1.7.2
4
4
  Summary: Common tools for all the repos at Dayhoff Labs
5
5
  Author: Daniel Martin-Alarcon
6
6
  Author-email: dma@dayhofflabs.com
@@ -4,9 +4,9 @@ dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P
4
4
  dayhoff_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  dayhoff_tools/cli/cloud_commands.py,sha256=33qcWLmq-FwEXMdL3F0OHm-5Stlh2r65CldyEZgQ1no,40904
6
6
  dayhoff_tools/cli/engine_commands.py,sha256=_NQI9x4VKtAC9vTDdA4NGrILf2kb005t3Kw0aZ5oroE,96485
7
- dayhoff_tools/cli/main.py,sha256=tRN7WCBHg6uyNp6rA54pKTCoVmBntta2i0Yas3bUpZ4,4853
7
+ dayhoff_tools/cli/main.py,sha256=vmT2P7-CkW3nY0yvfk1Q5F6DCg-Q5T-THJ9GBCwNn7k,5701
8
8
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
9
- dayhoff_tools/cli/utility_commands.py,sha256=FRZTPrjsG_qmIIqoNxd1Q1vVkS_5w8aY33IrVYVNCLg,18131
9
+ dayhoff_tools/cli/utility_commands.py,sha256=igPl3s9lsxhLV1Ul0TmPrsH060Bqv7bQffsO300u1IU,22257
10
10
  dayhoff_tools/deployment/base.py,sha256=mYp560l6hSDFtyY2H42VoM8k9VUzfwuiyh9Knqpgc28,17441
11
11
  dayhoff_tools/deployment/deploy_aws.py,sha256=GvZpE2YIFA5Dl9rkAljFjtUypmPDNbWgw8NicHYTP24,18265
12
12
  dayhoff_tools/deployment/deploy_gcp.py,sha256=xgaOVsUDmP6wSEMYNkm1yRNcVskfdz80qJtCulkBIAM,8860
@@ -27,7 +27,7 @@ dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJq
27
27
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
28
28
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
29
29
  dayhoff_tools/warehouse.py,sha256=heaYc64qplgN3_1WVPFmqj53goStioWwY5NqlWc4c0s,24453
30
- dayhoff_tools-1.7.1.dist-info/METADATA,sha256=SfgSoCKU9G3NVk4aeQprKBvjn8-bHUXPy5jT2EIS1sA,2914
31
- dayhoff_tools-1.7.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
- dayhoff_tools-1.7.1.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
- dayhoff_tools-1.7.1.dist-info/RECORD,,
30
+ dayhoff_tools-1.7.2.dist-info/METADATA,sha256=1KogZl3g9T9txdfivL4fwXNE5TOtpmAAUv4VwImxBpo,2914
31
+ dayhoff_tools-1.7.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ dayhoff_tools-1.7.2.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
+ dayhoff_tools-1.7.2.dist-info/RECORD,,