Coverage for python/lsst/ap/pipe/make_apdb.py: 25%

52 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-27 03:40 -0700

1# This file is part of ap_pipe. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://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 <https://www.gnu.org/licenses/>. 

21 

22__all__ = ["makeApdb"] 

23 

24import argparse 

25 

26import lsst.dax.apdb as daxApdb 

27from lsst.pipe.base.configOverrides import ConfigOverrides 

28from lsst.ap.association import DiaPipelineConfig 

29 

30 

31class ConfigOnlyParser(argparse.ArgumentParser): 

32 """Argument parser that knows standard config arguments. 

33 """ 

34 

35 def __init__(self, description=None, **kwargs): 

36 if description is None: 

37 # Description must be readable in both Sphinx and make_apdb.py -h 

38 description = """\ 

39Create a Alert Production Database using config overrides for 

40`lsst.dax.apdb.ApdbConfig`. 

41 

42This script takes the same ``--config`` and ``--config-file`` arguments as 

43pipeline runs. However, the configs are at a lower level than the AP pipeline. 

44 

45The config overrides must define ``db_url`` to create a valid config. 

46""" 

47 

48 super().__init__(description=description, **kwargs) 

49 

50 self.add_argument("-c", "--config", nargs="*", action=ConfigValueAction, 

51 help="config override(s), e.g. " 

52 "``-c prefix=fancy db_url=\"sqlite://\"``", 

53 metavar="NAME=VALUE") 

54 self.add_argument("-C", "--config-file", dest="configfile", nargs="*", action=ConfigFileAction, 

55 help="config override file(s) for ApdbConfig") 

56 

57 def parse_args(self, args=None, namespace=None): 

58 """Parse arguments for an `ApdbConfig`. 

59 

60 Parameters 

61 ---------- 

62 args : `list` [`str`], optional 

63 Argument list; if `None` then ``sys.argv`` is used. 

64 namespace : `argparse.Namespace`, optional 

65 An object to take the attributes. The default is a new empty 

66 `~argparse.Namespace` object 

67 

68 Returns 

69 ------- 

70 namespace : `argparse.Namespace` 

71 A `~argparse.Namespace` instance containing fields: 

72 - ``config``: the supplied config with all overrides applied, 

73 validated and frozen. 

74 """ 

75 if not namespace: 

76 namespace = argparse.Namespace() 

77 namespace.overrides = ConfigOverrides() 

78 

79 # ConfigFileAction and ConfigValueAction require namespace.overrides to exist 

80 namespace = super().parse_args(args, namespace) 

81 del namespace.configfile 

82 # Make ApdbConfig as a subconfig of DiaPipelineConfig to ensure correct defaults get set 

83 namespace.config = DiaPipelineConfig().apdb.value 

84 try: 

85 namespace.overrides.applyTo(namespace.config) 

86 except Exception as e: # yes, configs really can raise anything 

87 message = str(e) 

88 if "diaPipe" in message: 

89 message = "it looks like one of the config files uses ApPipeConfig; " \ 

90 "try dropping 'diaPipe.apdb'\n" + message 

91 self.error(f"cannot apply config: {message}") 

92 

93 namespace.config.validate() 

94 namespace.config.freeze() 

95 

96 return namespace 

97 

98 

99def makeApdb(args=None): 

100 """Create an APDB according to a config. 

101 

102 The command-line arguments should provide config values or a config file 

103 for `ApdbConfig`. 

104 

105 Parameters 

106 ---------- 

107 args : `list` [`str`], optional 

108 List of command-line arguments; if `None` use `sys.argv`. 

109 

110 Returns 

111 ------- 

112 apdb : `lsst.dax.apdb.Apdb` 

113 The newly configured APDB object. 

114 """ 

115 

116 parser = ConfigOnlyParser() 

117 parsedCmd = parser.parse_args(args=args) 

118 

119 apdb = daxApdb.make_apdb(config=parsedCmd.config) 

120 apdb.makeSchema() 

121 return apdb 

122 

123 

124# -------------------------------------------------------------------- 

125# argparse.Actions for use with ConfigOverrides 

126# ConfigOverrides is normally used with Click; there is no built-in 

127# argparse support. 

128 

129 

130class ConfigValueAction(argparse.Action): 

131 """argparse action to override config parameters using 

132 name=value pairs from the command-line. 

133 """ 

134 

135 def __call__(self, parser, namespace, values, option_string): 

136 if namespace.overrides is None: 

137 return 

138 for nameValue in values: 

139 name, sep, valueStr = nameValue.partition("=") 

140 if not valueStr: 

141 parser.error(f"{option_string} value {nameValue} must be in form name=value") 

142 if "diaPipe.apdb" in name: 

143 parser.error(f"{nameValue} looks like it uses ApPipeConfig; try dropping 'diaPipe.apdb'") 

144 

145 namespace.overrides.addValueOverride(name, valueStr) 

146 

147 

148class ConfigFileAction(argparse.Action): 

149 """argparse action to load config overrides from one or more files. 

150 """ 

151 

152 def __call__(self, parser, namespace, values, option_string=None): 

153 if namespace.overrides is None: 

154 return 

155 for configfile in values: 

156 namespace.overrides.addFileOverride(configfile)