Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# This file is part of daf_butler. 

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 __future__ import annotations 

23 

24__all__ = ("DimensionConfig",) 

25 

26from typing import Any, Dict, Tuple 

27 

28from ..config import Config, ConfigSubset 

29from ..utils import doImport 

30from .. import ddl 

31from .elements import DimensionElement, Dimension, SkyPixDimension, RelatedDimensions 

32 

33 

34class DimensionConfig(ConfigSubset): 

35 """Configuration that defines a `DimensionUniverse`. 

36 

37 The configuration tree for dimensions is a (nested) dictionary 

38 with four top-level entries: 

39 

40 - version: an integer version number, used as keys in a singleton registry 

41 of all `DimensionUniverse` instances; 

42 

43 - skypix: a dictionary whose entries each define a `SkyPixDimension`, 

44 along with a special "common" key whose value is the name of a skypix 

45 dimension that is used to relate all other spatial dimensions in the 

46 `Registry` database; 

47 

48 - elements: a nested dictionary whose entries each define a non-skypix 

49 `DimensionElement`; 

50 

51 - packers: a nested dictionary whose entries define a factory for a 

52 `DimensionPacker` instance. 

53 """ 

54 component = "dimensions" 

55 requiredKeys = ("version", "elements", "skypix") 

56 defaultConfigFile = "dimensions.yaml" 

57 

58 

59def processSkyPixConfig(config: Config) -> Tuple[Dict[str, SkyPixDimension], SkyPixDimension]: 

60 """Process the "skypix" section of a `DimensionConfig`. 

61 

62 Parameters 

63 ---------- 

64 config : `Config` 

65 The subset of a `DimensionConfig` that corresponds to the "skypix" key. 

66 

67 Returns 

68 ------- 

69 dimensions: `dict` 

70 A dictionary mapping `str` names to partially-constructed 

71 `SkyPixDimension` instances; the caller (i.e. a `DimensionUniverse`) 

72 is responsible for calling `DimensionElement._finish` to complete 

73 construction. 

74 common: `SkyPixDimension` 

75 The special dimension used to relate all other spatial dimensions in 

76 the universe. This instance is also guaranteed to be a value in 

77 the returned ``dimensions``. 

78 """ 

79 skyPixSysNames = set(config.keys()) 

80 try: 

81 skyPixSysNames.remove("common") 

82 except KeyError as err: 

83 raise ValueError("No common skypix dimension defined in configuration.") from err 

84 dimensions = {} 

85 for sysName in sorted(skyPixSysNames): 

86 subconfig = config[sysName] 

87 pixelizationClass = doImport(subconfig["class"]) 

88 max_level = subconfig.get("max_level", 24) 

89 for level in range(max_level + 1): 

90 name = f"{sysName}{level}" 

91 dimensions[name] = SkyPixDimension(name, pixelizationClass(level)) 

92 try: 

93 common = dimensions[config["common"]] 

94 except KeyError as err: 

95 raise ValueError(f"Undefined name for common skypix dimension ({config['common']}).") from err 

96 return dimensions, common 

97 

98 

99def processElementsConfig(config: Config) -> Dict[str, DimensionElement]: 

100 """Process the "elements" section of a `DimensionConfig`. 

101 

102 Parameters 

103 ---------- 

104 config : `Config` 

105 The subset of a `DimensionConfig` that corresponds to the "elements" 

106 key. 

107 

108 Returns 

109 ------- 

110 dimensions : `dict` 

111 A dictionary mapping `str` names to partially-constructed 

112 `DimensionElement` instances; the caller (i.e. a `DimensionUniverse`) 

113 is responsible for calling `DimensionElement._finish` to complete 

114 construction. 

115 """ 

116 elements: Dict[str, DimensionElement] = dict() 

117 for name, subconfig in config.items(): 

118 kwargs: Dict[str, Any] = {} 

119 kwargs["related"] = RelatedDimensions( 

120 required=set(subconfig.get("requires", ())), 

121 implied=set(subconfig.get("implies", ())), 

122 spatial=subconfig.get("spatial"), 

123 temporal=subconfig.get("temporal"), 

124 ) 

125 kwargs["metadata"] = [ddl.FieldSpec.fromConfig(c) for c in subconfig.get("metadata", ())] 

126 kwargs["cached"] = subconfig.get("cached", False) 

127 kwargs["viewOf"] = subconfig.get("view_of", None) 

128 kwargs["alwaysJoin"] = subconfig.get("always_join", False) 

129 keys = subconfig.get("keys") 

130 if keys is not None: 

131 uniqueKeys = [ddl.FieldSpec.fromConfig(c, nullable=False) for c in keys] 

132 uniqueKeys[0].primaryKey = True 

133 elements[name] = Dimension(name, uniqueKeys=uniqueKeys, **kwargs) 

134 else: 

135 elements[name] = DimensionElement(name, **kwargs) 

136 return elements