dayhoff-tools 1.14.15__tar.gz → 1.15.0__tar.gz

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.
Files changed (77) hide show
  1. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/PKG-INFO +1 -1
  2. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/main.py +2 -59
  3. dayhoff_tools-1.15.0/dayhoff_tools/cli/utility_commands.py +262 -0
  4. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/pyproject.toml +1 -1
  5. dayhoff_tools-1.14.15/dayhoff_tools/cli/utility_commands.py +0 -1150
  6. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/README.md +0 -0
  7. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/__init__.py +0 -0
  8. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/batch/__init__.py +0 -0
  9. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/batch/workers/__init__.py +0 -0
  10. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/batch/workers/base.py +0 -0
  11. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/batch/workers/boltz.py +0 -0
  12. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/batch/workers/embed_t5.py +0 -0
  13. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/chemistry/standardizer.py +0 -0
  14. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/chemistry/utils.py +0 -0
  15. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/__init__.py +0 -0
  16. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/__init__.py +0 -0
  17. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/aws_batch.py +0 -0
  18. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/__init__.py +0 -0
  19. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/boltz.py +0 -0
  20. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/cancel.py +0 -0
  21. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/clean.py +0 -0
  22. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/embed_t5.py +0 -0
  23. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/finalize.py +0 -0
  24. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/list_jobs.py +0 -0
  25. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/local.py +0 -0
  26. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/logs.py +0 -0
  27. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/retry.py +0 -0
  28. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/status.py +0 -0
  29. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/commands/submit.py +0 -0
  30. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/job_id.py +0 -0
  31. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/batch/manifest.py +0 -0
  32. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/cloud_commands.py +0 -0
  33. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/__init__.py +0 -0
  34. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/engine_core.py +0 -0
  35. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/engine_lifecycle.py +0 -0
  36. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/engine_maintenance.py +0 -0
  37. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/engine_management.py +0 -0
  38. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/shared.py +0 -0
  39. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engine1/studio_commands.py +0 -0
  40. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/__init__.py +0 -0
  41. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/api_client.py +0 -0
  42. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/auth.py +0 -0
  43. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/engine-studio-cli.md +0 -0
  44. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/engine_commands.py +0 -0
  45. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/progress.py +0 -0
  46. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/cli-simulators.md +0 -0
  47. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/demo.sh +0 -0
  48. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/engine_list_simulator.py +0 -0
  49. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/engine_status_simulator.py +0 -0
  50. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/idle_status_simulator.py +0 -0
  51. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/simulator_utils.py +0 -0
  52. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/studio_list_simulator.py +0 -0
  53. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/simulators/studio_status_simulator.py +0 -0
  54. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/ssh_config.py +0 -0
  55. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/engines_studios/studio_commands.py +0 -0
  56. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/github_commands.py +0 -0
  57. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/cli/swarm_commands.py +0 -0
  58. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/base.py +0 -0
  59. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/deploy_aws.py +0 -0
  60. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
  61. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/deploy_utils.py +0 -0
  62. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/job_runner.py +0 -0
  63. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/processors.py +0 -0
  64. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/deployment/swarm.py +0 -0
  65. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/embedders.py +0 -0
  66. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/fasta.py +0 -0
  67. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/file_ops.py +0 -0
  68. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/h5.py +0 -0
  69. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/gcp.py +0 -0
  70. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/gtdb.py +0 -0
  71. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/kegg.py +0 -0
  72. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/mmseqs.py +0 -0
  73. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/structure.py +0 -0
  74. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/intake/uniprot.py +0 -0
  75. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/logs.py +0 -0
  76. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/sqlite.py +0 -0
  77. {dayhoff_tools-1.14.15 → dayhoff_tools-1.15.0}/dayhoff_tools/warehouse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dayhoff-tools
3
- Version: 1.14.15
3
+ Version: 1.15.0
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
@@ -5,19 +5,13 @@ from importlib.metadata import PackageNotFoundError, version
5
5
 
6
6
  import typer
7
7
  from dayhoff_tools.cli.cloud_commands import aws_app, gcp_app
8
+ from dayhoff_tools.cli.engine1 import engine_app as engine1_app
9
+ from dayhoff_tools.cli.engine1 import studio_app as studio1_app
8
10
  from dayhoff_tools.cli.github_commands import gh_app
9
- from dayhoff_tools.cli.engine1 import (
10
- engine_app as engine1_app,
11
- studio_app as studio1_app,
12
- )
13
11
  from dayhoff_tools.cli.utility_commands import (
14
- add_dependency,
15
12
  build_and_upload_wheel,
16
13
  delete_local_branch,
17
- remove_dependency,
18
- sync_with_toml,
19
14
  test_github_actions_locally,
20
- update_dependencies,
21
15
  )
