Coverage for python / lsst / obs / base / cli / cmd / commands.py: 90%

72 statements  

« prev     ^ index     » next       coverage.py v7.13.2, created at 2026-02-04 01:12 -0800

1# This file is part of obs_base. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://www.lsst.org). 

6# See the COPYRIGHT file at the top-level directory of this distribution 

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21 

22from collections.abc import Sequence 

23from typing import Any 

24 

25import click 

26 

27from lsst.daf.butler import Butler 

28from lsst.daf.butler.cli.opt import ( 

29 collections_argument, 

30 config_file_option, 

31 config_option, 

32 locations_argument, 

33 options_file_option, 

34 processes_option, 

35 regex_option, 

36 repo_argument, 

37 run_option, 

38 transfer_option, 

39 where_option, 

40) 

41from lsst.daf.butler.cli.utils import ButlerCommand, split_commas, typeStrAcceptsMultiple 

42from lsst.pipe.base.cli.opt import instrument_argument 

43 

44from ... import script 

45from ..opt import failfast_option, labels_argument 

46 

47# regular expression that can be used to find supported fits file extensions. 

48fits_re = r"\.fit[s]?\b" 

49 

50 

51@click.command(short_help="Define visits from exposures.", cls=ButlerCommand) 

52@repo_argument(required=True) 

53@instrument_argument(required=True) 

54@config_file_option( 

55 help="Path to a pex_config override to be included after the Instrument config overrides are applied." 

56) 

57@click.option( 

58 "--collections", 

59 help="The collections to be searched (in order) for camera geometry.", 

60 multiple=True, 

61 callback=split_commas, 

62 metavar=typeStrAcceptsMultiple, 

63) 

64@where_option() 

65@click.option( 

66 "--update-records/--no-update-records", 

67 default=False, 

68 help="Use this option to force updates to the visit definition record. " 

69 "Should only be used if you know that there has been a change to the " 

70 "exposure records, such as a change to the metadata translator.", 

71) 

72@click.option( 

73 "--incremental/--no-incremental", 

74 default=False, 

75 help="Use this option to force updates to the visit definition record " 

76 "when multi-snap visits are being ingested incrementally and so you " 

77 "might encounter partial visits. Implies --update-records.", 

78) 

79@options_file_option() 

80def define_visits(*args: Any, **kwargs: Any) -> None: 

81 """Define visits from exposures in the butler registry. 

82 

83 The calibration collection containing the camera geometry can not 

84 be specified. 

85 """ 

86 script.defineVisits(*args, **kwargs) 

87 

88 

89@click.command(short_help="Ingest raw frames.", cls=ButlerCommand) 

90@repo_argument(required=True) 

91@locations_argument( 

92 help="LOCATIONS specifies files to ingest and/or locations to search for files.", required=True 

93) 

94@regex_option( 

95 default=fits_re, 

96 help="Regex string used to find files in directories listed in LOCATIONS. " 

97 "Searches for fits files by default.", 

98) 

99@config_option(metavar="TEXT=TEXT", multiple=True) 

100@config_file_option(type=click.Path(exists=True, writable=False, file_okay=True, dir_okay=False)) 

101@run_option(required=False) 

102@transfer_option() 

103@processes_option(help="Number of workers to use.") 

104@click.option( 

105 "--ingest-task", 

106 default="lsst.obs.base.RawIngestTask", 

107 help="The fully qualified class name of the ingest task to use.", 

108) 

109@click.option( 

110 "--track-file-attrs/--no-track-file-attrs", 

111 default=True, 

112 help="Indicate to the datastore whether file attributes such as file size" 

113 " or checksum should be tracked or not. Whether this parameter is honored" 

114 " depends on the specific datastore implentation.", 

115) 

116@failfast_option() 

117@click.option( 

118 "--update-records/--no-update-records", 

119 default=False, 

120 help="Use this option to force updates to the exposure records. " 

121 "Should only be used if you know that there has been a change to the " 

122 "exposure records, such as a change to the metadata translator.", 

123) 

