diff --git a/src/groundhog_hpc/templates/shell_command.sh.jinja b/src/groundhog_hpc/templates/shell_command.sh.jinja index 59f77b3..08b2740 100644 --- a/src/groundhog_hpc/templates/shell_command.sh.jinja +++ b/src/groundhog_hpc/templates/shell_command.sh.jinja @@ -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 %} @@ -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__" diff --git a/src/groundhog_hpc/templating.py b/src/groundhog_hpc/templating.py index f5823b0..4303009 100644 --- a/src/groundhog_hpc/templating.py +++ b/src/groundhog_hpc/templating.py @@ -10,6 +10,7 @@ import logging import os import uuid +from datetime import datetime, timezone from hashlib import sha1 from pathlib import Path @@ -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)) @@ -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)") diff --git a/tests/test_templating.py b/tests/test_templating.py index 1de25e6..61154b5 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -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)."""