lsst-pipe-base 30.2025.5100__py3-none-any.whl → 30.2026.100__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,17 +31,15 @@ __all__ = ["LogCapture"]
31
31
 
32
32
  import dataclasses
33
33
  import logging
34
- import os
35
- import shutil
36
- import tempfile
37
34
  import uuid
38
35
  from collections.abc import Iterator
39
- from contextlib import contextmanager, suppress
36
+ from contextlib import contextmanager
40
37
  from logging import FileHandler
41
38
 
42
39
  import pydantic
43
40
 
44
- from lsst.daf.butler import Butler, FileDataset, LimitedButler, Quantum
41
+ from lsst.daf.butler import Butler, LimitedButler, Quantum
42
+ from lsst.daf.butler._rubin.temporary_for_ingest import TemporaryForIngest
45
43
  from lsst.daf.butler.logging import (
46
44
  ButlerLogRecord,
47
45
  ButlerLogRecordHandler,
@@ -205,41 +203,37 @@ class LogCapture:
205
203
 
206
204
  # Add a handler to the root logger to capture execution log output.
207
205
  if log_dataset_name is not None:
206
+ try:
207
+ [ref] = quantum.outputs[log_dataset_name]
208
+ except LookupError as exc:
209
+ raise InvalidQuantumError(
210
+ f"Quantum outputs is missing log output dataset type {log_dataset_name};"
211
+ " this could happen due to inconsistent options between QuantumGraph generation"
212
+ " and execution"
213
+ ) from exc
208
214
  # Either accumulate into ButlerLogRecords or stream JSON records to
209
215
  # file and ingest that (ingest is possible only with full butler).
210
216
  if self.stream_json_logs and self.full_butler is not None:
211
- # Create the log file in a temporary directory rather than
212
- # creating a temporary file. This is necessary because
213
- # temporary files are created with restrictive permissions
214
- # and during file ingest these permissions persist in the
215
- # datastore. Using a temp directory allows us to create
216
- # a file with umask default permissions.
217
- tmpdir = tempfile.mkdtemp(prefix="butler-temp-logs-")
218
-
219
- # Construct a file to receive the log records and "touch" it.
220
- log_file = os.path.join(tmpdir, f"butler-log-{task_node.label}.json")
221
- with open(log_file, "w"):
222
- pass
223
- log_handler_file = FileHandler(log_file)
224
- log_handler_file.setFormatter(JsonLogFormatter())
225
- logging.getLogger().addHandler(log_handler_file)
226
-
227
- try:
228
- with ButlerMDC.set_mdc(mdc):
229
- yield ctx
230
- finally:
231
- # Ensure that the logs are stored in butler.
232
- logging.getLogger().removeHandler(log_handler_file)
233
- log_handler_file.close()
234
- if ctx.extra:
235
- with open(log_file, "a") as log_stream:
236
- ButlerLogRecords.write_streaming_extra(
237
- log_stream,
238
- ctx.extra.model_dump_json(exclude_unset=True, exclude_defaults=True),
239
- )
240
- if ctx.store:
241
- self._ingest_log_records(quantum, log_dataset_name, log_file)
242
- shutil.rmtree(tmpdir, ignore_errors=True)
217
+ with TemporaryForIngest(self.full_butler, ref) as temporary:
218
+ log_handler_file = FileHandler(temporary.ospath)
219
+ log_handler_file.setFormatter(JsonLogFormatter())
220
+ logging.getLogger().addHandler(log_handler_file)
221
+
222
+ try:
223
+ with ButlerMDC.set_mdc(mdc):
224
+ yield ctx
225
+ finally:
226
+ # Ensure that the logs are stored in butler.
227
+ logging.getLogger().removeHandler(log_handler_file)
228
+ log_handler_file.close()
229
+ if ctx.extra:
230
+ with open(temporary.ospath, "a") as log_stream:
231
+ ButlerLogRecords.write_streaming_extra(
232
+ log_stream,
233
+ ctx.extra.model_dump_json(exclude_unset=True, exclude_defaults=True),
234
+ )
235
+ if ctx.store:
236
+ temporary.ingest()
243
237
 
244
238
  else:
245
239
  log_handler_memory = ButlerLogRecordHandler()
@@ -281,41 +275,3 @@ class LogCapture:
281
275
  ) from exc
