lsst-ctrl-bps 29.2025.2800__py3-none-any.whl → 29.2025.3000__py3-none-any.whl

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.
@@ -31,9 +31,16 @@ __all__ = ["construct"]
31
31
 
32
32
  import logging
33
33
  import shutil
34
+ from collections.abc import Callable
34
35
  from pathlib import Path
35
36
 
36
- from lsst.ctrl.bps import BpsConfig, GenericWorkflow, GenericWorkflowExec, GenericWorkflowJob
37
+ from lsst.ctrl.bps import (
38
+ BpsConfig,
39
+ GenericWorkflow,
40
+ GenericWorkflowExec,
41
+ GenericWorkflowFile,
42
+ GenericWorkflowJob,
43
+ )
37
44
  from lsst.ctrl.bps.transform import _get_job_values
38
45
 
39
46
  _LOG = logging.getLogger(__name__)
@@ -73,7 +80,7 @@ def create_custom_workflow(config: BpsConfig) -> tuple[GenericWorkflow, BpsConfi
73
80
  generic_workflow_config : `lsst.ctrl.BpsConfig`
74
81
  Configuration to accompany created generic workflow.
75
82
  """
76
- gwjob = create_custom_job(config)
83
+ gwjob, inputs, outputs = create_custom_job(config)
77
84
 
78
85
  _, name = config.search("uniqProcName", opt={"required": True})
79
86
  generic_workflow = GenericWorkflow(name)
@@ -90,6 +97,10 @@ def create_custom_workflow(config: BpsConfig) -> tuple[GenericWorkflow, BpsConfi
90
97
  "bps_runsite": config["computeSite"],
91
98
  }
92
99
  )
100
+ if inputs:
101
+ generic_workflow.add_job_inputs(gwjob.name, inputs)
102
+ if outputs:
103
+ generic_workflow.add_job_outputs(gwjob.name, outputs)
93
104
 
94
105
  generic_workflow_config = BpsConfig(config)
95
106
  generic_workflow_config["workflowName"] = config["uniqProcName"]
@@ -98,7 +109,9 @@ def create_custom_workflow(config: BpsConfig) -> tuple[GenericWorkflow, BpsConfi
98
109
  return generic_workflow, generic_workflow_config
99
110
 
100
111
 
101
- def create_custom_job(config: BpsConfig) -> GenericWorkflowJob:
112
+ def create_custom_job(
113
+ config: BpsConfig,
114
+ ) -> tuple[GenericWorkflowJob, list[GenericWorkflowFile], list[GenericWorkflowFile]]:
102
115
  """Create a job that will run a custom command or script.
103
116
 
104
117
  Parameters
@@ -110,6 +123,10 @@ def create_custom_job(config: BpsConfig) -> GenericWorkflowJob:
110
123
  -------
111
124
  job : `lsst.ctrl.bps.GenericWorkflowJob`
112
125
  A custom job responsible for running the command.
126
+ inputs : `list` [`lsst.ctrl.bps.GenericWorkflowFile`]
127
+ List of job's input files, empty if the job has no input files.
128
+ outputs : `list` [`lsst.ctrl.bps.GenericWorkflowFile`]
129
+ List of job's output files, empty if the job has no output files.
113
130
  """
114
131
  prefix = Path(config["submitPath"])
115
132
  job_label = "customJob"
@@ -135,6 +152,92 @@ def create_custom_job(config: BpsConfig) -> GenericWorkflowJob:
135
152
  job.executable = GenericWorkflowExec(
136
153
  name=script_name, src_uri=str(prefix / script_name), transfer_executable=True
137
154
  )
138
- job.arguments = config[f".{job_label}.arguments"]
155
+ _, job.arguments = config.search("arguments", opt=search_opts | {"replaceVars": False})
139
156
 
140
- return job
157
+ inputs = []
158
+ found, mapping = config.search("inputs", opt=search_opts)
159
+ if found:
160
+ inputs = create_job_files(mapping, prefix, path_creator=create_input_path)
161
+
162
+ outputs = []
163
+ found, mapping = config.search("outputs", opt=search_opts)
164
+ if found:
165
+ outputs = create_job_files(mapping, prefix, path_creator=create_output_path)
166
+
167
+ for gwfile in inputs + outputs:
168
+ job.arguments = job.arguments.replace(f"{{{gwfile.name}}}", f"<FILE:{gwfile.name}>")
169
+
170
+ return job, inputs, outputs
171
+
172
+
173
+ def create_job_files(
174
+ file_specs: BpsConfig, prefix: str | Path, path_creator: Callable[[Path, Path], Path]
175
+ ) -> list[GenericWorkflowFile]:
176
+ """Create files for a job.
177
+
178
+ Parameters
179
+ ----------
180
+ file_specs : `lsst.ctrl.bps.BpsConfig`
181
+ The mapping between file keys and file paths.
182
+ prefix : `str` | `pathlib.Path`
183
+ The root directory to which the files will be written.
184
+ path_creator : `Callable` [[`Path`, `Path`], `Path`]
185
+ File category that determines actions that need to be taken during
186
+ file creation.
187
+
188
+ Returns
189
+ -------
190
+ gwfiles : `list` [`lsst.ctrl.bps.GenericWorkflowFile`]
191
+ List of files created for the job.
192
+ """
193
+ prefix = Path(prefix)
194
+
195
+ gwfiles = []
196
+ for key, path in file_specs.items():
197
+ src = Path(path)
198
+ dest = path_creator(src, prefix)
199
+ gwfiles.append(GenericWorkflowFile(name=key, src_uri=str(dest), wms_transfer=True))
200
+ return gwfiles
201
+
202
+
203
+ def create_input_path(path: Path, prefix: Path) -> Path:
204
+ """Process an input path.
205
+
206
+ Parameters
207
+ ----------
208
+ path : `pathlib.Path`
209
+ The input path.
210
+ prefix : `pathlib.Path`
211
+ The root directory to which the file will be written.
212
+
213
+ Raises
214
+ ------
215
+ ValueError
216
+ Raised if the input path does not exist or is a directory.
217
+ """
218
+ if path.exists():
219
+ if path.is_dir():
220
+ raise ValueError(f"input path '{path} is a directory, must be file")
221
+ else:
222
+ raise ValueError(f"input path '{path}' does not exist")
223
+ dest = prefix / path.name
224
+ shutil.copy2(path, dest)
225
+ return dest
226
+
227
+
228
+ def create_output_path(path: Path, prefix: Path) -> Path:
229
+ """Process an output path.
230
+
231
+ Parameters
232
+ ----------
233
+ path : `pathlib.Path`
234
+ The output path.
235
+ prefix : `pathlib.Path`
236
+ The root directory to which the file will be written.
237
+ """
238
+ if path.is_absolute():
239
+ dest = path
240
+ else:
241
+ dest = prefix / path
242
+ dest.parent.mkdir(parents=True, exist_ok=True)
243
+ return dest
@@ -316,13 +316,7 @@ def _fill_arguments(use_shared, generic_workflow, arguments, cmdvals):
316
316
  # Have shared filesystems and jobs can share file.
317
317
  uri = gwfile.src_uri
318
318
  else:
319
- # Taking advantage of inside knowledge. Not future-proof.
320
- # Temporary fix until have job wrapper that pulls files
321
- # within job.
322
- if gwfile.name == "butlerConfig" and os.path.splitext(gwfile.src_uri)[1] != ".yaml":
323
- uri = "butler.yaml"
324
- else:
325
- uri = os.path.basename(gwfile.src_uri)
319
+ uri = os.path.basename(gwfile.src_uri)
326
320
  else: # Using push transfer
327
321
  uri = os.path.basename(gwfile.src_uri)
328
322
 
lsst/ctrl/bps/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "29.2025.2800"
2
+ __version__ = "29.2025.3000"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-ctrl-bps
3
- Version: 29.2025.2800
3
+ Version: 29.2025.3000
4
4
  Summary: Pluggable execution of workflow graphs from Rubin pipelines.
5
5
  Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
6
6
  License: BSD 3-Clause License
@@ -9,7 +9,7 @@ lsst/ctrl/bps/bps_utils.py,sha256=-w0HSUXKw8jgJFl28yzwJuuqLqT_UOw12_XQBELUWrE,12
9
9
  lsst/ctrl/bps/cancel.py,sha256=mAdBi-oUpepyo-1MCqx_I34dbm6cqT0VJu3d2-y9T2Y,3317
10
10
  lsst/ctrl/bps/clustered_quantum_graph.py,sha256=mBf8s_DlTzGCFq7aAKmD1cAXq6Cqr8QxjwpgXPOQcRc,18765
11
11
  lsst/ctrl/bps/constants.py,sha256=dsnsNMqwU6Xl_ln6nQ0PmxsghlbBY9mLJWf2rlzYayQ,1733
12
- lsst/ctrl/bps/construct.py,sha256=a5Gb_oinowb7m9rLsk0R_hz8GFu9WGCzDd_QWbsK0Mk,4944
12
+ lsst/ctrl/bps/construct.py,sha256=o-JhTF_eehRiIxy3xe2UgBISyKNBg-kduthGiqfa50g,8100
13
13
  lsst/ctrl/bps/drivers.py,sha256=M_zWXvzK23MBBNvqdbJCnA_9DUCoFznCjWfwQw9BO6Q,22512
14
14
  lsst/ctrl/bps/generic_workflow.py,sha256=BwEFBudncziHTZaTTknOQroY_a-33mGf-mq9PzxH8G0,53720
15
15
  lsst/ctrl/bps/initialize.py,sha256=DCQwB9ZSo_36Ncs8jMJwxKZcYCu46jjww6rzyiuMFKY,7554
@@ -21,8 +21,8 @@ lsst/ctrl/bps/report.py,sha256=6qCt6-0apuVZrevtQzJLRmQc_ve_uPyNH3HkgC5KSjc,7898
21
21
  lsst/ctrl/bps/restart.py,sha256=yVwxeviLiehyIfPmwU-H3tJ9ou7OWZZcrNf8PMxjr8o,2298
22
22
  lsst/ctrl/bps/status.py,sha256=Lrt0cAqROv77B8UvYXGimCa4cDHBD1N0K2Xx7oS6fXk,3362
23
23
  lsst/ctrl/bps/submit.py,sha256=Ev-yhcoZwtBPIo5bRt_4XFJRtgQBd8JHUurEfn01HpU,2880
24
- lsst/ctrl/bps/transform.py,sha256=jGEA3YGIQIJiLv-4Qm00WPNW0EEKughX7lcoJRZhsKU,35600
25
- lsst/ctrl/bps/version.py,sha256=zkbtcIsz6tbu7rmamcut51DoG62vyYwam95urGw5Lis,55
24
+ lsst/ctrl/bps/transform.py,sha256=P3dGwKStoCLOn7F2Oez6B__f7bGV5jlUF_Vj9lJQcU0,35256
25
+ lsst/ctrl/bps/version.py,sha256=GKnpddvvmGJ8yPsnT--mhT32jeA31BaGZsJcw6cTK7k,55
26
26
  lsst/ctrl/bps/wms_service.py,sha256=l3T6i1MG72dhHY0KXMUlBjWUpCLOfaySs7o2W8oCwhs,18891
27
27
  lsst/ctrl/bps/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  lsst/ctrl/bps/cli/bps.py,sha256=CHfAL-U4mSi-FqeGKtmkX5nI5H9gkRre4XEWNVdeMRk,2559
@@ -35,13 +35,13 @@ lsst/ctrl/bps/cli/opt/options.py,sha256=pZQpjJ2Vrx6kYJGs5vVERBMFstPocwBXHffxkWkm
35
35
  lsst/ctrl/bps/etc/bps_defaults.yaml,sha256=UwKAKWl09-Xjtl6kiz-AiXA9SDczeCvPGRXOPG3fzb8,4828
36
36
  lsst/ctrl/bps/tests/config_test_utils.py,sha256=WM8Vrigk4OO0TBoL1A73a6hLhf2a6-ACD20fROJ0U7A,3537
37
37
  lsst/ctrl/bps/tests/gw_test_utils.py,sha256=zVVQqzwSiQgPgk9TnqDzgR7uDnaTMeuBLYKA8vOp5RI,22452
38
- lsst_ctrl_bps-29.2025.2800.dist-info/licenses/COPYRIGHT,sha256=Lc6NoAEFQ65v_SmtS9NwfHTOuSUtC2Umbjv5zyowiQM,61
39
- lsst_ctrl_bps-29.2025.2800.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
40
- lsst_ctrl_bps-29.2025.2800.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
41
- lsst_ctrl_bps-29.2025.2800.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
42
- lsst_ctrl_bps-29.2025.2800.dist-info/METADATA,sha256=z5rzEOPfSHOHJYHZVk8g8Fs_094g69mpw0ZqiaLaeJY,2190
43
- lsst_ctrl_bps-29.2025.2800.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- lsst_ctrl_bps-29.2025.2800.dist-info/entry_points.txt,sha256=d6FhN79h7s9frdBI7YkScsGEInwpGGub49pAjXWbIbI,51
45
- lsst_ctrl_bps-29.2025.2800.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
46
- lsst_ctrl_bps-29.2025.2800.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
47
- lsst_ctrl_bps-29.2025.2800.dist-info/RECORD,,
38
+ lsst_ctrl_bps-29.2025.3000.dist-info/licenses/COPYRIGHT,sha256=Lc6NoAEFQ65v_SmtS9NwfHTOuSUtC2Umbjv5zyowiQM,61
39
+ lsst_ctrl_bps-29.2025.3000.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
40
+ lsst_ctrl_bps-29.2025.3000.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
41
+ lsst_ctrl_bps-29.2025.3000.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
42
+ lsst_ctrl_bps-29.2025.3000.dist-info/METADATA,sha256=zu22RHR5V7RT4op1ilcxRCPPM89Bh347DIiKurkIBXs,2190
43
+ lsst_ctrl_bps-29.2025.3000.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
+ lsst_ctrl_bps-29.2025.3000.dist-info/entry_points.txt,sha256=d6FhN79h7s9frdBI7YkScsGEInwpGGub49pAjXWbIbI,51
45
+ lsst_ctrl_bps-29.2025.3000.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
46
+ lsst_ctrl_bps-29.2025.3000.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
47
+ lsst_ctrl_bps-29.2025.3000.dist-info/RECORD,,