groundhog-hpc 0.5.5__tar.gz → 0.5.6__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 (33) hide show
  1. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/PKG-INFO +1 -1
  2. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/run.py +3 -2
  3. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/compute.py +7 -7
  4. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/models.py +0 -3
  5. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/pep723.py +1 -1
  6. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/decorators.py +7 -10
  7. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/function.py +10 -17
  8. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/templates/init_script.py.jinja +1 -2
  9. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/.gitignore +0 -0
  10. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/LICENSE +0 -0
  11. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/README.md +0 -0
  12. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/pyproject.toml +0 -0
  13. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/__init__.py +0 -0
  14. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/__init__.py +0 -0
  15. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/add.py +0 -0
  16. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/init.py +0 -0
  17. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/main.py +0 -0
  18. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/remove.py +0 -0
  19. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/app/utils.py +0 -0
  20. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/__init__.py +0 -0
  21. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/defaults.py +0 -0
  22. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/endpoints.py +0 -0
  23. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/configuration/resolver.py +0 -0
  24. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/console.py +0 -0
  25. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/errors.py +0 -0
  26. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/future.py +0 -0
  27. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/harness.py +0 -0
  28. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/import_hook.py +0 -0
  29. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/serialization.py +0 -0
  30. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/templates/groundhog_run.py.jinja +0 -0
  31. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/templates/shell_command.sh.jinja +0 -0
  32. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/templating.py +0 -0
  33. {groundhog_hpc-0.5.5 → groundhog_hpc-0.5.6}/src/groundhog_hpc/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: groundhog-hpc
3
- Version: 0.5.5
3
+ Version: 0.5.6
4
4
  Summary: Iterative HPC function development. As many 'first tries' as you need.
5
5
  Author-email: Owen Price Skelly <OwenPriceSkelly@uchicago.edu>
6
6
  License: MIT