282
276
 
283
277
  self.butler.put(log_handler.records, ref)
284
-
285
- def _ingest_log_records(self, quantum: Quantum, dataset_type: str, filename: str) -> None:
286
- # If we are logging to an external file we must always try to
287
- # close it.
288
- assert self.full_butler is not None, "Expected to have full butler for ingest"
289
- ingested = False
290
- try:
291
- # DatasetRef has to be in the Quantum outputs, can lookup by name.
292
- try:
293
- [ref] = quantum.outputs[dataset_type]
294
- except LookupError as exc:
295
- raise InvalidQuantumError(
296
- f"Quantum outputs is missing log output dataset type {dataset_type};"
297
- " this could happen due to inconsistent options between QuantumGraph generation"
298
- " and execution"
299
- ) from exc
300
-
301
- # Need to ingest this file directly into butler.
302
- dataset = FileDataset(path=filename, refs=ref)
303
- try:
304
- self.full_butler.ingest(dataset, transfer="move")
305
- ingested = True
306
- except NotImplementedError:
307
- # Some datastores can't receive files (e.g. in-memory datastore
308
- # when testing), we store empty list for those just to have a
309
- # dataset. Alternative is to read the file as a
310
- # ButlerLogRecords object and put it.
311
- _LOG.info(
312
- "Log records could not be stored in this butler because the"
313
- " datastore can not ingest files, empty record list is stored instead."
314
- )
315
- records = ButlerLogRecords.from_records([])
316
- self.full_butler.put(records, ref)
317
- finally:
318
- # remove file if it is not ingested
319
- if not ingested:
320
- with suppress(OSError):
321
- os.remove(filename)
lsst/pipe/base/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "30.2025.5100"
2
+ __version__ = "30.2026.100"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-pipe-base
3
- Version: 30.2025.5100
3
+ Version: 30.2026.100
4
4
  Summary: Pipeline infrastructure for the Rubin Science Pipelines.
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
@@ -20,7 +20,7 @@ lsst/pipe/base/exec_fixup_data_id.py,sha256=9OjOcH-6AHZ1JnD_CemieI0wWX90J_VdaY9v
20
20
  lsst/pipe/base/execution_graph_fixup.py,sha256=ND0x4hlpeEW-gudo-i2K7HT7MoM5sp_mcoqRMCopSqQ,3815
21
21
  lsst/pipe/base/execution_reports.py,sha256=jYtWCD4PkEAeVUpKIxuiJJVgsCm7qiwCorWVgNHkVgU,17270
22
22
  lsst/pipe/base/graph_walker.py,sha256=Ij7JfYF0srA29VgM_DhbNBxUBeOHDOnujrTQPjVNha0,4694
23
- lsst/pipe/base/log_capture.py,sha256=5r99_Ek2A75vYOMo-z52ltWLdfYfWExm55UU9a4nqmM,12909
23
+ lsst/pipe/base/log_capture.py,sha256=2kuapttiMwpvevOleOMDcjEorXBCiVNSzsKj9fMDhI4,10818
24
24
  lsst/pipe/base/mermaid_tools.py,sha256=cdlDJQ1x8k7-VvCLEUqvSC3GR1zCsB-aUTxOjYejNWc,5216
25
25
  lsst/pipe/base/mp_graph_executor.py,sha256=FKlFxjtU2-6SFzX_wsdtMMAj5P09ZE8V65-Sg585g2Y,35501
26
26
  lsst/pipe/base/pipeline.py,sha256=FVaiLhgw9Pzo-nzXKS0dLNafegP0AMZKLtPlSvOSkRU,37563
@@ -42,7 +42,7 @@ lsst/pipe/base/task.py,sha256=XHBd-7m1a4-6LgobBYA1DgY4H7EV-_RWKfxbhZbMmD4,15145
42
42
  lsst/pipe/base/taskFactory.py,sha256=MsDGECJqZLSZk8SGhpuVhNaP32UWuNvxZiDcZExPFG8,3412
43
43
  lsst/pipe/base/testUtils.py,sha256=lSBKMhoKflbi8JkMNYfEqqHNl-rtFI8UYT3QneDYpLo,18477
44
44
  lsst/pipe/base/utils.py,sha256=JmEt3l0xrh9uayKrSXuQEq12aXOhDr2YXmbYduaxCko,1940
