33 from yaml.representer
import Representer
34 yaml.add_representer(collections.defaultdict, Representer.represent_dict)
44 class _PolicyBase(collections.UserDict, yaml.YAMLObject, metaclass=_PolicyMeta):
49 """Policy implements a datatype that is used by Butler for configuration parameters.
50 It is essentially a dict with key/value pairs, including nested dicts (as values). In fact, it can be
51 initialized with a dict. The only caveat is that keys may NOT contain dots ('.'). This is explained next:
52 Policy extends the dict api so that hierarchical values may be accessed with dot-delimited notiation.
53 That is, foo.getValue('a.b.c') is the same as foo['a']['b']['c'] is the same as foo['a.b.c'], and either
54 of these syntaxes may be used.
56 Storage format supported:
57 - yaml: read and write is supported.
61 """Initialize the Policy. Other can be used to initialize the Policy in a variety of ways:
62 other (string) Treated as a path to a policy file on disk. Must end with '.yaml'.
63 other (Policy) Copies the other Policy's values into this one.
64 other (dict) Copies the values from the dict into this Policy.
66 collections.UserDict.__init__(self)
71 if isinstance(other, collections.abc.Mapping):
73 elif isinstance(other, Policy):
74 self.
datadata = copy.deepcopy(other.data)
75 elif isinstance(other, str):
80 raise RuntimeError(
"A Policy could not be loaded from other:%s" % other)
83 """helper function for debugging, prints a policy out in a readable way in the debugger.
85 use: pdb> print myPolicyObject.pprint()
86 :return: a prettyprint formatted string representing the policy
89 return pprint.pformat(self.
datadata, indent=2, width=1)
94 def __initFromFile(self, path):
95 """Load a file from path. If path is a list, will pick one to use, according to order specified
96 by extensionPreference.
98 :param path: string or list of strings, to a persisted policy file.
99 :param extensionPreference: the order in which to try to open files. Will use the first one that
103 if path.endswith(
'yaml'):
106 raise RuntimeError(
"Unhandled policy file type:%s" % path)
108 def __initFromYamlFile(self, path):
109 """Opens a file at a given path and attempts to load it in from yaml.
114 with open(path,
'r')
as f:
117 def __initFromYaml(self, stream):
118 """Loads a YAML policy from any readable stream that contains one.
126 loader = yaml.UnsafeLoader
127 except AttributeError:
129 self.
datadata = yaml.load(stream, Loader=loader)
134 for key
in name.split(
'.'):
141 if isinstance(data, collections.abc.Mapping):
146 if isinstance(value, collections.abc.Mapping):
147 keys = name.split(
'.')
150 for key
in keys[0:-1]:
153 cur[keys[-1]] = value
156 keys = name.split(
'.')
157 for key
in keys[0:-1]:
158 data = data.setdefault(key, {})
159 data[keys[-1]] = value
163 keys = key.split(
'.')
173 """Get the path to a default policy file.
175 Determines a directory for the product specified by productName. Then Concatenates
176 productDir/relativePath/fileName (or productDir/fileName if relativePath is None) to find the path
177 to the default Policy file
179 @param productName (string) The name of the product that the default policy is installed as part of
180 @param fileName (string) The name of the policy file. Can also include a path to the file relative to
181 the directory where the product is installed.
182 @param relativePath (string) The relative path from the directior where the product is installed to
183 the location where the file (or the path to the file) is found. If None
184 (default), the fileName argument is relative to the installation
189 raise RuntimeError(
"No product installed for productName: %s" % basePath)
190 if relativePath
is not None:
191 basePath = os.path.join(basePath, relativePath)
192 fullFilePath = os.path.join(basePath, fileName)
196 """Like dict.update, but will add or modify keys in nested dicts, instead of overwriting the nested
199 For example, for the given code:
200 foo = {'a': {'b': 1}}
201 foo.update({'a': {'c': 2}})
203 If foo is a dict, then after the update foo == {'a': {'c': 2}}
204 But if foo is a Policy, then after the update foo == {'a': {'b': 1, 'c': 2}}
207 for k, v
in u.items():
208 if isinstance(d, collections.abc.Mapping):
209 if isinstance(v, collections.abc.Mapping):
210 r = doUpdate(d.get(k, {}), v)
217 doUpdate(self.
datadata, other)
220 """Like Policy.update, but will add keys & values from other that DO NOT EXIST in self. Keys and
221 values that already exist in self will NOT be overwritten.
226 otherCopy = copy.deepcopy(other)
227 otherCopy.update(self)
228 self.
datadata = otherCopy.data
230 def names(self, topLevelOnly=False):
231 """Get the dot-delimited name of all the keys in the hierarchy.
232 NOTE: this is different than the built-in method dict.keys, which will return only the first level
236 return list(self.keys())
238 def getKeys(d, keys, base):
241 levelKey = base +
'.' + key
if base
is not None else key
242 keys.append(levelKey)
243 if isinstance(val, collections.abc.Mapping):
244 getKeys(val, keys, levelKey)
246 getKeys(self.
datadata, keys,
None)
250 """Get a value as an array. May contain one or more elements.
256 if isinstance(val, str):
258 elif not isinstance(val, collections.abc.Container):
266 """Get the value for a parameter name/key. See class notes about dot-delimited access.
269 :return: the value for the given name.
271 warnings.warn_explicit(
"Deprecated. Use []", DeprecationWarning)
275 """Set the value for a parameter name/key. See class notes about dot-delimited access.
280 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
284 """For any keys in other that are not present in self, sets that key and its value into self.
286 :param other: another Policy
289 warnings.warn(
"Deprecated. Use .merge()", DeprecationWarning)
290 self.
mergemerge(other)
293 """Query if a key exists in this Policy
296 :return: True if the key exists, else false.
298 warnings.warn(
"Deprecated. Use 'key in object'", DeprecationWarning)
302 """Get the string value of a key.
305 :return: the value for key
307 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
308 return str(self[key])
311 """Get the value of a key.
314 :return: the value for key
316 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
317 return bool(self[key])
325 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
329 """Get a value as an array. May contain one or more elements.
334 warnings.warn(
"Deprecated. Use asArray()", DeprecationWarning)
336 if isinstance(val, str):
338 elif not isinstance(val, collections.abc.Container):
343 if isinstance(other, Policy):
345 return self.
datadata < other
348 if isinstance(other, Policy):
350 return self.
datadata <= other
353 if isinstance(other, Policy):
355 return self.
datadata == other
358 if isinstance(other, Policy):
360 return self.
datadata != other
363 if isinstance(other, Policy):
365 return self.
datadata > other
368 if isinstance(other, Policy):
370 return self.
datadata >= other
376 """Writes the policy to a yaml stream.
384 data = copy.copy(self.
datadata)
385 keys = [
'defects',
'needCalibRegistry',
'levels',
'defaultLevel',
'defaultSubLevels',
'camera',
386 'exposures',
'calibrations',
'datasets']
389 yaml.safe_dump({key: data.pop(key)}, output, default_flow_style=
False)
394 yaml.safe_dump(data, output, default_flow_style=
False)
397 """Writes the policy to a file.
402 with open(path,
'w')
as f:
def __initFromYamlFile(self, path)
def defaultPolicyFile(productName, fileName, relativePath=None)
def dump(self, output)
i/o #
def dumpToFile(self, path)
def __initFromYaml(self, stream)
def __init__(self, other=None)
def __contains__(self, key)
def __setitem__(self, name, value)
def __getitem__(self, name)
def __initFromFile(self, path)
def getStringArray(self, key)
def setValue(self, name, value)
def names(self, topLevelOnly=False)
def mergeDefaults(self, other)
daf::base::PropertyList * list
std::string getPackageDir(std::string const &packageName)
return the root directory of a setup package