124@click.option( 

125 "--skip-existing/--no-skip-existing", 

126 default=True, 

127 help="Use this option to control whether a raw file already existing " 

128 "in the Butler repository is an error or not.", 

129) 

130@click.option( 

131 "--search-indexes/--no-search-indexes", 

132 default=True, 

133 help="By default ingest searches for index files in each directory being " 

134 "searched. Turning this off can improve performance if you know for a fact " 

135 "you have no indexes and you are using an object store.", 

136) 

137@options_file_option() 

138def ingest_raws(*args: Any, **kwargs: Any) -> None: 

139 """Ingest raw frames into from a directory into the butler registry.""" 

140 script.ingestRaws(*args, **kwargs) 

141 

142 

143@click.command(short_help="Add an instrument's curated calibrations.", cls=ButlerCommand) 

144@repo_argument(required=True) 

145@instrument_argument(required=True) 

146@labels_argument() 

147@click.option( 

148 "--collection", 

149 required=False, 

150 help="Name of the calibration collection that associates datasets with validity ranges.", 

151) 

152@click.option( 

153 "--label", 

154 "labels", 

155 multiple=True, 

156 help=( 

157 "Extra strings to include (with automatic delimiters) in all RUN collection names, " 

158 "as well as the calibration collection name if it is not provided via --collection. " 

159 "May be provided as a positional argument instead of or in addition to this option, " 

160 "as long as at least one label is provided. Positional-argument labels appear before " 

161 "those provided by this option." 

162 ), 

163) 

164@click.option( 

165 "--prefix", 

166 required=False, 

167 help=( 

168 "Prefix for the collection name. Default is the instrument name. " 

169 "This is ignored if --collection is passed." 

170 ), 

171) 

172@options_file_option() 

173def write_curated_calibrations( 

174 *, 

175 repo: str, 

176 instrument: str, 

177 collection: str, 

178 labels: list[str], 

179 labels_arg: list[str], 

180 prefix: str, 

181) -> None: 

182 """Add an instrument's curated calibrations to the data repository.""" 

183 script.writeCuratedCalibrations( 

184 repo=repo, instrument=instrument, collection=collection, labels=labels_arg + labels, prefix=prefix 

185 ) 

186 

187 

188@click.command() 

189@repo_argument(required=True) 

190@instrument_argument(required=True, help="Name of the instrument to use for updates.") 

191@collections_argument(help="Collections to search for visit geometry datasets.") 

192@click.option("--dataset-type", default="visit_geometry", help="Name of the visit geometry dataset type.") 

193@click.option("--batch-size", default=11, help="Number of visits to process in each transaction.") 

194@where_option() 

195def update_dimension_regions( 

196 *, 

197 repo: str, 

198 instrument: str, 

199 collections: Sequence[str], 

200 dataset_type: str, 

201 batch_size: int, 

202 where: str, 

203) -> None: 

204 """Update dimension record regions from visit geometry datasets.""" 

205 from ...visit_geometry import VisitGeometry 

206 

207 with Butler.from_config(repo, writeable=True, collections=collections) as butler: 

208 VisitGeometry.update_dimension_records( 

209 butler, instrument, where, dataset_type=dataset_type, batch_size=batch_size 

210 ) 

211 

212 

213@click.command 

214@repo_argument(required=True) 

215@instrument_argument(required=True, help="Instrument to use for finding raw datasets.") 

216@collections_argument(help="List of collections to search for raws instead of the default.") 

217@where_option( 

218 help="A string expression to use to query the butler to find raw datasets to use for record updates." 

219) 

220@failfast_option() 

221@config_option(metavar="TEXT=TEXT", multiple=True) 

222@config_file_option(type=click.Path(exists=True, writable=False, file_okay=True, dir_okay=False)) 

223@processes_option() 

224@options_file_option() 

225def update_exposures_from_raws(*args: Any, **kwargs: Any) -> None: 

226 """Update exposure records associated with specific raw datasets.""" 

227 script.updateExposures(*args, **kwargs)