dayhoff-tools 1.7.5__py3-none-any.whl → 1.8.1__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.
@@ -9,7 +9,7 @@ import sys
9
9
  import time
10
10
  from datetime import datetime, timedelta, timezone
11
11
  from pathlib import Path
12
- from typing import Dict, List, Optional, Tuple
12
+ from typing import Any, Dict, List, Optional, Tuple
13
13
 
14
14
  import boto3
15
15
  import requests
@@ -647,7 +647,7 @@ def launch_engine(
647
647
  ) as progress:
648
648
  progress.add_task("Creating engine...", total=None)
649
649
 
650
- request_data = {
650
+ request_data: Dict[str, Any] = {
651
651
  "name": name,
652
652
  "user": username,
653
653
  "engine_type": engine_type,
@@ -797,18 +797,50 @@ def engine_status(
797
797
 
798
798
  engine_details = response.json()
799
799
  engine = engine_details.get("engine", engine) # Use detailed info if available
800
- idle_detector = engine_details.get("idle_detector", {})
800
+ idle_detector = engine_details.get("idle_detector", {}) or {}
801
801
  attached_studios = engine_details.get("attached_studios", [])
802
802
 
803
803
  # Calculate costs
804
804
  launch_time = parse_launch_time(engine["launch_time"])
805
805
  uptime = datetime.now(timezone.utc) - launch_time
806
806
  hourly_cost = HOURLY_COSTS.get(engine["engine_type"], 0)
807
- total_cost = hourly_cost * (uptime.total_seconds() / 3600)
807
+ # total_cost intentionally not shown in status view
808
808
 
809
809
  stages_map = _fetch_init_stages([engine["instance_id"]])
810
810
  stage_val = stages_map.get(engine["instance_id"], "-")
811
811
 
812
+ # Try to fetch actual boot time via SSM (best-effort)
813
+ boot_time_str: Optional[str] = None
814
+ try:
815
+ if engine["state"].lower() == "running":
816
+ ssm = boto3.client("ssm", region_name="us-east-1")
817
+ resp = ssm.send_command(
818
+ InstanceIds=[engine["instance_id"]],
819
+ DocumentName="AWS-RunShellScript",
820
+ Parameters={
821
+ "commands": ["uptime -s || who -b | awk '{print $3\" \"$4}'"]
822
+ },
823
+ )
824
+ cid = resp["Command"]["CommandId"]
825
+ time.sleep(1)
826
+ inv = ssm.get_command_invocation(
827
+ CommandId=cid, InstanceId=engine["instance_id"]
828
+ )
829
+ if inv.get("Status") == "Success":
830
+ boot_time_str = (
831
+ (inv.get("StandardOutputContent") or "").strip().splitlines()[0]
832
+ if inv.get("StandardOutputContent")
833
+ else None
834
+ )
835
+ except Exception:
836
+ boot_time_str = None
837
+
838
+ started_line = (
839
+ f"[bold]Started:[/bold] {boot_time_str} ({format_duration(uptime)} ago)"
840
+ if boot_time_str
841
+ else f"[bold]Started:[/bold] {launch_time.strftime('%Y-%m-%d %H:%M:%S')} ({format_duration(uptime)} ago)"
842
+ )
843
+
812
844
  status_lines = [
813
845
  f"[bold]Name:[/bold] {engine['name']}",
814
846
  f"[bold]Instance:[/bold] {engine['instance_id']}",
@@ -816,10 +848,15 @@ def engine_status(
816
848
  f"[bold]Status:[/bold] {format_status(engine['state'], engine.get('ready'))}",
817
849
  f"[bold]User:[/bold] {engine['user']}",
818
850
  f"[bold]IP:[/bold] {engine.get('public_ip', 'N/A')}",
819
- f"[bold]Launched:[/bold] {launch_time.strftime('%Y-%m-%d %H:%M:%S')} ({format_duration(uptime)} ago)",
820
- f"[bold]Cost:[/bold] ${hourly_cost:.2f}/hour (${total_cost:.2f} total)",
851
+ started_line,
852
+ f"[bold]$/hour:[/bold] ${hourly_cost:.2f}",
821
853
  ]
822
854
 
855
+ # Disk usage (like list --detailed)
856
+ if engine["state"].lower() == "running":
857
+ disk_usage = get_disk_usage_via_ssm(engine["instance_id"]) or "-"
858
+ status_lines.append(f"[bold]Disk:[/bold] {disk_usage}")
859
+
823
860
  # Health report (only if bootstrap finished)
824
861
  if stage_val == "finished":
825
862
  try:
@@ -854,7 +891,88 @@ def engine_status(
854
891
  except Exception:
855
892
  pass
856
893
 
857
- # Idle detector status (from new API endpoint)
894
+ # Try to enrich/fallback idle-detector details from on-engine summary file via SSM
895
+ def _fetch_idle_summary_via_ssm(instance_id: str) -> Optional[Dict]:
896
+ try:
897
+ ssm = boto3.client("ssm", region_name="us-east-1")
898
+ res = ssm.send_command(
899
+ InstanceIds=[instance_id],
900
+ DocumentName="AWS-RunShellScript",
901
+ Parameters={
902
+ "commands": [
903
+ "cat /var/run/idle-detector/last_state.json 2>/dev/null || true",
904
+ ],
905
+ "executionTimeout": ["5"],
906
+ },
907
+ )
908
+ cid = res["Command"]["CommandId"]
909
+ time.sleep(1)
910
+ inv = ssm.get_command_invocation(CommandId=cid, InstanceId=instance_id)
911
+ if inv["Status"] != "Success":
912
+ return None
913
+ content = inv["StandardOutputContent"].strip()
914
+ if not content:
915
+ return None
916
+ data = json.loads(content)
917
+ # Convert last_state schema to idle_detector schema used by CLI output
918
+ idle_info: Dict[str, Any] = {"available": True}
919
+ idle_info["status"] = "active" if not data.get("idle", True) else "idle"
920
+ # thresholds if present
921
+ if isinstance(data.get("timeout_sec"), (int, float)):
922
+ idle_info["idle_threshold"] = int(data["timeout_sec"]) # seconds
923
+ # keep raw reasons for sensor display
924
+ if isinstance(data.get("reasons"), list):
925
+ idle_info["_reasons_raw"] = data["reasons"]
926
+ # derive details from sensors
927
+ for r in data.get("reasons", []):
928
+ if not r.get("active"):
929
+ continue
930
+ sensor = (r.get("sensor") or "").lower()
931
+ forensic = r.get("forensic") or {}
932
+ if sensor == "ideconnectionsensor":
933
+ cnt = forensic.get("matches")
934
+ if isinstance(cnt, int):
935
+ idle_info["ide_connections"] = {"connection_count": cnt}
936
+ else:
937
+ idle_info["ide_connections"] = {"connection_count": 1}
938
+ elif sensor == "coffeelocksensor":
939
+ rem = forensic.get("remaining_sec")
940
+ if isinstance(rem, (int, float)) and rem > 0:
941
+ idle_info["coffee_lock"] = format_duration(
942
+ timedelta(seconds=int(rem))
943
+ )
944
+ elif sensor == "activeloginsensor":
945
+ # Provide a single summarized SSH session if available
946
+ sess = {
947
+ "tty": r.get("forensic", {}).get("tty", "pts/?"),
948
+ "pid": r.get("forensic", {}).get("pid", "?"),
949
+ "idle_time": r.get("forensic", {}).get("idle_sec", 0),
950
+ "from_ip": r.get("forensic", {}).get("remote_addr", "unknown"),
951
+ }
952
+ idle_info.setdefault("ssh_sessions", []).append(sess)
953
+ return idle_info
954
+ except Exception:
955
+ return None
956
+
957
+ # Enrich missing fields or provide full fallback when API lacks details
958
+ overlay = (
959
+ _fetch_idle_summary_via_ssm(engine["instance_id"])
960
+ if not idle_detector.get("available")
961
+ or not any(
962
+ k in idle_detector
963
+ for k in ("ide_connections", "ssh_sessions", "coffee_lock")
964
+ )
965
+ else None
966
+ )
967
+ if overlay:
968
+ # If API didn't indicate availability, replace entirely; otherwise fill gaps
969
+ if not idle_detector.get("available"):
970
+ idle_detector = overlay
971
+ else:
972
+ for k, v in overlay.items():
973
+ idle_detector.setdefault(k, v)
974
+
975
+ # Idle detector status (API and/or on-engine fallback)
858
976
  if idle_detector.get("available"):
859
977
  status_lines.append("")
860
978
  status_lines.append("[bold]Idle Detector:[/bold]")
@@ -882,8 +1000,13 @@ def engine_status(
882
1000
  if ssh_sessions:
883
1001
  status_lines.append(f" • [blue]SSH Sessions ({len(ssh_sessions)}):[/blue]")
884
1002
  for session in ssh_sessions:
1003
+ idle_time = session.get("idle_time")
1004
+ if isinstance(idle_time, (int, float)):
1005
+ idle_disp = f"{int(idle_time)//60}m"
1006
+ else:
1007
+ idle_disp = str(idle_time) if idle_time else "0m"
885
1008
  status_lines.append(
886
- f" - {session['tty']} (pid {session['pid']}, idle {session['idle_time']}) from {session['from_ip']}"
1009
+ f" - {session.get('tty', 'pts/?')} (pid {session.get('pid', '?')}, idle {idle_disp}) from {session.get('from_ip', 'unknown')}"
887
1010
  )
888
1011
 
889
1012
  # IDE connections
@@ -893,6 +1016,18 @@ def engine_status(
893
1016
  f" • [magenta]🖥 IDE connected ({ide_conn['connection_count']} connections)[/magenta]"
894
1017
  )
895
1018
 
1019
+ # Sensors contributing to ACTIVE
1020
+ reasons_raw = idle_detector.get("_reasons_raw")
1021
+ if isinstance(reasons_raw, list):
1022
+ active_sensors = [r for r in reasons_raw if r.get("active")]
1023
+ if active_sensors:
1024
+ status_lines.append("")
1025
+ status_lines.append("[bold]Active Sensors:[/bold]")
1026
+ for r in active_sensors:
1027
+ sensor = r.get("sensor", "Sensor")
1028
+ reason = r.get("reason") or "active"
1029
+ status_lines.append(f" • {sensor}: {reason}")
1030
+
896
1031
  # Audit one-liner (best-effort SSM fetch)
897
1032
  try:
898
1033
  last_audit = _fetch_last_audit_via_ssm(engine["instance_id"])
dayhoff_tools/cli/main.py CHANGED
@@ -22,6 +22,7 @@ from dayhoff_tools.warehouse import (
22
22
  import_from_warehouse_typer,
23
23
  )
24
24
 
25
+
25
26
  def _get_dht_version() -> str:
26
27
  try:
27
28
  return version("dayhoff-tools")
@@ -35,7 +36,9 @@ def _get_dht_version() -> str:
35
36
  return "unknown"
36
37
 
37
38
 
38
- app = typer.Typer(help=f"Dayhoff Tools (dh) v{_get_dht_version()}\n\nUse 'dh --version' to print version and exit.")
39
+ app = typer.Typer(
40
+ help=f"Dayhoff Tools (dh) v{_get_dht_version()}\n\nUse 'dh --version' to print version and exit."
41
+ )
39
42
 
40
43
  # Utility commands
41
44
  app.command("clean")(delete_local_branch)
@@ -73,7 +76,7 @@ def _version_option(
73
76
  "-v",
74
77
  help="Print version and exit.",
75
78
  is_eager=True,
76
- )
79
+ ),
77
80
  ):
78
81
  """Global options for the dh CLI (e.g., version)."""
79
82
  if version_flag:
@@ -9,7 +9,6 @@ from pathlib import Path
9
9
 
10
10
  import toml
11
11
  import typer
12
- import yaml
13
12
 
14
13
  # Import cloud helper lazily inside functions to avoid heavy deps at module load
15
14
 
@@ -370,11 +369,15 @@ def install_dependencies(
370
369
  print("Ensuring lock file matches pyproject.mac.toml (Mac devcon)…")
371
370
  lock_cmd = ["uv", "lock"]
372
371
  print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
373
- subprocess.run(lock_cmd, check=True, capture_output=True, cwd=str(mac_uv_dir))
372
+ subprocess.run(
373
+ lock_cmd, check=True, capture_output=True, cwd=str(mac_uv_dir)
374
+ )
374
375
 
375
376
  # Sync into the active environment
376
377
  if install_project:
377
- print("Syncing dependencies into ACTIVE env and installing project [full]…")
378
+ print(
379
+ "Syncing dependencies into ACTIVE env and installing project [full]…"
380
+ )
378
381
  sync_cmd = ["uv", "sync", "--all-groups", "--active"]
379
382
  print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
380
383
  subprocess.run(sync_cmd, check=True, cwd=str(mac_uv_dir))
@@ -385,7 +388,13 @@ def install_dependencies(
385
388
  print("Project installed with 'full' extras successfully.")
386
389
  else:
387
390
  print("Syncing dependencies into ACTIVE env (project not installed)…")
388
- sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project", "--active"]
391
+ sync_cmd = [
392
+ "uv",
393
+ "sync",
394
+ "--all-groups",
395
+ "--no-install-project",
396
+ "--active",
397
+ ]
389
398
  print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
390
399
  subprocess.run(sync_cmd, check=True, cwd=str(mac_uv_dir))
391
400
  print("Dependencies synced successfully (project not installed).")
@@ -403,7 +412,13 @@ def install_dependencies(
403
412
  subprocess.run(sync_cmd, check=True)
404
413
  else:
405
414
  print("Syncing dependencies into ACTIVE env (project not installed)…")
406
- sync_cmd = ["uv", "sync", "--all-groups", "--no-install-project", "--active"]
415
+ sync_cmd = [
416
+ "uv",
417
+ "sync",
418
+ "--all-groups",
419
+ "--no-install-project",
420
+ "--active",
421
+ ]
407
422
  print(f"Running command: {BLUE}{' '.join(sync_cmd)}{RESET}")
408
423
  subprocess.run(sync_cmd, check=True)
409
424
  print("Dependencies synced successfully (project not installed).")
@@ -436,16 +451,16 @@ def update_dependencies(
436
451
  """Update dependencies to newer versions (Mac-aware, active venv friendly).
437
452
 
438
453
  - Default Action (no flags): Updates only 'dayhoff-tools' package to latest,
439
- updates the manifest's version constraint, and syncs.
454
+ updates ALL manifest files with the version constraint, and syncs.
440
455
  - Flags:
441
456
  --all/-a: Updates all dependencies (uv lock --upgrade) and syncs.
442
457
 
443
- Mac devcontainer behavior:
444
- - If STUDIO_PLATFORM=mac and `pyproject.mac.toml` exists, operate in `.mac_uv_project/`:
445
- copy `pyproject.mac.toml` to `.mac_uv_project/pyproject.toml`, run uv there, and always
446
- use `--active` for sync so installs target the active venv.
447
- - Update the constraint inside `pyproject.mac.toml`. If not found, try `pyproject.toml`.
448
- Otherwise (non-Mac), operate in repo root and also target the active venv during sync.
458
+ Cross-platform behavior:
459
+ - Always updates BOTH `pyproject.toml` and `pyproject.mac.toml` (if they exist)
460
+ to ensure version consistency across AWS and Mac platforms.
461
+ - On Mac: If STUDIO_PLATFORM=mac and `pyproject.mac.toml` exists, operates in
462
+ `.mac_uv_project/` and copies `pyproject.mac.toml` to `.mac_uv_project/pyproject.toml`.
463
+ - Always uses `--active` for sync to target the active venv.
449
464
  """
450
465
  # ANSI color codes
451
466
  BLUE = "\033[94m"
@@ -491,7 +506,7 @@ def update_dependencies(
491
506
  print(f"Running command: {BLUE}{' '.join(lock_cmd)}{RESET}")
492
507
  subprocess.run(lock_cmd, check=True, capture_output=True, cwd=uv_cwd)
493
508
 
494
- # Step 2: Update pyproject.toml only if doing the dayhoff update (default)
509
+ # Step 2: Update both manifest files if doing the dayhoff update (default)
495
510
  if run_pyproject_update:
496
511
  print(f"Reading {lock_file_path} to find new dayhoff-tools version...")
497
512
  if not lock_file_path.exists():
@@ -518,59 +533,62 @@ def update_dependencies(
518
533
  return
519
534
 
520
535
  print(f"Found dayhoff-tools version {locked_version} in lock file.")
521
- print(f"Updating {manifest_path_for_constraint} version constraint...")
522
- try:
523
- content = manifest_path_for_constraint.read_text()
524
536
 
525
- package_name = "dayhoff-tools"
526
- package_name_esc = re.escape(package_name)
537
+ # Update both manifest files to ensure consistency across platforms
538
+ manifest_files_to_update = []
539
+ if pyproject_path.exists():
540
+ manifest_files_to_update.append(pyproject_path)
541
+ if mac_manifest.exists():
542
+ manifest_files_to_update.append(mac_manifest)
527
543
 
528
- # Regex to match the dependency line, with optional extras and version spec
529
- pattern = re.compile(
530
- rf"^(\s*['\"]){package_name_esc}(\[[^]]+\])?(?:[><=~^][^'\"]*)?(['\"].*)$",
531
- re.MULTILINE,
532
- )
544
+ if not manifest_files_to_update:
545
+ print("Warning: No manifest files found to update.")
546
+ return
533
547
 
534
- new_constraint_text = f">={locked_version}"
548
+ package_name = "dayhoff-tools"
549
+ package_name_esc = re.escape(package_name)
535
550
 
536
- def _repl(match: re.Match):
537
- prefix = match.group(1)
538
- extras = match.group(2) or ""
539
- suffix = match.group(3)
540
- return (
541
- f"{prefix}{package_name}{extras}{new_constraint_text}{suffix}"
542
- )
551
+ # Regex to match the dependency line, with optional extras and version spec
552
+ pattern = re.compile(
553
+ rf"^(\s*['\"]){package_name_esc}(\[[^]]+\])?(?:[><=~^][^'\"]*)?(['\"].*)$",
554
+ re.MULTILINE,
555
+ )
543
556
 
544
- new_content, num_replacements = pattern.subn(_repl, content)
545
- if num_replacements > 0:
546
- manifest_path_for_constraint.write_text(new_content)
547
- print(
548
- f"Updated dayhoff-tools constraint in {manifest_path_for_constraint} to '{new_constraint_text}'"
549
- )
550
- else:
551
- # Fallback: try the root pyproject if we were targeting mac manifest
552
- if manifest_path_for_constraint != pyproject_path and pyproject_path.exists():
553
- content2 = pyproject_path.read_text()
554
- new_content2, n2 = pattern.subn(_repl, content2)
555
- if n2 > 0:
556
- pyproject_path.write_text(new_content2)
557
- print(
558
- f"Updated dayhoff-tools constraint in {pyproject_path} to '{new_constraint_text}'"
559
- )
560
- else:
561
- print(
562
- f"Warning: Could not find dayhoff-tools dependency line in {manifest_path_for_constraint} or {pyproject_path} to update constraint."
563
- )
557
+ new_constraint_text = f">={locked_version}"
558
+
559
+ def _repl(match: re.Match):
560
+ prefix = match.group(1)
561
+ extras = match.group(2) or ""
562
+ suffix = match.group(3)
563
+ return f"{prefix}{package_name}{extras}{new_constraint_text}{suffix}"
564
+
565
+ # Update all manifest files
566
+ updated_files = []
567
+ for manifest_file in manifest_files_to_update:
568
+ try:
569
+ print(f"Updating {manifest_file} version constraint...")
570
+ content = manifest_file.read_text()
571
+ new_content, num_replacements = pattern.subn(_repl, content)
572
+ if num_replacements > 0:
573
+ manifest_file.write_text(new_content)
574
+ print(
575
+ f"Updated dayhoff-tools constraint in {manifest_file} to '{new_constraint_text}'"
576
+ )
577
+ updated_files.append(str(manifest_file))
564
578
  else:
565
579
  print(
566
- f"Warning: Could not find dayhoff-tools dependency line in {manifest_path_for_constraint} to update constraint."
580
+ f"Warning: Could not find dayhoff-tools dependency line in {manifest_file}"
567
581
  )
568
- except FileNotFoundError:
569
- print(f"Error: {manifest_path_for_constraint} not found.")
570
- return
571
- except Exception as e:
572
- print(f"Error updating {manifest_path_for_constraint}: {e}")
573
- print("Proceeding with sync despite pyproject.toml update error.")
582
+ except FileNotFoundError:
583
+ print(f"Warning: {manifest_file} not found.")
584
+ except Exception as e:
585
+ print(f"Error updating {manifest_file}: {e}")
586
+
587
+ if not updated_files:
588
+ print(
589
+ "Warning: No manifest files were successfully updated with dayhoff-tools constraint."
590
+ )
591
+ print("Proceeding with sync despite manifest update failures.")
574
592
 
575
593
  # Step 3: Sync environment
576
594
  print("Syncing environment with updated lock file...")
@@ -584,7 +602,7 @@ def update_dependencies(
584
602
  print("All dependencies updated and environment synced successfully.")
585
603
  else: # Default case (dayhoff update)
586
604
  print(
587
- "dayhoff-tools updated, pyproject.toml modified, and environment synced successfully."
605
+ "dayhoff-tools updated, manifest files modified, and environment synced successfully."
588
606
  )
589
607
 
590
608
  except subprocess.CalledProcessError as e:
@@ -19,7 +19,9 @@ def _find_project_root() -> Path | None:
19
19
  """
20
20
  current_dir = Path.cwd().resolve()
21
21
  while current_dir != current_dir.parent:
22
- if (current_dir / ".git").is_dir() or (current_dir / "pyproject.toml").is_file():
22
+ if (current_dir / ".git").is_dir() or (
23
+ current_dir / "pyproject.toml"
24
+ ).is_file():
23
25
  return current_dir
24
26
  current_dir = current_dir.parent
25
27
  # Check the final directory in the hierarchy (e.g., '/')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.7.5
3
+ Version: 1.8.1
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
@@ -3,10 +3,10 @@ dayhoff_tools/chemistry/standardizer.py,sha256=uMn7VwHnx02nc404eO6fRuS4rsl4dvSPf
3
3
  dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P-_M,2257
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
- dayhoff_tools/cli/engine_commands.py,sha256=0syRVrJjWtRi7Y_q7MbEA5PKJ8TSXtEodHzxXu2Ymhs,102461
7
- dayhoff_tools/cli/main.py,sha256=LLMybU9KbtV_F4rwvoYAQZKTTF1nswlSZIfDMKdkh00,5925
6
+ dayhoff_tools/cli/engine_commands.py,sha256=yFloQmS3IEvoVWIQzlWKIBedb5XJPmJFsOHbW_EJH-U,108516
7
+ dayhoff_tools/cli/main.py,sha256=LoFs3SI4fdCjP4pdxEAhri-_q0dmNYupmBCRE4KbBac,5933
8
8
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
9
- dayhoff_tools/cli/utility_commands.py,sha256=q2XyNy1uMGKg95cRXv1uA4MhaUDqlDBvkQwmvRo3hnA,25865
9
+ dayhoff_tools/cli/utility_commands.py,sha256=WQTHOh1MttuxaJjl2c6zMa4x7_JuaKMQgcyotYrU3GA,25883
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
@@ -26,8 +26,8 @@ dayhoff_tools/intake/structure.py,sha256=ufN3gAodQxhnt7psK1VTQeu9rKERmo_PhoxIbB4
26
26
  dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJqE4,16456
27
27
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
28
28
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
29
- dayhoff_tools/warehouse.py,sha256=heaYc64qplgN3_1WVPFmqj53goStioWwY5NqlWc4c0s,24453
30
- dayhoff_tools-1.7.5.dist-info/METADATA,sha256=tnZl6OD70iojC4Avmej4LaBhAAQO2afIzZ4PBj6BEws,2914
31
- dayhoff_tools-1.7.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
- dayhoff_tools-1.7.5.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
- dayhoff_tools-1.7.5.dist-info/RECORD,,
29
+ dayhoff_tools/warehouse.py,sha256=UETBtZD3r7WgvURqfGbyHlT7cxoiVq8isjzMuerKw8I,24475
30
+ dayhoff_tools-1.8.1.dist-info/METADATA,sha256=gwCqNlp8VZ8npiW7RY6kbQ5r-tYUCubDruy38BvdsFY,2914
31
+ dayhoff_tools-1.8.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ dayhoff_tools-1.8.1.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
+ dayhoff_tools-1.8.1.dist-info/RECORD,,