Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/groundhog_hpc/templates/shell_command.sh.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ mkdir -p "$UV_CACHE_DIR" "$UV_PYTHON_INSTALL_DIR"
{% if log_level %}
# Local override - use value from dispatching environment
export GROUNDHOG_LOG_LEVEL="{{ log_level }}"
export RUST_LOG=uv="${{GROUNDHOG_LOG_LEVEL}}"
{% else %}
{% raw %}
# Respect remote environment if set, otherwise default to WARNING
export GROUNDHOG_LOG_LEVEL="${{GROUNDHOG_LOG_LEVEL:-WARNING}}"
export RUST_LOG=uv="${{GROUNDHOG_LOG_LEVEL:-WARNING}}"
{% endraw %}
{% endif %}

Expand All @@ -57,6 +59,7 @@ cat > {{ script_name }}.in << 'PAYLOAD_EOF'
PAYLOAD_EOF

"$UV_BIN" run --with {{ version_spec }} \
--exclude-newer-package groundhog-hpc={{ groundhog_timestamp }} \
{{ runner_name }}.py

echo "__GROUNDHOG_RESULT__"
Expand Down
6 changes: 6 additions & 0 deletions src/groundhog_hpc/templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import logging
import os
import uuid
from datetime import datetime, timezone
from hashlib import sha1
from pathlib import Path

Expand Down Expand Up @@ -74,6 +75,10 @@ def template_shell_command(script_path: str, function_name: str, payload: str) -
version_spec = get_groundhog_version_spec()
logger.debug(f"Using groundhog version spec: {version_spec}")

# Generate timestamp for groundhog-hpc exclude-newer override
# This allows groundhog to bypass user's exclude-newer restrictions
groundhog_timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

# Load runner template
templates_dir = Path(__file__).parent / "templates"
jinja_env = Environment(loader=FileSystemLoader(templates_dir))
Expand Down Expand Up @@ -106,6 +111,7 @@ def template_shell_command(script_path: str, function_name: str, payload: str) -
version_spec=version_spec,
payload=payload,
log_level=local_log_level,
groundhog_timestamp=groundhog_timestamp,
)

logger.debug(f"Generated shell command ({len(shell_command_string)} chars)")
Expand Down
35 changes: 35 additions & 0 deletions tests/test_templating.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,41 @@ def func2():
# They should have different hashes since content differs
assert command1 != command2

def test_includes_exclude_newer_package_flag(self, tmp_path):
"""Test that shell command always includes --exclude-newer-package for groundhog-hpc.

This prevents user's exclude-newer settings from blocking groundhog installation.
"""
script_path = tmp_path / "script.py"
script_content = """# /// script
# requires-python = ">=3.12"
# dependencies = []
#
# [tool.uv]
# exclude-newer = "2020-01-01T00:00:00Z"
# ///

import groundhog_hpc as hog

@hog.function()
def func():
return 1
"""
script_path.write_text(script_content)

shell_command = template_shell_command(str(script_path), "func", "test_payload")

# Should include the package-specific exclude-newer override
assert "--exclude-newer-package groundhog-hpc=" in shell_command
# Timestamp should be in ISO format (basic validation)
import re

match = re.search(
r"--exclude-newer-package groundhog-hpc=(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z)",
shell_command,
)
assert match, "exclude-newer-package timestamp should be in ISO 8601 format"


class TestDottedQualnames:
"""Test that templating handles dotted qualnames (class methods)."""
Expand Down
Loading