24 from builtins
import str
25 from past.builtins
import basestring
26 from future.utils
import with_metaclass
38 from yaml.representer
import Representer
39 yaml.add_representer(collections.defaultdict, Representer.represent_dict)
46 if sys.version_info[0] >= 3:
47 class _PolicyMeta(type(collections.UserDict), type(yaml.YAMLObject)):
53 class _PolicyBase(collections.UserDict, yaml.YAMLObject):
58 """Policy implements a datatype that is used by Butler for configuration parameters. 59 It is essentially a dict with key/value pairs, including nested dicts (as values). In fact, it can be 60 initialized with a dict. The only caveat is that keys may NOT contain dots ('.'). This is explained next: 61 Policy extends the dict api so that hierarchical values may be accessed with dot-delimited notiation. 62 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 63 of these syntaxes may be used. 65 Storage formats supported: 66 - yaml: read and write is supported. 67 - pex policy: read is supported, although this is deprecated and will at some point be removed. 71 """Initialize the Policy. Other can be used to initialize the Policy in a variety of ways: 72 other (string) Treated as a path to a policy file on disk. Must end with '.paf' or '.yaml'. 73 other (Pex Policy) Initializes this Policy with the values in the passed-in Pex Policy. 74 other (Policy) Copies the other Policy's values into this one. 75 other (dict) Copies the values from the dict into this Policy. 77 collections.UserDict.__init__(self)
82 if isinstance(other, collections.Mapping):
84 elif isinstance(other, Policy):
85 self.
data = copy.deepcopy(other.data)
86 elif isinstance(other, basestring):
94 raise RuntimeError(
"A Policy could not be loaded from other:%s" % other)
97 """helper function for debugging, prints a policy out in a readable way in the debugger. 99 use: pdb> print myPolicyObject.pprint() 100 :return: a prettyprint formatted string representing the policy 103 return pprint.pformat(self.
data, indent=2, width=1)
108 def __initFromFile(self, path):
109 """Load a file from path. If path is a list, will pick one to use, according to order specified 110 by extensionPreference. 112 :param path: string or list of strings, to a persisted policy file. 113 :param extensionPreference: the order in which to try to open files. Will use the first one that 118 if path.endswith(
'yaml'):
120 elif path.endswith(
'paf'):
121 policy = pexPolicy.Policy.createPolicy(path)
124 raise RuntimeError(
"Unhandled policy file type:%s" % path)
126 def __initFromPexPolicy(self, pexPolicy):
127 """Load values from a pex policy. 132 names = pexPolicy.names()
135 if pexPolicy.getValueType(name) == pexPolicy.POLICY:
141 if pexPolicy.isArray(name):
142 self[name] = pexPolicy.getArray(name)
144 self[name] = pexPolicy.get(name)
147 def __initFromYamlFile(self, path):
148 """Opens a file at a given path and attempts to load it in from yaml. 153 with open(path,
'r') as f: 156 def __initFromYaml(self, stream):
157 """Loads a YAML policy from any readable stream that contains one. 163 self.
data = yaml.load(stream)
168 for key
in name.split(
'.'):
175 if isinstance(data, collections.Mapping):
180 if isinstance(value, collections.Mapping):
181 keys = name.split(
'.')
184 for key
in keys[0:-1]:
187 cur[keys[-1]] = value
190 keys = name.split(
'.')
191 for key
in keys[0:-1]:
192 data = data.setdefault(key, {})
193 data[keys[-1]] = value
197 keys = key.split(
'.')
207 """Get the path to a default policy file. 209 Determines a directory for the product specified by productName. Then Concatenates 210 productDir/relativePath/fileName (or productDir/fileName if relativePath is None) to find the path 211 to the default Policy file 213 @param productName (string) The name of the product that the default policy is installed as part of 214 @param fileName (string) The name of the policy file. Can also include a path to the file relative to 215 the directory where the product is installed. 216 @param relativePath (string) The relative path from the directior where the product is installed to 217 the location where the file (or the path to the file) is found. If None 218 (default), the fileName argument is relative to the installation 223 raise RuntimeError(
"No product installed for productName: %s" % basePath)
224 if relativePath
is not None:
225 basePath = os.path.join(basePath, relativePath)
226 fullFilePath = os.path.join(basePath, fileName)
230 """Like dict.update, but will add or modify keys in nested dicts, instead of overwriting the nested 233 For example, for the given code: 234 foo = {'a': {'b': 1}} 235 foo.update({'a': {'c': 2}}) 237 If foo is a dict, then after the update foo == {'a': {'c': 2}} 238 But if foo is a Policy, then after the update foo == {'a': {'b': 1, 'c': 2}} 241 for k, v
in u.items():
242 if isinstance(d, collections.Mapping):
243 if isinstance(v, collections.Mapping):
244 r = doUpdate(d.get(k, {}), v)
251 doUpdate(self.
data, other)
254 """Like Policy.update, but will add keys & values from other that DO NOT EXIST in self. Keys and 255 values that already exist in self will NOT be overwritten. 260 otherCopy = copy.deepcopy(other)
261 otherCopy.update(self)
262 self.
data = otherCopy.data
264 def names(self, topLevelOnly=False):
265 """Get the dot-delimited name of all the keys in the hierarchy. 266 NOTE: this is different than the built-in method dict.keys, which will return only the first level 270 return list(self.keys())
272 def getKeys(d, keys, base):
275 levelKey = base +
'.' + key
if base
is not None else key
276 keys.append(levelKey)
277 if isinstance(val, collections.Mapping):
278 getKeys(val, keys, levelKey)
280 getKeys(self.
data, keys,
None)
284 """Get a value as an array. May contain one or more elements. 290 if isinstance(val, basestring):
292 elif not isinstance(val, collections.Container):
300 """Get the value for a parameter name/key. See class notes about dot-delimited access. 303 :return: the value for the given name. 305 warnings.warn_explicit(
"Deprecated. Use []", DeprecationWarning)
309 """Set the value for a parameter name/key. See class notes about dot-delimited access. 314 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
318 """For any keys in other that are not present in self, sets that key and its value into self. 320 :param other: another Policy 323 warnings.warn(
"Deprecated. Use .merge()", DeprecationWarning)
327 """Query if a key exists in this Policy 330 :return: True if the key exists, else false. 332 warnings.warn(
"Deprecated. Use 'key in object'", DeprecationWarning)
336 """Get the string value of a key. 339 :return: the value for key 341 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
342 return str(self[key])
345 """Get the value of a key. 348 :return: the value for key 350 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
351 return bool(self[key])
359 warnings.warn(
"Deprecated. Use []", DeprecationWarning)
363 """Get a value as an array. May contain one or more elements. 368 warnings.warn(
"Deprecated. Use asArray()", DeprecationWarning)
370 if isinstance(val, basestring):
372 elif not isinstance(val, collections.Container):
377 if isinstance(other, Policy):
379 return self.
data < other
382 if isinstance(other, Policy):
384 return self.
data <= other
387 if isinstance(other, Policy):
389 return self.
data == other
392 if isinstance(other, Policy):
394 return self.
data != other
397 if isinstance(other, Policy):
399 return self.
data > other
402 if isinstance(other, Policy):
404 return self.
data >= other
410 """Writes the policy to a yaml stream. 418 data = copy.copy(self.
data)
419 keys = [
'defects',
'needCalibRegistry',
'levels',
'defaultLevel',
'defaultSubLevels',
'camera',
420 'exposures',
'calibrations',
'datasets']
423 yaml.safe_dump({key: data.pop(key)}, output, default_flow_style=
False)
428 yaml.safe_dump(data, output, default_flow_style=
False)
431 """Writes the policy to a file. 436 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)
def getStringArray(self, key)
def __setitem__(self, name, value)
std::string getPackageDir(std::string const &packageName)
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)
def setValue(self, name, value)