@@ -92,8 +92,9 @@ def run(
92
92
  except RemoteExecutionError as e:
93
93
  if e.returncode == 124:
94
94
  typer.echo(
95
- "Remote execution failed (timed out - try "
96
- "increasing walltime for long running jobs)",
95
+ "Remote execution failed: (exit code 124 - timed out). \nTry increasing walltime for "
96
+ "long running jobs by setting my_function.walltime (in seconds) "
97
+ "before invoking my_function.remote/submit()",
97
98
  err=True,
98
99
  )
99
100
  raise
@@ -44,7 +44,10 @@ def _get_compute_client() -> Client:
44
44
 
45
45
 
46
46
  def script_to_submittable(
47
- script_path: str, function_name: str, payload: str
47
+ script_path: str,
48
+ function_name: str,
49
+ payload: str,
50
+ walltime: int | float | None = None,
48
51
  ) -> ShellFunction:
49
52
  """Convert a user script and function name into a Globus Compute ShellFunction.
50
53
 
@@ -52,6 +55,7 @@ def script_to_submittable(
52
55
  script_path: Path to the Python script containing the function
53
56
  function_name: Name of the function to execute remotely
54
57
  payload: Serialized arguments string
58
+ walltime: Optional maximum execution time in seconds for ShellFunction timeout
55
59
 
56
60
  Returns:
57
61
  A ShellFunction ready to be submitted to a Globus Compute executor
@@ -60,7 +64,7 @@ def script_to_submittable(
60
64
 
61
65
  shell_command = template_shell_command(script_path, function_name, payload)
62
66
  shell_function = gc.ShellFunction(
63
- shell_command, name=function_name.replace(".", "_")
67
+ shell_command, name=function_name.replace(".", "_"), walltime=walltime
64
68
  )
65
69
  return shell_function
66
70
 
@@ -82,12 +86,8 @@ def submit_to_executor(
82
86
  """
83
87
  import globus_compute_sdk as gc
84
88
 
85
- # Extract walltime and set it on the shell function
86
- config = user_endpoint_config.copy()
87
- if "walltime" in config:
88
- shell_function.walltime = config.pop("walltime")
89
-
90
89
  # Validate config against endpoint schema and filter out unexpected keys
90
+ config = user_endpoint_config.copy()
91
91
  if schema := get_endpoint_schema(endpoint):
92
92
  expected_keys = set(schema.get("properties", {}).keys())
93
93
  unexpected_keys = set(config.keys()) - expected_keys
@@ -24,12 +24,10 @@ class EndpointConfig(BaseModel, extra="allow"):
24
24
 
25
25
  Attributes:
26
26
  endpoint: Globus Compute endpoint UUID (required for base configs)
27
- walltime: Maximum execution time in seconds (must be positive)
28
27
  worker_init: Shell commands to run in worker initialization
29
28
  """
30
29
 
31
30
  endpoint: str | UUID
32
- walltime: int | None = Field(None, gt=0)
33
31
  worker_init: str | None = None
34
32
 
35
33
 
@@ -50,7 +48,6 @@ class EndpointVariant(BaseModel, extra="allow"):
50
48
  """
51
49
 
52
50
  endpoint: None = None
53
- walltime: int | None = Field(None, gt=0)
54
51
  worker_init: str | None = None
55
52
 
56
53
  @model_validator(mode="before")
@@ -39,7 +39,7 @@ def read_pep723(script: str) -> Pep723Metadata | None:
39
39
 
40
40
  Raises:
41
41
  ValueError: If multiple 'script' metadata blocks are found
42
- ValidationError: If metadata contains invalid configuration (e.g., negative walltime)
42
+ ValidationError: If metadata contains invalid configuration
43
43
  """
44
44
  name = "script"
45
45
  matches = list(
@@ -45,7 +45,6 @@ def harness() -> Callable[[FunctionType], Harness]:
45
45
 
46
46
  def function(
47
47
  endpoint: str | None = None,
48
- walltime: int | None = None,
49
48
  **user_endpoint_config: Any,
50
49
  ) -> Callable[[FunctionType], Function]:
51
50
  """Decorator to mark a function for remote execution on Globus Compute.
@@ -56,17 +55,17 @@ def function(
56
55
  - Submitted asynchronously: func.submit(args)
57
56
 
58
57
  Args:
59
- endpoint: Globus Compute endpoint UUID
60
- walltime: Maximum execution time in seconds
58
+ endpoint: Globus Compute endpoint UUID or named endpoint from
59
+ `[tool.hog.<name>]` PEP 723 metadata
61
60
  **user_endpoint_config: Options to pass through to the Executor as
62
- user_endpoint_config (e.g. account, partition, etc)
61
+ user_endpoint_config (e.g. account, partition, walltime, etc)
63
62
 
64
63
  Returns:
65
64
  A decorator function that wraps the function as a Function instance
66
65
 
67
66
  Example:
68
67
  ```python
69
- @hog.function(endpoint="my-remote-endpoint-uuid", walltime=300)
68
+ @hog.function(endpoint="my-remote-endpoint-uuid", account='my-account')
70
69
  def train_model(data):
71
70
  # This runs on the remote HPC cluster
72
71
  model = train(data)
@@ -81,7 +80,7 @@ def function(
81
80
  """
82
81
 
83
82
  def decorator(func: FunctionType) -> Function:
84
- wrapper = Function(func, endpoint, walltime, **user_endpoint_config)
83
+ wrapper = Function(func, endpoint, **user_endpoint_config)
85
84
  functools.update_wrapper(wrapper, func)
86
85
  return wrapper
87
86
 
@@ -90,7 +89,6 @@ def function(
90
89
 
91
90
  def method(
92
91
  endpoint: str | None = None,
93
- walltime: int | None = None,
94
92
  **user_endpoint_config: Any,
95
93
  ) -> Callable[[FunctionType], Method]:
96
94
  """Decorator to mark a class method for remote execution on Globus Compute.
@@ -105,9 +103,8 @@ def method(
105
103
 
106
104
  Args:
107
105
  endpoint: Globus Compute endpoint UUID
108
- walltime: Maximum execution time in seconds
109
106
  **user_endpoint_config: Options to pass through to the Executor as
110
- user_endpoint_config (e.g. account, partition, etc)
107
+ user_endpoint_config (e.g. account, partition, walltime, etc)
111
108
 
112
109
  Returns:
113
110
  A decorator function that wraps the function as a Method instance
@@ -137,7 +134,7 @@ def method(
137
134
  stacklevel=2,
138
135
  )
139
136
 
140
- wrapper = Method(func, endpoint, walltime, **user_endpoint_config)
137
+ wrapper = Method(func, endpoint, **user_endpoint_config)
141
138
  functools.update_wrapper(wrapper, func)
142
139
  return wrapper
143
140
 
@@ -51,15 +51,13 @@ class Function:
51
51
 
52
52
  Attributes:
53
53
  endpoint: Default Globus Compute endpoint UUID or None to use resolved config
54
- walltime: Default walltime in seconds for remote execution or None to use resolved config
55
- default_user_endpoint_config: Default endpoint configuration (e.g., worker_init)
54
+ default_user_endpoint_config: Default endpoint configuration (e.g., worker_init, walltime)
56
55
  """
57
56
 
58
57
  def __init__(
59
58
  self,
60
59
  func: FunctionType,
61
60
  endpoint: str | None = None,
62
- walltime: int | None = None,
63
61
  **user_endpoint_config: Any,
64
62
  ) -> None:
65
63
  """Initialize a Function wrapper.
@@ -67,15 +65,18 @@ class Function:
67
65
  Args:
68
66
  func: The Python function to wrap
69
67
  endpoint: Globus Compute endpoint UUID or named endpoint from `[tool.hog.<name>]` PEP 723
70
- walltime: Maximum execution time in seconds (can also be set in config)
71
68
  **user_endpoint_config: Additional endpoint configuration to pass to
72
- Globus Compute Executor (e.g., worker_init commands)
69
+ Globus Compute Executor (e.g., worker_init commands, walltime)
73
70
  """
74
71
  self._script_path: str | None = None
75
72
  self.endpoint: str | None = endpoint
76
- self.walltime: int | None = walltime
77
73
  self.default_user_endpoint_config: dict[str, Any] = user_endpoint_config
78
74
 
75
+ # ShellFunction walltime - always None here to prevent conflicts with a
76
+ # 'walltime' endpoint config, but the attribute exists as an escape
77
+ # hatch if users need to set it after the function's been created
78
+ self.walltime: int | float | None = None
79
+
79
80
  self._local_function: FunctionType = func
80
81
  self._config_resolver: ConfigResolver | None = None
81
82
 
@@ -103,7 +104,6 @@ class Function:
103
104
  self,
104
105
  *args: Any,
105
106
  endpoint: str | None = None,
106
- walltime: int | None = None,
107
107
  user_endpoint_config: dict[str, Any] | None = None,
108
108
  **kwargs: Any,
109
109
  ) -> GroundhogFuture:
@@ -112,7 +112,6 @@ class Function:
112
112
  Args:
113
113
  *args: Positional arguments to pass to the function
114
114
  endpoint: Globus Compute endpoint UUID (overrides decorator default)
115
- walltime: Maximum execution time in seconds (overrides decorator default)
116
115
  user_endpoint_config: Endpoint configuration dict (merged with decorator default)
117
116
  **kwargs: Keyword arguments to pass to the function
118
117
 
@@ -134,12 +133,7 @@ class Function:
134
133
  endpoint = endpoint or self.endpoint
135
134
 
136
135
  decorator_config = self.default_user_endpoint_config.copy()
137
- if self.walltime is not None:
138
- decorator_config["walltime"] = self.walltime
139
-
140
136
  call_time_config = user_endpoint_config.copy() if user_endpoint_config else {}
141
- if walltime is not None:
142
- call_time_config["walltime"] = walltime
143
137
 
144
138
  # merge all config sources
145
139
  config = self.config_resolver.resolve(
@@ -166,7 +160,9 @@ class Function:
166
160
  raise ValueError("No endpoint specified")
167
161
 
168
162
  payload = serialize((args, kwargs), use_proxy=False, proxy_threshold_mb=None)
169
- shell_function = script_to_submittable(self.script_path, self.name, payload)
163
+ shell_function = script_to_submittable(
164
+ self.script_path, self.name, payload, walltime=self.walltime
165
+ )
170
166
 
171
167
  future: GroundhogFuture = submit_to_executor(
172
168
  UUID(endpoint),
@@ -182,7 +178,6 @@ class Function:
182
178
  self,
183
179
  *args: Any,
184
180
  endpoint: str | None = None,
185
- walltime: int | None = None,
186
181
  user_endpoint_config: dict[str, Any] | None = None,
187
182
  **kwargs: Any,
188
183
  ) -> Any:
@@ -194,7 +189,6 @@ class Function:
194
189
  Args:
195
190
  *args: Positional arguments to pass to the function
196
191
  endpoint: Globus Compute endpoint UUID (overrides decorator default)
197
- walltime: Maximum execution time in seconds (overrides decorator default)
198
192
  user_endpoint_config: Endpoint configuration dict (merged with decorator default)
199
193
  **kwargs: Keyword arguments to pass to the function
200
194
 
@@ -210,7 +204,6 @@ class Function:
210
204
  future = self.submit(
211
205
  *args,
212
206
  endpoint=endpoint,
213
- walltime=walltime,
214
207
  user_endpoint_config=user_endpoint_config,
215
208
  **kwargs,
216
209
  )
@@ -11,8 +11,7 @@
11
11
  # endpoint = "TODO: Add Globus Compute endpoint UUID here"
12
12
  # # Uncomment and configure default options for "my_endpoint" here (available options vary by endpoint):
13
13
  # # account = "my-account"
14
- # # partition = "standard"
15
- # # walltime = 300 {% endif %}
14
+ # # partition = "standard" {% endif %}
16
15
  # ///
17
16
 
18
17
  import groundhog_hpc as hog
File without changes
File without changes
File without changes