lsst-ctrl-bps-parsl 29.2025.4900__tar.gz → 30.0.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 (36) hide show
  1. {lsst_ctrl_bps_parsl-29.2025.4900/python/lsst_ctrl_bps_parsl.egg-info → lsst_ctrl_bps_parsl-30.0.0}/PKG-INFO +1 -1
  2. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/pyproject.toml +1 -1
  3. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/job.py +17 -8
  4. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/site.py +4 -6
  5. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/__init__.py +1 -0
  6. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/ccin2p3.py +2 -0
  7. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/local.py +5 -0
  8. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/slurm.py +5 -0
  9. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/torque.py +5 -0
  10. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/work_queue.py +2 -2
  11. lsst_ctrl_bps_parsl-30.0.0/python/lsst/ctrl/bps/parsl/version.py +2 -0
  12. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/workflow.py +1 -1
  13. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0/python/lsst_ctrl_bps_parsl.egg-info}/PKG-INFO +1 -1
  14. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst_ctrl_bps_parsl.egg-info/SOURCES.txt +2 -1
  15. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/tests/test_job.py +25 -0
  16. lsst_ctrl_bps_parsl-30.0.0/tests/test_sites.py +78 -0
  17. lsst_ctrl_bps_parsl-29.2025.4900/python/lsst/ctrl/bps/parsl/version.py +0 -2
  18. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/COPYRIGHT +0 -0
  19. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/LICENSE +0 -0
  20. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/README.md +0 -0
  21. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/bsd_license.txt +0 -0
  22. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/gpl-v3.0.txt +0 -0
  23. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/__init__.py +0 -0
  24. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/configuration.py +0 -0
  25. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/environment.py +0 -0
  26. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/service.py +0 -0
  27. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/nersc.py +0 -0
  28. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/princeton.py +0 -0
  29. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst/ctrl/bps/parsl/sites/slac.py +0 -0
  30. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst_ctrl_bps_parsl.egg-info/dependency_links.txt +0 -0
  31. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst_ctrl_bps_parsl.egg-info/requires.txt +0 -0
  32. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst_ctrl_bps_parsl.egg-info/top_level.txt +0 -0
  33. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/python/lsst_ctrl_bps_parsl.egg-info/zip-safe +0 -0
  34. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/setup.cfg +0 -0
  35. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/tests/test_config.py +0 -0
  36. {lsst_ctrl_bps_parsl-29.2025.4900 → lsst_ctrl_bps_parsl-30.0.0}/tests/test_import.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-ctrl-bps-parsl
3
- Version: 29.2025.4900
3
+ Version: 30.0.0
4
4
  Summary: Parsl-based plugin for lsst-ctrl-bps.
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License-Expression: BSD-3-Clause OR GPL-3.0-or-later
@@ -55,7 +55,7 @@ version = { attr = "lsst_versions.get_lsst_version" }
55
55
  package_dir = "python"
56
56
  filename = "doc/lsst.ctrl.bps.parsl/CHANGES.rst"
57
57
  directory = "doc/changes"
58
- title_format = "lsst-ctrl-bps-parsl {version} {project_date}"
58
+ title_format = "lsst-ctrl-bps-parsl {version} ({project_date})"
59
59
  issue_format = "`{issue} <https://rubinobs.atlassian.net/browse/{issue}>`_"
60
60
 
61
61
  [[tool.towncrier.type]]
@@ -237,11 +237,18 @@ class ParslJob:
237
237
  ("request_cpus", "cores", None),
238
238
  ("request_disk", "disk", None), # Both are MB
239
239
  ("request_walltime", "running_time_min", None), # Both are minutes
240
+ ("priority", "priority", None),
240
241
  ):
241
242
  value = getattr(self.generic, bps_name)
242
- if scale is not None:
243
+ if value is not None and scale is not None:
243
244
  value *= scale
