11"""A pythonic wrapper over the OKS Configuration wrapper.
13Necessary to give the user a more pythonic experience than dealing with
14std::vector objects and memory management.
17from .
import ConfigObject
18from ._daq_conffwk_py
import _Configuration
20from .proxy
import _DelegateMetaFunction
25 metaclass=_DelegateMetaFunction):
26 memberclass = _Configuration
30 """Access OKS/RDB configuration databases from python.
40 if self.get_impl_param():
41 self.
databases.append(self.get_impl_param())
49 """Initializes a Configuration database.
53 connection -- A connection string, in the form of <backend>:<database>
54 name, where <backend> may be set to be 'oksconflibs' or 'rdbconffwk' and
55 <database> is either the name of the database XML file (in the case of
56 'oksconflibs') or the name of a database associated with an RDB server
57 (in the case of 'rdbconffwk').
59 Warning: To use the RDB server, the IPC subsystem has to be initialized
60 beforehand and as this is not done by this package. If the parameter
61 'connection' is empty, the default is whatever is the default for the
62 conffwk::Configuration C++ class, which at this time boils down to look
63 if TDAQ_DB is set and take that default.
65 Raises RuntimeError, in case of problems.
69 super(Configuration, self).
__init__(connection)
71 preamble = f
"Unable to open database off of \"{connection}\""
72 if not re.search(
r"^oksconflibs:", connection):
73 raise RuntimeError(f
"""
74{preamble}; one reason is that it looks
75like the database type wasn't specified in the name (i.e. \"oksconflibs:<filename>\")
78 dbfilename = connection[len(
"oksconflibs:"):]
79 if not os.path.exists(dbfilename):
80 raise RuntimeError(f
"{preamble}; one reason is that it looks like \"{dbfilename}\" doesn't exist")
81 elif not re.search(
r".xml$", dbfilename):
82 raise RuntimeError(f
"{preamble}; one reason is that it looks like \"{dbfilename}\" isn't an XML file")
84 raise RuntimeError(f
"""
85{preamble}; try running
86\"oks_dump --files-only {dbfilename}\"
87to see if there's a problem with the input database""")
92 """Returns a list of associated databases which are opened"""
96 """Sets a database to become active when adding new objects.
98 This method raises NameError in case a database cannot be made active.
104 raise NameError(
'database "%s is not loaded in this object' % name)
107 """Initializes the internal DAL cache"""
113 """Updates the internal DAL cache"""
115 for oks_type
in obj.oksTypes():
119 """Updates the internal DAL cache"""
121 for oks_type
in obj.oksTypes():
126 """Retrieves all objects that match a certain class_name/id"""
131 return iter(self.
__cache__[class_name].values())
134 """Returns a python list of ConfigObject's with the given class name.
138 class_name -- This is the name of the OKS Class to be used for the
139 search. It has to be amongst one of the classes returned by the
142 query -- This is specific OKS query you may want to perform to reduce
143 the returned subset. By default it is empty, what makes me return all
144 objects for which the class (or base class) matches the 'class_name'
147 Returns a (python) list with conffwk.ConfigObject's
149 objs = super(Configuration, self).
get_objs(class_name, query)
154 """Returns a list of attributes of the named class
156 This method will return a list of direct (not inherited) attributes of
157 a certain class as a python list. If the 'all' flag is set to True,
158 then direct and inherited attributes are returned.
162 class_name -- This is the class of the object you want to inspect.
164 all -- If set to 'True', returns direct and inherited attributes,
165 otherwise, only direct attributes (the default).
167 Raises RuntimeError on problems
169 attribute_properties_as_strings = super(Configuration, self).
attributes(class_name, all)
170 attribute_properties_to_return = {}
171 for attribute, properties
in attribute_properties_as_strings.items():
173 for k, v
in properties.items():
179 properties[k] =
False
181 attribute_properties_to_return[attribute] = properties
183 return attribute_properties_to_return
186 """Returns a list of attributes of the named class
188 This method will return a list of direct (not inherited) relationships
189 of a certain class as a python list. If the 'all' flag is set to True,
190 then direct and inherited attributes are returned.
194 class_name -- This is the class of the object you want to inspect.
196 all -- If set to 'True', returns direct and inherited relationships,
197 otherwise, only direct relationships (the default).
199 Raises RuntimeError on problems
201 relationship_properties_as_strings = super(Configuration, self).
relations(class_name, all)
202 relationship_properties_to_return = {}
204 for relationship, properties
in relationship_properties_as_strings.items():
206 for k, v
in properties.items():
212 properties[k] =
False
214 relationship_properties_to_return[relationship] = properties
216 return relationship_properties_to_return
220 """Returns a list of superclasses of the named class
222 This method will return a list of direct (not inherited) superclasses
223 of a certain class as a python list. If the 'all' flag is set to True,
224 then direct and inherited attributes are returned.
228 class_name -- This is the class of the object you want to inspect.
230 all -- If set to 'True', returns direct and inherited superclasses,
231 otherwise, only direct superclasses (the default).
233 Raises RuntimeError on problems
235 return super(Configuration, self).
superclasses(class_name, all)
238 """Returns a list of subclasses of the named class
240 This method will return a list of direct (not inherited) subclasses of
241 a certain class as a python list. If the 'all' flag is set to True,
242 then direct and inherited attributes are returned.
246 class_name -- This is the class of the object you want to inspect.
248 all -- If set to 'True', returns direct and inherited subclasses,
249 otherwise, only direct subclasses (the default).
251 Raises RuntimeError on problems
253 return super(Configuration, self).
subclasses(class_name, all)
256 """Returns a list of all classes loaded in this Configuration."""
257 return list(super(Configuration, self).
classes())
260 """Creates a new database on the specified server, sets it active.
262 This method creates a new database on the specified server. If the
263 server is not specified, what is returned by get_impl_name() is used.
264 After the creation, this database immediately becomes the "active"
265 database where new objects will be created at. You can reset that
266 using the "set_active()" call in objects of this class.
270 db_name -- The name of the database to create.
272 includes -- A list of includes this database will have.
274 super(Configuration, self).
create_db(db_name, includes)
287 """Returns a a list of all includes in a certain database.
291 at -- This is the name of the database you want to get the includes
292 from. If set to 'None' (the default) we use whatever
293 self.active_database is set to hoping for the best.
300 """Removes a included file in a certain database.
302 This method will remove include files from the active database or from
303 any other include database if mentioned.
307 include -- A single include to remove from the database.
309 at -- This is the name of database you want to remove the include(s)
310 from, If set to None (the default), I'll simply use the value of
311 'self.active_database', hoping for the best.
318 """Adds a new include to the database.
320 This method includes new files in the include section of your database.
321 You can specify the file to which you want to add the include file.
322 If you don't, it uses the last opened (active) file.
326 include -- This is a single include to add into your database
328 at -- This is the name of database you want to add the include at,
329 If set to None (the default), I'll simply use the value of
330 'self.active_database', hoping for the best.
335 super(Configuration, self).
add_include(at, include)
342 return self.get_impl_spec() + \
343 ', %d classes loaded' % len(self.
classes())
346 return '<Configuration \'' + self.get_impl_spec() +
'\'>'
349 """Creates a new ConfigObject, related with the database you specify.
353 class_name -- This is the name of the OKS Class to be used for the
354 newly created object. It has to be amongst one of the classes returned
355 by the "classes()" method.
357 uid -- This is the UID of the object inside the OKS database.
359 at -- This is either the name of database you want to create the object
360 at, or another ConfigObject that will be used as a reference to
361 determine at which database to create the new object. If set to None
362 (the default), I'll simply use the value of 'self.active_database',
367 obj = super(Configuration, self).
create_obj(at, class_name, uid)
371 """Retrieves a ConfigObject you specified.
375 class_name -- This is the name of the OKS Class to be used for the
376 search. It has to be amongst one of the classes returned by the
379 uid -- This is the UID of the object inside the OKS database.
382 obj = super(Configuration, self).
get_obj(class_name, uid)
385 def add_dal(self, dal_obj, at=None, cache=None, recurse=True):
386 """Updates the related ConfigObject in the database using a DAL
389 This method will take the properties of the DAL object passed as
390 parameter and will try to either create or update the relevant
391 ConfigObject in the database, at the file specified. It does this
392 recursively, in colaboration with the ConfigObject class.
396 dal_obj -- This is the DAL object that will be used for the operation.
397 It should be a reflection of the ConfigObject you want to create.
399 at -- This is either the name of database you want to create the object
400 at, or another ConfigObject that will be used as a reference to
401 determine at which database to create the new object. If set to None
402 (the default), I'll simply use the value of 'self.active_database',
405 cache -- This is a cache that may be set by the Configuration object if
406 necessary. Users should *never* set this variable. This variable is
407 there to handle recursions gracefully.
409 recurse -- This is a boolean flag that indicates if you want to enable
410 recursion or not in the update. If set to 'True' (the default), I'll
411 recurse until all objects in the tree that do *not* exist yet in the
412 database are created (existing objects are gracefully ignored).
413 Otherwise, I'll not recurse at all and just make sure the attributes
414 and relationships of the object passed as parameter are set to what you
415 determine they should be. Please note that if you decide to update
416 relationships, that the objects to which you are pointing to should be
417 available in the database (directly or indirectly through includes) if
418 you choose to do this non-recursively.
420 Returns the ConfigObject you wanted to create or update, that you may
421 ignore for practical purposes.
426 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
427 obj = super(Configuration, self).
get_obj(
428 dal_obj.className(), dal_obj.id)
430 cache[dal_obj.fullName()] = co
436 obj = super(Configuration, self) \
440 cache[dal_obj.fullName()] = co
447 def update_dal(self, dal_obj, ignore_error=True, at=None, cache=None,
449 """Updates the related ConfigObject in the database using a DAL
452 This method will take the properties of the DAL object passed as
453 parameter and will try to either create or update the relevant
454 ConfigObject in the database, at the file specified. It does this
455 recursively, in colaboration with the ConfigObject class.
459 dal_obj -- This is the DAL object that will be used for the operation.
460 It should be a reflection of the ConfigObject you want to create.
462 ignore_error -- This flag will make me ignore errors related to the
463 update of objects in this database. It is useful if you want to
464 overwrite as much as you can and leave the other objects which you
465 cannot write to untouched.
466 Otherwise, objects you cannot touch (write permissions or other
467 problems), when tried to be set, will raise a 'ValueError'.
469 at -- This is either the name of database you want to create the
470 object at, or another ConfigObject that will be used as a reference to
471 determine at which database to create the new object. If set to None
472 (the default), I'll simply use the value of 'self.active_database',
475 cache -- This is a cache that may be set by the Configuration object if
476 necessary. Users should *never* set this variable. This variable is
477 there to handle recursions gracefully.
479 recurse -- If this flag is set, the update will recurse until all
480 objects linked from the given object are updated. This encompasses
481 'include-file' objects. The default is a safe "False". Please,
482 understand the impact of what you are doing before setting this to
485 Returns the ConfigObject you wanted to create or update, that you may
486 ignore for practical purposes.
494 if hasattr(dal_obj,
'__old_id'):
495 old_id = getattr(dal_obj,
'__old_id')
496 if old_id != dal_obj.id:
497 old = super(Configuration, self).
get_obj(
498 dal_obj.className(), old_id)
500 old.rename(dal_obj.id)
501 delattr(dal_obj,
'__old_id')
503 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
504 obj = super(Configuration, self).
get_obj(
505 dal_obj.className(), dal_obj.id)
507 cache[dal_obj.fullName()] = co
509 co.update_dal(dal_obj, co_func, self.
get_obj, cache=cache,
511 except ValueError
as e:
516 'Ignoring error in setting %s: %s'
517 % (repr(co), str(e)))
523 obj = super(Configuration, self) \
527 cache[dal_obj.fullName()] = co
528 co.update_dal(dal_obj, co_func, self.
get_obj, cache=cache,
536 """Alias to update_dal() with ignore_error=True"""
537 return self.
update_dal(dal_obj,
True, at, cache, recurse)
540 """Alias to update_dal() with ignore_error=False"""
541 return self.
update_dal(dal_obj,
False, at, cache, recurse)
544 """Retrieves a DAL reflection of a ConfigObject in this OKS database.
546 This method acts recursively, until all objects deriving from the
547 object you are retrieving have been returned. It is possible to reach
548 the python limit using this. If that is the case, make sure to extend
549 this limit with the following technique:
552 sys.setrecursionlimit(10000) # for example
556 class_name -- The name of the OKS class of the object you are trying to
559 uid -- This is the object's UID.
561 Returns DAL representations of object in this Configuration database.
563 if uid
not in self.
__cache__[class_name]:
564 obj = self.
get_obj(class_name, uid)
569 """Retrieves (multiple) DAL reflections of ConfigObjects in this
572 This method acts recursively, until all objects deriving from the
573 object you are retrieving have been returned.
577 class_name -- The name of the OKS class of the objects you are trying
580 Returns DAL representations of objects in this Configuration database.
584 if k.UID()
not in self.
__cache__[class_name]:
586 return list(self.
__cache__[class_name].values())
589 """Retrieves (multiple) DAL reflections of ConfigObjects in this
592 This method acts recursively, until all objects deriving from the
593 object you are retrieving have been returned.
595 Returns DAL representations of objects in this Configuration database.
597 from .ConfigObject
import ConfigObject
as CO
603 if k.fullName()
not in retval:
604 retval[k.fullName()] = k
607 for class_name
in self.
classes():
608 for k
in super(Configuration,
610 '(this (object-id \"\" !=))'):
611 if k.UID()
not in self.
__cache__[class_name]:
613 retval[j.fullName()] = j
616 retval[j.fullName()] = j
621 """Destroyes the Database counterpart of the DAL object given.
623 This method will destroy the equivalent ConfigObject reflection from
624 this Configuration object.
628 dal_obj -- This is the DAL reflection of the object you want to delete.
631 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
632 obj = self.
get_obj(dal_obj.className(), dal_obj.id)
637 """Destroyes the given database object.
639 This method will destroy the given ConfigObject object.
646 return super(Configuration, self).
destroy_obj(obj._obj)
__init__(self, connection='oksconflibs:')
update_dal(self, dal_obj, ignore_error=True, at=None, cache=None, recurse=False)
superclasses(self, class_name, all=False)
attributes(self, class_name, all=False)
get_includes(self, at=None)
create_obj(self, class_name, uid, at=None)
update_dal_permissive(self, dal_obj, at=None, cache=None, recurse=False)
create_db(self, db_name, includes)
get_dal(self, class_name, uid)
__update_cache__(self, objs)
add_include(self, include, at=None)
remove_include(self, include, at=None)
relations(self, class_name, all=False)
__initialize_cache__(self)
destroy_dal(self, dal_obj)
get_dals(self, class_name)
update_dal_pedantic(self, dal_obj, at=None, cache=None, recurse=False)
subclasses(self, class_name, all=False)
__delete_cache__(self, objs)
get_objs(self, class_name, query='')
__retrieve_cache__(self, class_name, id=None)