22
16
  from dayhoff_tools.warehouse import (
23
17
  _warn_if_gcp_default_sa,
@@ -48,19 +42,6 @@ app = typer.Typer(
48
42
  # Utility commands
49
43
  app.command("clean")(delete_local_branch)
50
44
 
51
- # Dependency Management
52
- app.command(
53
- "tomlsync",
54
- help="Sync environment with platform-specific TOML manifest (install/update dependencies).",
55
- )(sync_with_toml)
56
- app.command("add", help="Add a dependency to all platform manifests.")(add_dependency)
57
- app.command("remove", help="Remove a dependency from all platform manifests.")(
58
- remove_dependency
59
- )
60
- app.command("update", help="Update dayhoff-tools (or all deps) and sync environment.")(
61
- update_dependencies
62
- )
63
-
64
45
  # Other Utilities
65
46
  app.command("gha")(test_github_actions_locally)
66
47
  app.command("wadd")(add_to_warehouse_typer)
@@ -183,44 +164,6 @@ def build_and_upload_wheel_command(
183
164
  build_and_upload_wheel(bump_part=bump)
184
165
 
185
166
 
186
- # Use lazy loading for slow-loading swarm commands
187
- @app.command("reset")
188
- def reset_wrapper(
189
- firestore_collection: str = typer.Option(prompt=True),
190
- old_status: str = typer.Option(default="failed", prompt=True),
191
- new_status: str = typer.Option(default="available", prompt=True),
192
- delete_old: bool = typer.Option(default=True, prompt=True),
193
- ):
194
- """Find all the documents in the database with a given status, and
195
- make a new document with the same name and a new status."""
196
- from dayhoff_tools.cli.swarm_commands import reset_failed_cards
197
-
198
- reset_failed_cards(firestore_collection, old_status, new_status, delete_old)
199
-
200
-
201
- @app.command("zombie")
202
- def zombie_wrapper(
203
- firestore_collection: str = typer.Option(prompt=True),
204
- delete_old: bool = typer.Option(default=True, prompt=True),
205
- minutes_threshold: int = typer.Option(default=60, prompt=True),
206
- ):
207
- """Find all the documents in the database with status "assigned", and "last_updated"
208
- older than a specified threshold, and make a new "available" document for them."""
209
- from dayhoff_tools.cli.swarm_commands import reset_zombie_cards
210
-
211
- reset_zombie_cards(firestore_collection, delete_old, minutes_threshold)
212
-
213
-
214
- @app.command("status")
215
- def status_wrapper(
216
- firestore_collection: str = typer.Argument(),
217
- ):
218
- """Count the various statuses of items in a given collection."""
219
- from dayhoff_tools.cli.swarm_commands import get_firestore_collection_status
220
-
221
- get_firestore_collection_status(firestore_collection)
222
-
223
-
224
167
  # Deployment commands - use lazy loading but preserve argument passing
225
168
  @app.command("deploy")
226
169
  def deploy_command(
@@ -0,0 +1,262 @@
1
+ """CLI commands common to all repos."""
2
+
3
+ import os
4
+ import re
5
+ import shutil
6
+ import subprocess
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ import toml
11
+ import typer
12
+
13
+ # Import cloud helper lazily inside functions to avoid heavy deps at module load
14
+
15
+
16
+ def test_github_actions_locally():
17
+ """Run the script test_pytest_in_github_actions_container.sh.sh."""
18
+ script_path = ".devcontainer/scripts/test_pytest_in_github_actions_container.sh"
19
+
20
+ try:
21
+ subprocess.check_call(["bash", script_path])
22
+ print("Script ran successfully!")
23
+ except subprocess.CalledProcessError as e:
24
+ print(f"Error occurred while running the script: {e}")
25
+
26
+
27
+ def delete_local_branch(branch_name: str, folder_path: str):
28
+ """Delete a local Git branch after fetching with pruning.
29
+
30
+ Args:
31
+ branch_name: Name of the branch to delete
32
+ folder_path: Path to the git repository folder
33
+ """
34
+ try:
35
+ # Store current working directory
36
+ original_dir = os.getcwd()
37
+
38
+ # Change to the specified directory
39
+ os.chdir(folder_path)
40
+ print(f"Changed to directory: {folder_path}")
41
+
42
+ # Delete the specified branch
43
+ delete_branch_cmd = ["git", "branch", "-D", branch_name]
44
+ subprocess.run(delete_branch_cmd, check=True)
45
+ print(f"Deleted branch: {branch_name}")
46
+
47
+ # Fetch changes from the remote repository and prune obsolete branches
48
+ fetch_prune_cmd = ["git", "fetch", "-p"]
49
+ subprocess.run(fetch_prune_cmd, check=True)
50
+ print("Fetched changes and pruned obsolete branches")
51
+
52
+ except subprocess.CalledProcessError as e:
53
+ print(f"Error occurred while running Git commands: {e}")
54
+ finally:
55
+ # Always return to the original directory
56
+ os.chdir(original_dir)
57
+
58
+
59
+ def get_current_version_from_toml(file_path="pyproject.toml"):
60
+ """Reads the version from a pyproject.toml file."""
61
+ try:
62
+ with open(file_path, "r") as f:
63
+ content = f.read()
64
+ version_match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE)
65
+ if version_match:
66
+ return version_match.group(1)
67
+ else:
68
+ raise ValueError(f"Could not find version string in {file_path}")
69
+ except FileNotFoundError:
70
+ raise FileNotFoundError(f"{file_path} not found.")
71
+ except Exception as e:
72
+ raise e
73
+
74
+
75
+ def build_and_upload_wheel(bump_part: str = "patch"):
76
+ """Build a Python wheel and upload to PyPI using UV.
77
+
78
+ Automatically increments the version number in pyproject.toml before building
79
+ based on the bump_part argument ('major', 'minor', 'patch').
80
+
81
+ Expects PyPI authentication to be configured via the environment variable:
82
+ - UV_PUBLISH_TOKEN
83
+
84
+ Args:
85
+ bump_part (str): The part of the version to bump. Defaults to 'patch'.
86
+ """
87
+ if bump_part not in ["major", "minor", "patch"]:
88
+ print(
89
+ f"Error: Invalid bump_part '{bump_part}'. Must be 'major', 'minor', or 'patch'."
90
+ )
91
+ return
92
+
93
+ # ANSI color codes
94
+ BLUE = "\033[94m"
95
+ RESET = "\033[0m"
96
+
97
+ # --- Authentication Setup ---
98
+ token = os.environ.get("UV_PUBLISH_TOKEN")
99
+
100
+ if not token:
101
+ print("Error: PyPI authentication not configured.")
102
+ print(
103
+ "Please set the UV_PUBLISH_TOKEN environment variable with your PyPI API token."
104
+ )
105
+ return
106
+
107
+ # Build the command with token authentication
108
+ # IMPORTANT: Mask token for printing
109
+ publish_cmd_safe_print = ["uv", "publish", "--token", "*****"]
110
+ publish_cmd = ["uv", "publish", "--token", token]
111
+ print("Using UV_PUBLISH_TOKEN for authentication.")
112
+
113
+ # Use standard pyproject.toml
114
+ pyproject_path = "pyproject.toml"
115
+ if not Path(pyproject_path).exists():
116
+ print("Error: pyproject.toml not found in current directory.")
117
+ return
118
+ current_version = None # Initialize in case the first try block fails
119
+
120
+ try:
121
+ # --- Clean dist directory ---
122
+ dist_dir = Path("dist")
123
+ if dist_dir.exists():
124
+ print(f"Removing existing build directory: {dist_dir}")
125
+ shutil.rmtree(dist_dir)
126
+ # --- End Clean dist directory ---
127
+
128
+ # --- Version Bumping Logic ---
129
+ current_version = get_current_version_from_toml(pyproject_path)
130
+ print(f"Current version: {current_version}")
131
+
132
+ try:
133
+ major, minor, patch = map(int, current_version.split("."))
134
+ except ValueError:
135
+ print(
136
+ f"Error: Could not parse version '{current_version}'. Expected format X.Y.Z"
137
+ )
138
+ return
139
+
140
+ if bump_part == "major":
141
+ major += 1
142
+ minor = 0
143
+ patch = 0
144
+ elif bump_part == "minor":
145
+ minor += 1
146
+ patch = 0
147
+ else: # patch
148
+ patch += 1
149
+
150
+ new_version = f"{major}.{minor}.{patch}"
151
+ print(f"Bumping {bump_part} version to: {new_version}")
152
+
153
+ # Read pyproject.toml
154
+ with open(pyproject_path, "r") as f:
155
+ content = f.read()
156
+
157
+ # Replace the version string
158
+ pattern = re.compile(
159
+ f'^version\s*=\s*"{re.escape(current_version)}"', re.MULTILINE
160
+ )
161
+ new_content, num_replacements = pattern.subn(
162
+ f'version = "{new_version}"', content
163
+ )
164
+
165
+ if num_replacements == 0:
166
+ print(
167
+ f"Error: Could not find 'version = \"{current_version}\"' in {pyproject_path}"
168
+ )
169
+ return # Exit before build/publish if version wasn't updated
170
+ if num_replacements > 1:
171
+ print(
172
+ f"Warning: Found multiple version lines for '{current_version}'. Only the first was updated."
173
+ )
174
+
175
+ # Write the updated content back
176
+ with open(pyproject_path, "w") as f:
177
+ f.write(new_content)
178
+ print(f"Updated {pyproject_path} with version {new_version}")
179
+
180
+ # --- End Version Bumping Logic ---
181
+
182
+ # Build wheel and sdist
183
+ build_cmd = ["uv", "build"]
184
+ print(f"Running command: {BLUE}{' '.join(build_cmd)}{RESET}")
185
+ subprocess.run(build_cmd, check=True)
186
+
187
+ # Upload to PyPI
188
+ print(f"Running command: {BLUE}{' '.join(publish_cmd_safe_print)}{RESET}")
189
+ subprocess.run(publish_cmd, check=True)
190
+
191
+ print(f"Successfully built and uploaded version {new_version} to PyPI")
192
+
193
+ # Re-install DHT in Pixi environment when building from DHT itself
194
+ try:
195
+ proj_toml = toml.load(pyproject_path)
196
+ proj_name = proj_toml.get("project", {}).get("name")
197
+ if proj_name == "dayhoff-tools":
198
+ print("Re-installing dayhoff-tools into the Pixi environment...")
199
+ reinstall_cmd = ["pixi", "install"]
200
+ print(f"Running command: {BLUE}{' '.join(reinstall_cmd)}{RESET}")
201
+ subprocess.run(reinstall_cmd, check=True)
202
+ print("dayhoff-tools reinstalled in the Pixi environment.")
203
+ except subprocess.CalledProcessError as e:
204
+ print(f"Warning: Failed to reinstall dayhoff-tools locally: {e}")
205
+ except Exception:
206
+ pass # Not dayhoff-tools or couldn't read toml
207
+
208
+ except FileNotFoundError:
209
+ print(f"Error: {pyproject_path} not found.")
210
+ # No version change happened, so no rollback needed
211
+ except subprocess.CalledProcessError as e:
212
+ print(f"Error during build/upload: {e}")
213
+ # Attempt to roll back version change only if it was bumped successfully
214
+ if current_version and new_version:
215
+ try:
216
+ print(
217
+ f"Attempting to revert version in {pyproject_path} back to {current_version}..."
218
+ )
219
+ with open(pyproject_path, "r") as f:
220
+ content_revert = f.read()
221
+ # Use new_version in pattern for reverting
222
+ pattern_revert = re.compile(
223
+ f'^version\s*=\s*"{re.escape(new_version)}"', re.MULTILINE
224
+ )
225
+ reverted_content, num_revert = pattern_revert.subn(
226
+ f'version = "{current_version}"', content_revert
227
+ )
228
+ if num_revert > 0:
229
+ with open(pyproject_path, "w") as f:
230
+ f.write(reverted_content)
231
+ print(f"Successfully reverted version in {pyproject_path}.")
232
+ else:
233
+ print(
234
+ f"Warning: Could not find version {new_version} to revert in {pyproject_path}."
235
+ )
236
+
237
+ except Exception as revert_e:
238
+ print(f"Warning: Failed to revert version change: {revert_e}")
239
+ except Exception as e:
240
+ print(f"An unexpected error occurred: {e}")
241
+ # Attempt rollback if version was bumped
242
+ if current_version and "new_version" in locals() and new_version:
243
+ try:
244
+ print(f"Attempting to revert version back to {current_version}...")
245
+ with open(pyproject_path, "r") as f:
246
+ content_revert = f.read()
247
+ pattern_revert = re.compile(
248
+ f'^version\\s*=\\s*"{re.escape(new_version)}"', re.MULTILINE
249
+ )
250
+ reverted_content, num_revert = pattern_revert.subn(
251
+ f'version = "{current_version}"', content_revert
252
+ )
253
+ if num_revert > 0:
254
+ with open(pyproject_path, "w") as f:
255
+ f.write(reverted_content)
256
+ print("Successfully reverted version in pyproject.toml.")
257
+ else:
258
+ print(f"Warning: Could not find version {new_version} to revert.")
259
+ except Exception as revert_e:
260
+ print(f"Warning: Failed to revert version change: {revert_e}")
261
+
262
+
@@ -11,7 +11,7 @@ build-backend = "poetry.core.masonry.api"
11
11
 
12
12
  [project]
13
13
  name = "dayhoff-tools"
14
- version = "1.14.15"
14
+ version = "1.15.0"
15
15
  description = "Common tools for all the repos at Dayhoff Labs"
16
16
  authors = [
17
17
  {name = "Daniel Martin-Alarcon", email = "dma@dayhofflabs.com"}