244
- resources[parsl_name] = value
245
+ # Parsl's `HighThroughputExecutor` cannot have
246
+ # `priority=None`, but it can be omitted. By contrast,
247
+ # `WorkQueueExecutor` needs to have the other resource
248
+ # requests provided, but `priority` can be omitted, so we
249
+ # need special handling for `priority`.
250
+ if (parsl_name == "priority" and value is not None) or parsl_name != "priority":
251
+ resources[parsl_name] = value
245
252
  return resources
246
253
 
247
254
  def get_future(
@@ -249,7 +256,7 @@ class ParslJob:
249
256
  app: BashApp,
250
257
  inputs: list[Future],
251
258
  command_prefix: str | None = None,
252
- add_resources: bool = False,
259
+ resource_list: list | None = None,
253
260
  ) -> Future | None:
254
261
  """Get the parsl app future for the job.
255
262
 
@@ -265,10 +272,8 @@ class ParslJob:
265
272
  command_prefix : `str`, optional
266
273
  Bash commands to execute before the job command, e.g., for setting
267
274
  the environment.
268
- add_resources : `bool`
269
- Add resource specification when submitting the job? This is only
270
- appropriate for the ``WorkQueue`` executor; other executors will
271
- raise an exception.
275
+ resource_list : `list`, optional
276
+ List of resource specifications to pass to the Parsl executor.
272
277
 
273
278
  Returns
274
279
  -------
@@ -283,7 +288,11 @@ class ParslJob:
283
288
  command = self.evaluate_command_line(command)
284
289
  if command_prefix:
285
290
  command = command_prefix + "\n" + command
286
- resources = self.get_resources() if add_resources else {}
291
+ resources = (
292
+ {k: v for k, v in self.get_resources().items() if k in resource_list}
293
+ if resource_list is not None
294
+ else {}
295
+ )
287
296
 
288
297
  # Add a layer of indirection to which we can add a useful name.
289
298
  # This name is used by parsl for tracking workflow status.
@@ -56,16 +56,14 @@ class SiteConfig(ABC):
56
56
  ----------
57
57
  config : `BpsConfig`
58
58
  BPS configuration.
59
- add_resources : `bool`
60
- Add resource specification when submitting the job? This is only
61
- appropriate for the ``WorkQueue`` executor; other executors will
62
- raise an exception.
59
+ resource_list : `list`, optional
60
+ List of parsl resource specifications to pass to the executor.
63
61
  """
64
62
 
65
- def __init__(self, config: BpsConfig, add_resources: bool = False):
63
+ def __init__(self, config: BpsConfig, resource_list: list = None):
66
64
  self.config = config
67
65
  self.site = self.get_site_subconfig(config)
68
- self.add_resources = add_resources
66
+ self.resource_list = resource_list
69
67
 
70
68
  @staticmethod
71
69
  def get_site_subconfig(config: BpsConfig) -> BpsConfig:
@@ -29,3 +29,4 @@ from .local import *
29
29
  from .slurm import *
30
30
  from .torque import *
31
31
  from .work_queue import *
32
+ from .ccin2p3 import *
@@ -122,6 +122,8 @@ class Ccin2p3(SiteConfig):
122
122
  ]
123
123
 
124
124
  def __init__(self, *args, **kwargs):
125
+ # Have BPS-defined resource requests for each job passed to executor.
126
+ kwargs["resource_list"] = ["priority"]
125
127
  super().__init__(*args, **kwargs)
126
128
  self._account = get_bps_config_value(self.site, ".account", str, self.DEFAULT_ACCOUNT)
