6"""A pythonic wrapper over the OKS Configuration wrapper.
8Necessary to give the user a more pythonic experience than dealing with
9std::vector objects and memory management.
12from .
import ConfigObject
13from ._daq_conffwk_py
import _Configuration
15from .proxy
import _DelegateMetaFunction
20 metaclass=_DelegateMetaFunction):
21 memberclass = _Configuration
25 """Access OKS/RDB configuration databases from python.
35 if self.get_impl_param():
44 """Initializes a Configuration database.
48 connection -- A connection string, in the form of <backend>:<database>
49 name, where <backend> may be set to be 'oksconflibs' or 'rdbconffwk' and
50 <database> is either the name of the database XML file (in the case of
51 'oksconflibs') or the name of a database associated with an RDB server
52 (in the case of 'rdbconffwk').
54 Warning: To use the RDB server, the IPC subsystem has to be initialized
55 beforehand and as this is not done by this package. If the parameter
56 'connection' is empty, the default is whatever is the default for the
57 conffwk::Configuration C++ class, which at this time boils down to look
58 if TDAQ_DB is set and take that default.
60 Raises RuntimeError, in case of problems.
64 super(Configuration, self).
__init__(connection)
66 preamble = f
"Unable to open database off of \"{connection}\""
67 if not re.search(
r"^oksconflibs:", connection):
68 raise RuntimeError(f
"""
69{preamble}; one reason is that it looks
70like the database type wasn't specified in the name (i.e. \"oksconflibs:<filename>\")
73 dbfilename = connection[len(
"oksconflibs:"):]
74 if not os.path.exists(dbfilename):
75 raise RuntimeError(f
"{preamble}; one reason is that it looks like \"{dbfilename}\" doesn't exist")
76 elif not re.search(
r".xml$", dbfilename):
77 raise RuntimeError(f
"{preamble}; one reason is that it looks like \"{dbfilename}\" isn't an XML file")
79 raise RuntimeError(f
"""
80{preamble}; try running
81\"oks_dump --files-only {dbfilename}\"
82to see if there's a problem with the input database""")
87 """Returns a list of associated databases which are opened"""
91 """Sets a database to become active when adding new objects.
93 This method raises NameError in case a database cannot be made active.
99 raise NameError(
'database "%s is not loaded in this object' % name)
102 """Initializes the internal DAL cache"""
108 """Updates the internal DAL cache"""
110 for oks_type
in obj.oksTypes():
114 """Updates the internal DAL cache"""
116 for oks_type
in obj.oksTypes():
121 """Retrieves all objects that match a certain class_name/id"""
126 return iter(self.
__cache__[class_name].values())
129 """Returns a python list of ConfigObject's with the given class name.
133 class_name -- This is the name of the OKS Class to be used for the
134 search. It has to be amongst one of the classes returned by the
137 query -- This is specific OKS query you may want to perform to reduce
138 the returned subset. By default it is empty, what makes me return all
139 objects for which the class (or base class) matches the 'class_name'
142 Returns a (python) list with conffwk.ConfigObject's
144 objs = super(Configuration, self).
get_objs(class_name, query)
149 """Returns a list of attributes of the named class
151 This method will return a list of direct (not inherited) attributes of
152 a certain class as a python list. If the 'all' flag is set to True,
153 then direct and inherited attributes are returned.
157 class_name -- This is the class of the object you want to inspect.
159 all -- If set to 'True', returns direct and inherited attributes,
160 otherwise, only direct attributes (the default).
162 Raises RuntimeError on problems
164 attribute_properties_as_strings = super(Configuration, self).
attributes(class_name, all)
165 attribute_properties_to_return = {}
166 for attribute, properties
in attribute_properties_as_strings.items():
168 for k, v
in properties.items():
174 properties[k] =
False
176 attribute_properties_to_return[attribute] = properties
178 return attribute_properties_to_return
181 """Returns a list of attributes of the named class
183 This method will return a list of direct (not inherited) relationships
184 of a certain class as a python list. If the 'all' flag is set to True,
185 then direct and inherited attributes are returned.
189 class_name -- This is the class of the object you want to inspect.
191 all -- If set to 'True', returns direct and inherited relationships,
192 otherwise, only direct relationships (the default).
194 Raises RuntimeError on problems
196 relationship_properties_as_strings = super(Configuration, self).
relations(class_name, all)
197 relationship_properties_to_return = {}
199 for relationship, properties
in relationship_properties_as_strings.items():
201 for k, v
in properties.items():
207 properties[k] =
False
209 relationship_properties_to_return[relationship] = properties
211 return relationship_properties_to_return
215 """Returns a list of superclasses of the named class
217 This method will return a list of direct (not inherited) superclasses
218 of a certain class as a python list. If the 'all' flag is set to True,
219 then direct and inherited attributes are returned.
223 class_name -- This is the class of the object you want to inspect.
225 all -- If set to 'True', returns direct and inherited superclasses,
226 otherwise, only direct superclasses (the default).
228 Raises RuntimeError on problems
230 return super(Configuration, self).
superclasses(class_name, all)
233 """Returns a list of subclasses of the named class
235 This method will return a list of direct (not inherited) subclasses of
236 a certain class as a python list. If the 'all' flag is set to True,
237 then direct and inherited attributes are returned.
241 class_name -- This is the class of the object you want to inspect.
243 all -- If set to 'True', returns direct and inherited subclasses,
244 otherwise, only direct subclasses (the default).
246 Raises RuntimeError on problems
248 return super(Configuration, self).
subclasses(class_name, all)
251 """Returns a list of all classes loaded in this Configuration."""
252 return list(super(Configuration, self).
classes())
255 """Creates a new database on the specified server, sets it active.
257 This method creates a new database on the specified server. If the
258 server is not specified, what is returned by get_impl_name() is used.
259 After the creation, this database immediately becomes the "active"
260 database where new objects will be created at. You can reset that
261 using the "set_active()" call in objects of this class.
265 db_name -- The name of the database to create.
267 includes -- A list of includes this database will have.
269 super(Configuration, self).
create_db(db_name, includes)
282 """Returns a a list of all includes in a certain database.
286 at -- This is the name of the database you want to get the includes
287 from. If set to 'None' (the default) we use whatever
288 self.active_database is set to hoping for the best.
295 """Removes a included file in a certain database.
297 This method will remove include files from the active database or from
298 any other include database if mentioned.
302 include -- A single include to remove from the database.
304 at -- This is the name of database you want to remove the include(s)
305 from, If set to None (the default), I'll simply use the value of
306 'self.active_database', hoping for the best.
313 """Adds a new include to the database.
315 This method includes new files in the include section of your database.
316 You can specify the file to which you want to add the include file.
317 If you don't, it uses the last opened (active) file.
321 include -- This is a single include to add into your database
323 at -- This is the name of database you want to add the include at,
324 If set to None (the default), I'll simply use the value of
325 'self.active_database', hoping for the best.
330 super(Configuration, self).
add_include(at, include)
337 return self.get_impl_spec() + \
338 ', %d classes loaded' % len(self.
classes())
341 return '<Configuration \'' + self.get_impl_spec() +
'\'>'
344 """Creates a new ConfigObject, related with the database you specify.
348 class_name -- This is the name of the OKS Class to be used for the
349 newly created object. It has to be amongst one of the classes returned
350 by the "classes()" method.
352 uid -- This is the UID of the object inside the OKS database.
354 at -- This is either the name of database you want to create the object
355 at, or another ConfigObject that will be used as a reference to
356 determine at which database to create the new object. If set to None
357 (the default), I'll simply use the value of 'self.active_database',
362 obj = super(Configuration, self).
create_obj(at, class_name, uid)
366 """Retrieves a ConfigObject you specified.
370 class_name -- This is the name of the OKS Class to be used for the
371 search. It has to be amongst one of the classes returned by the
374 uid -- This is the UID of the object inside the OKS database.
377 obj = super(Configuration, self).
get_obj(class_name, uid)
380 def add_dal(self, dal_obj, at=None, cache=None, recurse=True):
381 """Updates the related ConfigObject in the database using a DAL
384 This method will take the properties of the DAL object passed as
385 parameter and will try to either create or update the relevant
386 ConfigObject in the database, at the file specified. It does this
387 recursively, in colaboration with the ConfigObject class.
391 dal_obj -- This is the DAL object that will be used for the operation.
392 It should be a reflection of the ConfigObject you want to create.
394 at -- This is either the name of database you want to create the object
395 at, or another ConfigObject that will be used as a reference to
396 determine at which database to create the new object. If set to None
397 (the default), I'll simply use the value of 'self.active_database',
400 cache -- This is a cache that may be set by the Configuration object if
401 necessary. Users should *never* set this variable. This variable is
402 there to handle recursions gracefully.
404 recurse -- This is a boolean flag that indicates if you want to enable
405 recursion or not in the update. If set to 'True' (the default), I'll
406 recurse until all objects in the tree that do *not* exist yet in the
407 database are created (existing objects are gracefully ignored).
408 Otherwise, I'll not recurse at all and just make sure the attributes
409 and relationships of the object passed as parameter are set to what you
410 determine they should be. Please note that if you decide to update
411 relationships, that the objects to which you are pointing to should be
412 available in the database (directly or indirectly through includes) if
413 you choose to do this non-recursively.
415 Returns the ConfigObject you wanted to create or update, that you may
416 ignore for practical purposes.
421 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
422 obj = super(Configuration, self).
get_obj(
423 dal_obj.className(), dal_obj.id)
425 cache[dal_obj.fullName()] = co
431 obj = super(Configuration, self) \
435 cache[dal_obj.fullName()] = co
442 def update_dal(self, dal_obj, ignore_error=True, at=None, cache=None,
444 """Updates the related ConfigObject in the database using a DAL
447 This method will take the properties of the DAL object passed as
448 parameter and will try to either create or update the relevant
449 ConfigObject in the database, at the file specified. It does this
450 recursively, in colaboration with the ConfigObject class.
454 dal_obj -- This is the DAL object that will be used for the operation.
455 It should be a reflection of the ConfigObject you want to create.
457 ignore_error -- This flag will make me ignore errors related to the
458 update of objects in this database. It is useful if you want to
459 overwrite as much as you can and leave the other objects which you
460 cannot write to untouched.
461 Otherwise, objects you cannot touch (write permissions or other
462 problems), when tried to be set, will raise a 'ValueError'.
464 at -- This is either the name of database you want to create the
465 object at, or another ConfigObject that will be used as a reference to
466 determine at which database to create the new object. If set to None
467 (the default), I'll simply use the value of 'self.active_database',
470 cache -- This is a cache that may be set by the Configuration object if
471 necessary. Users should *never* set this variable. This variable is
472 there to handle recursions gracefully.
474 recurse -- If this flag is set, the update will recurse until all
475 objects linked from the given object are updated. This encompasses
476 'include-file' objects. The default is a safe "False". Please,
477 understand the impact of what you are doing before setting this to
480 Returns the ConfigObject you wanted to create or update, that you may
481 ignore for practical purposes.
489 if hasattr(dal_obj,
'__old_id'):
490 old_id = getattr(dal_obj,
'__old_id')
491 if old_id != dal_obj.id:
492 old = super(Configuration, self).
get_obj(
493 dal_obj.className(), old_id)
495 old.rename(dal_obj.id)
496 delattr(dal_obj,
'__old_id')
498 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
499 obj = super(Configuration, self).
get_obj(
500 dal_obj.className(), dal_obj.id)
502 cache[dal_obj.fullName()] = co
506 except ValueError
as e:
511 'Ignoring error in setting %s: %s'
512 % (repr(co), str(e)))
518 obj = super(Configuration, self) \
522 cache[dal_obj.fullName()] = co
531 """Alias to update_dal() with ignore_error=True"""
532 return self.
update_dal(dal_obj,
True, at, cache, recurse)
535 """Alias to update_dal() with ignore_error=False"""
536 return self.
update_dal(dal_obj,
False, at, cache, recurse)
539 """Retrieves a DAL reflection of a ConfigObject in this OKS database.
541 This method acts recursively, until all objects deriving from the
542 object you are retrieving have been returned. It is possible to reach
543 the python limit using this. If that is the case, make sure to extend
544 this limit with the following technique:
547 sys.setrecursionlimit(10000) # for example
551 class_name -- The name of the OKS class of the object you are trying to
554 uid -- This is the object's UID.
556 Returns DAL representations of object in this Configuration database.
558 if uid
not in self.
__cache__[class_name]:
564 """Retrieves (multiple) DAL reflections of ConfigObjects in this
567 This method acts recursively, until all objects deriving from the
568 object you are retrieving have been returned.
572 class_name -- The name of the OKS class of the objects you are trying
575 Returns DAL representations of objects in this Configuration database.
579 if k.UID()
not in self.
__cache__[class_name]:
581 return list(self.
__cache__[class_name].values())
584 """Retrieves (multiple) DAL reflections of ConfigObjects in this
587 This method acts recursively, until all objects deriving from the
588 object you are retrieving have been returned.
590 Returns DAL representations of objects in this Configuration database.
592 from .ConfigObject
import ConfigObject
as CO
598 if k.fullName()
not in retval:
599 retval[k.fullName()] = k
602 for class_name
in self.
classes():
603 for k
in super(Configuration,
605 '(this (object-id \"\" !=))'):
606 if k.UID()
not in self.
__cache__[class_name]:
608 retval[j.fullName()] = j
611 retval[j.fullName()] = j
616 """Destroyes the Database counterpart of the DAL object given.
618 This method will destroy the equivalent ConfigObject reflection from
619 this Configuration object.
623 dal_obj -- This is the DAL reflection of the object you want to delete.
626 if self.test_object(dal_obj.className(), dal_obj.id, 0, []):
632 """Destroyes the given database object.
634 This method will destroy the given ConfigObject object.
641 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)
add_dal(self, dal_obj, at=None, cache=None, recurse=True)
__delete_cache__(self, objs)
get_objs(self, class_name, query='')
get_obj(self, class_name, uid)
__retrieve_cache__(self, class_name, id=None)