lsst-ctrl-bps 29.2025.3700__py3-none-any.whl → 29.2025.3900__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.
- lsst/ctrl/bps/bps_reports.py +131 -43
- lsst/ctrl/bps/report.py +38 -19
- lsst/ctrl/bps/version.py +1 -1
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/METADATA +1 -1
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/RECORD +13 -13
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/WHEEL +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/entry_points.txt +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/COPYRIGHT +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/LICENSE +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/bsd_license.txt +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/gpl-v3.0.txt +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/top_level.txt +0 -0
- {lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/zip-safe +0 -0
lsst/ctrl/bps/bps_reports.py
CHANGED
|
@@ -27,7 +27,14 @@
|
|
|
27
27
|
|
|
28
28
|
"""Classes and functions used in reporting run status."""
|
|
29
29
|
|
|
30
|
-
__all__ = [
|
|
30
|
+
__all__ = [
|
|
31
|
+
"BaseRunReport",
|
|
32
|
+
"DetailedRunReport",
|
|
33
|
+
"ExitCodesReport",
|
|
34
|
+
"SummaryRunReport",
|
|
35
|
+
"compile_code_summary",
|
|
36
|
+
"compile_job_summary",
|
|
37
|
+
]
|
|
31
38
|
|
|
32
39
|
import abc
|
|
33
40
|
import logging
|
|
@@ -55,7 +62,7 @@ class BaseRunReport(abc.ABC):
|
|
|
55
62
|
|
|
56
63
|
def __eq__(self, other):
|
|
57
64
|
if isinstance(other, BaseRunReport):
|
|
58
|
-
return
|
|
65
|
+
return self._table.pformat() == other._table.pformat()
|
|
59
66
|
return False
|
|
60
67
|
|
|
61
68
|
def __len__(self):
|
|
@@ -195,7 +202,7 @@ class DetailedRunReport(BaseRunReport):
|
|
|
195
202
|
job_summary = run_report.job_summary
|
|
196
203
|
if job_summary is None:
|
|
197
204
|
id_ = run_report.global_wms_id if use_global_id else run_report.wms_id
|
|
198
|
-
self._msg = f"WARNING: Job summary for run '{id_}' not available, report
|
|
205
|
+
self._msg = f"WARNING: Job summary for run '{id_}' not available, report may be incomplete."
|
|
199
206
|
return
|
|
200
207
|
|
|
201
208
|
if by_label_expected:
|
|
@@ -231,44 +238,60 @@ class ExitCodesReport(BaseRunReport):
|
|
|
231
238
|
error handling from the wms service.
|
|
232
239
|
"""
|
|
233
240
|
|
|
234
|
-
def add(self, run_report, use_global_id=False):
|
|
241
|
+
def add(self, run_report: WmsRunReport, use_global_id: bool = False) -> None:
|
|
235
242
|
# Docstring inherited from the base class.
|
|
236
243
|
|
|
237
|
-
|
|
238
|
-
|
|
244
|
+
exit_code_summary = run_report.exit_code_summary
|
|
245
|
+
if not exit_code_summary:
|
|
246
|
+
id_ = run_report.global_wms_id if use_global_id else run_report.wms_id
|
|
247
|
+
self._msg = f"WARNING: Exit code summary for run '{id_}' not available, report may be incomplete."
|
|
248
|
+
return
|
|
249
|
+
|
|
250
|
+
warnings = []
|
|
251
|
+
|
|
252
|
+
# If available, use label ordering from the run summary as it should
|
|
253
|
+
# reflect the ordering of the pipetasks in the pipeline.
|
|
239
254
|
labels = []
|
|
240
255
|
if run_report.run_summary:
|
|
241
256
|
for part in run_report.run_summary.split(";"):
|
|
242
257
|
label, _ = part.split(":")
|
|
243
258
|
labels.append(label)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return
|
|
259
|
+
if not labels:
|
|
260
|
+
labels = sorted(exit_code_summary)
|
|
261
|
+
warnings.append("WARNING: Could not determine order of pipeline, instead sorted alphabetically.")
|
|
248
262
|
|
|
249
263
|
# Payload (e.g. pipetask) error codes:
|
|
250
264
|
# * 1: general failure,
|
|
251
265
|
# * 2: command line error (e.g. unknown command and/or option).
|
|
252
266
|
pyld_error_codes = {1, 2}
|
|
253
267
|
|
|
254
|
-
|
|
268
|
+
missing_labels = set()
|
|
255
269
|
for label in labels:
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
try:
|
|
271
|
+
exit_codes = exit_code_summary[label]
|
|
272
|
+
except KeyError:
|
|
273
|
+
missing_labels.add(label)
|
|
274
|
+
else:
|
|
275
|
+
pyld_errors = [code for code in exit_codes if code in pyld_error_codes]
|
|
276
|
+
pyld_error_count = len(pyld_errors)
|
|
277
|
+
pyld_error_summary = (
|
|
278
|
+
", ".join(sorted(str(code) for code in set(pyld_errors))) if pyld_errors else "None"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
infra_errors = [code for code in exit_codes if code not in pyld_error_codes]
|
|
282
|
+
infra_error_count = len(infra_errors)
|
|
283
|
+
infra_error_summary = (
|
|
284
|
+
", ".join(sorted(str(code) for code in set(infra_errors))) if infra_errors else "None"
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
run = [label, pyld_error_count, pyld_error_summary, infra_error_count, infra_error_summary]
|
|
288
|
+
self._table.add_row(run)
|
|
289
|
+
if missing_labels:
|
|
290
|
+
warnings.append(
|
|
291
|
+
f"WARNING: Exit code summary was not available for job labels: {', '.join(missing_labels)}"
|
|
268
292
|
)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
self._table.add_row(run)
|
|
293
|
+
if warnings:
|
|
294
|
+
self._msg = "\n".join(warnings)
|
|
272
295
|
|
|
273
296
|
def __str__(self):
|
|
274
297
|
alignments = ["<"] + [">"] * (len(self._table.colnames) - 1)
|
|
@@ -276,7 +299,7 @@ class ExitCodesReport(BaseRunReport):
|
|
|
276
299
|
return str("\n".join(lines))
|
|
277
300
|
|
|
278
301
|
|
|
279
|
-
def compile_job_summary(report: WmsRunReport) ->
|
|
302
|
+
def compile_job_summary(report: WmsRunReport) -> list[str]:
|
|
280
303
|
"""Add a job summary to the run report if necessary.
|
|
281
304
|
|
|
282
305
|
If the job summary is not provided, the function will attempt to compile
|
|
@@ -289,24 +312,89 @@ def compile_job_summary(report: WmsRunReport) -> None:
|
|
|
289
312
|
report : `lsst.ctrl.bps.WmsRunReport`
|
|
290
313
|
Information about a single run.
|
|
291
314
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
315
|
+
Returns
|
|
316
|
+
-------
|
|
317
|
+
warnings : `list` [`str`]
|
|
318
|
+
List of messages describing any non-critical issues encountered during
|
|
319
|
+
processing. Empty if none.
|
|
297
320
|
"""
|
|
321
|
+
warnings: list[str] = []
|
|
322
|
+
|
|
323
|
+
# If the job summary already exists, exit early.
|
|
298
324
|
if report.job_summary:
|
|
299
|
-
return
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
325
|
+
return warnings
|
|
326
|
+
|
|
327
|
+
if report.jobs:
|
|
328
|
+
job_summary = {}
|
|
329
|
+
by_label = group_jobs_by_label(report.jobs)
|
|
330
|
+
for label, job_group in by_label.items():
|
|
331
|
+
by_label_state = group_jobs_by_state(job_group)
|
|
332
|
+
_LOG.debug("by_label_state = %s", by_label_state)
|
|
333
|
+
counts = {state: len(jobs) for state, jobs in by_label_state.items()}
|
|
334
|
+
job_summary[label] = counts
|
|
335
|
+
report.job_summary = job_summary
|
|
336
|
+
else:
|
|
337
|
+
warnings.append("information about individual jobs not available")
|
|
338
|
+
|
|
339
|
+
return warnings
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def compile_code_summary(report: WmsRunReport) -> list[str]:
|
|
343
|
+
"""Add missing entries to the exit code summary if necessary.
|
|
344
|
+
|
|
345
|
+
A WMS plugin may exclude job labels for which there are no failures from
|
|
346
|
+
the exit code summary. The function will attempt to use the job summary,
|
|
347
|
+
if available, to add missing entries for these labels.
|
|
348
|
+
|
|
349
|
+
Parameters
|
|
350
|
+
----------
|
|
351
|
+
report : `lsst.ctrl.bps.WmsRunReport`
|
|
352
|
+
Information about a single run.
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
warnings : `list` [`str`]
|
|
357
|
+
List of messages describing any non-critical issues encountered during
|
|
358
|
+
processing. Empty if none.
|
|
359
|
+
"""
|
|
360
|
+
warnings: list[str] = []
|
|
361
|
+
|
|
362
|
+
# If the job summary is not available, exit early.
|
|
363
|
+
if not report.job_summary:
|
|
364
|
+
return warnings
|
|
365
|
+
|
|
366
|
+
# A shallow copy is enough here because we won't be modifying the existing
|
|
367
|
+
# entries, only adding new ones if necessary.
|
|
368
|
+
exit_code_summary = dict(report.exit_code_summary) if report.exit_code_summary else {}
|
|
369
|
+
|
|
370
|
+
# Use the job summary to add the entries for labels with no failures
|
|
371
|
+
# *without* modifying already existing entries.
|
|
372
|
+
failure_summary = {label: states[WmsStates.FAILED] for label, states in report.job_summary.items()}
|
|
373
|
+
for label, count in failure_summary.items():
|
|
374
|
+
if count == 0:
|
|
375
|
+
exit_code_summary.setdefault(label, [])
|
|
376
|
+
|
|
377
|
+
# Check if there are any discrepancies between the data in the exit code
|
|
378
|
+
# summary and the job summary.
|
|
379
|
+
code_summary_labels = set(exit_code_summary)
|
|
380
|
+
failure_summary_labels = set(failure_summary)
|
|
381
|
+
mismatches = {
|
|
382
|
+
label
|
|
383
|
+
for label in failure_summary_labels & code_summary_labels
|
|
384
|
+
if len(exit_code_summary[label]) != failure_summary[label]
|
|
385
|
+
}
|
|
386
|
+
if mismatches:
|
|
387
|
+
warnings.append(
|
|
388
|
+
f"number of exit codes differs from number of failures for job labels: {', '.join(mismatches)}"
|
|
389
|
+
)
|
|
390
|
+
missing = failure_summary_labels - code_summary_labels
|
|
391
|
+
if missing:
|
|
392
|
+
warnings.append(f"exit codes not available for job labels: {', '.join(missing)}")
|
|
393
|
+
|
|
394
|
+
if exit_code_summary:
|
|
395
|
+
report.exit_code_summary = exit_code_summary
|
|
396
|
+
|
|
397
|
+
return warnings
|
|
310
398
|
|
|
311
399
|
|
|
312
400
|
def group_jobs_by_state(jobs):
|
lsst/ctrl/bps/report.py
CHANGED
|
@@ -38,12 +38,18 @@ import sys
|
|
|
38
38
|
from collections.abc import Callable, Sequence
|
|
39
39
|
from typing import TextIO
|
|
40
40
|
|
|
41
|
-
from lsst.utils import
|
|
42
|
-
|
|
43
|
-
from .bps_reports import
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
from lsst.utils import doImportType
|
|
42
|
+
|
|
43
|
+
from .bps_reports import (
|
|
44
|
+
DetailedRunReport,
|
|
45
|
+
ExitCodesReport,
|
|
46
|
+
SummaryRunReport,
|
|
47
|
+
compile_code_summary,
|
|
48
|
+
compile_job_summary,
|
|
49
|
+
)
|
|
50
|
+
from .wms_service import BaseWmsService, WmsRunReport, WmsStates
|
|
51
|
+
|
|
52
|
+
BPS_POSTPROCESSORS = (compile_job_summary, compile_code_summary)
|
|
47
53
|
"""Postprocessors for massaging run reports
|
|
48
54
|
(`tuple` [`Callable` [[`WmsRunReport`], None]).
|
|
49
55
|
"""
|
|
@@ -111,7 +117,7 @@ def display_report(
|
|
|
111
117
|
|
|
112
118
|
run_report.add(run, use_global_id=is_global)
|
|
113
119
|
if run_report.message:
|
|
114
|
-
|
|
120
|
+
messages.append(run_report.message)
|
|
115
121
|
|
|
116
122
|
print(run_brief, file=file)
|
|
117
123
|
print("\n", file=file)
|
|
@@ -132,6 +138,8 @@ def display_report(
|
|
|
132
138
|
]
|
|
133
139
|
run_exits_report = ExitCodesReport(fields)
|
|
134
140
|
run_exits_report.add(run, use_global_id=is_global)
|
|
141
|
+
if run_exits_report.message:
|
|
142
|
+
messages.append(run_exits_report.message)
|
|
135
143
|
print("\n", file=file)
|
|
136
144
|
print(run_exits_report, file=file)
|
|
137
145
|
run_exits_report.clear()
|
|
@@ -145,12 +153,13 @@ def display_report(
|
|
|
145
153
|
print(run_brief, file=file)
|
|
146
154
|
|
|
147
155
|
if messages:
|
|
148
|
-
|
|
156
|
+
uniques = list(dict.fromkeys(messages))
|
|
157
|
+
print("\n".join(uniques), file=file)
|
|
149
158
|
print("\n", file=file)
|
|
150
159
|
|
|
151
160
|
|
|
152
161
|
def retrieve_report(
|
|
153
|
-
|
|
162
|
+
wms_service_fqn: str,
|
|
154
163
|
*,
|
|
155
164
|
run_id: str | None = None,
|
|
156
165
|
user: str | None = None,
|
|
@@ -163,7 +172,7 @@ def retrieve_report(
|
|
|
163
172
|
|
|
164
173
|
Parameters
|
|
165
174
|
----------
|
|
166
|
-
|
|
175
|
+
wms_service_fqn : `str`
|
|
167
176
|
Name of the WMS service class.
|
|
168
177
|
run_id : `str`, optional
|
|
169
178
|
A run id the report will be restricted to.
|
|
@@ -196,11 +205,21 @@ def retrieve_report(
|
|
|
196
205
|
messages : `list` [`str`]
|
|
197
206
|
Errors that happened during report retrieval and/or processing.
|
|
198
207
|
Empty if no issues were encountered.
|
|
208
|
+
|
|
209
|
+
Raises
|
|
210
|
+
------
|
|
211
|
+
TypeError
|
|
212
|
+
Raised if the WMS service class is not a subclass of BaseWmsService.
|
|
199
213
|
"""
|
|
200
|
-
messages = []
|
|
214
|
+
messages: list[str] = []
|
|
201
215
|
|
|
202
|
-
wms_service_class =
|
|
216
|
+
wms_service_class = doImportType(wms_service_fqn)
|
|
217
|
+
if not issubclass(wms_service_class, BaseWmsService):
|
|
218
|
+
raise TypeError(
|
|
219
|
+
f"Invalid WMS service class '{wms_service_fqn}'; must be a subclass of BaseWmsService"
|
|
220
|
+
)
|
|
203
221
|
wms_service = wms_service_class({})
|
|
222
|
+
|
|
204
223
|
reports, message = wms_service.report(
|
|
205
224
|
wms_workflow_id=run_id, user=user, hist=hist, pass_thru=pass_thru, is_global=is_global
|
|
206
225
|
)
|
|
@@ -210,12 +229,12 @@ def retrieve_report(
|
|
|
210
229
|
if postprocessors:
|
|
211
230
|
for report in reports:
|
|
212
231
|
for postprocessor in postprocessors:
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
232
|
+
if warnings := postprocessor(report):
|
|
233
|
+
for warning in warnings:
|
|
234
|
+
messages.append(
|
|
235
|
+
f"WARNING: Report may be incomplete. "
|
|
236
|
+
f"There was an issue with report postprocessing for '{report.wms_id}': "
|
|
237
|
+
f"{warning} (origin: {postprocessor.__name__})"
|
|
238
|
+
)
|
|
220
239
|
|
|
221
240
|
return reports, messages
|
lsst/ctrl/bps/version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
__all__ = ["__version__"]
|
|
2
|
-
__version__ = "29.2025.
|
|
2
|
+
__version__ = "29.2025.3900"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-ctrl-bps
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.3900
|
|
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
|
|
@@ -4,7 +4,7 @@ lsst/ctrl/bps/__init__.py,sha256=qNei3h4EwqUnyyCsBUkYXcRNNlSvzUzbM6Zdkd4eklE,166
|
|
|
4
4
|
lsst/ctrl/bps/_exceptions.py,sha256=qNftFVE8yhiRD8yvACKEf5iHhi1o2eaa69ZCBvw6lDo,1974
|
|
5
5
|
lsst/ctrl/bps/bps_config.py,sha256=4t1jyIBiw9leAySjkcksCaZ3CPJMOt8afxGxTEWRSyQ,18460
|
|
6
6
|
lsst/ctrl/bps/bps_draw.py,sha256=Sl04jpbm6jB_5lBzfJprqnDes9t_aqQQhr0Ag5RSv-Y,1984
|
|
7
|
-
lsst/ctrl/bps/bps_reports.py,sha256=
|
|
7
|
+
lsst/ctrl/bps/bps_reports.py,sha256=73l5Gz00VQq8NgoBrGkvCaUQJE5kw2emhQxxzthMQzs,15574
|
|
8
8
|
lsst/ctrl/bps/bps_utils.py,sha256=-w0HSUXKw8jgJFl28yzwJuuqLqT_UOw12_XQBELUWrE,12206
|
|
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
|
|
@@ -17,12 +17,12 @@ lsst/ctrl/bps/ping.py,sha256=orwTZUNFtlexMYFcNWW_48jaa7Jo1oK4_eb_HuC-p5E,2235
|
|
|
17
17
|
lsst/ctrl/bps/pre_transform.py,sha256=mPUW1QuHwgkSgZGVK6xO4RN590z4g1zf3p4kNsx_yOg,10222
|
|
18
18
|
lsst/ctrl/bps/prepare.py,sha256=Fa2OEQIo4Pa8R5WmRo0PvJgXWNjynRijATvu1x80qlw,3129
|
|
19
19
|
lsst/ctrl/bps/quantum_clustering_funcs.py,sha256=8fidDw53MpcqeWVXs0F0jIvSU0fLV_-1fEbC-Jhqg28,31816
|
|
20
|
-
lsst/ctrl/bps/report.py,sha256=
|
|
20
|
+
lsst/ctrl/bps/report.py,sha256=893m2KBBaQouAml8DKmmVxBo-Q7fFizxl_OT6wyFBXk,8575
|
|
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
24
|
lsst/ctrl/bps/transform.py,sha256=P3dGwKStoCLOn7F2Oez6B__f7bGV5jlUF_Vj9lJQcU0,35256
|
|
25
|
-
lsst/ctrl/bps/version.py,sha256=
|
|
25
|
+
lsst/ctrl/bps/version.py,sha256=qaaoasFkyU8Kx3tKT5jPh3H-bKD5Y8pAmsL3Scaq2UU,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.
|
|
39
|
-
lsst_ctrl_bps-29.2025.
|
|
40
|
-
lsst_ctrl_bps-29.2025.
|
|
41
|
-
lsst_ctrl_bps-29.2025.
|
|
42
|
-
lsst_ctrl_bps-29.2025.
|
|
43
|
-
lsst_ctrl_bps-29.2025.
|
|
44
|
-
lsst_ctrl_bps-29.2025.
|
|
45
|
-
lsst_ctrl_bps-29.2025.
|
|
46
|
-
lsst_ctrl_bps-29.2025.
|
|
47
|
-
lsst_ctrl_bps-29.2025.
|
|
38
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/licenses/COPYRIGHT,sha256=Lc6NoAEFQ65v_SmtS9NwfHTOuSUtC2Umbjv5zyowiQM,61
|
|
39
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
|
|
40
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
|
|
41
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
42
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/METADATA,sha256=Etf24NWJ8pPnq6jmRV-0n55ZhvJ29kDoSXiYFsRHzso,2190
|
|
43
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/entry_points.txt,sha256=d6FhN79h7s9frdBI7YkScsGEInwpGGub49pAjXWbIbI,51
|
|
45
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
|
|
46
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
47
|
+
lsst_ctrl_bps-29.2025.3900.dist-info/RECORD,,
|
|
File without changes
|
{lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/COPYRIGHT
RENAMED
|
File without changes
|
{lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
{lsst_ctrl_bps-29.2025.3700.dist-info → lsst_ctrl_bps-29.2025.3900.dist-info}/licenses/gpl-v3.0.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|