127
129
  self._scheduler_options = get_bps_config_value(
@@ -47,6 +47,11 @@ class Local(SiteConfig):
47
47
  ``site.<computeSite>.cores`` (`int`).
48
48
  """
49
49
 
50
+ def __init__(self, *args, **kwargs):
51
+ # Have BPS-defined resource requests for each job passed to executor.
52
+ kwargs["resource_list"] = ["priority"]
53
+ super().__init__(*args, **kwargs)
54
+
50
55
  def get_executors(self) -> list[ParslExecutor]:
51
56
  """Get a list of executors to be used in processing.
52
57
 
@@ -80,6 +80,11 @@ class Slurm(SiteConfig):
80
80
  script (each line usually starting with ``#SBATCH``).
81
81
  """
82
82
 
83
+ def __init__(self, *args, **kwargs):
84
+ # Have BPS-defined resource requests for each job passed to executor.
85
+ kwargs["resource_list"] = ["priority"]
86
+ super().__init__(*args, **kwargs)
87
+
83
88
  def make_executor(
84
89
  self,
85
90
  label: str,
@@ -75,6 +75,11 @@ class Torque(SiteConfig):
75
75
  script (each line usually starting with ``#PBS``).
76
76
  """
77
77
 
78
+ def __init__(self, *args, **kwargs):
79
+ # Have BPS-defined resource requests for each job passed to executor.
80
+ kwargs["resource_list"] = ["priority"]
81
+ super().__init__(*args, **kwargs)
82
+
78
83
  def make_executor(
79
84
  self,
80
85
  label: str,
@@ -59,7 +59,7 @@ class WorkQueue(SiteConfig):
59
59
  Parameters forwarded to base class constructor.
60
60
  **kwargs : `~typing.Any`
61
61
  Keyword arguments passed to base class constructor, augmented by
62
- the ``add_resources`` argument.
62
+ the ``resource_list`` argument.
63
63
 
64
64
  Notes
65
65
  -----
@@ -79,7 +79,7 @@ class WorkQueue(SiteConfig):
79
79
 
80
80
  def __init__(self, *args, **kwargs):
81
81
  # Have BPS-defined resource requests for each job passed to work_queue.
82
- kwargs["add_resources"] = True
82
+ kwargs["resource_list"] = ["memory", "cores", "disk", "running_time_min", "priority"]
83
83
  super().__init__(*args, **kwargs)
84
84
 
85
85
  def make_executor(
@@ -0,0 +1,2 @@
1
+ __all__ = ["__version__"]
2
+ __version__ = "30.0.0"
@@ -278,7 +278,7 @@ class ParslWorkflow(BaseWmsWorkflow):
278
278
  self.apps[label],
279
279
  [ff for ff in inputs if ff is not None],
280
280
  self.command_prefix,
281
- self.site.add_resources,
281
+ self.site.resource_list,
282
282
  )
283
283
 
284
284
  def load_dfk(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-ctrl-bps-parsl
3
- Version: 29.2025.4900
3
+ Version: 30.0.0
4
4
  Summary: Parsl-based plugin for lsst-ctrl-bps.
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License-Expression: BSD-3-Clause OR GPL-3.0-or-later
@@ -30,4 +30,5 @@ python/lsst_ctrl_bps_parsl.egg-info/top_level.txt
30
30
  python/lsst_ctrl_bps_parsl.egg-info/zip-safe
31
31
  tests/test_config.py
32
32
  tests/test_import.py
33
- tests/test_job.py
33
+ tests/test_job.py
34
+ tests/test_sites.py
@@ -82,3 +82,28 @@ def testInitWithoutTemplate():
82
82
  parsl_job = ParslJob(gwjob, config, {})
83
83
  assert parsl_job.stdout == os.path.join(submit_path, "logs/job3.stdout")
84
84
  assert parsl_job.stderr == os.path.join(submit_path, "logs/job3.stderr")
85
+
86
+
87
+ def testJobResourceLists():
88
+ """Test that ParslJob.get_resources() returns resource specifications
89
+ expected by Parsl Executors, including special handling needed for the
90
+ `priority` request.
91
+ """
92
+ # Test doesn't actually use directory
93
+ submit_path = os.path.join(TESTDIR, "without_template")
94
+ config = BpsConfig({"subDirTemplate": "", "submitPath": submit_path}, search_order=[])
95
+ gwjob = GenericWorkflowJob("job", label="label")
96
+
97
+ # If gwjob.priority is None, for Parsl's HighThroughputExecutor
98
+ # `"priority"` must be omitted, but WorkQueueExecutor requires
99
+ # `("cores", "disk", "memory")` to be provided.
100
+ gwjob.priority = None
101
+ parsl_job = ParslJob(gwjob, config, {})
102
+ assert "priority" not in parsl_job.get_resources()
103
+ for resource in ("cores", "disk", "memory"):
104
+ assert resource in parsl_job.get_resources()
105
+
106
+ # Check case where gwjob.priority is not None.
107
+ gwjob.priority = 1
108
+ for resource in ("cores", "disk", "memory", "priority"):
109
+ assert resource in parsl_job.get_resources()
@@ -0,0 +1,78 @@
1
+ # This file is part of ctrl_bps_parsl.
2
+ #
3
+ # Developed for the LSST Data Management System.
4
+ # This product includes software developed by the LSST Project
5
+ # (https://www.lsst.org) and the LSST DESC (https://www.lsstdesc.org/).
6
+ # See the COPYRIGHT file at the top-level directory of this distribution
7
+ # for details of code ownership.
8
+ #
9
+ # This software is dual licensed under the GNU General Public License and also
10
+ # under a 3-clause BSD license. Recipients may choose which of these licenses
11
+ # to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
12
+ # respectively. If you choose the GPL option then the following text applies
13
+ # (but note that there is still no warranty even if you opt for BSD instead):
14
+ #
15
+ # This program is free software: you can redistribute it and/or modify
16
+ # it under the terms of the GNU General Public License as published by
17
+ # the Free Software Foundation, either version 3 of the License, or
18
+ # (at your option) any later version.
19
+ #
20
+ # This program is distributed in the hope that it will be useful,
21
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ # GNU General Public License for more details.
24
+ #
25
+ # You should have received a copy of the GNU General Public License
26
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
27
+
28
+
29
+ import platform
30
+
31
+ from parsl.executors import HighThroughputExecutor, WorkQueueExecutor
32
+
33
+ from lsst.ctrl.bps import BpsConfig
34
+ from lsst.ctrl.bps.parsl.sites import Ccin2p3, Local, LocalSrunWorkQueue, Slurm, Torque
35
+
36
+
37
+ def testSiteResourceLists():
38
+ """Test compute site resource lists."""
39
+ # Provide a minimal config that allows compute site classes to be created.
40
+ config = BpsConfig(
41
+ {
42
+ "submitPath": ".",
43
+ "operator": "operator",
44
+ "computeSite": "local",
45
+ "site": {
46
+ "local": {
47
+ "class": "lsst.ctrl.bps.parsl.sites.Local",
48
+ "cores": 1,
49
+ "nodes": 1,
50
+ "walltime": "00:01:00",
51
+ }
52
+ },
53
+ }
54
+ )
55
+
56
+ expected_resources = {
57
+ HighThroughputExecutor: {"priority"},
58
+ WorkQueueExecutor: {"memory", "cores", "disk", "running_time_min", "priority"},
59
+ }
60
+
61
+ site_classes = [Local, Slurm, Torque]
62
+ if platform.machine() in ("aarch64", "x86_64"):
63
+ # If running on a supported architecture, then add Ccin2p3 site class.
64
+ site_classes.append(Ccin2p3)
65
+
66
+ try:
67
+ # If the ndcctools module is available, then add WorkQueue
68
+ # subclasses to the site_classes list.
69
+ import ndcctools # noqa F401
70
+
71
+ site_classes.append(LocalSrunWorkQueue)
72
+ except ImportError:
73
+ pass
74
+
75
+ for site_class in site_classes:
76
+ compute_site = site_class(config)
77
+ executor_type = type(compute_site.get_executors()[0])
78
+ assert expected_resources[executor_type] == set(compute_site.resource_list)
@@ -1,2 +0,0 @@
1
- __all__ = ["__version__"]
2
- __version__ = "29.2025.4900"