270 lines
11 KiB
Python
270 lines
11 KiB
Python
# -*- 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.Configuration`` : to be used in ``with`` construct.
|
|
* ``overlay.CfgCache`` : A cache for Cfg parameters.
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
import Cfg
|
|
import Hurricane
|
|
|
|
|
|
class UpdateSession ( object ):
|
|
"""
|
|
Context manager for a GO update session. See Hurricane reference manual
|
|
for an info on Hurricane::UpdateSession class.
|
|
"""
|
|
|
|
def __enter__ ( self ):
|
|
Hurricane.UpdateSession.open()
|
|
|
|
def __exit__( self, *args ):
|
|
Hurricane.UpdateSession.close()
|
|
|
|
|
|
class Configuration:
|
|
"""
|
|
Allow access to Cfg parameter as attributes. For attribute syntax,
|
|
the dot (.) used in C++ or raw access is replaced by an underscore (_)
|
|
in Python mode.
|
|
|
|
Also provides a context manager.
|
|
"""
|
|
|
|
PRIORITY_USE_DEFAULT = Cfg.Parameter.Priority.UseDefault
|
|
PRIORITY_APPLICATION_BUILTIN = Cfg.Parameter.Priority.ApplicationBuiltin
|
|
PRIORITY_CONFIGURATION_FILE = Cfg.Parameter.Priority.ConfigurationFile
|
|
PRIORITY_USER_FILE = Cfg.Parameter.Priority.UserFile
|
|
PRIORITY_COMMAND_LINE = Cfg.Parameter.Priority.CommandLine
|
|
PRIORITY_INTERACTIVE = Cfg.Parameter.Priority.Interactive
|
|
|
|
def __init__ ( self, priority=None ):
|
|
self._priority = priority
|
|
|
|
def __enter__( self ):
|
|
if self._priority is not None:
|
|
Cfg.Configuration.pushDefaultPriority( self._priority )
|
|
return self
|
|
|
|
def __setattr__( self, attr, val ):
|
|
if attr.startswith("_"):
|
|
self.__dict__[attr] = val
|
|
return
|
|
attr = attr.replace("_", ".")
|
|
if isinstance(val, bool):
|
|
Cfg.getParamBool(attr).setBool( val )
|
|
elif isinstance(val, int):
|
|
p = Cfg.getParamInt( attr ) # all params have a type
|
|
if p.type == 'Enumerate':
|
|
Cfg.getParamEnumerate(attr).setInt( val )
|
|
else:
|
|
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:
|
|
Cfg.getParamPercentage(attr).setPercentage( float(val[:-1]) )
|
|
else:
|
|
Cfg.getParamString(attr).setString( val )
|
|
|
|
def __exit__( self, *args ):
|
|
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 __enter__( self ):
|
|
return self
|
|
|
|
def __exit__( self, *args ):
|
|
self.apply()
|
|
self.display()
|
|
|
|
def __init__ ( self, path='', priority=None ):
|
|
"""Create a new CfgCache with a ``path`` as parent path."""
|
|
self._priority = priority
|
|
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, self._priority )
|
|
return self._rattr[attr]
|
|
|
|
def apply ( self, priority=None ):
|
|
"""Apply the parameters values stored in the cache to the ``Cfg`` database."""
|
|
if priority is None: priority = self._priority
|
|
if not len(self._path) and priority is not None:
|
|
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) and priority is not None:
|
|
Cfg.Configuration.popDefaultPriority()
|
|
|
|
def display ( self ):
|
|
"""Print all the parameters stored in that CfgCache."""
|
|
if not len(self._path):
|
|
print( ' o Applying configuration (CfgCache):' )
|
|
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]) )
|
|
|