New Python class helpers.overlay.CfgCache.
* New: In CRL/helpers/overlay.py, CfgCache class to hold a set of configuration parameters and apply it on demand. It has a different behavior than Configuration.
This commit is contained in:
parent
3996a8e15d
commit
1e3788d93e
|
@ -1,13 +1,31 @@
|
|||
# -*- mode:Python; explicit-buffer-name: "__init__.py<crlcore/helpers>" -*-
|
||||
#
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) UPMC 2012-2018, All Rights Reserved
|
||||
#
|
||||
# +-----------------------------------------------------------------+
|
||||
# | C O R I O L I S |
|
||||
# | C o r i o l i s / C h a m s B u i l d e r |
|
||||
# | |
|
||||
# | Author : Jean-Paul Chaput |
|
||||
# | E-mail : Jean-Paul.Chaput@lip6.fr |
|
||||
# | =============================================================== |
|
||||
# | Python : "./crlcore/helpers/overlay.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
#
|
||||
# Those classes are based on the work of Jock Tanner from Libre-SOC.
|
||||
|
||||
|
||||
"""
|
||||
Overlay to make some C++ objects provide a more Pythonic interface.
|
||||
Contains:
|
||||
|
||||
* ``overlay.UpdateSession`` : to be used in ``with`` construct.
|
||||
* ``overlay.Cfg`` : to be used in ``with`` construct.
|
||||
* ``overlay.Configuration`` : to be used in ``with`` construct.
|
||||
* ``overlay.CfgCache`` : A cache for Cfg parameters.
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import print_function
|
||||
import Cfg
|
||||
import Hurricane
|
||||
|
||||
|
@ -64,6 +82,7 @@ class Configuration:
|
|||
Cfg.getParamInt(attr).setInt( val )
|
||||
elif isinstance(val, long):
|
||||
p = Cfg.getParamInt( attr ) # all params have a type
|
||||
p.setInt( val )
|
||||
elif isinstance(val, float):
|
||||
p = Cfg.getParamDouble( attr ).setDouble( val )
|
||||
elif '%' in val:
|
||||
|
@ -75,3 +94,167 @@ class Configuration:
|
|||
if self._priority is not None:
|
||||
Cfg.Configuration.popDefaultPriority()
|
||||
|
||||
|
||||
class CfgCache ( object ):
|
||||
"""
|
||||
CgfCache cache a set of configuration parameters. The values of the
|
||||
parameters are not set in the system *until* the ``apply()`` function
|
||||
is called.
|
||||
|
||||
If a parameter do not exists in the ``Cfg`` module, it is created
|
||||
when ``apply()`` is called. Be aware that it is not able to guess
|
||||
the right type between Double and Percentage or Int and Enumerate.
|
||||
It will, by default, only create Double or Int. So, when setting
|
||||
Percentage or Enumerate, be sure that they exists beforehand in
|
||||
the ``Cfg`` module.
|
||||
|
||||
The attributes of CfgCache exactly mimic the behavior of the
|
||||
``Cfg`` parameter string identifiers. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Direct access to a Cfg parameter.
|
||||
p = Cfg.getParamInt('katana.eventsLimit').setInt( 4000000 )
|
||||
|
||||
# Setup of a CfgCache parameter.
|
||||
cache = CfgCache('')
|
||||
cache.katana.eventsLimit = 4000000
|
||||
|
||||
# ...
|
||||
# Effective setting of the Cfg parameter.
|
||||
cache.apply()
|
||||
|
||||
|
||||
This is done by overloading ``__setattr__()`` and ``__getattr__()``
|
||||
which recursively create CfgCache objects for intermediate levels
|
||||
attributes (in the previous example, a CfgCache for ``katana``
|
||||
will automatically be created). To separate between attributes
|
||||
that are part of configuration parameters and attributes belonging
|
||||
to CfgCache itself, we prepend a '_' to the laters.
|
||||
|
||||
.. note:: It is important to understand the difference of behavior
|
||||
with ``Configuration``, the former set the parameters
|
||||
at once, it directly act on the ``Cfg`` settings.
|
||||
The later keep a state and set the ``Cfg`` parameters
|
||||
*only* when ``apply()`` is called.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def setCfgParameter ( paramPath, value ):
|
||||
""""
|
||||
Set the value of parameter ``paramPath`` to ``value`` in Cfg.
|
||||
Percentage are set as Double and Enumerate as Int.
|
||||
"""
|
||||
if Cfg.hasParameter(paramPath):
|
||||
confDb = Cfg.Configuration.get()
|
||||
p = confDb.getParameter( paramPath )
|
||||
else:
|
||||
if isinstance(value,bool ): p = Cfg.getParamBool ( paramPath )
|
||||
elif isinstance(value,int ): p = Cfg.getParamInt ( paramPath )
|
||||
elif isinstance(value,long ): p = Cfg.getParamInt ( paramPath )
|
||||
elif isinstance(value,float): p = Cfg.getParamDouble( paramPath )
|
||||
else: p = Cfg.getParamString( paramPath )
|
||||
|
||||
if p.type == Cfg.Parameter.Type.Enumerate: p.setInt ( value )
|
||||
elif p.type == Cfg.Parameter.Type.Int: p.setInt ( value )
|
||||
elif p.type == Cfg.Parameter.Type.Bool: p.setBool ( value )
|
||||
elif p.type == Cfg.Parameter.Type.Double: p.setDouble( value )
|
||||
elif p.type == Cfg.Parameter.Type.Percentage: p.setDouble( value*100.0 )
|
||||
else: p.setString( str(value) )
|
||||
|
||||
@staticmethod
|
||||
def getDefaultCfgParameter ( paramPath ):
|
||||
""""Get the value of parameter ``paramPath`` from Cfg."""
|
||||
if not Cfg.hasParameter(paramPath):
|
||||
raise AttributeError( 'CfgCache.getDefaultCfgParameter(): Undefined "{}"'.format(paramPath) )
|
||||
confDb = Cfg.Configuration.get()
|
||||
p = confDb.getParameter( paramPath )
|
||||
if p:
|
||||
if p.type == Cfg.Parameter.Type.Enumerate: return p.asInt()
|
||||
if p.type == Cfg.Parameter.Type.Int: return p.asInt()
|
||||
if p.type == Cfg.Parameter.Type.Bool: return p.asBool()
|
||||
if p.type == Cfg.Parameter.Type.String: return p.asString()
|
||||
if p.type == Cfg.Parameter.Type.Double: return p.asDouble()
|
||||
if p.type == Cfg.Parameter.Type.Percentage: return p.asDouble()/100.0
|
||||
return p.asString()
|
||||
|
||||
def __init__ ( self, path ):
|
||||
"""Create a new CfgCache with a ``path`` as parent path."""
|
||||
self._path = path
|
||||
self._rattr = {}
|
||||
return
|
||||
|
||||
def __setattr__ ( self, attr, v ):
|
||||
"""
|
||||
Recursively set an attribute. Attributes names starting by an '_' are
|
||||
treated as belonging to *this* object (self).
|
||||
|
||||
How does the recursive attributes/CfgCache works? Assumes that we
|
||||
are doing:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Setup of a CfgCache parameter.
|
||||
cache = CfgCache('')
|
||||
cache.katana.eventsLimit = 4000000
|
||||
|
||||
The explicit call sequence will be:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cache.__getattr__('katana').__setattr__( 'eventsLimit', 4000000 )
|
||||
|
||||
1. For the intermediate hierarchy level ``katana``, it is __getattr__()
|
||||
which is called, if the attribute do not exists, we create a new
|
||||
CfgCache().
|
||||
|
||||
2. Second, and only then, __setattr__() is called, which will create a
|
||||
parameter entry named ``eventsLimit``.
|
||||
|
||||
The decision of whether create a parameter entry *or* a CfgCache
|
||||
intermediate level will always be correctly handled because prior
|
||||
to any access, an attribute needs to be set. So we always have
|
||||
first a call chain of __getattr__() with one final __setattr__().
|
||||
For any subsequent access to ``cache.katana.eventsLimit``, as
|
||||
the attribute already exists, there is no type creation problem.
|
||||
"""
|
||||
if attr[0] == '_':
|
||||
object.__setattr__( self, attr, v )
|
||||
return
|
||||
if v is None:
|
||||
v = CfgCache.getDefaultCfgParameter( self._path+'.'+attr )
|
||||
self._rattr[ attr ] = v
|
||||
return
|
||||
|
||||
def __getattr__ ( self, attr ):
|
||||
"""
|
||||
Get an attribute, if it doesn't exists, then we are in an intermediate
|
||||
level like ``katana``, so create a new sub CfgCache for that attribute.
|
||||
"""
|
||||
if not self._rattr.has_key(attr):
|
||||
path = self._path+'.'+attr if len(self._path) else attr
|
||||
self._rattr[attr] = CfgCache( path )
|
||||
return self._rattr[attr]
|
||||
|
||||
def apply ( self, priority=Cfg.Parameter.Priority.UserFile ):
|
||||
"""Apply the parameters values stored in the cache to the ``Cfg`` database."""
|
||||
if not len(self._path):
|
||||
Cfg.Configuration.pushDefaultPriority( priority )
|
||||
for attrName in self._rattr.keys():
|
||||
if isinstance(self._rattr[attrName],CfgCache):
|
||||
self._rattr[attrName].apply()
|
||||
continue
|
||||
CfgCache.setCfgParameter( self._path+'.'+attrName,self._rattr[attrName] )
|
||||
if not len(self._path):
|
||||
Cfg.Configuration.popDefaultPriority()
|
||||
|
||||
def display ( self ):
|
||||
"""Print all the parameters stored in that CfgCache."""
|
||||
if not len(self._path):
|
||||
print( 'Configuration (Cfg) cache:' )
|
||||
for attrName in self._rattr.keys():
|
||||
if isinstance(self._rattr[attrName],CfgCache):
|
||||
self._rattr[attrName].display()
|
||||
continue
|
||||
print( '* {}.{} = {}'.format(self._path,attrName,self._rattr[attrName]) )
|
||||
|
||||
|
|
Loading…
Reference in New Issue