24 from builtins
import str
25 from past.builtins
import basestring
26 from future.utils
import with_metaclass
29 import collections.abc
39 from yaml.representer
import Representer
40 yaml.add_representer(collections.defaultdict, Representer.represent_dict)
47 if sys.version_info[0] >= 3:
54 class _PolicyBase(collections.UserDict, yaml.YAMLObject):
59 """Policy implements a datatype that is used by Butler for configuration parameters. 60 It is essentially a dict with key/value pairs, including nested dicts (as values). In fact, it can be 61 initialized with a dict. The only caveat is that keys may NOT contain dots ('.'). This is explained next: 62 Policy extends the dict api so that hierarchical values may be accessed with dot-delimited notiation. 63 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 64 of these syntaxes may be used. 66 Storage formats supported: 67 - yaml: read and write is supported. 68 - pex policy: read is supported, although this is deprecated and will at some point be removed. 72 """Initialize the Policy. Other can be used to initialize the Policy in a variety of ways: 73 other (string) Treated as a path to a policy file on disk. Must end with '.paf' or '.yaml'. 74 other (Pex Policy) Initializes this Policy with the values in the passed-in Pex Policy. 75 other (Policy) Copies the other Policy's values into this one. 76 other (dict) Copies the values from the dict into this Policy. 78 collections.UserDict.__init__(self)
83 if isinstance(other, collections.abc.Mapping):
85 elif isinstance(other, Policy):
86 self.
data = copy.deepcopy(other.data)
87 elif isinstance(other, basestring):
95 raise RuntimeError(
"A Policy could not be loaded from other:%s" % other)
98 """helper function for debugging, prints a policy out in a readable way in the debugger. 100 use: pdb> print myPolicyObject.pprint() 101 :return: a prettyprint formatted string representing the policy 104 return pprint.pformat(self.
data, indent=2, width=1)
109 def __initFromFile(self, path):
110 """Load a file from path. If path is a list, will pick one to use, according to order specified 111 by extensionPreference. 113 :param path: string or list of strings, to a persisted policy file. 114 :param extensionPreference: the order in which to try to open files. Will use the first one that 119 if path.endswith(
'yaml'):
121 elif path.endswith(
'paf'):
122 policy = pexPolicy.Policy.createPolicy(path)
125 raise RuntimeError(
"Unhandled policy file type:%s" % path)
127 def __initFromPexPolicy(self, pexPolicy):
128 """Load values from a pex policy. 133 names = pexPolicy.names()
136 if pexPolicy.getValueType(name) == pexPolicy.POLICY:
142 if pexPolicy.isArray(name):
143 self[name] = pexPolicy.getArray(name)
145 self[name] = pexPolicy.get(name)
148 def __initFromYamlFile(self, path):
149 """Opens a file at a given path and attempts to load it in from yaml. 154 with open(path,
'r') as f: 157 def __initFromYaml(self, stream):
158 """Loads a YAML policy from any readable stream that contains one. 166 loader = yaml.FullLoader
167 except AttributeError:
169 self.
data = yaml.load(stream, Loader=loader)
174 for key
in name.split(
'.'):
181 if isinstance(data, collections.abc.Mapping):
186 if isinstance(value, collections.abc.Mapping):
187 keys = name.split(
'.')
190 for key
in keys[0:-1]:
193 cur[keys[-1]] = value
196 keys = name.split(
'.')
197 for key
in keys[0:-1]:
198 data = data.setdefault(key, {})
199 data[keys[-1]] = value
203 keys = key.split(
'.')
213 """Get the path to a default policy file. 215 Determines a directory for the product specified by productName. Then Concatenates 216 productDir/relativePath/fileName (or productDir/fileName if relativePath is None) to find the path 217 to the default Policy file 219 @param productName (string) The name of the product that the default policy is installed as part of 220 @param fileName (string) The name of the policy file. Can also include a path to the file relative to 221 the directory where the product is installed. 222 @param relativePath (string) The relative path from the directior where the product is installed to 223 the location where the file (or the path to the file) is found. If None 224 (default), the fileName argument is relative to the installation 229 raise RuntimeError(
"No product installed for productName: %s" % basePath)
230 if relativePath
is not None:
231 basePath = os.path.join(basePath, relativePath)
232 fullFilePath = os.path.join(basePath, fileName)
236 """Like dict.update, but will add or modify keys in nested dicts, instead of overwriting the nested 239 For example, for the given code: 240 foo = {'a': {'b': 1}} 241 foo.update({'a': {'c': 2}}) 243 If foo is a dict, then after the update foo == {'a': {'c': 2}} 244 But if foo is a Policy, then after the update foo == {'a': {'b': 1, 'c': 2}} 247 for k, v
in u.items():
248 if isinstance(d, collections.abc.Mapping):
249 if isinstance(v, collections.abc.Mapping):
250 r = doUpdate(d.get(k, {}), v)
257 doUpdate(self.
data, other)
260 """Like Policy.update, but will add keys & values from other that DO NOT EXIST in self. Keys and 261 values that already exist in self will NOT be overwritten. 266 otherCopy = copy.deepcopy(other)
267 otherCopy.update(self)
268 self.
data = otherCopy.data
270 def names(self, topLevelOnly=False):
271 """Get the dot-delimited name of all the keys in the hierarchy. 272 NOTE: this is different than the built-in method dict.keys, which will return only the first level 276 return list(self.keys())
278 def getKeys(d, keys, base):
281 levelKey = base +
'.' + key
if base
is not None else key
282 keys.append(levelKey)
283 if isinstance(val, collections.abc.Mapping):
284 getKeys(val, keys, levelKey)
286 getKeys(self.
data, keys,
None)
290 """Get a value as an array. May contain one or more elements. 296 if isinstance(val, basestring):
298 elif not isinstance(val, collections.abc.Container):
306 """Get the value for a parameter name/key. See class notes about dot-delimited access. 309 :return: the value for the given name. 311 warnings.warn_explicit(
"Deprecated. Use []", DeprecationWarning)
315 """Set the value for a parameter name/key. See class notes about dot-delimited access. 320 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
324 """For any keys in other that are not present in self, sets that key and its value into self. 326 :param other: another Policy 329 warnings.warn(
"Deprecated. Use .merge()", DeprecationWarning)
333 """Query if a key exists in this Policy 336 :return: True if the key exists, else false. 338 warnings.warn(
"Deprecated. Use 'key in object'", DeprecationWarning)
342 """Get the string value of a key. 345 :return: the value for key 347 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
348 return str(self[key])
351 """Get the value of a key. 354 :return: the value for key 356 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
357 return bool(self[key])
365 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
369 """Get a value as an array. May contain one or more elements. 374 warnings.warn(
"Deprecated. Use asArray()", DeprecationWarning)
376 if isinstance(val, basestring):
378 elif not isinstance(val, collections.abc.Container):
383 if isinstance(other, Policy):
385 return self.
data < other
388 if isinstance(other, Policy):
390 return self.
data <= other
393 if isinstance(other, Policy):
395 return self.
data == other
398 if isinstance(other, Policy):
400 return self.
data != other
403 if isinstance(other, Policy):
405 return self.
data > other
408 if isinstance(other, Policy):
410 return self.
data >= other
416 """Writes the policy to a yaml stream. 424 data = copy.copy(self.
data)
425 keys = [
'defects',
'needCalibRegistry',
'levels',
'defaultLevel',
'defaultSubLevels',
'camera',
426 'exposures',
'calibrations',
'datasets']
429 yaml.safe_dump({key: data.pop(key)}, output, default_flow_style=
False)
434 yaml.safe_dump(data, output, default_flow_style=
False)
437 """Writes the policy to a file. 442 with open(path,
'w')
as f:
def __initFromYaml(self, stream)
def __initFromYamlFile(self, path)
def dump(self, output)
i/o #
def dumpToFile(self, path)
def __initFromPexPolicy(self, pexPolicy)
a container for holding hierarchical configuration data in memory.
def getStringArray(self, key)
def __setitem__(self, name, value)
std::string getPackageDir(std::string const &packageName)
return the root directory of a setup package
def __getitem__(self, name)
def __initFromFile(self, path)
def __init__(self, other=None)
def defaultPolicyFile(productName, fileName, relativePath=None)
def __contains__(self, key)
def mergeDefaults(self, other)
def names(self, topLevelOnly=False)
daf::base::PropertyList * list
def setValue(self, name, value)