Skip to content

Commit

Permalink
Pin dependencies during hatch builds
Browse files Browse the repository at this point in the history
  • Loading branch information
techdragon committed Nov 25, 2024
1 parent d5205d4 commit d19f7bd
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 7 deletions.
69 changes: 69 additions & 0 deletions hatch_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
import tomlkit
import pathlib
from pprint import pprint


class PinDuringBuild(BuildHookInterface):
PLUGIN_NAME = "pin-during-build"

original_dependencies: list = None
made_changes: bool = False

def initialize(self, version, build_data):
# Get the hook configuration and do nothing if not configured correctly.
if 'config' not in self.config:
if "pinned_dependencies" not in self.config['config']:
print(f"Plugin {self.PLUGIN_NAME} is not configured correctly.")
pprint(self.config)
return super().initialize(version, build_data)

# Get the pinned dependencies, this is a list of package specifier strings that are the dependencies to pin.
pinned_dependencies = self.config["config"]["pinned_dependencies"]

# Load the toml file
pyproject_file = pathlib.Path("pyproject.toml")
toml_data = tomlkit.loads(pyproject_file.read_text())
print(type(toml_data))
pprint(toml_data)
for key in toml_data:
print(key)

# Get the dependencies from the toml file, this is a list of package specifier strings.
dependencies = toml_data["project"]["dependencies"]

# Save the original dependencies for later.
self.original_dependencies = dependencies.copy()

change_count = 0

# Overlay the pinned dependencies, replacing dependencies if they already exist.
for pinned_dep in pinned_dependencies:
pinned_dep_name = pinned_dep.split(" ")[0]
for dep in dependencies:
dep_name = dep.split(" ")[0]
# If the dependency is already in the list, replace it with the pinned version.
if dep_name == pinned_dep_name:
index = dependencies.index(dep)
dependencies[index] = pinned_dep
change_count += 1
break

# If we made any changes, write the changes back to the pyroject.toml file for the build.
if change_count > 0:
# Write the changes back to the file.
pyproject_file.write_text(tomlkit.dumps(toml_data))
print(f"Updated {change_count} dependencies to pinned versions.")
# Set a flag to restore the original dependencies after the build.
self.made_changes = True

return super().initialize(version, build_data)

def finalize(self, version, build_data, artefact_path):
# If we have made changes restore the original dependencies after the build to keep the git repo clean.
if self.made_changes:
pyproject_file = pathlib.Path("pyproject.toml")
toml_data = tomlkit.loads(pyproject_file.read_text())
toml_data["project"]["dependencies"] = self.original_dependencies
pyproject_file.write_text(tomlkit.dumps(toml_data))
print("Restored original dependencies.")
20 changes: 13 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ classifiers = [
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
]
dependencies = [
"xarray",
"pandas",
"scipy",
"bottleneck",
"scikit-learn",
]
dependencies = ["xarray", "pandas", "scipy", "bottleneck", "scikit-learn"]

[project.optional-dependencies]
dev = [
Expand Down Expand Up @@ -77,6 +71,18 @@ exclude = [
"/docs/",
"/tests/"
]
dependencies = [
"tomlkit",
]

[tool.hatch.build.hooks.custom.config]
pinned_dependencies = [
"xarray ~= 2024.1",
"pandas ~= 2.0",
"scipy ~= 1.1",
"bottleneck ~= 1.3",
"scikit-learn ~= 1.4",
]

[tool.hatch.version]
path = "src/scores/__init__.py"
Expand Down

0 comments on commit d19f7bd

Please sign in to comment.