45
- lsst/pipe/base/version.py,sha256=T_ii-AmyfLEzX_XiWTNw5GEFMy94NcXrbg2rkzKZg7g,55
45
+ lsst/pipe/base/version.py,sha256=BC5axNzZNKnyS8niPRP5v8FOY10ThRUTtQL-d2K4BdU,54
46
46
  lsst/pipe/base/cli/__init__.py,sha256=861tXIAW7SqtqNUYkjbeEdfg8lDswXsjJQca0gVCFz4,54
47
47
  lsst/pipe/base/cli/_get_cli_subcommands.py,sha256=g_af64klRybBGKAg7fmBSZBdw2LYBAsFON_yQIMZON0,1289
48
48
  lsst/pipe/base/cli/cmd/__init__.py,sha256=3UF2IQEEBor4YMGRNPdcZAVCAI5yFyeHp5nGul4IoyM,1557
@@ -113,13 +113,13 @@ lsst/pipe/base/tests/mocks/_data_id_match.py,sha256=jVekStcrItC0tqOCc01VjYaiE9ex
113
113
  lsst/pipe/base/tests/mocks/_pipeline_task.py,sha256=N3fC4OMAMWWnYtyLkVdMfb9ZiFse39HniRDvlAOofOY,30691
114
114
  lsst/pipe/base/tests/mocks/_repo.py,sha256=SH-jzynS-H2xc_3GLjF7ln-kHdRoSeVVaal5qLd2hXI,28359
115
115
  lsst/pipe/base/tests/mocks/_storage_class.py,sha256=12IFfJMbZ5GkYlMX6ZMWiG8pMZc2Jlxke3qQW-bljdU,27434
116
- lsst_pipe_base-30.2025.5100.dist-info/licenses/COPYRIGHT,sha256=kB3Z9_f6a6uFLGpEmNJT_n186CE65H6wHu4F6BNt_zA,368
117
- lsst_pipe_base-30.2025.5100.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
118
- lsst_pipe_base-30.2025.5100.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
119
- lsst_pipe_base-30.2025.5100.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
120
- lsst_pipe_base-30.2025.5100.dist-info/METADATA,sha256=AZu2-D91gCmfRmP0m2ETbsiRKZwX8DXqBiO-rvyDzFo,2257
121
- lsst_pipe_base-30.2025.5100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
122
- lsst_pipe_base-30.2025.5100.dist-info/entry_points.txt,sha256=bnmUhJBsChxMdqST9VmFBYYKxLQoToOfqW1wjW7khjk,64
123
- lsst_pipe_base-30.2025.5100.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
124
- lsst_pipe_base-30.2025.5100.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
125
- lsst_pipe_base-30.2025.5100.dist-info/RECORD,,
116
+ lsst_pipe_base-30.2026.100.dist-info/licenses/COPYRIGHT,sha256=kB3Z9_f6a6uFLGpEmNJT_n186CE65H6wHu4F6BNt_zA,368
117
+ lsst_pipe_base-30.2026.100.dist-info/licenses/LICENSE,sha256=pRExkS03v0MQW-neNfIcaSL6aiAnoLxYgtZoFzQ6zkM,232
118
+ lsst_pipe_base-30.2026.100.dist-info/licenses/bsd_license.txt,sha256=7MIcv8QRX9guUtqPSBDMPz2SnZ5swI-xZMqm_VDSfxY,1606
119
+ lsst_pipe_base-30.2026.100.dist-info/licenses/gpl-v3.0.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
120
+ lsst_pipe_base-30.2026.100.dist-info/METADATA,sha256=TTpe8bR7EgNLhCX02RnYtBxB9WOIAsmdJSbrUpS-XUA,2256
121
+ lsst_pipe_base-30.2026.100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
122
+ lsst_pipe_base-30.2026.100.dist-info/entry_points.txt,sha256=bnmUhJBsChxMdqST9VmFBYYKxLQoToOfqW1wjW7khjk,64
123
+ lsst_pipe_base-30.2026.100.dist-info/top_level.txt,sha256=eUWiOuVVm9wwTrnAgiJT6tp6HQHXxIhj2QSZ7NYZH80,5
124
+ lsst_pipe_base-30.2026.100.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
125
+ lsst_pipe_base-30.2026.100.dist-info/RECORD,,