first revision
|
@ -0,0 +1,7 @@
|
||||||
|
"enables us to carry out a calculation and return an option's value"
|
||||||
|
|
||||||
|
# FIXME: import eosfunc here
|
||||||
|
def identical(name, config, *args):
|
||||||
|
return "identical" + name
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,460 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"pretty small and local configuration management tool"
|
||||||
|
# The original `Config` design model is unproudly borrowed from
|
||||||
|
# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||||
|
from error import (HiddenOptionError, ConfigError, NotFoundError,
|
||||||
|
AmbigousOptionError, ConflictConfigError, NoMatchingOptionFound,
|
||||||
|
SpecialOwnersError, MandatoryError, MethodCallError,
|
||||||
|
DisabledOptionError, ModeOptionError)
|
||||||
|
from option import (OptionDescription, Option, SymLinkOption, group_types,
|
||||||
|
apply_requires, modes)
|
||||||
|
import autolib
|
||||||
|
# ____________________________________________________________
|
||||||
|
# automatic Option object
|
||||||
|
special_owners = ['auto', 'fill']
|
||||||
|
|
||||||
|
def special_owner_factory(name, owner, default=None,
|
||||||
|
callback=None, config=None):
|
||||||
|
# auto behavior: carries out a calculation
|
||||||
|
if owner == 'auto':
|
||||||
|
return auto_factory(name, callback, config)
|
||||||
|
# fill behavior: carries out a calculation only if a default value isn't set
|
||||||
|
if owner == 'fill':
|
||||||
|
if default == None:
|
||||||
|
return auto_factory(name, callback, config)
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
def auto_factory(name, callback, config):
|
||||||
|
try:
|
||||||
|
return getattr(autolib, callback)(name, config)
|
||||||
|
except AttributeError:
|
||||||
|
raise SpecialOwnersError("callback: {0} not found for "
|
||||||
|
"option: {1}".format(callback, name))
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
class Config(object):
|
||||||
|
_cfgimpl_hidden = True
|
||||||
|
_cfgimpl_disabled = True
|
||||||
|
_cfgimpl_mandatory = True
|
||||||
|
_cfgimpl_frozen = False
|
||||||
|
_cfgimpl_owner = "user"
|
||||||
|
_cfgimpl_toplevel = None
|
||||||
|
_cfgimpl_mode = 'normal'
|
||||||
|
|
||||||
|
def __init__(self, descr, parent=None, **overrides):
|
||||||
|
self._cfgimpl_descr = descr
|
||||||
|
self._cfgimpl_value_owners = {}
|
||||||
|
self._cfgimpl_parent = parent
|
||||||
|
# `Config()` indeed supports the configuration `Option()`'s values...
|
||||||
|
self._cfgimpl_values = {}
|
||||||
|
self._cfgimpl_previous_values = {}
|
||||||
|
# XXX warnings are a great idea, let's make up a better use of it
|
||||||
|
self._cfgimpl_warnings = []
|
||||||
|
self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
|
||||||
|
# `freeze()` allows us to carry out this calculation again if necessary
|
||||||
|
self._cfgimpl_frozen = self._cfgimpl_toplevel._cfgimpl_frozen
|
||||||
|
#
|
||||||
|
self._cfgimpl_build(overrides)
|
||||||
|
|
||||||
|
def _validate_duplicates(self, children):
|
||||||
|
duplicates = []
|
||||||
|
for dup in children:
|
||||||
|
if dup._name not in duplicates:
|
||||||
|
duplicates.append(dup._name)
|
||||||
|
else:
|
||||||
|
raise ConflictConfigError('duplicate option name: <%s>' % \
|
||||||
|
dup._name)
|
||||||
|
|
||||||
|
def _cfgimpl_build(self, overrides):
|
||||||
|
self._validate_duplicates(self._cfgimpl_descr._children)
|
||||||
|
for child in self._cfgimpl_descr._children:
|
||||||
|
if isinstance(child, Option):
|
||||||
|
self._cfgimpl_values[child._name] = child.getdefault()
|
||||||
|
self._cfgimpl_value_owners[child._name] = 'default'
|
||||||
|
elif isinstance(child, OptionDescription):
|
||||||
|
self._validate_duplicates(child._children)
|
||||||
|
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||||
|
self.override(overrides)
|
||||||
|
|
||||||
|
def cfgimpl_update(self):
|
||||||
|
"dynamically adds `Option()` or `OptionDescription()`"
|
||||||
|
# Nothing is static. Everything evolve.
|
||||||
|
# FIXME this is an update for new options in the schema only
|
||||||
|
# see the update_child() method of the descr object
|
||||||
|
for child in self._cfgimpl_descr._children:
|
||||||
|
if isinstance(child, Option):
|
||||||
|
if child._name not in self._cfgimpl_values:
|
||||||
|
self._cfgimpl_values[child._name] = child.getdefault()
|
||||||
|
self._cfgimpl_value_owners[child._name] = 'default'
|
||||||
|
elif isinstance(child, OptionDescription):
|
||||||
|
if child._name not in self._cfgimpl_values:
|
||||||
|
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||||
|
|
||||||
|
def override(self, overrides):
|
||||||
|
for name, value in overrides.iteritems():
|
||||||
|
homeconfig, name = self._cfgimpl_get_home_by_path(name)
|
||||||
|
# if there are special_owners, impossible to override
|
||||||
|
if homeconfig._cfgimpl_value_owners[name] in special_owners:
|
||||||
|
raise SpecialOwnersError("cannot override option: {0} because "
|
||||||
|
"of its special owner".format(name))
|
||||||
|
homeconfig.setoption(name, value, 'default')
|
||||||
|
|
||||||
|
def cfgimpl_set_owner(self, owner):
|
||||||
|
self._cfgimpl_owner = owner
|
||||||
|
for child in self._cfgimpl_descr._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
self._cfgimpl_values[child._name].cfgimpl_set_owner(owner)
|
||||||
|
# ____________________________________________________________
|
||||||
|
def cfgimpl_hide(self):
|
||||||
|
if self._cfgimpl_parent != None:
|
||||||
|
raise MethodCallError("this method root_hide() shall not be"
|
||||||
|
"used with non-root Config() object")
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_hidden = True
|
||||||
|
|
||||||
|
def cfgimpl_show(self):
|
||||||
|
if self._cfgimpl_parent != None:
|
||||||
|
raise MethodCallError("this method root_hide() shall not be"
|
||||||
|
"used with non-root Config() object")
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_hidden = False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def cfgimpl_disable(self):
|
||||||
|
if self._cfgimpl_parent != None:
|
||||||
|
raise MethodCallError("this method root_hide() shall not be"
|
||||||
|
"used with non-root Confit() object")
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_disabled = True
|
||||||
|
|
||||||
|
def cfgimpl_enable(self):
|
||||||
|
if self._cfgimpl_parent != None:
|
||||||
|
raise MethodCallError("this method root_hide() shall not be"
|
||||||
|
"used with non-root Confit() object")
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_disabled = False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def __setattr__(self, name, value):
|
||||||
|
if '.' in name:
|
||||||
|
homeconfig, name = self._cfgimpl_get_home_by_path(name)
|
||||||
|
return setattr(homeconfig, name, value)
|
||||||
|
|
||||||
|
if name.startswith('_cfgimpl_'):
|
||||||
|
self.__dict__[name] = value
|
||||||
|
return
|
||||||
|
if self._cfgimpl_frozen and getattr(self, name) != value:
|
||||||
|
raise TypeError("trying to change a value in a frozen config"
|
||||||
|
": {0} {1}".format(name, value))
|
||||||
|
if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
|
||||||
|
self._validate(name, getattr(self._cfgimpl_descr, name))
|
||||||
|
self.setoption(name, value, self._cfgimpl_owner)
|
||||||
|
|
||||||
|
def _validate(self, name, opt_or_descr):
|
||||||
|
if not type(opt_or_descr) == OptionDescription:
|
||||||
|
apply_requires(opt_or_descr, self)
|
||||||
|
# hidden options
|
||||||
|
if self._cfgimpl_toplevel._cfgimpl_hidden and \
|
||||||
|
(opt_or_descr._is_hidden() or self._cfgimpl_descr._is_hidden()):
|
||||||
|
raise HiddenOptionError("trying to access to a hidden option:"
|
||||||
|
" {0}".format(name))
|
||||||
|
# disabled options
|
||||||
|
if self._cfgimpl_toplevel._cfgimpl_disabled and \
|
||||||
|
(opt_or_descr._is_disabled() or self._cfgimpl_descr._is_disabled()):
|
||||||
|
raise DisabledOptionError("this option is disabled:"
|
||||||
|
" {0}".format(name))
|
||||||
|
# expert options
|
||||||
|
# XXX currently doesn't look at the group, is it really necessary ?
|
||||||
|
if self._cfgimpl_toplevel._cfgimpl_mode != 'normal':
|
||||||
|
if opt_or_descr.get_mode() != 'normal':
|
||||||
|
raise ModeOptionError("this option's mode is not normal:"
|
||||||
|
" {0}".format(name))
|
||||||
|
if type(opt_or_descr) == OptionDescription:
|
||||||
|
apply_requires(opt_or_descr, self)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
# attribute access by passing a path,
|
||||||
|
# for instance getattr(self, "creole.general.family.adresse_ip_eth0")
|
||||||
|
if '.' in name:
|
||||||
|
homeconfig, name = self._cfgimpl_get_home_by_path(name)
|
||||||
|
return getattr(homeconfig, name)
|
||||||
|
opt_or_descr = getattr(self._cfgimpl_descr, name)
|
||||||
|
# symlink options
|
||||||
|
if type(opt_or_descr) == SymLinkOption:
|
||||||
|
return getattr(self, opt_or_descr.path)
|
||||||
|
self._validate(name, opt_or_descr)
|
||||||
|
# special attributes
|
||||||
|
if name.startswith('_cfgimpl_'):
|
||||||
|
# if it were in __dict__ it would have been found already
|
||||||
|
return self.__dict__[name]
|
||||||
|
raise AttributeError("%s object has no attribute %s" %
|
||||||
|
(self.__class__, name))
|
||||||
|
if name not in self._cfgimpl_values:
|
||||||
|
raise AttributeError("%s object has no attribute %s" %
|
||||||
|
(self.__class__, name))
|
||||||
|
if name in self._cfgimpl_value_owners:
|
||||||
|
owner = self._cfgimpl_value_owners[name]
|
||||||
|
# special owners
|
||||||
|
if owner in special_owners:
|
||||||
|
return special_owner_factory(name, owner,
|
||||||
|
default=opt_or_descr.getdefault(),
|
||||||
|
callback=opt_or_descr.getcallback(),
|
||||||
|
config=self)
|
||||||
|
# mandatory options
|
||||||
|
if not isinstance(opt_or_descr, OptionDescription):
|
||||||
|
homeconfig = self._cfgimpl_get_toplevel()
|
||||||
|
mandatory = homeconfig._cfgimpl_mandatory
|
||||||
|
if opt_or_descr.is_mandatory() and mandatory:
|
||||||
|
if self._cfgimpl_values[name] == None\
|
||||||
|
and opt_or_descr.getdefault() == None:
|
||||||
|
raise MandatoryError("option: {0} is mandatory "
|
||||||
|
"and shall have a value".format(name))
|
||||||
|
return self._cfgimpl_values[name]
|
||||||
|
|
||||||
|
def __dir__(self):
|
||||||
|
#from_type = dir(type(self))
|
||||||
|
from_dict = list(self.__dict__)
|
||||||
|
extras = list(self._cfgimpl_values)
|
||||||
|
return sorted(set(extras + from_dict))
|
||||||
|
|
||||||
|
def unwrap_from_name(self, name):
|
||||||
|
# didn't have to stoop so low: `self.get()` must be the proper method
|
||||||
|
# **and it is slow**: it recursively searches into the namespaces
|
||||||
|
paths = self.getpaths(allpaths=True)
|
||||||
|
opts = dict([(path, self.unwrap_from_path(path)) for path in paths])
|
||||||
|
all_paths = [p.split(".") for p in self.getpaths()]
|
||||||
|
for pth in all_paths:
|
||||||
|
if name in pth:
|
||||||
|
return opts[".".join(pth)]
|
||||||
|
raise NotFoundError("name: {0} not found".format(name))
|
||||||
|
|
||||||
|
def unwrap_from_path(self, path):
|
||||||
|
# didn't have to stoop so low, `geattr(self, path)` is much better
|
||||||
|
# **fast**: finds the option directly in the appropriate namespace
|
||||||
|
if '.' in path:
|
||||||
|
homeconfig, path = self._cfgimpl_get_home_by_path(path)
|
||||||
|
return getattr(homeconfig._cfgimpl_descr, path)
|
||||||
|
return getattr(self._cfgimpl_descr, path)
|
||||||
|
|
||||||
|
def __delattr__(self, name):
|
||||||
|
# if you use delattr you are responsible for all bad things happening
|
||||||
|
if name.startswith('_cfgimpl_'):
|
||||||
|
del self.__dict__[name]
|
||||||
|
return
|
||||||
|
self._cfgimpl_value_owners[name] = 'default'
|
||||||
|
opt = getattr(self._cfgimpl_descr, name)
|
||||||
|
if isinstance(opt, OptionDescription):
|
||||||
|
raise AttributeError("can't option subgroup")
|
||||||
|
self._cfgimpl_values[name] = getattr(opt, 'default', None)
|
||||||
|
|
||||||
|
def setoption(self, name, value, who=None):
|
||||||
|
if who == None:
|
||||||
|
who == self._cfgimpl_owner
|
||||||
|
child = getattr(self._cfgimpl_descr, name)
|
||||||
|
if type(child) != SymLinkOption:
|
||||||
|
if name not in self._cfgimpl_values:
|
||||||
|
raise AttributeError('unknown option %s' % (name,))
|
||||||
|
# special owners, a value with a owner *auto* cannot be changed
|
||||||
|
oldowner = self._cfgimpl_value_owners[child._name]
|
||||||
|
if oldowner == 'auto':
|
||||||
|
if who == 'auto':
|
||||||
|
raise ConflictConfigError('cannot override value to %s for '
|
||||||
|
'option %s' % (value, name))
|
||||||
|
if oldowner == who:
|
||||||
|
oldvalue = getattr(self, name)
|
||||||
|
if oldvalue == value: #or who in ("default",):
|
||||||
|
return
|
||||||
|
child.setoption(self, value, who)
|
||||||
|
# if the value owner is 'auto', set the option to hidden
|
||||||
|
if who == 'auto':
|
||||||
|
if not child._is_hidden():
|
||||||
|
child.hide()
|
||||||
|
self._cfgimpl_value_owners[name] = who
|
||||||
|
else:
|
||||||
|
homeconfig = self._cfgimpl_get_toplevel()
|
||||||
|
child.setoption(homeconfig, value, who)
|
||||||
|
|
||||||
|
def set(self, **kwargs):
|
||||||
|
all_paths = [p.split(".") for p in self.getpaths(allpaths=True)]
|
||||||
|
for key, value in kwargs.iteritems():
|
||||||
|
key_p = key.split('.')
|
||||||
|
candidates = [p for p in all_paths if p[-len(key_p):] == key_p]
|
||||||
|
if len(candidates) == 1:
|
||||||
|
name = '.'.join(candidates[0])
|
||||||
|
homeconfig, name = self._cfgimpl_get_home_by_path(name)
|
||||||
|
try:
|
||||||
|
getattr(homeconfig, name)
|
||||||
|
except MandatoryError:
|
||||||
|
pass
|
||||||
|
except Exception, e:
|
||||||
|
raise e # HiddenOptionError or DisabledOptionError
|
||||||
|
homeconfig.setoption(name, value, self._cfgimpl_owner)
|
||||||
|
elif len(candidates) > 1:
|
||||||
|
raise AmbigousOptionError(
|
||||||
|
'more than one option that ends with %s' % (key, ))
|
||||||
|
else:
|
||||||
|
raise NoMatchingOptionFound(
|
||||||
|
'there is no option that matches %s'
|
||||||
|
' or the option is hidden or disabled'% (key, ))
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
paths = self.getpaths(allpaths=True)
|
||||||
|
pathsvalues = []
|
||||||
|
for path in paths:
|
||||||
|
pathname = path.split('.')[-1]
|
||||||
|
if pathname == name:
|
||||||
|
try:
|
||||||
|
value = getattr(self, path)
|
||||||
|
return value
|
||||||
|
except Exception, e:
|
||||||
|
raise e
|
||||||
|
raise NotFoundError("option {0} not found in config".format(name))
|
||||||
|
|
||||||
|
def _cfgimpl_get_home_by_path(self, path):
|
||||||
|
"""returns tuple (config, name)"""
|
||||||
|
path = path.split('.')
|
||||||
|
|
||||||
|
for step in path[:-1]:
|
||||||
|
self = getattr(self, step)
|
||||||
|
return self, path[-1]
|
||||||
|
|
||||||
|
def _cfgimpl_get_toplevel(self):
|
||||||
|
while self._cfgimpl_parent is not None:
|
||||||
|
self = self._cfgimpl_parent
|
||||||
|
return self
|
||||||
|
|
||||||
|
def add_warning(self, warning):
|
||||||
|
self._cfgimpl_get_toplevel()._cfgimpl_warnings.append(warning)
|
||||||
|
|
||||||
|
def get_warnings(self):
|
||||||
|
return self._cfgimpl_get_toplevel()._cfgimpl_warnings
|
||||||
|
# ____________________________________________________________
|
||||||
|
# freeze and read-write statuses
|
||||||
|
def cfgimpl_freeze(self):
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_frozen = True
|
||||||
|
self._cfgimpl_frozen = True
|
||||||
|
|
||||||
|
def cfgimpl_unfreeze(self):
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_frozen = False
|
||||||
|
self._cfgimpl_frozen = False
|
||||||
|
|
||||||
|
def is_frozen(self):
|
||||||
|
# it should be the same value as self._cfgimpl_frozen...
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
return rootconfig.__dict__['_cfgimpl_frozen']
|
||||||
|
|
||||||
|
def cfgimpl_read_only(self):
|
||||||
|
# hung up on freeze, hidden and disabled concepts
|
||||||
|
self.cfgimpl_freeze()
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_hidden = False
|
||||||
|
rootconfig._cfgimpl_disabled = True
|
||||||
|
rootconfig._cfgimpl_mandatory = True
|
||||||
|
|
||||||
|
def cfgimpl_set_mode(self, mode):
|
||||||
|
# normal or expert mode
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
if mode not in modes:
|
||||||
|
raise ConfigError("mode {0} not available".format(mode))
|
||||||
|
rootconfig._cfgimpl_mode = mode
|
||||||
|
|
||||||
|
def cfgimpl_read_write(self):
|
||||||
|
# hung up on freeze, hidden and disabled concepts
|
||||||
|
self.cfgimpl_unfreeze()
|
||||||
|
rootconfig = self._cfgimpl_get_toplevel()
|
||||||
|
rootconfig._cfgimpl_hidden = True
|
||||||
|
rootconfig._cfgimpl_disabled = False
|
||||||
|
rootconfig._cfgimpl_mandatory = False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def getkey(self):
|
||||||
|
return self._cfgimpl_descr.getkey(self)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.getkey())
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.getkey() == other.getkey()
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
# iteration only on Options (not OptionDescriptions)
|
||||||
|
for child in self._cfgimpl_descr._children:
|
||||||
|
if isinstance(child, Option):
|
||||||
|
try:
|
||||||
|
yield child._name, getattr(self, child._name)
|
||||||
|
except:
|
||||||
|
pass # hidden, disabled option group
|
||||||
|
|
||||||
|
def iter_groups(self, group_type=None):
|
||||||
|
"iteration on OptionDescriptions"
|
||||||
|
if group_type == None:
|
||||||
|
groups = group_types
|
||||||
|
else:
|
||||||
|
if group_type not in group_types:
|
||||||
|
raise TypeError("Unknown group_type: {0}".format(group_type))
|
||||||
|
groups = [group_type]
|
||||||
|
for child in self._cfgimpl_descr._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
try:
|
||||||
|
if child.get_group_type() in groups:
|
||||||
|
yield child._name, getattr(self, child._name)
|
||||||
|
except:
|
||||||
|
pass # hidden, disabled option
|
||||||
|
|
||||||
|
def __str__(self, indent=""):
|
||||||
|
lines = []
|
||||||
|
children = [(child._name, child)
|
||||||
|
for child in self._cfgimpl_descr._children]
|
||||||
|
children.sort()
|
||||||
|
for name, child in children:
|
||||||
|
if self._cfgimpl_value_owners.get(name, None) == 'default':
|
||||||
|
continue
|
||||||
|
value = getattr(self, name)
|
||||||
|
if isinstance(value, Config):
|
||||||
|
substr = value.__str__(indent + " ")
|
||||||
|
else:
|
||||||
|
substr = "%s %s = %s" % (indent, name, value)
|
||||||
|
if substr:
|
||||||
|
lines.append(substr)
|
||||||
|
if indent and not lines:
|
||||||
|
return '' # hide subgroups with all default values
|
||||||
|
lines.insert(0, "%s[%s]" % (indent, self._cfgimpl_descr._name,))
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def getpaths(self, include_groups=False, allpaths=False):
|
||||||
|
"""returns a list of all paths in self, recursively, taking care of
|
||||||
|
the context (hidden/disabled)
|
||||||
|
"""
|
||||||
|
paths = []
|
||||||
|
for path in self._cfgimpl_descr.getpaths(include_groups=include_groups):
|
||||||
|
try:
|
||||||
|
value = getattr(self, path)
|
||||||
|
except Exception, e:
|
||||||
|
if not allpaths:
|
||||||
|
pass # hidden or disabled option
|
||||||
|
else:
|
||||||
|
paths.append(path) # hidden or disabled option added
|
||||||
|
else:
|
||||||
|
paths.append(path)
|
||||||
|
return paths
|
||||||
|
|
||||||
|
def make_dict(config, flatten=False):
|
||||||
|
paths = config.getpaths()
|
||||||
|
pathsvalues = []
|
||||||
|
for path in paths:
|
||||||
|
if flatten:
|
||||||
|
pathname = path.split('.')[-1]
|
||||||
|
else:
|
||||||
|
pathname = path
|
||||||
|
try:
|
||||||
|
value = getattr(config, path)
|
||||||
|
pathsvalues.append((pathname, value))
|
||||||
|
except:
|
||||||
|
pass # this just a hidden or disabled option
|
||||||
|
options = dict(pathsvalues)
|
||||||
|
return options
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
2012-03-23
|
||||||
|
|
||||||
|
- set_group_type (instead of set_descr())
|
||||||
|
- iteration utilities (for -> on option, iter_group -> on
|
||||||
|
OptionDescriptions (group of options)
|
||||||
|
- hide and disable for option groups (and subgroups) -> not OK
|
||||||
|
|
||||||
|
2012-03-20
|
||||||
|
|
||||||
|
- get() method for recursive attribute access
|
||||||
|
- make_path() in a flatten way
|
||||||
|
- ro and rw
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
SRC=$(wildcard *.txt)
|
||||||
|
HTMLFRAGMENT=$(addsuffix .html, $(basename $(SRC)))
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: html code
|
||||||
|
# make -C ./build/code all
|
||||||
|
# make -C ./build/test all
|
||||||
|
# make -C ./build all
|
||||||
|
|
||||||
|
html: $(HTMLFRAGMENT)
|
||||||
|
|
||||||
|
%.html: %.txt
|
||||||
|
./rst2html.py --stylesheet ./build/style.css $< > ./build/$@
|
||||||
|
|
||||||
|
code:
|
||||||
|
./code2html
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C ./build clean
|
||||||
|
make -C ./pydoc/ clean
|
||||||
|
# make -C ./build/test clean
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
.PHONY: clean
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.html
|
||||||
|
rm -f api/*.html
|
|
@ -0,0 +1 @@
|
||||||
|
API's directory
|
After Width: | Height: | Size: 8.3 KiB |
|
@ -0,0 +1,1080 @@
|
||||||
|
body,body.editor,body.body {
|
||||||
|
font: 110% "Times New Roman", Arial, Verdana, Helvetica, serif;
|
||||||
|
background: White;
|
||||||
|
color: Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a.reference {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a[href]:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, div.text {
|
||||||
|
text-align: left;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin: 0.5em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
p a:active {
|
||||||
|
color: Red;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
p img {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.inlinephoto {
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 1em;
|
||||||
|
padding-top: 0.7em;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
clear: both;
|
||||||
|
height: 1px;
|
||||||
|
color: #8CACBB;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul {
|
||||||
|
line-height: 1.5em;
|
||||||
|
/*list-style-image: url("bullet.gif"); */
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul a, ol a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
font-family: Times, "Times New Roman", serif;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: Black;
|
||||||
|
/*background-color: #dee7ec;*/
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
background-color: #cccccc;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.netscape4 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main page styles */
|
||||||
|
|
||||||
|
/*a[href]:hover { color: black; text-decoration: underline; }
|
||||||
|
a[href]:link { color: black; text-decoration: underline; }
|
||||||
|
a[href] { color: black; text-decoration: underline; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
span.menu_selected {
|
||||||
|
color: black;
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.menu {
|
||||||
|
/*color: #3ba6ec; */
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.menu[href]:visited, a.menu[href]:link{
|
||||||
|
/*color: #3ba6ec; */
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.menu[href]:hover {
|
||||||
|
/*color: black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
div.project_title{
|
||||||
|
/*border-spacing: 20px;*/
|
||||||
|
font: 160% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
color: #3ba6ec;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikicurrent {
|
||||||
|
font: 100% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
color: #3ba6ec;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table.body {
|
||||||
|
border: 0;
|
||||||
|
/*padding: 0;
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.page-header-left {
|
||||||
|
padding: 5px;
|
||||||
|
/*border-bottom: 1px solid #444444;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.page-header-top {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
/*border-bottom: 1px solid #444444;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar {
|
||||||
|
padding: 1 0 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar p.classblock {
|
||||||
|
padding: 0 5 0 5;
|
||||||
|
margin: 1 1 1 1;
|
||||||
|
border: 1px solid #444444;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar p.userblock {
|
||||||
|
padding: 0 5 0 5;
|
||||||
|
margin: 1 1 1 1;
|
||||||
|
border: 1px solid #444444;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.content {
|
||||||
|
padding: 1 5 1 5;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.ok-message {
|
||||||
|
background-color: #22bb22;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
p.error-message {
|
||||||
|
background-color: #bb2222;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin: 0 ;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for forms */
|
||||||
|
table.form {
|
||||||
|
padding: 2;
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form th {
|
||||||
|
color: #333388;
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: top;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
table.form th.header {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form th.required {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td {
|
||||||
|
color: #333333;
|
||||||
|
empty-cells: show;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td.optional {
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td.html {
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for lists */
|
||||||
|
table.list {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
vertical-align: top;
|
||||||
|
padding-top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list th {
|
||||||
|
padding: 0 4 0 4;
|
||||||
|
color: #404070;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
border-top: 1px solid #404070;
|
||||||
|
border-bottom: 1px solid #404070;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
table.list th a[href]:hover { color: #404070 }
|
||||||
|
table.list th a[href]:link { color: #404070 }
|
||||||
|
table.list th a[href] { color: #404070 }
|
||||||
|
table.list th.group {
|
||||||
|
background-color: #f4f4ff;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list td {
|
||||||
|
padding: 0 4 0 4;
|
||||||
|
border: 0 2 0 2;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
color: #404070;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.normal td {
|
||||||
|
background-color: white;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.alt td {
|
||||||
|
background-color: #efefef;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list td:first-child {
|
||||||
|
border-left: 1px solid #404070;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list th:first-child {
|
||||||
|
border-left: 1px solid #404070;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.navigation th {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
table.list tr.navigation th:first-child {
|
||||||
|
border-right: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for message displays */
|
||||||
|
table.messages {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages th {
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages td {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: #efefef;
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
color: black;
|
||||||
|
empty-cells: show;
|
||||||
|
border-right: 1px solid #afafaf;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 2 5 2 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages td:first-child {
|
||||||
|
border-left: 1px solid #afafaf;
|
||||||
|
border-right: 1px solid #afafaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for file displays */
|
||||||
|
table.files {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files td {
|
||||||
|
font-family: monospace;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for history displays */
|
||||||
|
table.history {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history td {
|
||||||
|
font-size: 90%;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for class list */
|
||||||
|
table.classlist {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classlist th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classlist th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for class help display */
|
||||||
|
table.classhelp {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classhelp th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classhelp td {
|
||||||
|
padding: 2 2 2 2;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for "other" displays */
|
||||||
|
table.otherinfo {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.otherinfo th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.otherinfo th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 1px; /* IE bug fix */
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 1px; /* IE bug fix */
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.nonexistent {
|
||||||
|
color: #FF2222;
|
||||||
|
}
|
||||||
|
a.nonexistent:visited {
|
||||||
|
color: #FF2222;
|
||||||
|
}
|
||||||
|
a.external {
|
||||||
|
color: #AA6600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
dl,ul,ol {
|
||||||
|
margin-top: 1pt;
|
||||||
|
}
|
||||||
|
tt,pre {
|
||||||
|
font-family: Lucida Console,Courier New,Courier,monotype;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
pre.code {
|
||||||
|
margin-top: 8pt;
|
||||||
|
margin-bottom: 8pt;
|
||||||
|
background-color: #FFFFEE;
|
||||||
|
white-space:pre;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1pt;
|
||||||
|
border-color:#999999;
|
||||||
|
color:#111111;
|
||||||
|
padding:5px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
div.diffold {
|
||||||
|
background-color: #FFFF80;
|
||||||
|
border-style:none;
|
||||||
|
border-width:thin;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
div.diffnew {
|
||||||
|
background-color: #80FF80;
|
||||||
|
border-style:none;
|
||||||
|
border-width:thin;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
div.message {
|
||||||
|
margin-top: 6pt;
|
||||||
|
background-color: #E8FFE8;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1pt;
|
||||||
|
border-color:#999999;
|
||||||
|
color:#440000;
|
||||||
|
padding:5px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
strong.highlight {
|
||||||
|
background-color: #FFBBBB;
|
||||||
|
/* as usual, NetScape fucks up with innocent CSS
|
||||||
|
border-color: #FFAAAA;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1pt;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
table.navibar {
|
||||||
|
background-color: #C8C8C8;
|
||||||
|
border-spacing: 3px;
|
||||||
|
}
|
||||||
|
td.navibar {
|
||||||
|
background-color: #E8E8E8;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pagename {
|
||||||
|
font-size: 140%;
|
||||||
|
color: blue;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
padding: 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikiaction, input.wikiaction {
|
||||||
|
color: black;
|
||||||
|
text-decoration: None;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
/*border: 1px solid #3ba6ec; */
|
||||||
|
margin: 4px;
|
||||||
|
padding: 5;
|
||||||
|
padding-bottom: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikiaction[href]:hover {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
/*background-color: #dddddd; */
|
||||||
|
}
|
||||||
|
|
||||||
|
span.wikiuserpref {
|
||||||
|
padding-top: 1em;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikitrail {
|
||||||
|
vertical-align: bottom;
|
||||||
|
/*font-size: -1;*/
|
||||||
|
padding-top: 1em;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiaction {
|
||||||
|
vertical-align: middle;
|
||||||
|
/*border-bottom: 1px solid #8cacbb;*/
|
||||||
|
padding-bottom:1em;
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikieditmenu {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.wikiedit {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
background-color: #fabf00;
|
||||||
|
padding: 1em;
|
||||||
|
padding-right: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.legenditem {
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-left: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.wikitoken {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div#contentspace h1:first-child, div.heading:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
div#contentspace h2:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* heading and paragraph text */
|
||||||
|
|
||||||
|
div.heading, h1 {
|
||||||
|
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
background-color: #58b3ef;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
/*color: #4893cf;*/
|
||||||
|
color: black;
|
||||||
|
padding-top: 1.0em;
|
||||||
|
padding-bottom:0.2em;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 0em;
|
||||||
|
/*margin-bottom:8pt;*/
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 115%;
|
||||||
|
border-bottom: 1px solid #8CACBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: orange;
|
||||||
|
clear: left;
|
||||||
|
font: 100% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0em;
|
||||||
|
padding-top: 1em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
/*border-bottom: 1px solid #8CACBB;*/
|
||||||
|
}
|
||||||
|
/* h1,h2 { padding-top: 0; }*/
|
||||||
|
|
||||||
|
|
||||||
|
h1 { font-size: 145%; }
|
||||||
|
h2 { font-size: 135%; }
|
||||||
|
h3 { font-size: 125%; }
|
||||||
|
h4 { font-size: 120%; }
|
||||||
|
h5 { font-size: 110%; }
|
||||||
|
h6 { font-size: 80%; }
|
||||||
|
|
||||||
|
h1 a { text-decoration: None;}
|
||||||
|
|
||||||
|
div.exception {
|
||||||
|
background-color: #bb2222;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
pre.exception {
|
||||||
|
font-size: 110%;
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defines for navgiation bar (documentation) */
|
||||||
|
|
||||||
|
|
||||||
|
div.direntry {
|
||||||
|
padding-top: 0.3em;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
margin-right: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.fileentry {
|
||||||
|
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.fileentry {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
span.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
span.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navbar {
|
||||||
|
/*margin: 0;*/
|
||||||
|
font-size: 80% /*smaller*/;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
/* position: fixed; */
|
||||||
|
top: 100pt;
|
||||||
|
left: 0pt; /* auto; */
|
||||||
|
width: 120pt;
|
||||||
|
/* right: auto;
|
||||||
|
right: 0pt; 2em; */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.history a {
|
||||||
|
/* font-size: 70%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiactiontitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* REST defines */
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.toplist {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
img#pyimg {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#navspace {
|
||||||
|
position: absolute;
|
||||||
|
top: 130px;
|
||||||
|
left: 11px;
|
||||||
|
font-size: 100%;
|
||||||
|
width: 150px;
|
||||||
|
overflow: hidden; /* scroll; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div#metaspace {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#errorline {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#contentspace {
|
||||||
|
position: absolute;
|
||||||
|
/* font: 120% "Times New Roman", serif;*/
|
||||||
|
font: 110% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
top: 130px;
|
||||||
|
left: 170px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#menubar {
|
||||||
|
/* width: 400px; */
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the documentation page */
|
||||||
|
div#docinfoline {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
left: 0px;
|
||||||
|
|
||||||
|
/*background-color: #dee7ec; */
|
||||||
|
padding: 5pt;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
color: black;
|
||||||
|
/*border-width: 1pt;
|
||||||
|
border-style: solid;*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div#docnavlist {
|
||||||
|
/*background-color: #dee7ec; */
|
||||||
|
padding: 5pt;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
color: black;
|
||||||
|
border-width: 1pt;
|
||||||
|
/*border-style: solid;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* text markup */
|
||||||
|
|
||||||
|
div.listtitle {
|
||||||
|
color: Black;
|
||||||
|
clear: left;
|
||||||
|
font: 120% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0em;
|
||||||
|
padding-top: 0em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
border-bottom: 1px solid #8CACBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox h3 {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
background-color: #fabf00;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid black; /* 8cacbb; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox a {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox a.history {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
overflow: hidden; /* scroll; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* taken from docutils (oh dear, a bit senseless) */
|
||||||
|
ol.simple, ul.simple {
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal }
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha }
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha }
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman }
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
:Author: David Goodger
|
||||||
|
:Contact: goodger@users.sourceforge.net
|
||||||
|
:date: $Date: 2003/01/22 22:26:48 $
|
||||||
|
:version: $Revision: 1.29 $
|
||||||
|
:copyright: This stylesheet has been placed in the public domain.
|
||||||
|
|
||||||
|
Default cascading style sheet for the HTML output of Docutils.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
.first {
|
||||||
|
margin-top: 0 }
|
||||||
|
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0 }
|
||||||
|
|
||||||
|
a.toc-backref {
|
||||||
|
text-decoration: none ;
|
||||||
|
color: black }
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.abstract {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
div.abstract p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
div.attention, div.caution, div.danger, div.error, div.hint,
|
||||||
|
div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.hint p.admonition-title, div.important p.admonition-title,
|
||||||
|
div.note p.admonition-title, div.tip p.admonition-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.dedication {
|
||||||
|
margin: 2em 5em ;
|
||||||
|
text-align: center ;
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
div.dedication p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-style: normal }
|
||||||
|
|
||||||
|
div.figure {
|
||||||
|
margin-left: 2em }
|
||||||
|
|
||||||
|
div.footer, div.header {
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
div.system-messages {
|
||||||
|
margin: 5em }
|
||||||
|
|
||||||
|
div.system-messages h1 {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
div.system-message {
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.system-message p.system-message-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
margin: 2em }
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
text-align: center ;
|
||||||
|
color: orange}
|
||||||
|
|
||||||
|
h2.subtitle {
|
||||||
|
color: orange;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 75% }
|
||||||
|
|
||||||
|
p.caption {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
p.credits {
|
||||||
|
font-style: italic ;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
p.label {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
pre.address {
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-top: 0 ;
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.line-block {
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.literal-block, pre.doctest-block {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em ;
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
span.classifier {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-style: oblique }
|
||||||
|
|
||||||
|
span.classifier-delimiter {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
span.interpreted {
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
span.option {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
span.option-argument {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
span.pre {
|
||||||
|
white-space: pre }
|
||||||
|
|
||||||
|
span.problematic {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-top: 0.5em ;
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid thin gray ;
|
||||||
|
padding-left: 0.5ex }
|
||||||
|
|
||||||
|
table.docinfo {
|
||||||
|
margin: 2em 4em }
|
||||||
|
|
||||||
|
table.footnote {
|
||||||
|
border-left: solid thin black ;
|
||||||
|
padding-left: 0.5ex }
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
padding-left: 0.5em ;
|
||||||
|
padding-right: 0.5em ;
|
||||||
|
vertical-align: top }
|
||||||
|
|
||||||
|
th.docinfo-name, th.field-name {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: left ;
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
tt {
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
ul.auto-toc {
|
||||||
|
list-style-type: none }
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.section {
|
||||||
|
margin-top: 1.0em ;
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
.first {
|
||||||
|
margin-top: 0 ! important }
|
||||||
|
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0 ! important }
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none }
|
||||||
|
|
||||||
|
a.toc-backref {
|
||||||
|
text-decoration: none ;
|
||||||
|
color: inherit }
|
||||||
|
|
||||||
|
blockquote.epigraph {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
dl.docutils dd {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
dl.docutils dt {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
dl dt { line-height: 150% }
|
||||||
|
|
||||||
|
div.abstract {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
div.abstract p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||||
|
div.hint, div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||||
|
div.important p.admonition-title, div.note p.admonition-title,
|
||||||
|
div.tip p.admonition-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.compound .compound-first, div.compound .compound-middle {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.compound .compound-last, div.compound .compound-middle {
|
||||||
|
margin-top: 0.5em }
|
||||||
|
|
||||||
|
div.dedication {
|
||||||
|
margin: 2em 5em ;
|
||||||
|
text-align: center ;
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
div.dedication p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-style: normal }
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
width: 600px ;
|
||||||
|
margin-left: 5em ;
|
||||||
|
margin-right: 5em }
|
||||||
|
|
||||||
|
div.figure {
|
||||||
|
margin-left: 2em }
|
||||||
|
|
||||||
|
div.footer, div.header {
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
div.line-block {
|
||||||
|
display: block ;
|
||||||
|
margin-top: 1em ;
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
div.line-block div.line-block {
|
||||||
|
margin-top: 0 ;
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-left: 1.5em }
|
||||||
|
|
||||||
|
div.sidebar {
|
||||||
|
margin-left: 1em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em ;
|
||||||
|
background-color: #ffffee ;
|
||||||
|
width: 40% ;
|
||||||
|
float: right ;
|
||||||
|
clear: right }
|
||||||
|
|
||||||
|
div.sidebar p.rubric {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-size: medium }
|
||||||
|
|
||||||
|
div.system-messages {
|
||||||
|
margin: 5em }
|
||||||
|
|
||||||
|
div.system-messages h1 {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
div.system-message {
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.system-message p.system-message-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
margin: 2em }
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5 {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
line-height: 150% ;
|
||||||
|
color: orange} /* #666 } */
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
h2.subtitle {
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
hr.docutils {
|
||||||
|
width: 75% }
|
||||||
|
|
||||||
|
ol.simple, ul.simple {
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal }
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha }
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha }
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman }
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman }
|
||||||
|
|
||||||
|
p.attribution {
|
||||||
|
text-align: right ;
|
||||||
|
margin-left: 50% }
|
||||||
|
|
||||||
|
p.caption {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
p.credits {
|
||||||
|
font-style: italic ;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
p.label {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
p.rubric {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger ;
|
||||||
|
color: maroon ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
p.sidebar-title {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger }
|
||||||
|
|
||||||
|
p.sidebar-subtitle {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
pre.address {
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-top: 0 ;
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.line-block {
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.literal-block, pre.doctest-block {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em ;
|
||||||
|
font-size: small ;
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
span.classifier {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-style: oblique }
|
||||||
|
|
||||||
|
span.classifier-delimiter {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
span.interpreted {
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
span.option {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
span.option-argument {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
span.pre {
|
||||||
|
white-space: pre }
|
||||||
|
|
||||||
|
span.problematic {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid thin gray }
|
||||||
|
|
||||||
|
table.docinfo {
|
||||||
|
/* float: right ; */
|
||||||
|
margin: 2em 4em ;
|
||||||
|
color: #666 }
|
||||||
|
|
||||||
|
table.docutils {
|
||||||
|
margin-top: 0.5em ;
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
table.footnote {
|
||||||
|
border-left: solid thin black }
|
||||||
|
|
||||||
|
table.docutils td, table.docutils th,
|
||||||
|
table.docinfo td, table.docinfo th {
|
||||||
|
padding-left: 0.5em ;
|
||||||
|
padding-right: 0.5em ;
|
||||||
|
vertical-align: top }
|
||||||
|
|
||||||
|
th.docinfo-name, th.field-name {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: right ;
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
tt.docutils {
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
ul.auto-toc {
|
||||||
|
list-style-type: none }
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
@import url(docutils.css);
|
||||||
|
@import url(default.css);
|
||||||
|
a:link {
|
||||||
|
color: orange;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:active {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: orange;
|
||||||
|
background-color: white;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
color: #666;
|
||||||
|
background-color: inherit;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 27 KiB |
|
@ -0,0 +1,72 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import types
|
||||||
|
from os.path import join
|
||||||
|
from inspect import getsource, getmembers, isclass, isfunction, ismethod, ismodule
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
root="./build/api"
|
||||||
|
|
||||||
|
htmltmpl = """
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{title}</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8">
|
||||||
|
<meta http-equiv="content-style-type" content="text/css">
|
||||||
|
<meta http-equiv="expires" content="0">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre>
|
||||||
|
{content}
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
def write_source(name, content):
|
||||||
|
fh = file(join(root, name)+'.html', 'w')
|
||||||
|
fh.write(format_html(name, content))
|
||||||
|
fh.close()
|
||||||
|
|
||||||
|
def format_html(title, content):
|
||||||
|
return htmltmpl.format(title=title, content=content)
|
||||||
|
|
||||||
|
def parse_module(module):
|
||||||
|
module = import_module(module)
|
||||||
|
write_source(module.__name__, getsource(module))
|
||||||
|
# classes = [(cls, value) for cls, value in getattr(module, '__dict__').items() if value == types.ClassType]
|
||||||
|
classes = getmembers(module, isclass)
|
||||||
|
for name, obj in classes:
|
||||||
|
write_source(module.__name__ + '.' + name, getsource(obj))
|
||||||
|
# methods = [(meth, value) for meth, value in getattr(obj, '__dict__').items() if type(value) == types.MethodType]
|
||||||
|
methods = getmembers(obj, ismethod)
|
||||||
|
for meth, value in methods:
|
||||||
|
write_source(module.__name__ + '.' + name + '.' + meth, getsource(value))
|
||||||
|
|
||||||
|
#functions = [(func, value) for func, value in getattr(module, '__dict__').items() if type(value) == types.FunctionType]
|
||||||
|
functions = getmembers(module, isfunction)
|
||||||
|
for name, obj in functions:
|
||||||
|
write_source(module.__name__ + '.' + name, getsource(obj))
|
||||||
|
|
||||||
|
def process_modules():
|
||||||
|
from glob import glob
|
||||||
|
from os.path import abspath, dirname, normpath, splitext, basename
|
||||||
|
here = abspath(__file__)
|
||||||
|
directory = dirname(here)
|
||||||
|
pyfiles = glob(normpath(join(directory, '..', '*.py')))
|
||||||
|
for pyf in pyfiles:
|
||||||
|
pyf = splitext(basename(pyf))[0]
|
||||||
|
modname = 'tiramisu.' + pyf
|
||||||
|
if not '__init__' in modname:
|
||||||
|
parse_module(modname)
|
||||||
|
|
||||||
|
pyfiles = glob(normpath(join(directory, '..', 'test', '*.py')))
|
||||||
|
for pyf in pyfiles:
|
||||||
|
pyf = splitext(basename(pyf))[0]
|
||||||
|
modname = 'tiramisu.test.' + pyf
|
||||||
|
if not '__init__' in modname:
|
||||||
|
parse_module(modname)
|
||||||
|
|
||||||
|
process_modules()
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
=======================
|
||||||
|
Configuration Handling
|
||||||
|
=======================
|
||||||
|
|
||||||
|
:module: :api:`config.py`
|
||||||
|
:tests: - :api:`test_config.py`
|
||||||
|
- :api:`test_option_setting.py`
|
||||||
|
|
||||||
|
Main Assumption
|
||||||
|
===============
|
||||||
|
|
||||||
|
Configuration option objects :api:`config.Config()` are produced at the
|
||||||
|
entry points and handed down to where they are actually used. This keeps
|
||||||
|
configuration local but available everywhere and consistent.
|
||||||
|
|
||||||
|
`Config` and `Option` objects
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Configuration option objects can be created in different ways. Let's perform
|
||||||
|
very basic `Config` object manipulations:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> from tiramisu.config import Config
|
||||||
|
>>> from tiramisu.option import OptionDescription, BoolOption
|
||||||
|
>>> descr = OptionDescription("optgroup", "", [
|
||||||
|
... BoolOption("bool", "", default=False)])
|
||||||
|
>>>
|
||||||
|
>>> config = Config(descr)
|
||||||
|
>>> config.bool
|
||||||
|
False
|
||||||
|
>>> config.bool = True
|
||||||
|
>>> config.bool
|
||||||
|
True
|
||||||
|
|
||||||
|
Take a look at :api:`test_config.test_base_config()` or
|
||||||
|
:api:`test_config.test_base_config_and_groups()`.
|
||||||
|
|
||||||
|
|
||||||
|
Accessing the configuration `Option`'s
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
The `Config` object attribute access notation stands for the value of the
|
||||||
|
configuration's `Option`. That is, the `Config`'s object attribute is the name
|
||||||
|
of the `Option`, and the value is the value accessed by the `__getattr__`
|
||||||
|
attribute access mechanism.
|
||||||
|
|
||||||
|
If the attribute of the `Config` called by `__getattr__` has not been set before
|
||||||
|
(by the classic `__setattr__` mechanism), the default value of the `Option`
|
||||||
|
object is returned, and if no `Option` has been declared in the
|
||||||
|
`OptionDescription` (that is the schema of the configuration), an
|
||||||
|
`AttributeError` is raised.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
>>> gcdummy._name
|
||||||
|
'dummy'
|
||||||
|
>>> gcdummy.getdefault()
|
||||||
|
False
|
||||||
|
>>> descr = OptionDescription('tiramisu', '', [gcdummy])
|
||||||
|
>>> cfg = Config(descr)
|
||||||
|
>>> cfg.dummy
|
||||||
|
False
|
||||||
|
>>> cfg.dummy = True
|
||||||
|
>>> cfg.dummy
|
||||||
|
True
|
||||||
|
>>> cfg.idontexist
|
||||||
|
AttributeError: 'OptionDescription' object has no attribute 'idontexist'
|
||||||
|
|
||||||
|
The configuration `Option` objects (in this case the `BoolOption`), are
|
||||||
|
organized into a tree into nested `OptionDescription` objects. Every
|
||||||
|
option has a name, as does every option group. The parts of the full
|
||||||
|
name of the option are separated by dots: e.g.
|
||||||
|
``config.optgroup.optname``.
|
||||||
|
|
||||||
|
**Can you repeat it, what is the protocol of accessing a config's attribute ?**
|
||||||
|
|
||||||
|
1. If the option has not been declared, an `AttributeError` is raised,
|
||||||
|
|
||||||
|
2. If an option is declared, but neither a value nor a default value has
|
||||||
|
been set, the returned value is `None`,
|
||||||
|
|
||||||
|
3. If an option is declared and a default value has been set, but no value
|
||||||
|
has been set, the returned value is the default value of the option,
|
||||||
|
|
||||||
|
4. If an option is declared, and a value has been set, the returned value is
|
||||||
|
the value of the option.
|
||||||
|
|
||||||
|
If you do not want to use the pythonic way, that is the attribute access
|
||||||
|
way to obtain the value of the configuration option, you can also search
|
||||||
|
for it recursively in the whole config namespaces with the ``get()``
|
||||||
|
method :
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> config.get('bool')
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
|
To find the right option, `get()` searches recursively into the whole
|
||||||
|
tree. For example, to find an option which is in the `gc` namespace
|
||||||
|
there are two possibilites.
|
||||||
|
|
||||||
|
If you know the path:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> config.gc.dummy
|
||||||
|
False
|
||||||
|
|
||||||
|
If you don't remember the path:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> config.get('dummy')
|
||||||
|
False
|
||||||
|
|
||||||
|
Setting the values of the options
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
An important part of the setting of the configuration consists of setting the
|
||||||
|
values of the configuration options. There are different ways of setting values,
|
||||||
|
the first one is of course the `__setattr__` method
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cfg.name = value
|
||||||
|
|
||||||
|
wich has the same effect that the "global" `set()` method : it expects that
|
||||||
|
the value owner is the default :ref:`glossary#valueowner`
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cfg.set(name=value)
|
||||||
|
|
||||||
|
The global `setoption()` method of the config objects can set a value with a specific owner
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cfg.setoption('name', value, 'owner')
|
||||||
|
|
||||||
|
|
||||||
|
Finally, the local `setoption()` method directly in the `Option` object can be
|
||||||
|
used. While the `Option` object refers to his parent, the config knows that the
|
||||||
|
value has been changed and no bad side effect won't occur
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
>>> descr = OptionDescription('descr', '', [booloption])
|
||||||
|
>>> cfg = Config(descr)
|
||||||
|
>>> booloption.setoption(cfg, False, 'owner')
|
||||||
|
>>> cfg.bool
|
||||||
|
>>> False
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
Config API Details
|
||||||
|
==================
|
||||||
|
|
||||||
|
:module: :api:`config.py`
|
||||||
|
:test cases: - :api:`test_config_api.py`
|
||||||
|
- :api:`test_config_big_example.py`
|
||||||
|
|
||||||
|
|
||||||
|
The handling of options is split into two parts: the description of
|
||||||
|
which options are available, what their possible values and defaults are
|
||||||
|
and how they are organized into a tree. A specific choice of options is
|
||||||
|
bundled into a configuration object which has a reference to its option
|
||||||
|
description (and therefore makes sure that the configuration values
|
||||||
|
adhere to the option description).
|
||||||
|
|
||||||
|
The configuration object
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
:api:`config.Config()` object that lives in :api:`config.py` hold the
|
||||||
|
choosen values for the options (or the default value for the
|
||||||
|
:api:`option.Option()` object, if no choice was made).
|
||||||
|
|
||||||
|
A `Config` object is informed by an :api:`option.OptionDescription`
|
||||||
|
instance. The attributes of the ``Config`` objects are the names of the
|
||||||
|
children of the ``OptionDescription``.
|
||||||
|
|
||||||
|
Here are the (useful) methods on ``Config``:
|
||||||
|
|
||||||
|
:api:`config.Config.__init__(self, descr, **overrides)`:
|
||||||
|
``descr`` is an instance of :api:`option.OptionDescription` that
|
||||||
|
describes the configuration object. ``override`` can be used to
|
||||||
|
set different default values (see method ``override``).
|
||||||
|
|
||||||
|
:api:`config.Config.override(self, overrides)`:
|
||||||
|
override default values. This marks the overridden values as defaults.
|
||||||
|
``overrides`` is a dictionary of path strings to values.
|
||||||
|
|
||||||
|
:api:`config.Config.set(self, **kwargs)`:
|
||||||
|
"do what I mean"-interface to option setting. Searches all paths
|
||||||
|
starting from that config for matches of the optional arguments
|
||||||
|
and sets the found option if the match is not ambiguous.
|
||||||
|
|
||||||
|
:api:`config.Config.get(self, name)`:
|
||||||
|
the behavior is much like the attribute access way, except that
|
||||||
|
the search for the option is performed recursively in the whole
|
||||||
|
configuration tree.
|
||||||
|
|
||||||
|
:api:`config.Config.cfgimpl_read_write()`:
|
||||||
|
configuration level `read_write` status, see :doc:`status`
|
||||||
|
|
||||||
|
:api:`config.Config.cfgimpl_read_only()`:
|
||||||
|
configuration level `read_only` status, see :doc:`status`
|
||||||
|
|
||||||
|
Here are some private attributes of a `Config()` object, for a
|
||||||
|
comprehension of the internal merchanism:
|
||||||
|
|
||||||
|
- `_cfgimpl_descr =` :api:`option.OptionDescription()`,
|
||||||
|
e.g. the :ref:`optionapi#schema`
|
||||||
|
|
||||||
|
- `_cfgimpl_values` contains the :api:`option.Option()`'s values.
|
||||||
|
Yes, the values of the options: remember that the values are stored **inside**
|
||||||
|
the :api:`config.Config()` and not in the `Option()`
|
||||||
|
|
||||||
|
`_cfgimpl_values` contains something like that
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{'int': 0, 'wantframework': False, 'objspace': 'std', 'bool': False,
|
||||||
|
'str': 'abc', 'gc': <config.Config object at 0xa33f8ec>, 'wantref': False}
|
||||||
|
|
||||||
|
We can see that values can also be config objects, it's the
|
||||||
|
sub-namespaces that are stored in the values as `Config()` objects.
|
||||||
|
|
||||||
|
convenience utilities (iteration, exports...)
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
With this :api:`config.Config()` configuration management entry point,
|
||||||
|
it is possible to
|
||||||
|
|
||||||
|
- `iter` on config, notice that there is an iteration order wich is
|
||||||
|
the order of the :ref:`optionapi#schema` specification entries,
|
||||||
|
- compare two configs (equality),
|
||||||
|
- export the whole config into a `dict` with :api:`config.make_dict()`,
|
||||||
|
- `validate()` an option value into a config, see :doc:`consistency`.
|
||||||
|
|
||||||
|
:api:`option.Option()` objects in a config are iterable in the pythonic
|
||||||
|
way, that is something like `[(name, value) for name, value in config]`.
|
||||||
|
|
||||||
|
To iter on groups in the same manner, use the
|
||||||
|
:api:`config.Config.iter_groups()` method wich yields generators too.
|
||||||
|
|
||||||
|
**iteration utilities**
|
||||||
|
|
||||||
|
:api:`config.Config.__iter__()`
|
||||||
|
Pythonesque way of parsing group's ordered options.
|
||||||
|
|
||||||
|
:api:`config.Config.iter_groups(group_type=None)`:
|
||||||
|
To iter on groups objects only.
|
||||||
|
All groups are returned if `group_type` is `None`, otherwise the groups
|
||||||
|
can be filtered by categories (families, or whatever).
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
The global configuration's consistency
|
||||||
|
========================================
|
||||||
|
|
||||||
|
:module: :api:`config.py`
|
||||||
|
:tests: :api:`test_option_consistency.py`
|
||||||
|
|
||||||
|
Option's values type validation
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
When a value is set to the option, the value is validated by the
|
||||||
|
option's :api:`option.Option()` validator's type.
|
||||||
|
|
||||||
|
Notice that if the option is `multi`, that is the `multi` attribute is set to
|
||||||
|
`True`, then the validation of the option value accepts a list of values
|
||||||
|
of the same type.
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Configuration options can specify requirements as parameters at the init
|
||||||
|
time, the specification of some links between options or groups allows
|
||||||
|
to carry out a dependencies calculation. For example, an option can ben
|
||||||
|
hidden if another option has been set with some expected value. This is
|
||||||
|
just an example, because the possibilities are hudge.
|
||||||
|
|
||||||
|
A requirement is specified using a list of triplets. The first element
|
||||||
|
of the triplet gives the path of the option that is required, the second
|
||||||
|
element is the value wich is expected to trigger the callback, and the
|
||||||
|
third one is the callback's action name (`hide`, `show`...)::
|
||||||
|
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide')])
|
||||||
|
|
||||||
|
Take a look at an example here
|
||||||
|
:api:`test_option_consistency.test_hidden_if_in()`
|
||||||
|
|
||||||
|
Config updates
|
||||||
|
---------------
|
||||||
|
|
||||||
|
New configuration options and groups can be dynamically added.
|
||||||
|
|
||||||
|
The configuration has to be *updated* after that the description has been
|
||||||
|
passed to the Config objet, see:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> config = Config(descr)
|
||||||
|
>>> newoption = BoolOption('newoption', 'dummy twoo', default=False)
|
||||||
|
>>> descr.add_child(newoption)
|
||||||
|
>>> config.update()
|
||||||
|
>>> config.newoption
|
||||||
|
False
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
- :api:`test_option_consistency.test_newoption_add_in_descr()`
|
||||||
|
- :api:`test_option_consistency.test_newoption_add_in_subdescr()`
|
||||||
|
- :api:`test_option_consistency.test_newoption_add_in_config()`
|
||||||
|
|
||||||
|
|
||||||
|
Validation upon a whole configuration object
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
An option's integrity can be validated towards a whole configuration.
|
||||||
|
|
||||||
|
This type of validation is very open. Let's take a use case : an option
|
||||||
|
has a certain value, and the value of this option can change the owner
|
||||||
|
of another option or option group... Everything is possible.
|
||||||
|
|
||||||
|
FIXME : put an example here
|
||||||
|
|
||||||
|
Identical option names
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
If an :api:`option.Option()` happens to be defined twice in the
|
||||||
|
:ref:`glossary#schema` (e.g. the :api:`option.OptionDescription()`),
|
||||||
|
:that is the two options actually have the same name, an exception is raised.
|
||||||
|
|
||||||
|
The calculation is currently carried out in the samespace, for example
|
||||||
|
if `config.gc.name` is defined, another option in `gc` with the name
|
||||||
|
`name` is **not** allowed, whereas `config.whateverelse.name` is still
|
||||||
|
allowed.
|
||||||
|
|
||||||
|
.. the calculation was carried out by the requires, wich is not a goog idead
|
||||||
|
|
||||||
|
Type constraints with the `multi` type
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
By convention, if a multi option has somme requires, the constraints on
|
||||||
|
the multi type is in all the OptionGroup (a group has to be `multi`, and
|
||||||
|
a multi of the same length).
|
||||||
|
|
||||||
|
See :api:`test_option_consistency.test_multi_constraints()`
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
.. include:: inc/preambule.txt
|
||||||
|
|
||||||
|
Accès aux variables
|
||||||
|
====================
|
||||||
|
|
||||||
|
Protocole d'accès aux valeurs
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
**Créole**
|
||||||
|
|
||||||
|
- Si la variable n'a pas été déclarée, une erreur est levée
|
||||||
|
- Si la variable a été déclarée, mais qu'aucune valeur n'a été définie, (ni valeur affectée, ni valeur par défaut) la valeur retournée est `[]` ou `""` ou `[""]` ou `["",""]`,
|
||||||
|
- Si la variable a été déclarée et qu'une valeur par défaut a été définie, la valeur retournée et la valeur par défaut,
|
||||||
|
- Si la variable a été déclarée et qu'une valeur a été définie, la valeur retournée est la valeur de la variable.
|
||||||
|
|
||||||
|
**tiramisu**
|
||||||
|
|
||||||
|
- Si la variable n'a pas été déclarée, une erreur est levée
|
||||||
|
- Si la variable a été déclarée, mais qu'aucune valeur n'a été définie, (ni valeur affectée, ni valeur par défaut) la valeur retournée est `None`,
|
||||||
|
- Si la variable a été déclarée et qu'une valeur par défaut a été définie, la valeur retournée et la valeur par défaut,
|
||||||
|
- Si la variable a été déclarée et qu'une valeur a été définie, la valeur retournée est la valeur de la variable.
|
||||||
|
|
||||||
|
la différence tient au fait de la valeur nulle (`None`) qui a été mal définie
|
||||||
|
dès le début dans `Créole`.
|
||||||
|
|
||||||
|
Accès Créole par "dictionnaire"
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
La définition est dans le `XML`
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
<family name="general">
|
||||||
|
|
||||||
|
<variable name="adresse_ip_eth0">
|
||||||
|
|
||||||
|
Le dictionnaire est chargé dans un `EoleDict()`
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from creole.cfgparser import EoleDict
|
||||||
|
eoldict = EoleDict(...)
|
||||||
|
|
||||||
|
Un export dans un dictionnaire est necessaire pour manipuler les données
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from creole.parsedico import parse_dico
|
||||||
|
|
||||||
|
flatdict = parse_dico(eoldict)
|
||||||
|
|
||||||
|
assert dico['ip'] == '10.10.1.11'
|
||||||
|
|
||||||
|
|
||||||
|
le resultat de l'accès aux données vient de `typeole.EoleVar('ip').get_value()`
|
||||||
|
|
||||||
|
|
||||||
|
Accès `tiramisu` par espace de nommage
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
- espaces de nommages ;
|
||||||
|
- c'est la configuration qui est responsable de l'accès aux valeurs ;
|
||||||
|
- une configuration par accès direct (pas d'export) ;
|
||||||
|
- un point d'entrée unique aisément manipulable grâce aux espaces de nommage.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from tiramisu.config import Config
|
||||||
|
from tiramisu.option import OptionDescription
|
||||||
|
subdescr = OptionDescription("creole", [IPOption('ip')])
|
||||||
|
descr = OptionDescription("creole", [subdescr])
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.creole.general.ip == '10.10.1.11'
|
||||||
|
|
||||||
|
Les valeurs sont dépendantes **de la configuration** et donc la responsabilité
|
||||||
|
des valeurs dépend de la configuration et pas de la variable elle-même.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
.. include:: inc/preambule.txt
|
||||||
|
|
||||||
|
Cohérence des valeurs des variables
|
||||||
|
====================================
|
||||||
|
|
||||||
|
type des variables
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
**Créole**
|
||||||
|
|
||||||
|
pas d'unicité du type abstrait : `Multivar`, `CreoleVar` et `TypedVar`
|
||||||
|
|
||||||
|
- `String`
|
||||||
|
- `Ip`
|
||||||
|
- `Netmask`
|
||||||
|
- `Number`
|
||||||
|
- `Boolean`
|
||||||
|
- `OuiNon`
|
||||||
|
|
||||||
|
**tiramisu**
|
||||||
|
|
||||||
|
unicité du type abstrait : `Option()`
|
||||||
|
|
||||||
|
pas de nouveau type multivalué, mais un attribut des types existants::
|
||||||
|
|
||||||
|
>>> from option import BoolOption
|
||||||
|
>>> boolopt = BoolOption('bool', 'description de bool', multi=True)
|
||||||
|
|
||||||
|
tous les types Créole, plus
|
||||||
|
|
||||||
|
- `SymlinkOption`
|
||||||
|
- `CheckOption` qui permet de définir les "oui/non", "On/Off"
|
||||||
|
|
||||||
|
Validations suivant l'organisation en familles
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
**Créole**
|
||||||
|
|
||||||
|
**Organisation par accumulation de références sur des dictionnaires (`EoleDict`)**
|
||||||
|
|
||||||
|
On peut charger un EoleDict avec des variables qui pointent vers des families
|
||||||
|
qui n'existent pas, aucune validation n'est faite (confiance absolument faite au
|
||||||
|
moment du chargemzent du XML)
|
||||||
|
|
||||||
|
exemple, dans l'espace de nommage racine::
|
||||||
|
|
||||||
|
<variables>
|
||||||
|
<variable name="adresse_ip_eth0">
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from creole.parsedico import parse_dico
|
||||||
|
flatdict = parse_dico(eoldict)
|
||||||
|
dico['adresse_ip_eth0']
|
||||||
|
KeyError: 'adresse_ip_eth0'
|
||||||
|
|
||||||
|
**Tiramisu**
|
||||||
|
|
||||||
|
**Organisation par arborescence.**
|
||||||
|
|
||||||
|
Un espace de nommage doit systématiquement être défini, la variable n'est
|
||||||
|
accessible **que** par un path.
|
||||||
|
|
||||||
|
|
||||||
|
Variables présentes deux fois
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
- Créole : pas de validation possible
|
||||||
|
- tiramisu : comportement règlable (on autorise l'unicité ou pas)
|
||||||
|
|
||||||
|
- dans Créole les valeurs sont **fausses** (c'est la dernière variable qui qui gagne)
|
||||||
|
|
||||||
|
Il faut faire confiance au XML
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
<family name="general">
|
||||||
|
<variable name="adresse_ip_eth0">
|
||||||
|
<valeur>toto
|
||||||
|
|
||||||
|
|
||||||
|
<family name="services">
|
||||||
|
<variable name="adresse_ip_eth0">
|
||||||
|
<valeur>tutu
|
||||||
|
|
||||||
|
|
||||||
|
dans `gen_config` la valeur retenue est::
|
||||||
|
|
||||||
|
general/adresse_ip_eth0 -> tutu
|
||||||
|
services/adresse_ip_eth0 -> tutu
|
||||||
|
|
||||||
|
dans `parsedico`, la variable est écrasée::
|
||||||
|
|
||||||
|
>>> from creole.parsedico import parse_dico
|
||||||
|
>>> d = parse_dico()
|
||||||
|
>>> d['adresse_ip_eth0']
|
||||||
|
tutu
|
||||||
|
|
||||||
|
dans tiramisu::
|
||||||
|
|
||||||
|
>>> config.general.adresse_ip_eth0
|
||||||
|
toto
|
||||||
|
>>> config.services.adresse_ip_eth0
|
||||||
|
tutu
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
.. include:: inc/preambule.txt
|
||||||
|
|
||||||
|
Etats et statuts des options de configuration
|
||||||
|
================================================
|
||||||
|
|
||||||
|
état des variables et lisibilité de l'API
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
**Creole**
|
||||||
|
|
||||||
|
`EoleVar()`
|
||||||
|
|
||||||
|
- `get_value()`
|
||||||
|
- `get_final_value()`
|
||||||
|
- `get_final_value_at_index()`
|
||||||
|
- `check_value()`
|
||||||
|
- `get_prec_value()`
|
||||||
|
- `get_calculated_value()` -> automatique
|
||||||
|
|
||||||
|
**tiramisu**
|
||||||
|
|
||||||
|
`Option()`
|
||||||
|
|
||||||
|
- **aucune API** d'accès à la valeur d'une option au niveau de l'option de configuration
|
||||||
|
- `option.getdefault()`
|
||||||
|
- `option.setoption(config, value, owner)`
|
||||||
|
|
||||||
|
variables "automatiques"
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
si `owner` == 'auto', la variable est automatique et la configuration le sait,
|
||||||
|
elle lance alors les fonctions de calcul à chaque évaluation
|
||||||
|
|
||||||
|
dans Créole, c'est validé aux niveau de la variable par un appel à `eval_func()`
|
||||||
|
|
||||||
|
Accès suivant les états de la configuration
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
- disabled
|
||||||
|
- hidden
|
||||||
|
- mode (normal/expert)
|
||||||
|
- obligatoire (mandatory)
|
||||||
|
- ...
|
||||||
|
|
||||||
|
- `EoleVar.hidden`
|
||||||
|
- `EoleVar.disabled`
|
||||||
|
|
||||||
|
pas d'objet `Family` dans Créole donc l'organisation des hiérarchie de
|
||||||
|
hidden est opaque
|
||||||
|
|
||||||
|
- `EoleDict.families['hidden']` pour avoir accès à l'état d'une famille
|
||||||
|
|
||||||
|
dans Tiramisu
|
||||||
|
|
||||||
|
- `hidden` au niveau `Option`, `OptionDescription` et **aussi** au niveau de
|
||||||
|
la configuration ce qui permet d'avoir des états (inexistant dans `Créole`)
|
||||||
|
|
||||||
|
.. maitres/esclaves avec Créole : `mavar.get_slaves()`
|
||||||
|
|
||||||
|
|
||||||
|
`hidden_if_in`, `hidden_if_not_in`
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
La notion est généralisée dans tiramisu avec les `requires`.
|
||||||
|
|
||||||
|
Dans Créole : très difficile de conserver une cohérence des `hidden_if_in`
|
||||||
|
quand il y en a plusieurs.
|
||||||
|
|
||||||
|
Dans Tiramisu : validation et levée d'exception si les **requirements** sont
|
||||||
|
incohérents, action inverse si aucun requires n'est matché.
|
||||||
|
|
||||||
|
exemple de requires
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
<family name="clamav">
|
||||||
|
<variable name="activer_clam">
|
||||||
|
|
||||||
|
<variable name="activer_clam_exim">
|
||||||
|
<valeur>non
|
||||||
|
|
||||||
|
<variable name="activer_clam_samba">
|
||||||
|
<valeur>oui
|
||||||
|
|
||||||
|
<condition name='hidden_if_in' source='activer_clam_exim'>
|
||||||
|
<param>non
|
||||||
|
<target type='variable'>activer_clam
|
||||||
|
<!-- ça hide (momentanément)-->
|
||||||
|
|
||||||
|
<condition name='hidden_if_in' source='activer_clam_samba'>
|
||||||
|
<param>non
|
||||||
|
<target type='variable'>activer_clam
|
||||||
|
<!-- ça show (et c'est le dernier qui a raison) -->
|
||||||
|
|
||||||
|
:résultat: `activer_clam` est visible, c'est la dernière condition qui a raison
|
||||||
|
|
||||||
|
avec tiramisu, `activer_clam` **dans les même conditions**, est cachée.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
>>> activer_clam = StrOption('activer_clam', 'activer clamav',
|
||||||
|
requires=[('activer_clam_exim', 'non', 'hide'),
|
||||||
|
('activer_clam_samba', 'non', 'hide'),])
|
||||||
|
>>> config.clamav.activer_clam_exim = 'non'
|
||||||
|
>>> config.clamav.activer_clam_samba = 'oui'
|
||||||
|
>>> config.clamav.activer_clam
|
||||||
|
>>> Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
HiddenOptionError("trying to access to a hidden option:activer_clam")
|
||||||
|
>>>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
%.odt: %.txt
|
||||||
|
rst2odt --create-links --custom-odt-footer="Page %p% de %P%" --endnotes-end-doc --no-generator --stylesheet=styles.odt $< $@
|
||||||
|
|
||||||
|
%.html: %.txt
|
||||||
|
rst2html --stylesheet ./build/style.css $< > ./build/$@
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
.PHONY: clean
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.html
|
||||||
|
rm -f api/*.html
|
|
@ -0,0 +1,1080 @@
|
||||||
|
body,body.editor,body.body {
|
||||||
|
font: 110% "Times New Roman", Arial, Verdana, Helvetica, serif;
|
||||||
|
background: White;
|
||||||
|
color: Black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, a.reference {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a[href]:hover { text-decoration: underline; }
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, div.text {
|
||||||
|
text-align: left;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin: 0.5em 0em 0em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
p a:active {
|
||||||
|
color: Red;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
p img {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.inlinephoto {
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 1em;
|
||||||
|
padding-top: 0.7em;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
clear: both;
|
||||||
|
height: 1px;
|
||||||
|
color: #8CACBB;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ul {
|
||||||
|
line-height: 1.5em;
|
||||||
|
/*list-style-image: url("bullet.gif"); */
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul a, ol a {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
font-family: Times, "Times New Roman", serif;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
color: Black;
|
||||||
|
/*background-color: #dee7ec;*/
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
background-color: #cccccc;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.netscape4 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main page styles */
|
||||||
|
|
||||||
|
/*a[href]:hover { color: black; text-decoration: underline; }
|
||||||
|
a[href]:link { color: black; text-decoration: underline; }
|
||||||
|
a[href] { color: black; text-decoration: underline; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
span.menu_selected {
|
||||||
|
color: black;
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.menu {
|
||||||
|
/*color: #3ba6ec; */
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-right: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.menu[href]:visited, a.menu[href]:link{
|
||||||
|
/*color: #3ba6ec; */
|
||||||
|
font: 140% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.menu[href]:hover {
|
||||||
|
/*color: black;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
div.project_title{
|
||||||
|
/*border-spacing: 20px;*/
|
||||||
|
font: 160% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
color: #3ba6ec;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikicurrent {
|
||||||
|
font: 100% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
color: #3ba6ec;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table.body {
|
||||||
|
border: 0;
|
||||||
|
/*padding: 0;
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.page-header-left {
|
||||||
|
padding: 5px;
|
||||||
|
/*border-bottom: 1px solid #444444;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.page-header-top {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
/*border-bottom: 1px solid #444444;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar {
|
||||||
|
padding: 1 0 0 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar p.classblock {
|
||||||
|
padding: 0 5 0 5;
|
||||||
|
margin: 1 1 1 1;
|
||||||
|
border: 1px solid #444444;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.sidebar p.userblock {
|
||||||
|
padding: 0 5 0 5;
|
||||||
|
margin: 1 1 1 1;
|
||||||
|
border: 1px solid #444444;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.content {
|
||||||
|
padding: 1 5 1 5;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.ok-message {
|
||||||
|
background-color: #22bb22;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
p.error-message {
|
||||||
|
background-color: #bb2222;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin: 0 ;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for forms */
|
||||||
|
table.form {
|
||||||
|
padding: 2;
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form th {
|
||||||
|
color: #333388;
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: top;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
table.form th.header {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form th.required {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td {
|
||||||
|
color: #333333;
|
||||||
|
empty-cells: show;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td.optional {
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.form td.html {
|
||||||
|
color: #777777;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for lists */
|
||||||
|
table.list {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
vertical-align: top;
|
||||||
|
padding-top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list th {
|
||||||
|
padding: 0 4 0 4;
|
||||||
|
color: #404070;
|
||||||
|
background-color: #eeeeff;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
border-top: 1px solid #404070;
|
||||||
|
border-bottom: 1px solid #404070;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
table.list th a[href]:hover { color: #404070 }
|
||||||
|
table.list th a[href]:link { color: #404070 }
|
||||||
|
table.list th a[href] { color: #404070 }
|
||||||
|
table.list th.group {
|
||||||
|
background-color: #f4f4ff;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list td {
|
||||||
|
padding: 0 4 0 4;
|
||||||
|
border: 0 2 0 2;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
color: #404070;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.normal td {
|
||||||
|
background-color: white;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.alt td {
|
||||||
|
background-color: #efefef;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list td:first-child {
|
||||||
|
border-left: 1px solid #404070;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list th:first-child {
|
||||||
|
border-left: 1px solid #404070;
|
||||||
|
border-right: 1px solid #404070;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.list tr.navigation th {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
table.list tr.navigation th:first-child {
|
||||||
|
border-right: none;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for message displays */
|
||||||
|
table.messages {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages th {
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages td {
|
||||||
|
font-family: monospace;
|
||||||
|
background-color: #efefef;
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
color: black;
|
||||||
|
empty-cells: show;
|
||||||
|
border-right: 1px solid #afafaf;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 2 5 2 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.messages td:first-child {
|
||||||
|
border-left: 1px solid #afafaf;
|
||||||
|
border-right: 1px solid #afafaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for file displays */
|
||||||
|
table.files {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.files td {
|
||||||
|
font-family: monospace;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* style for history displays */
|
||||||
|
table.history {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history td {
|
||||||
|
font-size: 90%;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for class list */
|
||||||
|
table.classlist {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classlist th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classlist th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for class help display */
|
||||||
|
table.classhelp {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classhelp th {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classhelp td {
|
||||||
|
padding: 2 2 2 2;
|
||||||
|
border: 1px solid black;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
empty-cells: show;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* style for "other" displays */
|
||||||
|
table.otherinfo {
|
||||||
|
border-spacing: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.otherinfo th.header{
|
||||||
|
padding-top: 10px;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
color: #707040;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.otherinfo th {
|
||||||
|
border-bottom: 1px solid #afafaf;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 1px; /* IE bug fix */
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: white;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 1px; /* IE bug fix */
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.nonexistent {
|
||||||
|
color: #FF2222;
|
||||||
|
}
|
||||||
|
a.nonexistent:visited {
|
||||||
|
color: #FF2222;
|
||||||
|
}
|
||||||
|
a.external {
|
||||||
|
color: #AA6600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
dl,ul,ol {
|
||||||
|
margin-top: 1pt;
|
||||||
|
}
|
||||||
|
tt,pre {
|
||||||
|
font-family: Lucida Console,Courier New,Courier,monotype;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
pre.code {
|
||||||
|
margin-top: 8pt;
|
||||||
|
margin-bottom: 8pt;
|
||||||
|
background-color: #FFFFEE;
|
||||||
|
white-space:pre;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1pt;
|
||||||
|
border-color:#999999;
|
||||||
|
color:#111111;
|
||||||
|
padding:5px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
div.diffold {
|
||||||
|
background-color: #FFFF80;
|
||||||
|
border-style:none;
|
||||||
|
border-width:thin;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
div.diffnew {
|
||||||
|
background-color: #80FF80;
|
||||||
|
border-style:none;
|
||||||
|
border-width:thin;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
div.message {
|
||||||
|
margin-top: 6pt;
|
||||||
|
background-color: #E8FFE8;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:1pt;
|
||||||
|
border-color:#999999;
|
||||||
|
color:#440000;
|
||||||
|
padding:5px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
strong.highlight {
|
||||||
|
background-color: #FFBBBB;
|
||||||
|
/* as usual, NetScape fucks up with innocent CSS
|
||||||
|
border-color: #FFAAAA;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1pt;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
table.navibar {
|
||||||
|
background-color: #C8C8C8;
|
||||||
|
border-spacing: 3px;
|
||||||
|
}
|
||||||
|
td.navibar {
|
||||||
|
background-color: #E8E8E8;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.pagename {
|
||||||
|
font-size: 140%;
|
||||||
|
color: blue;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: white;
|
||||||
|
padding: 0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikiaction, input.wikiaction {
|
||||||
|
color: black;
|
||||||
|
text-decoration: None;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
/*border: 1px solid #3ba6ec; */
|
||||||
|
margin: 4px;
|
||||||
|
padding: 5;
|
||||||
|
padding-bottom: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.wikiaction[href]:hover {
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
/*background-color: #dddddd; */
|
||||||
|
}
|
||||||
|
|
||||||
|
span.wikiuserpref {
|
||||||
|
padding-top: 1em;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikitrail {
|
||||||
|
vertical-align: bottom;
|
||||||
|
/*font-size: -1;*/
|
||||||
|
padding-top: 1em;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiaction {
|
||||||
|
vertical-align: middle;
|
||||||
|
/*border-bottom: 1px solid #8cacbb;*/
|
||||||
|
padding-bottom:1em;
|
||||||
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikieditmenu {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.wikiedit {
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
background-color: #fabf00;
|
||||||
|
padding: 1em;
|
||||||
|
padding-right: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.legenditem {
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-left: 0.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.wikitoken {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div#contentspace h1:first-child, div.heading:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
div#contentspace h2:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* heading and paragraph text */
|
||||||
|
|
||||||
|
div.heading, h1 {
|
||||||
|
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
background-color: #58b3ef;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
/*color: #4893cf;*/
|
||||||
|
color: black;
|
||||||
|
padding-top: 1.0em;
|
||||||
|
padding-bottom:0.2em;
|
||||||
|
text-align: left;
|
||||||
|
margin-top: 0em;
|
||||||
|
/*margin-bottom:8pt;*/
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 115%;
|
||||||
|
border-bottom: 1px solid #8CACBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
color: orange;
|
||||||
|
clear: left;
|
||||||
|
font: 100% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0em;
|
||||||
|
padding-top: 1em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
/*border-bottom: 1px solid #8CACBB;*/
|
||||||
|
}
|
||||||
|
/* h1,h2 { padding-top: 0; }*/
|
||||||
|
|
||||||
|
|
||||||
|
h1 { font-size: 145%; }
|
||||||
|
h2 { font-size: 135%; }
|
||||||
|
h3 { font-size: 125%; }
|
||||||
|
h4 { font-size: 120%; }
|
||||||
|
h5 { font-size: 110%; }
|
||||||
|
h6 { font-size: 80%; }
|
||||||
|
|
||||||
|
h1 a { text-decoration: None;}
|
||||||
|
|
||||||
|
div.exception {
|
||||||
|
background-color: #bb2222;
|
||||||
|
padding: 5 5 5 5;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
pre.exception {
|
||||||
|
font-size: 110%;
|
||||||
|
padding: 1em;
|
||||||
|
border: 1px solid #8cacbb;
|
||||||
|
color: Black;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
background-color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defines for navgiation bar (documentation) */
|
||||||
|
|
||||||
|
|
||||||
|
div.direntry {
|
||||||
|
padding-top: 0.3em;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
margin-right: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #dee7ec;
|
||||||
|
font-size: 110%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.fileentry {
|
||||||
|
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.fileentry {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
span.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
span.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.navbar {
|
||||||
|
/*margin: 0;*/
|
||||||
|
font-size: 80% /*smaller*/;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
/* position: fixed; */
|
||||||
|
top: 100pt;
|
||||||
|
left: 0pt; /* auto; */
|
||||||
|
width: 120pt;
|
||||||
|
/* right: auto;
|
||||||
|
right: 0pt; 2em; */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.history a {
|
||||||
|
/* font-size: 70%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiactiontitle {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* REST defines */
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.toplist {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
img#pyimg {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#navspace {
|
||||||
|
position: absolute;
|
||||||
|
top: 130px;
|
||||||
|
left: 11px;
|
||||||
|
font-size: 100%;
|
||||||
|
width: 150px;
|
||||||
|
overflow: hidden; /* scroll; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div#metaspace {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#errorline {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#contentspace {
|
||||||
|
position: absolute;
|
||||||
|
/* font: 120% "Times New Roman", serif;*/
|
||||||
|
font: 110% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
top: 130px;
|
||||||
|
left: 170px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#menubar {
|
||||||
|
/* width: 400px; */
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the documentation page */
|
||||||
|
div#docinfoline {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
left: 0px;
|
||||||
|
|
||||||
|
/*background-color: #dee7ec; */
|
||||||
|
padding: 5pt;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
color: black;
|
||||||
|
/*border-width: 1pt;
|
||||||
|
border-style: solid;*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div#docnavlist {
|
||||||
|
/*background-color: #dee7ec; */
|
||||||
|
padding: 5pt;
|
||||||
|
padding-bottom: 2em;
|
||||||
|
color: black;
|
||||||
|
border-width: 1pt;
|
||||||
|
/*border-style: solid;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* text markup */
|
||||||
|
|
||||||
|
div.listtitle {
|
||||||
|
color: Black;
|
||||||
|
clear: left;
|
||||||
|
font: 120% Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 0em;
|
||||||
|
padding-top: 0em;
|
||||||
|
padding-bottom: 0.2em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
border-bottom: 1px solid #8CACBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox h3 {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-right: 0.5em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
background-color: #fabf00;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid black; /* 8cacbb; */
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox a {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox a.history {
|
||||||
|
display: block;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.actionbox {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
padding-bottom: 1em;
|
||||||
|
overflow: hidden; /* scroll; */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* taken from docutils (oh dear, a bit senseless) */
|
||||||
|
ol.simple, ul.simple {
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal }
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha }
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha }
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman }
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
:Author: David Goodger
|
||||||
|
:Contact: goodger@users.sourceforge.net
|
||||||
|
:date: $Date: 2003/01/22 22:26:48 $
|
||||||
|
:version: $Revision: 1.29 $
|
||||||
|
:copyright: This stylesheet has been placed in the public domain.
|
||||||
|
|
||||||
|
Default cascading style sheet for the HTML output of Docutils.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
.first {
|
||||||
|
margin-top: 0 }
|
||||||
|
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0 }
|
||||||
|
|
||||||
|
a.toc-backref {
|
||||||
|
text-decoration: none ;
|
||||||
|
color: black }
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.abstract {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
div.abstract p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
div.attention, div.caution, div.danger, div.error, div.hint,
|
||||||
|
div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.hint p.admonition-title, div.important p.admonition-title,
|
||||||
|
div.note p.admonition-title, div.tip p.admonition-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.dedication {
|
||||||
|
margin: 2em 5em ;
|
||||||
|
text-align: center ;
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
div.dedication p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-style: normal }
|
||||||
|
|
||||||
|
div.figure {
|
||||||
|
margin-left: 2em }
|
||||||
|
|
||||||
|
div.footer, div.header {
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
div.system-messages {
|
||||||
|
margin: 5em }
|
||||||
|
|
||||||
|
div.system-messages h1 {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
div.system-message {
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.system-message p.system-message-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
margin: 2em }
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
text-align: center ;
|
||||||
|
color: orange}
|
||||||
|
|
||||||
|
h2.subtitle {
|
||||||
|
color: orange;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 75% }
|
||||||
|
|
||||||
|
p.caption {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
p.credits {
|
||||||
|
font-style: italic ;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
p.label {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
pre.address {
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-top: 0 ;
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.line-block {
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.literal-block, pre.doctest-block {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em ;
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
span.classifier {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-style: oblique }
|
||||||
|
|
||||||
|
span.classifier-delimiter {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
span.interpreted {
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
span.option {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
span.option-argument {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
span.pre {
|
||||||
|
white-space: pre }
|
||||||
|
|
||||||
|
span.problematic {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
table {
|
||||||
|
margin-top: 0.5em ;
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid thin gray ;
|
||||||
|
padding-left: 0.5ex }
|
||||||
|
|
||||||
|
table.docinfo {
|
||||||
|
margin: 2em 4em }
|
||||||
|
|
||||||
|
table.footnote {
|
||||||
|
border-left: solid thin black ;
|
||||||
|
padding-left: 0.5ex }
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
padding-left: 0.5em ;
|
||||||
|
padding-right: 0.5em ;
|
||||||
|
vertical-align: top }
|
||||||
|
|
||||||
|
th.docinfo-name, th.field-name {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: left ;
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
tt {
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
ul.auto-toc {
|
||||||
|
list-style-type: none }
|
||||||
|
*/
|
||||||
|
|
||||||
|
div.section {
|
||||||
|
margin-top: 1.0em ;
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
.first {
|
||||||
|
margin-top: 0 ! important }
|
||||||
|
|
||||||
|
.last {
|
||||||
|
margin-bottom: 0 ! important }
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none }
|
||||||
|
|
||||||
|
a.toc-backref {
|
||||||
|
text-decoration: none ;
|
||||||
|
color: inherit }
|
||||||
|
|
||||||
|
blockquote.epigraph {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
dl.docutils dd {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
dl.docutils dt {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
dl dt { line-height: 150% }
|
||||||
|
|
||||||
|
div.abstract {
|
||||||
|
margin: 2em 5em }
|
||||||
|
|
||||||
|
div.abstract p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||||
|
div.hint, div.important, div.note, div.tip, div.warning {
|
||||||
|
margin: 2em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||||
|
div.important p.admonition-title, div.note p.admonition-title,
|
||||||
|
div.tip p.admonition-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||||
|
div.danger p.admonition-title, div.error p.admonition-title,
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
div.compound .compound-first, div.compound .compound-middle {
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
div.compound .compound-last, div.compound .compound-middle {
|
||||||
|
margin-top: 0.5em }
|
||||||
|
|
||||||
|
div.dedication {
|
||||||
|
margin: 2em 5em ;
|
||||||
|
text-align: center ;
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
div.dedication p.topic-title {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-style: normal }
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
width: 600px ;
|
||||||
|
margin-left: 5em ;
|
||||||
|
margin-right: 5em }
|
||||||
|
|
||||||
|
div.figure {
|
||||||
|
margin-left: 2em }
|
||||||
|
|
||||||
|
div.footer, div.header {
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
div.line-block {
|
||||||
|
display: block ;
|
||||||
|
margin-top: 1em ;
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
div.line-block div.line-block {
|
||||||
|
margin-top: 0 ;
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-left: 1.5em }
|
||||||
|
|
||||||
|
div.sidebar {
|
||||||
|
margin-left: 1em ;
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em ;
|
||||||
|
background-color: #ffffee ;
|
||||||
|
width: 40% ;
|
||||||
|
float: right ;
|
||||||
|
clear: right }
|
||||||
|
|
||||||
|
div.sidebar p.rubric {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-size: medium }
|
||||||
|
|
||||||
|
div.system-messages {
|
||||||
|
margin: 5em }
|
||||||
|
|
||||||
|
div.system-messages h1 {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
div.system-message {
|
||||||
|
border: medium outset ;
|
||||||
|
padding: 1em }
|
||||||
|
|
||||||
|
div.system-message p.system-message-title {
|
||||||
|
color: red ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
margin: 2em }
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5 {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
line-height: 150% ;
|
||||||
|
color: orange} /* #666 } */
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
h2.subtitle {
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
hr.docutils {
|
||||||
|
width: 75% }
|
||||||
|
|
||||||
|
ol.simple, ul.simple {
|
||||||
|
margin-bottom: 1em }
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal }
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha }
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha }
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman }
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman }
|
||||||
|
|
||||||
|
p.attribution {
|
||||||
|
text-align: right ;
|
||||||
|
margin-left: 50% }
|
||||||
|
|
||||||
|
p.caption {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
p.credits {
|
||||||
|
font-style: italic ;
|
||||||
|
font-size: smaller }
|
||||||
|
|
||||||
|
p.label {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
p.rubric {
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger ;
|
||||||
|
color: maroon ;
|
||||||
|
text-align: center }
|
||||||
|
|
||||||
|
p.sidebar-title {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold ;
|
||||||
|
font-size: larger }
|
||||||
|
|
||||||
|
p.sidebar-subtitle {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
pre.address {
|
||||||
|
margin-bottom: 0 ;
|
||||||
|
margin-top: 0 ;
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.line-block {
|
||||||
|
font-family: serif ;
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
pre.literal-block, pre.doctest-block {
|
||||||
|
margin-left: 2em ;
|
||||||
|
margin-right: 2em ;
|
||||||
|
font-size: small ;
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
span.classifier {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-style: oblique }
|
||||||
|
|
||||||
|
span.classifier-delimiter {
|
||||||
|
font-family: sans-serif ;
|
||||||
|
font-weight: bold }
|
||||||
|
|
||||||
|
span.interpreted {
|
||||||
|
font-family: sans-serif }
|
||||||
|
|
||||||
|
span.option {
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
span.option-argument {
|
||||||
|
font-style: italic }
|
||||||
|
|
||||||
|
span.pre {
|
||||||
|
white-space: pre }
|
||||||
|
|
||||||
|
span.problematic {
|
||||||
|
color: red }
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid thin gray }
|
||||||
|
|
||||||
|
table.docinfo {
|
||||||
|
/* float: right ; */
|
||||||
|
margin: 2em 4em ;
|
||||||
|
color: #666 }
|
||||||
|
|
||||||
|
table.docutils {
|
||||||
|
margin-top: 0.5em ;
|
||||||
|
margin-bottom: 0.5em }
|
||||||
|
|
||||||
|
table.footnote {
|
||||||
|
border-left: solid thin black }
|
||||||
|
|
||||||
|
table.docutils td, table.docutils th,
|
||||||
|
table.docinfo td, table.docinfo th {
|
||||||
|
padding-left: 0.5em ;
|
||||||
|
padding-right: 0.5em ;
|
||||||
|
vertical-align: top }
|
||||||
|
|
||||||
|
th.docinfo-name, th.field-name {
|
||||||
|
font-weight: bold ;
|
||||||
|
text-align: right ;
|
||||||
|
white-space: nowrap }
|
||||||
|
|
||||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||||
|
font-size: 100% }
|
||||||
|
|
||||||
|
tt.docutils {
|
||||||
|
background-color: #eeeeee }
|
||||||
|
|
||||||
|
ul.auto-toc {
|
||||||
|
list-style-type: none }
|
||||||
|
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 37 KiB |
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta name="generator" content="Docutils 0.9: http://docutils.sourceforge.net/" />
|
||||||
|
<title>rapports eole</title>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
@import url(docutils.css);
|
||||||
|
@import url(default.css);
|
||||||
|
a:link {
|
||||||
|
color: orange;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:active {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: orange;
|
||||||
|
background-color: white;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
color: #666;
|
||||||
|
background-color: inherit;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="document">
|
||||||
|
|
||||||
|
|
||||||
|
<img alt="imgs/eol.png" class="align-right" src="imgs/eol.png" />
|
||||||
|
<table class="docutils field-list" frame="void" rules="none">
|
||||||
|
<col class="field-name" />
|
||||||
|
<col class="field-body" />
|
||||||
|
<tbody valign="top">
|
||||||
|
<tr class="field"><th class="field-name">date:</th><td class="field-body">mai 2012</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="field"><th class="field-name">description:</th><td class="field-body">rapports <tt class="docutils literal">Créole</tt>, compatibilités <tt class="docutils literal">Creole</tt> et <tt class="docutils literal">tiramisu</tt></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="section" id="vue-d-ensemble-des-rapports">
|
||||||
|
<h1>Vue d'ensemble des rapports</h1>
|
||||||
|
<p>Les rapports ci-dessous résument et permettent de donner des points d'appui à
|
||||||
|
des discussions de recherche et développement concernant l'évolution du
|
||||||
|
projet <tt class="docutils literal">Creole</tt> (comprenant <tt class="docutils literal">Creole_Serv</tt>). Il y a aussi le support de
|
||||||
|
documentation développeur <tt class="docutils literal">tiramisu</tt> (en anglais) qui constitue une bonne
|
||||||
|
base pour connaître et comprendre plus en détails les motivations de
|
||||||
|
la nouvelle implementation.</p>
|
||||||
|
<ul class="simple">
|
||||||
|
<li><a class="reference external" href="pdfreport/D01AccesVariables.pdf">D01AccesVariables.pdf</a></li>
|
||||||
|
<li><a class="reference external" href="pdfreport/D02CoherenceVariables.pdf">D02CoherenceVariables.pdf</a></li>
|
||||||
|
<li><a class="reference external" href="pdfreport/D03ReglesEtats.pdf">D03ReglesEtats.pdf</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
from glob import glob
|
||||||
|
from os.path import isfile, dirname, abspath, join, basename, splitext
|
||||||
|
from rst import Rest, Paragraph, Strong, ListItem, Link
|
||||||
|
|
||||||
|
|
||||||
|
here = abspath(dirname(__file__))
|
||||||
|
html = glob(join(here, '*.pdf'))
|
||||||
|
|
||||||
|
basehtml = [basename(htm) for htm in html]
|
||||||
|
basehtml.sort()
|
||||||
|
|
||||||
|
content = Rest()
|
||||||
|
|
||||||
|
for htm in basehtml:
|
||||||
|
link = Link( htm , "pdfreport/" +htm)
|
||||||
|
content.add(ListItem(link))
|
||||||
|
|
||||||
|
sys.stdout.write(content.text())
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,410 @@
|
||||||
|
# unproudly borrowed from pypy :
|
||||||
|
# http://codespeak.net/svn/pypy/trunk/pypy/tool/rest/rst.py
|
||||||
|
""" reStructuredText generation tools
|
||||||
|
|
||||||
|
provides an api to build a tree from nodes, which can be converted to
|
||||||
|
ReStructuredText on demand
|
||||||
|
|
||||||
|
note that not all of ReST is supported, a usable subset is offered, but
|
||||||
|
certain features aren't supported, and also certain details (like how links
|
||||||
|
are generated, or how escaping is done) can not be controlled
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
def escape(txt):
|
||||||
|
"""escape ReST markup"""
|
||||||
|
if not isinstance(txt, str) and not isinstance(txt, unicode):
|
||||||
|
txt = str(txt)
|
||||||
|
# XXX this takes a very naive approach to escaping, but it seems to be
|
||||||
|
# sufficient...
|
||||||
|
for c in '\\*`|:_':
|
||||||
|
txt = txt.replace(c, '\\%s' % (c,))
|
||||||
|
return txt
|
||||||
|
|
||||||
|
class RestError(Exception):
|
||||||
|
""" raised on containment errors (wrong parent) """
|
||||||
|
|
||||||
|
class AbstractMetaclass(type):
|
||||||
|
def __new__(cls, *args):
|
||||||
|
obj = super(AbstractMetaclass, cls).__new__(cls, *args)
|
||||||
|
parent_cls = obj.parentclass
|
||||||
|
if parent_cls is None:
|
||||||
|
return obj
|
||||||
|
if not isinstance(parent_cls, list):
|
||||||
|
class_list = [parent_cls]
|
||||||
|
else:
|
||||||
|
class_list = parent_cls
|
||||||
|
if obj.allow_nesting:
|
||||||
|
class_list.append(obj)
|
||||||
|
|
||||||
|
for _class in class_list:
|
||||||
|
if not _class.allowed_child:
|
||||||
|
_class.allowed_child = {obj:True}
|
||||||
|
else:
|
||||||
|
_class.allowed_child[obj] = True
|
||||||
|
return obj
|
||||||
|
|
||||||
|
class AbstractNode(object):
|
||||||
|
""" Base class implementing rest generation
|
||||||
|
"""
|
||||||
|
sep = ''
|
||||||
|
__metaclass__ = AbstractMetaclass
|
||||||
|
parentclass = None # this exists to allow parent to know what
|
||||||
|
# children can exist
|
||||||
|
allow_nesting = False
|
||||||
|
allowed_child = {}
|
||||||
|
defaults = {}
|
||||||
|
|
||||||
|
_reg_whitespace = re.compile('\s+')
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.parent = None
|
||||||
|
self.children = []
|
||||||
|
for child in args:
|
||||||
|
self._add(child)
|
||||||
|
for arg in kwargs:
|
||||||
|
setattr(self, arg, kwargs[arg])
|
||||||
|
|
||||||
|
def join(self, *children):
|
||||||
|
""" add child nodes
|
||||||
|
|
||||||
|
returns a reference to self
|
||||||
|
"""
|
||||||
|
for child in children:
|
||||||
|
self._add(child)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def add(self, child):
|
||||||
|
""" adds a child node
|
||||||
|
|
||||||
|
returns a reference to the child
|
||||||
|
"""
|
||||||
|
self._add(child)
|
||||||
|
return child
|
||||||
|
|
||||||
|
def _add(self, child):
|
||||||
|
if child.__class__ not in self.allowed_child:
|
||||||
|
raise RestError("%r cannot be child of %r" % \
|
||||||
|
(child.__class__, self.__class__))
|
||||||
|
self.children.append(child)
|
||||||
|
child.parent = self
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return self.children[item]
|
||||||
|
|
||||||
|
def __setitem__(self, item, value):
|
||||||
|
self.children[item] = value
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
""" return a ReST string representation of the node """
|
||||||
|
return self.sep.join([child.text() for child in self.children])
|
||||||
|
|
||||||
|
def wordlist(self):
|
||||||
|
""" return a list of ReST strings for this node and its children """
|
||||||
|
return [self.text()]
|
||||||
|
|
||||||
|
class Rest(AbstractNode):
|
||||||
|
""" Root node of a document """
|
||||||
|
|
||||||
|
sep = "\n\n"
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
AbstractNode.__init__(self, *args, **kwargs)
|
||||||
|
self.links = {}
|
||||||
|
|
||||||
|
def render_links(self, check=False):
|
||||||
|
"""render the link attachments of the document"""
|
||||||
|
assert not check, "Link checking not implemented"
|
||||||
|
if not self.links:
|
||||||
|
return ""
|
||||||
|
link_texts = []
|
||||||
|
# XXX this could check for duplicates and remove them...
|
||||||
|
for link, target in self.links.iteritems():
|
||||||
|
link_texts.append(".. _`%s`: %s" % (escape(link), target))
|
||||||
|
return "\n" + "\n".join(link_texts) + "\n\n"
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
outcome = []
|
||||||
|
if (isinstance(self.children[0], Transition) or
|
||||||
|
isinstance(self.children[-1], Transition)):
|
||||||
|
raise ValueError, ('document must not begin or end with a '
|
||||||
|
'transition')
|
||||||
|
for child in self.children:
|
||||||
|
outcome.append(child.text())
|
||||||
|
|
||||||
|
# always a trailing newline
|
||||||
|
text = self.sep.join([i for i in outcome if i]) + "\n"
|
||||||
|
return text + self.render_links()
|
||||||
|
|
||||||
|
class Transition(AbstractNode):
|
||||||
|
""" a horizontal line """
|
||||||
|
parentclass = Rest
|
||||||
|
|
||||||
|
def __init__(self, char='-', width=80, *args, **kwargs):
|
||||||
|
self.char = char
|
||||||
|
self.width = width
|
||||||
|
super(Transition, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
return (self.width - 1) * self.char
|
||||||
|
|
||||||
|
class Paragraph(AbstractNode):
|
||||||
|
""" simple paragraph """
|
||||||
|
|
||||||
|
parentclass = Rest
|
||||||
|
sep = " "
|
||||||
|
indent = ""
|
||||||
|
# FIXME
|
||||||
|
width = 880
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# make shortcut
|
||||||
|
args = list(args)
|
||||||
|
for num, arg in enumerate(args):
|
||||||
|
if isinstance(arg, str):
|
||||||
|
args[num] = Text(arg)
|
||||||
|
super(Paragraph, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
texts = []
|
||||||
|
for child in self.children:
|
||||||
|
texts += child.wordlist()
|
||||||
|
|
||||||
|
buf = []
|
||||||
|
outcome = []
|
||||||
|
lgt = len(self.indent)
|
||||||
|
|
||||||
|
def grab(buf):
|
||||||
|
outcome.append(self.indent + self.sep.join(buf))
|
||||||
|
|
||||||
|
texts.reverse()
|
||||||
|
while texts:
|
||||||
|
next = texts[-1]
|
||||||
|
if not next:
|
||||||
|
texts.pop()
|
||||||
|
continue
|
||||||
|
if lgt + len(self.sep) + len(next) <= self.width or not buf:
|
||||||
|
buf.append(next)
|
||||||
|
lgt += len(next) + len(self.sep)
|
||||||
|
texts.pop()
|
||||||
|
else:
|
||||||
|
grab(buf)
|
||||||
|
lgt = len(self.indent)
|
||||||
|
buf = []
|
||||||
|
grab(buf)
|
||||||
|
return "\n".join(outcome)
|
||||||
|
|
||||||
|
class SubParagraph(Paragraph):
|
||||||
|
""" indented sub paragraph """
|
||||||
|
|
||||||
|
indent = " "
|
||||||
|
|
||||||
|
class Title(Paragraph):
|
||||||
|
""" title element """
|
||||||
|
|
||||||
|
parentclass = Rest
|
||||||
|
belowchar = "="
|
||||||
|
abovechar = ""
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
txt = self._get_text()
|
||||||
|
lines = []
|
||||||
|
if self.abovechar:
|
||||||
|
lines.append(self.abovechar * len(txt))
|
||||||
|
lines.append(txt)
|
||||||
|
if self.belowchar:
|
||||||
|
lines.append(self.belowchar * len(txt))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def _get_text(self):
|
||||||
|
txt = []
|
||||||
|
for node in self.children:
|
||||||
|
txt += node.wordlist()
|
||||||
|
return ' '.join(txt)
|
||||||
|
|
||||||
|
class AbstractText(AbstractNode):
|
||||||
|
parentclass = [Paragraph, Title]
|
||||||
|
start = ""
|
||||||
|
end = ""
|
||||||
|
def __init__(self, _text):
|
||||||
|
self._text = _text
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
text = self.escape(self._text)
|
||||||
|
return self.start + text + self.end
|
||||||
|
|
||||||
|
def escape(self, text):
|
||||||
|
if not isinstance(text, str) and not isinstance(text, unicode):
|
||||||
|
text = str(text)
|
||||||
|
if self.start:
|
||||||
|
text = text.replace(self.start, '\\%s' % (self.start,))
|
||||||
|
if self.end and self.end != self.start:
|
||||||
|
text = text.replace(self.end, '\\%s' % (self.end,))
|
||||||
|
return text
|
||||||
|
|
||||||
|
class Text(AbstractText):
|
||||||
|
def wordlist(self):
|
||||||
|
text = escape(self._text)
|
||||||
|
return self._reg_whitespace.split(text)
|
||||||
|
|
||||||
|
class LiteralBlock(AbstractText):
|
||||||
|
parentclass = Rest
|
||||||
|
start = '::\n\n'
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
if not self._text.strip():
|
||||||
|
return ''
|
||||||
|
text = self.escape(self._text).split('\n')
|
||||||
|
for i, line in enumerate(text):
|
||||||
|
if line.strip():
|
||||||
|
text[i] = ' %s' % (line,)
|
||||||
|
return self.start + '\n'.join(text)
|
||||||
|
|
||||||
|
class Em(AbstractText):
|
||||||
|
start = "*"
|
||||||
|
end = "*"
|
||||||
|
|
||||||
|
class Strong(AbstractText):
|
||||||
|
start = "**"
|
||||||
|
end = "**"
|
||||||
|
|
||||||
|
class Quote(AbstractText):
|
||||||
|
start = '``'
|
||||||
|
end = '``'
|
||||||
|
|
||||||
|
class Anchor(AbstractText):
|
||||||
|
start = '_`'
|
||||||
|
end = '`'
|
||||||
|
|
||||||
|
class Footnote(AbstractText):
|
||||||
|
def __init__(self, note, symbol=False):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class Citation(AbstractText):
|
||||||
|
def __init__(self, text, cite):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class ListItem(Paragraph):
|
||||||
|
allow_nesting = True
|
||||||
|
item_chars = '*+-'
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
idepth = self.get_indent_depth()
|
||||||
|
indent = self.indent + (idepth + 1) * ' '
|
||||||
|
txt = '\n\n'.join(self.render_children(indent))
|
||||||
|
ret = []
|
||||||
|
item_char = self.item_chars[idepth]
|
||||||
|
ret += [indent[len(item_char)+1:], item_char, ' ', txt[len(indent):]]
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
def render_children(self, indent):
|
||||||
|
txt = []
|
||||||
|
buffer = []
|
||||||
|
def render_buffer(fro, to):
|
||||||
|
if not fro:
|
||||||
|
return
|
||||||
|
p = Paragraph(indent=indent, *fro)
|
||||||
|
p.parent = self.parent
|
||||||
|
to.append(p.text())
|
||||||
|
for child in self.children:
|
||||||
|
if isinstance(child, AbstractText):
|
||||||
|
buffer.append(child)
|
||||||
|
else:
|
||||||
|
if buffer:
|
||||||
|
render_buffer(buffer, txt)
|
||||||
|
buffer = []
|
||||||
|
txt.append(child.text())
|
||||||
|
|
||||||
|
render_buffer(buffer, txt)
|
||||||
|
return txt
|
||||||
|
|
||||||
|
def get_indent_depth(self):
|
||||||
|
depth = 0
|
||||||
|
current = self
|
||||||
|
while (current.parent is not None and
|
||||||
|
isinstance(current.parent, ListItem)):
|
||||||
|
depth += 1
|
||||||
|
current = current.parent
|
||||||
|
return depth
|
||||||
|
|
||||||
|
class OrderedListItem(ListItem):
|
||||||
|
item_chars = ["#."] * 5
|
||||||
|
|
||||||
|
class DListItem(ListItem):
|
||||||
|
item_chars = None
|
||||||
|
def __init__(self, term, definition, *args, **kwargs):
|
||||||
|
self.term = term
|
||||||
|
super(DListItem, self).__init__(definition, *args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
idepth = self.get_indent_depth()
|
||||||
|
indent = self.indent + (idepth + 1) * ' '
|
||||||
|
txt = '\n\n'.join(self.render_children(indent))
|
||||||
|
ret = []
|
||||||
|
ret += [indent[2:], self.term, '\n', txt]
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
class Link(AbstractText):
|
||||||
|
start = '`'
|
||||||
|
end = '`_'
|
||||||
|
|
||||||
|
def __init__(self, _text, target):
|
||||||
|
self._text = _text
|
||||||
|
self.target = target
|
||||||
|
self.rest = None
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
if self.rest is None:
|
||||||
|
self.rest = self.find_rest()
|
||||||
|
if self.rest.links.get(self._text, self.target) != self.target:
|
||||||
|
raise ValueError('link name %r already in use for a different '
|
||||||
|
'target' % (self.target,))
|
||||||
|
self.rest.links[self._text] = self.target
|
||||||
|
return AbstractText.text(self)
|
||||||
|
|
||||||
|
def find_rest(self):
|
||||||
|
# XXX little overkill, but who cares...
|
||||||
|
next = self
|
||||||
|
while next.parent is not None:
|
||||||
|
next = next.parent
|
||||||
|
return next
|
||||||
|
|
||||||
|
class InternalLink(AbstractText):
|
||||||
|
start = '`'
|
||||||
|
end = '`_'
|
||||||
|
|
||||||
|
class LinkTarget(Paragraph):
|
||||||
|
def __init__(self, name, target):
|
||||||
|
self.name = name
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
return ".. _`%s`:%s\n" % (self.name, self.target)
|
||||||
|
|
||||||
|
class Substitution(AbstractText):
|
||||||
|
def __init__(self, text, **kwargs):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class Directive(Paragraph):
|
||||||
|
indent = ' '
|
||||||
|
def __init__(self, name, *args, **options):
|
||||||
|
self.name = name
|
||||||
|
self.content = args
|
||||||
|
super(Directive, self).__init__()
|
||||||
|
self.options = options
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
# XXX not very pretty...
|
||||||
|
txt = '.. %s::' % (self.name,)
|
||||||
|
options = '\n'.join([' :%s: %s' % (k, v) for (k, v) in
|
||||||
|
self.options.iteritems()])
|
||||||
|
if options:
|
||||||
|
txt += '\n%s' % (options,)
|
||||||
|
|
||||||
|
if self.content:
|
||||||
|
txt += '\n'
|
||||||
|
for item in self.content:
|
||||||
|
txt += '\n ' + item
|
||||||
|
|
||||||
|
return txt
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
@import url(docutils.css);
|
||||||
|
@import url(default.css);
|
||||||
|
a:link {
|
||||||
|
color: orange;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:visited {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
a:active {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: orange;
|
||||||
|
background-color: white;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
color: #666;
|
||||||
|
background-color: inherit;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
.. container:: rubric
|
||||||
|
|
||||||
|
**Rédacteurs**
|
||||||
|
|
||||||
|
| Gwenaël Rémond (gremond@cadoles.com)
|
||||||
|
| Emmanuel Garette (egarette@cadoles.com)
|
||||||
|
|
||||||
|
**Référence**
|
||||||
|
|
||||||
|
| ``tiramisu/doc/eole-reports``
|
||||||
|
| ``git clone ssh://gitosis@git.cadol.es:2222/tiramisu.git``
|
||||||
|
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,18 @@
|
||||||
|
.. csv-table::
|
||||||
|
|
||||||
|
.. image:: inc/logo.png, .. image:: inc/eol.png
|
||||||
|
|
||||||
|
.. container:: title
|
||||||
|
|
||||||
|
Rapports de discussions de recherche et développements
|
||||||
|
|
||||||
|
------------
|
||||||
|
|
||||||
|
.. container:: subtitle
|
||||||
|
|
||||||
|
Comparaison ``tiramisu`` et ``Créole``
|
||||||
|
|
||||||
|
.. include:: 00-Redacteur.txt
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
.. title:: rapports eole
|
||||||
|
|
||||||
|
|
||||||
|
.. image:: imgs/eol.png
|
||||||
|
:align: right
|
||||||
|
|
||||||
|
:date: mai 2012
|
||||||
|
:description: rapports `Créole`, compatibilités `Creole` et `tiramisu`
|
||||||
|
|
||||||
|
|
||||||
|
Vue d'ensemble des rapports
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Les rapports ci-dessous résument et permettent de donner des points d'appui à
|
||||||
|
des discussions de recherche et développement concernant l'évolution du
|
||||||
|
projet `Creole` (comprenant `Creole_Serv`). Il y a aussi le support de
|
||||||
|
documentation développeur `tiramisu` (en anglais) qui constitue une bonne
|
||||||
|
base pour connaître et comprendre plus en détails les motivations de
|
||||||
|
la nouvelle implementation.
|
||||||
|
|
||||||
|
|
||||||
|
* `D01AccesVariables.pdf`_
|
||||||
|
|
||||||
|
* `D02CoherenceVariables.pdf`_
|
||||||
|
|
||||||
|
* `D03ReglesEtats.pdf`_
|
||||||
|
|
||||||
|
.. _`D03ReglesEtats.pdf`: pdfreport/D03ReglesEtats.pdf
|
||||||
|
.. _`D02CoherenceVariables.pdf`: pdfreport/D02CoherenceVariables.pdf
|
||||||
|
.. _`D01AccesVariables.pdf`: pdfreport/D01AccesVariables.pdf
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
SRC=$(wildcard *.tex)
|
||||||
|
OBJ=$(subst .tex,.pdf,$(SRC))
|
||||||
|
|
||||||
|
pdf: $(OBJ)
|
||||||
|
|
||||||
|
%.pdf: %.tex
|
||||||
|
pdflatex $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJ)
|
||||||
|
rm -f *.aux *.log *.toc *.snm *.out *.nav
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Comparaison entre le noyau de Créole et Tiramisu}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{Créole} : \texttt{cfgparser.py + typeeole.py} $ \Rightarrow 2500$ lignes ;
|
||||||
|
\item \emph{Tiramisu} : \texttt{config.py + option.py} $ \Rightarrow 800$ lignes ;
|
||||||
|
\item Et en plus :
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{Créole} valide le type mais pas la structure (fait confiance au \texttt{XML}) ;
|
||||||
|
\item \emph{Créole} difficile d'ajouter un type à cause de la métaclasse ;
|
||||||
|
\item \emph{Tiramisu} valide le type \emph{et} la structure, ajout de types aisé.
|
||||||
|
\end{itemize}
|
||||||
|
\item \texttt{eole-report/D02CoherenceVariables.pdf}
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Définition d'un gestionnaire de configuration}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \emph{dictionnaire} de données (au sens python) ;
|
||||||
|
\item clefs-valeurs, mais quelles valeurs exactement ? ;
|
||||||
|
\item \texttt{eole-report/D01AccesVariables.pdf}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Définition d'un gestionnaire de configuration}
|
||||||
|
\begin{itemize}
|
||||||
|
\item espaces de nommages ;
|
||||||
|
\item c'est la configuration qui est responsable de l'accès aux valeurs ;
|
||||||
|
\item une configuration aisément manipulable ;
|
||||||
|
\item un point d'entrée unique.
|
||||||
|
\item \texttt{eole-report/D01AccesVariables.pdf}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Définition d'un gestionnaire de configuration 2}
|
||||||
|
\begin{itemize}
|
||||||
|
\item serveur de données de configuration ;
|
||||||
|
\item $1^{ere}$ méthode : exportation (snapshot) d'un état de la config $\Rightarrow$ Créole ;
|
||||||
|
\item $2^{eme}$ méthode : JIT (just in time) calculation, une modification
|
||||||
|
de l'état de la configuration est possible \emph{pendant} la manipulation et l'utilisation $\Rightarrow$ Tiramisu.
|
||||||
|
\item \texttt{doc/getting-started.html}
|
||||||
|
\end{itemize}
|
||||||
|
\end{frame}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Organisation en espace de nommage}
|
||||||
|
\begin{itemize}
|
||||||
|
\item dans \emph{tiramisu} l'accent est mis sur l'organisation arborescente des données ;
|
||||||
|
\item la validation des options de configuration se fait par l'appartenance aux groupes (families, master/slaves \dots) ;
|
||||||
|
\item l'organisation en groupes est unifiée par l'espace de nommage ;
|
||||||
|
\item la lisibilité de l'API excellente, contrairement à \emph{Creole}
|
||||||
|
\item \texttt{eole-report/D03ReglesEtats.pdf}
|
||||||
|
\item lisibilité d'une config : \texttt{tiramisu/report/build/index.html} rapport html d'une config
|
||||||
|
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{Etats de la configuration}
|
||||||
|
\begin{itemize}
|
||||||
|
\item système d'états de la configuration par droits d'accès
|
||||||
|
\item \texttt{read write}, \texttt{read only};
|
||||||
|
\item correspond à \texttt{freeze}, \texttt{hidden}, \texttt{disabled} \dots ;
|
||||||
|
\item \texttt{doc/status.html}
|
||||||
|
\item \texttt{eole-report/D03ReglesEtats.pdf}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{hidden if in, hidden if not in}
|
||||||
|
\begin{itemize}
|
||||||
|
\item les hidden if in, disabled if, \dots sont généralisés
|
||||||
|
\item dans tiramisu, ce sont des pré-requis sur une (des) variables
|
||||||
|
\item \texttt{eole-report/D03ReglesEtats.pdf}
|
||||||
|
\item \texttt{doc/consistency.html}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
\begin{frame}
|
||||||
|
\frametitle{compatibilité Créole : ce qui reste à faire}
|
||||||
|
\begin{itemize}
|
||||||
|
\item tous les options spéciales sont implémentées (auto, fill, obligatoire, \dots)
|
||||||
|
\item tous les états sont implémentés (hidden, disabled, mode (normal/expert), \dots)
|
||||||
|
\item reste la librairie des fonctions pour les variables automatiques
|
||||||
|
\item les "valprec" (valeur précédentes)
|
||||||
|
\item fixer les comportement des hides (sous-groupes récursifs, \dots)
|
||||||
|
\item validations master/slaves, validations globales (au regard de la configuration entière) éventuellement
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{frame}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
%%presentation
|
||||||
|
\documentclass{beamer}
|
||||||
|
\usepackage{beamerthemetree}
|
||||||
|
%%impression
|
||||||
|
%\documentclass[a4paper,9pt]{extarticle}
|
||||||
|
%\usepackage{beamerarticle}
|
||||||
|
%%
|
||||||
|
|
||||||
|
% class FR
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[frenchb]{babel}
|
||||||
|
|
||||||
|
% image
|
||||||
|
\usepackage{graphicx}
|
||||||
|
% code
|
||||||
|
%\usepackage{listings}
|
||||||
|
%\lstset{language=python,
|
||||||
|
% caption=Descriptive Caption Text,
|
||||||
|
% label=DescriptiveLabel,
|
||||||
|
% tabsize=2,
|
||||||
|
% frame=tb,
|
||||||
|
% basicstyle=\small,
|
||||||
|
% }
|
||||||
|
\usepackage{alltt}
|
||||||
|
\usecolortheme{crane}
|
||||||
|
\beamertemplatetransparentcovered
|
||||||
|
|
||||||
|
% le logo
|
||||||
|
%\logo{\includegraphics[height=1cm]{ban.png}}
|
||||||
|
|
||||||
|
\title{Présentation de Tiramisu}
|
||||||
|
\subtitle{gestionnaire de configuration}
|
||||||
|
|
||||||
|
\author{REMOND Gwenaël}
|
||||||
|
\institute{Cadoles}
|
||||||
|
\date{\today}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\frame{\titlepage}
|
||||||
|
|
||||||
|
\include{definition}
|
||||||
|
\include{comparaison}
|
||||||
|
\include{statut}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
epydoc --css grayscale -o ./pydoc ../config.py ../option.py
|
||||||
|
#apirst2html.py --stylesheet=docutils.css --external-api=epydoc --external-api-root=epydoc:./api/ --external-api-file=epydoc:./api/api-objects.txt doc.txt > doc.htm
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
- abstract values from `gaspacho`
|
||||||
|
|
||||||
|
Les types possibles :
|
||||||
|
|
||||||
|
- sans valeur : `boolean`
|
||||||
|
- avec valeur : `unicode` (un texte libre), `integer` (un chiffre), `enum` (une liste de choix prédéfinies) et `list` (une liste de choix libres).
|
||||||
|
|
||||||
|
Les types sans valeurs sont les plus simples. Par exemple cette règle n’attend
|
||||||
|
aucune valeur particulière Vérifier que Firefox est le navigateur par défaut.
|
||||||
|
|
||||||
|
Alors que celle-ci attend une adresse IP Configuration du serveur proxy manuelle.
|
||||||
|
|
||||||
|
Il existe un autre type (multi) qui permet de mêler plusieurs types.
|
||||||
|
|
||||||
|
Il s’agit bien de définir ici le type de la règle (et uniquement de la règle).
|
||||||
|
|
||||||
|
- configuration levels in `creole`
|
||||||
|
|
||||||
|
*thu, 28 april 2011*
|
||||||
|
|
||||||
|
Exemple de niveau de configuration (dans l'ordre) :
|
||||||
|
|
||||||
|
1. - Coeur
|
||||||
|
|
||||||
|
2.
|
||||||
|
- Coeur
|
||||||
|
- gen_config
|
||||||
|
|
||||||
|
3.
|
||||||
|
- Coeur
|
||||||
|
- gen_config
|
||||||
|
- EAD
|
||||||
|
|
||||||
|
4.
|
||||||
|
- Coeur
|
||||||
|
- EAD
|
||||||
|
|
||||||
|
5.
|
||||||
|
- Coeur
|
||||||
|
- baculaconfig.py
|
||||||
|
|
||||||
|
(`fill` : calcule une valeur jusqu'à ce que l'utilisateur change la
|
||||||
|
valeur)
|
||||||
|
|
||||||
|
Gestion des ACL en écriture :
|
||||||
|
|
||||||
|
Le coeur charge les variables
|
||||||
|
|
||||||
|
- si auto : seul le coeur peut la modifier (cas 1) ;
|
||||||
|
|
||||||
|
- si fill : le coeur calcule une valeur tant que pas configuré par
|
||||||
|
l'utilisateur. L'utilisateur peut modifier (cas 2 ou 3) ;
|
||||||
|
|
||||||
|
- des variables modifiables que par gen_config (cas 2) ;
|
||||||
|
|
||||||
|
- des variables modifiables par gen_config ou l'EAD (cas 3) ;
|
||||||
|
|
||||||
|
- des variables d'autres applications (cas 4 et 5).
|
||||||
|
|
||||||
|
Gestion des ACLs en lecture :
|
||||||
|
|
||||||
|
- seule une application peut lire certaines variables (exemple un mot de
|
||||||
|
passe).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
==================================
|
||||||
|
`Tiramisu` - Getting Started
|
||||||
|
==================================
|
||||||
|
|
||||||
|
What is Configuration handling ?
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Due to more and more available configuration options required to set up
|
||||||
|
an operating system, it became quite annoying to hand the necessary
|
||||||
|
options to where they are actually used and even more annoying to add
|
||||||
|
new options. To circumvent these problems the configuration management
|
||||||
|
was introduced.
|
||||||
|
|
||||||
|
What is Tiramisu ?
|
||||||
|
===================
|
||||||
|
|
||||||
|
Tiramisu is yet another configuration handler, wich aims at producing
|
||||||
|
flexible and fast configuration options access. The main advantages are
|
||||||
|
its access :ref:`glossary#rules` and the fact that the configuration 's
|
||||||
|
consistency is preserved at any time, see :ref:`glossary#consistency`.
|
||||||
|
|
||||||
|
There are type and structures's validations for configuration options,
|
||||||
|
and validations towards the whole configuration.
|
||||||
|
|
||||||
|
Last but not least, configuration options can be reached and changed
|
||||||
|
according to the access rules from nearly everywhere in the OS boxes,
|
||||||
|
e.g. the containers via the `http/json` server.
|
||||||
|
|
||||||
|
Just the facts
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. _gettingtiramisu:
|
||||||
|
|
||||||
|
Download
|
||||||
|
---------
|
||||||
|
|
||||||
|
To obtain a copy of the sources, check it out from the repository using
|
||||||
|
`git`. We suggest using `git` if one wants to access the current development.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
git clone ssh://gitosis@git.cadol.es:2222/tiramisu.git
|
||||||
|
|
||||||
|
This will get you a fresh checkout of the code repository in a local
|
||||||
|
directory named ``tiramisu``.
|
||||||
|
|
||||||
|
Understanding Tiramisu's architecture
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
The :ref:`glossary#schema` is loaded from an XML file, and the values of
|
||||||
|
the configuration options are recovered from a `.ini` like file.
|
||||||
|
|
||||||
|
By now, all the in-depth informations about the configuration are stored
|
||||||
|
in a **single** object, the :api:`config.Config()` object, wich is
|
||||||
|
responsible of nearly everything. All the necessary options are stored
|
||||||
|
into a configuration object, which is available nearly everywhere, so
|
||||||
|
that adding new options becomes trivial.
|
||||||
|
|
||||||
|
This `Config()` is available from everywhere with the help of an http server
|
||||||
|
that serves configuration datas as `json` strings (take a look at the server
|
||||||
|
here: :api:`server`).
|
||||||
|
|
||||||
|
.. figure:: architecture.png
|
||||||
|
|
||||||
|
The basics of Tiramisu's architecture.
|
||||||
|
Once loaded, http server serves the :api:`config.Config()` object, that is,
|
||||||
|
the configuration options and the configuration groups.
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
glossary
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. _configuration:
|
||||||
|
|
||||||
|
**configuration**
|
||||||
|
|
||||||
|
Global configuration object, wich contains the whole configuration
|
||||||
|
options *and* their descriptions (option types and group)
|
||||||
|
|
||||||
|
.. _`option description`:
|
||||||
|
.. _`schema`:
|
||||||
|
|
||||||
|
**schema**:
|
||||||
|
**option description**
|
||||||
|
|
||||||
|
see :api:`option.OptionDescription`, see :ref:`optionapi#schema`
|
||||||
|
|
||||||
|
The schema of a configuration :
|
||||||
|
|
||||||
|
- the option types
|
||||||
|
|
||||||
|
- how they are organised in groups or even subgroups, that's why we
|
||||||
|
call them **groups** too.
|
||||||
|
|
||||||
|
.. _`configoption`:
|
||||||
|
|
||||||
|
**configuration option**
|
||||||
|
|
||||||
|
An option object wich has a name and a value and can be accessed
|
||||||
|
from the configuration object
|
||||||
|
|
||||||
|
.. _`defaultvalue`:
|
||||||
|
|
||||||
|
**default value**
|
||||||
|
|
||||||
|
Default value of a configuration option. The default value can be
|
||||||
|
set at instanciation time, or even at any moment. Remember that if
|
||||||
|
you reset the default value, the owner reset to `default`
|
||||||
|
|
||||||
|
.. _`rules`:
|
||||||
|
|
||||||
|
**acces rules**
|
||||||
|
|
||||||
|
Access rules are : :api:`config.Config.cfgimpl_read_write()` or
|
||||||
|
:api:`config.Config.cfgimpl_read_only()`, see :doc:`status`
|
||||||
|
|
||||||
|
**freeze**
|
||||||
|
|
||||||
|
A whole configuration can be frozen (used in read only access). See
|
||||||
|
:doc:`status` for details.
|
||||||
|
|
||||||
|
.. _`valueowner`:
|
||||||
|
|
||||||
|
**value owner**
|
||||||
|
|
||||||
|
When an option is modified, including at the instanciation, we
|
||||||
|
always know who has modified it. It's the owner of the option, see
|
||||||
|
:doc:`status` for more details.
|
||||||
|
|
||||||
|
**hidden option**
|
||||||
|
|
||||||
|
a hidden option has a different behaviour on regards to the access
|
||||||
|
of the value in the configuration, see :doc:`status` for more details.
|
||||||
|
|
||||||
|
**disabled option**
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
**fill option**
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
**auto option**
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
.. _mandatory:
|
||||||
|
|
||||||
|
**mandatory option**
|
||||||
|
|
||||||
|
A mandatory option is a configuration option wich value has to be
|
||||||
|
set, that is the default value cannot be `None`, see
|
||||||
|
:ref:`optionapi#optioninit`
|
||||||
|
|
||||||
|
|
||||||
|
.. _consistency:
|
||||||
|
|
||||||
|
**consistency**
|
||||||
|
|
||||||
|
Preserve the consistency in a whole configuration is a tricky thing,
|
||||||
|
tiramisu takes care of it for you, see :doc:`consistency` for details.
|
|
@ -0,0 +1,37 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
|
||||||
|
:description: configuration management
|
||||||
|
:keywords: config, configuration
|
||||||
|
|
||||||
|
.. title:: tiramisu
|
||||||
|
|
||||||
|
.. |version| replace:: 0.1
|
||||||
|
|
||||||
|
The tasting of `Tiramisu`
|
||||||
|
=========================
|
||||||
|
|
||||||
|
.. image:: tiramisu.jpeg
|
||||||
|
:height: 150px
|
||||||
|
|
||||||
|
`Tiramisu`
|
||||||
|
|
||||||
|
is a cool, refreshing Italian dessert,
|
||||||
|
|
||||||
|
it is also a configuration management tool.
|
||||||
|
|
||||||
|
|
||||||
|
It's a pretty small, local (that is, straight on the operating system)
|
||||||
|
configuration handler.
|
||||||
|
|
||||||
|
- :doc:`getting-started`: where to go from here,
|
||||||
|
- :doc:`config` explains the good praticies of configuration handling,
|
||||||
|
- :doc:`configapi` and :doc:`optionapi` describe the API's details,
|
||||||
|
- :doc:`status` for a summary of the `Option`'s and `Config`'s statuses,
|
||||||
|
- :doc:`consistency` for the local and global integrity constraints,
|
||||||
|
- :doc:`glossary` describes the specific terms used in Tiramisu.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
Options API Details
|
||||||
|
=====================
|
||||||
|
|
||||||
|
:module: :api:`option.py`
|
||||||
|
|
||||||
|
.. _schema:
|
||||||
|
|
||||||
|
Description of Options
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
All the constructors take a ``name`` and a ``doc`` argument as first
|
||||||
|
arguments to give the option or option group a name and to document it.
|
||||||
|
Most constructors take a ``default`` argument that specifies the default
|
||||||
|
value of the option. If this argument is not supplied the default value
|
||||||
|
is assumed to be ``None``.
|
||||||
|
|
||||||
|
Appart from that, the `Option` object is not supposed to contain any
|
||||||
|
other value than the `tainted` attribute, which is explained later. The
|
||||||
|
container of the value is in the `Config` object.
|
||||||
|
|
||||||
|
``OptionDescription``
|
||||||
|
+++++++++++++++++++++
|
||||||
|
|
||||||
|
This class is used to group suboptions.
|
||||||
|
|
||||||
|
``__init__(self, name, doc, children)``
|
||||||
|
``children`` is a list of option descriptions (including
|
||||||
|
``OptionDescription`` instances for nested namespaces).
|
||||||
|
|
||||||
|
``set_group_type(self, group_name)``
|
||||||
|
Three available group_types : `default`, `family`, `group` and
|
||||||
|
`master` (for master~slave group type). Notice that for a
|
||||||
|
master~slave group, the name of the group and the name of the
|
||||||
|
master option are identical.
|
||||||
|
|
||||||
|
`Options description` objects lives in the `_cfgimpl_descr` config attribute.
|
||||||
|
|
||||||
|
If you need to access an option object, you can do it with the OptionDescription
|
||||||
|
object. Not only the value of the option by attribute access, but the option
|
||||||
|
object itself that lives behind the scene. It can always be accessed internally
|
||||||
|
with the `_cfgimpl_descr` attribute of the `config` objects. For example, with a
|
||||||
|
option named `name` in a `gc` group the `name` object can be accessed like
|
||||||
|
this::
|
||||||
|
|
||||||
|
conf._cfgimpl_descr.name
|
||||||
|
|
||||||
|
of sub configs with ::
|
||||||
|
|
||||||
|
conf.gc._cfgimpl_descr.name
|
||||||
|
|
||||||
|
This is a binding. The option objects are in the `_children` config's attribute.
|
||||||
|
|
||||||
|
Why accessing an option object ? It is possible for example freeze the
|
||||||
|
configuration option
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
conf.gc._cfgimpl_descr.dummy.freeze()
|
||||||
|
|
||||||
|
or to hide it, or disable it, or... anything.
|
||||||
|
|
||||||
|
.. _optioninit:
|
||||||
|
|
||||||
|
generic option ``__init__`` method:
|
||||||
|
|
||||||
|
``__init__(name, doc, default=None, requires=None, multi=False, mandatory=False)``
|
||||||
|
|
||||||
|
:``default``: specifies the default value of the option.
|
||||||
|
:``requires``: is a list of names of options located anywhere in the configuration.
|
||||||
|
:``multi``: means the value can be a list.
|
||||||
|
:``mandatory``: see :ref:`glossary#mandatory`.
|
||||||
|
|
||||||
|
.. _optiontype:
|
||||||
|
|
||||||
|
``BoolOption``
|
||||||
|
++++++++++++++
|
||||||
|
|
||||||
|
Represents a choice between ``True`` and ``False``.
|
||||||
|
|
||||||
|
``IntOption``
|
||||||
|
+++++++++++++
|
||||||
|
|
||||||
|
Represents a choice of an integer.
|
||||||
|
|
||||||
|
``FloatOption``
|
||||||
|
+++++++++++++++
|
||||||
|
|
||||||
|
Represents a choice of a floating point number.
|
||||||
|
|
||||||
|
``StrOption``
|
||||||
|
+++++++++++++
|
||||||
|
|
||||||
|
Represents the choice of a string.
|
||||||
|
|
||||||
|
``SymLinkOption``
|
||||||
|
++++++++++++++++++
|
||||||
|
|
||||||
|
Redirects to another configuration option in the configuration, that is :
|
||||||
|
|
||||||
|
- retrieves the value of the tagert,
|
||||||
|
- can set the value of the target too.
|
||||||
|
|
||||||
|
``__init__(self, name, path)``
|
||||||
|
|
||||||
|
`path` is the path to the target, the option
|
||||||
|
|
||||||
|
``IPOption``
|
||||||
|
+++++++++++++
|
||||||
|
|
||||||
|
Represents the choice of an ip.
|
||||||
|
|
||||||
|
``NetmaskOption``
|
||||||
|
+++++++++++++++++++
|
||||||
|
|
||||||
|
Represents the choice of a netmask.
|
||||||
|
|
||||||
|
``ChoiceOption``
|
||||||
|
++++++++++++++++
|
||||||
|
|
||||||
|
Represents a choice out of several objects. The option can also have the value
|
||||||
|
``None``.
|
||||||
|
|
||||||
|
``__init__(self, name, doc, values, default=None, requires=None)``
|
||||||
|
``values`` is a list of values the option can possibly take.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
.PHONY: clean
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.html
|
After Width: | Height: | Size: 340 B |
|
@ -0,0 +1,322 @@
|
||||||
|
|
||||||
|
|
||||||
|
/* Epydoc CSS Stylesheet
|
||||||
|
*
|
||||||
|
* This stylesheet can be used to customize the appearance of epydoc's
|
||||||
|
* HTML output.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Default Colors & Styles
|
||||||
|
* - Set the default foreground & background color with 'body'; and
|
||||||
|
* link colors with 'a:link' and 'a:visited'.
|
||||||
|
* - Use bold for decision list terms.
|
||||||
|
* - The heading styles defined here are used for headings *within*
|
||||||
|
* docstring descriptions. All headings used by epydoc itself use
|
||||||
|
* either class='epydoc' or class='toc' (CSS styles for both
|
||||||
|
* defined below).
|
||||||
|
*/
|
||||||
|
body { background: #ffffff; color: #000000; }
|
||||||
|
p { margin-top: 0.5em; margin-bottom: 0.5em; }
|
||||||
|
a:link { color: #000000; }
|
||||||
|
a:visited { color: #404040; }
|
||||||
|
dt { font-weight: bold; }
|
||||||
|
h1 { font-size: +140%; font-style: italic;
|
||||||
|
font-weight: bold; }
|
||||||
|
h2 { font-size: +125%; font-style: italic;
|
||||||
|
font-weight: bold; }
|
||||||
|
h3 { font-size: +110%; font-style: italic;
|
||||||
|
font-weight: normal; }
|
||||||
|
code { font-size: 100%; }
|
||||||
|
/* N.B.: class, not pseudoclass */
|
||||||
|
a.link { font-family: monospace; }
|
||||||
|
|
||||||
|
/* Page Header & Footer
|
||||||
|
* - The standard page header consists of a navigation bar (with
|
||||||
|
* pointers to standard pages such as 'home' and 'trees'); a
|
||||||
|
* breadcrumbs list, which can be used to navigate to containing
|
||||||
|
* classes or modules; options links, to show/hide private
|
||||||
|
* variables and to show/hide frames; and a page title (using
|
||||||
|
* <h1>). The page title may be followed by a link to the
|
||||||
|
* corresponding source code (using 'span.codelink').
|
||||||
|
* - The footer consists of a navigation bar, a timestamp, and a
|
||||||
|
* pointer to epydoc's homepage.
|
||||||
|
*/
|
||||||
|
h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; }
|
||||||
|
h2.epydoc { font-size: +130%; font-weight: bold; }
|
||||||
|
h3.epydoc { font-size: +115%; font-weight: bold;
|
||||||
|
margin-top: 0.2em; }
|
||||||
|
td h3.epydoc { font-size: +115%; font-weight: bold;
|
||||||
|
margin-bottom: 0; }
|
||||||
|
table.navbar { background: #c0c0c0; color: #000000;
|
||||||
|
border: 2px groove #d0d0d0; }
|
||||||
|
table.navbar table { color: #000000; }
|
||||||
|
th.navbar-select { background: #b0b0b0;
|
||||||
|
color: #000000; }
|
||||||
|
table.navbar a { text-decoration: none; }
|
||||||
|
table.navbar a:link { color: #000000; }
|
||||||
|
table.navbar a:visited { color: #404040; }
|
||||||
|
span.breadcrumbs { font-size: 85%; font-weight: bold; }
|
||||||
|
span.options { font-size: 70%; }
|
||||||
|
span.codelink { font-size: 85%; }
|
||||||
|
td.footer { font-size: 85%; }
|
||||||
|
|
||||||
|
/* Table Headers
|
||||||
|
* - Each summary table and details section begins with a 'header'
|
||||||
|
* row. This row contains a section title (marked by
|
||||||
|
* 'span.table-header') as well as a show/hide private link
|
||||||
|
* (marked by 'span.options', defined above).
|
||||||
|
* - Summary tables that contain user-defined groups mark those
|
||||||
|
* groups using 'group header' rows.
|
||||||
|
*/
|
||||||
|
td.table-header { background: #b0b0b0; color: #000000;
|
||||||
|
border: 1px solid #808080; }
|
||||||
|
td.table-header table { color: #000000; }
|
||||||
|
td.table-header table a:link { color: #000000; }
|
||||||
|
td.table-header table a:visited { color: #404040; }
|
||||||
|
span.table-header { font-size: 120%; font-weight: bold; }
|
||||||
|
th.group-header { background: #e0e0e0; color: #000000;
|
||||||
|
text-align: left; font-style: italic;
|
||||||
|
font-size: 115%;
|
||||||
|
border: 1px solid #808080; }
|
||||||
|
|
||||||
|
/* Summary Tables (functions, variables, etc)
|
||||||
|
* - Each object is described by a single row of the table with
|
||||||
|
* two cells. The left cell gives the object's type, and is
|
||||||
|
* marked with 'code.summary-type'. The right cell gives the
|
||||||
|
* object's name and a summary description.
|
||||||
|
* - CSS styles for the table's header and group headers are
|
||||||
|
* defined above, under 'Table Headers'
|
||||||
|
*/
|
||||||
|
table.summary { border-collapse: collapse;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #808080;
|
||||||
|
margin-bottom: 0.5em; }
|
||||||
|
td.summary { border: 1px solid #808080; }
|
||||||
|
code.summary-type { font-size: 85%; }
|
||||||
|
table.summary a:link { color: #000000; }
|
||||||
|
table.summary a:visited { color: #404040; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Details Tables (functions, variables, etc)
|
||||||
|
* - Each object is described in its own div.
|
||||||
|
* - A single-row summary table w/ table-header is used as
|
||||||
|
* a header for each details section (CSS style for table-header
|
||||||
|
* is defined above, under 'Table Headers').
|
||||||
|
*/
|
||||||
|
table.details { border-collapse: collapse;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #808080;
|
||||||
|
margin: .2em 0 0 0; }
|
||||||
|
table.details table { color: #000000; }
|
||||||
|
table.details a:link { color: #000000; }
|
||||||
|
table.details a:visited { color: #404040; }
|
||||||
|
|
||||||
|
/* Fields */
|
||||||
|
dl.fields { margin-left: 2em; margin-top: 1em;
|
||||||
|
margin-bottom: 1em; }
|
||||||
|
dl.fields dd ul { margin-left: 0em; padding-left: 0em; }
|
||||||
|
dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; }
|
||||||
|
div.fields { margin-left: 2em; }
|
||||||
|
div.fields p { margin-bottom: 0.5em; }
|
||||||
|
|
||||||
|
/* Index tables (identifier index, term index, etc)
|
||||||
|
* - link-index is used for indices containing lists of links
|
||||||
|
* (namely, the identifier index & term index).
|
||||||
|
* - index-where is used in link indices for the text indicating
|
||||||
|
* the container/source for each link.
|
||||||
|
* - metadata-index is used for indices containing metadata
|
||||||
|
* extracted from fields (namely, the bug index & todo index).
|
||||||
|
*/
|
||||||
|
table.link-index { border-collapse: collapse;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #808080; }
|
||||||
|
td.link-index { border-width: 0px; }
|
||||||
|
table.link-index a:link { color: #000000; }
|
||||||
|
table.link-index a:visited { color: #404040; }
|
||||||
|
span.index-where { font-size: 70%; }
|
||||||
|
table.metadata-index { border-collapse: collapse;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #808080;
|
||||||
|
margin: .2em 0 0 0; }
|
||||||
|
td.metadata-index { border-width: 1px; border-style: solid; }
|
||||||
|
table.metadata-index a:link { color: #000000; }
|
||||||
|
table.metadata-index a:visited { color: #404040; }
|
||||||
|
|
||||||
|
/* Function signatures
|
||||||
|
* - sig* is used for the signature in the details section.
|
||||||
|
* - .summary-sig* is used for the signature in the summary
|
||||||
|
* table, and when listing property accessor functions.
|
||||||
|
* */
|
||||||
|
.sig-name { color: #606060; }
|
||||||
|
.sig-arg { color: #808080; }
|
||||||
|
.sig-default { color: #202020; }
|
||||||
|
.summary-sig { font-family: monospace; }
|
||||||
|
.summary-sig-name { color: #606060; font-weight: bold; }
|
||||||
|
table.summary a.summary-sig-name:link
|
||||||
|
{ color: #606060; font-weight: bold; }
|
||||||
|
table.summary a.summary-sig-name:visited
|
||||||
|
{ color: #606060; font-weight: bold; }
|
||||||
|
.summary-sig-arg { color: #606060; }
|
||||||
|
.summary-sig-default { color: #181818; }
|
||||||
|
|
||||||
|
/* Subclass list
|
||||||
|
*/
|
||||||
|
ul.subclass-list { display: inline; }
|
||||||
|
ul.subclass-list li { display: inline; }
|
||||||
|
|
||||||
|
/* To render variables, classes etc. like functions */
|
||||||
|
table.summary .summary-name { color: #606060; font-weight: bold;
|
||||||
|
font-family: monospace; }
|
||||||
|
table.summary
|
||||||
|
a.summary-name:link { color: #606060; font-weight: bold;
|
||||||
|
font-family: monospace; }
|
||||||
|
table.summary
|
||||||
|
a.summary-name:visited { color: #606060; font-weight: bold;
|
||||||
|
font-family: monospace; }
|
||||||
|
|
||||||
|
/* Variable values
|
||||||
|
* - In the 'variable details' sections, each varaible's value is
|
||||||
|
* listed in a 'pre.variable' box. The width of this box is
|
||||||
|
* restricted to 80 chars; if the value's repr is longer than
|
||||||
|
* this it will be wrapped, using a backslash marked with
|
||||||
|
* class 'variable-linewrap'. If the value's repr is longer
|
||||||
|
* than 3 lines, the rest will be ellided; and an ellipsis
|
||||||
|
* marker ('...' marked with 'variable-ellipsis') will be used.
|
||||||
|
* - If the value is a string, its quote marks will be marked
|
||||||
|
* with 'variable-quote'.
|
||||||
|
* - If the variable is a regexp, it is syntax-highlighted using
|
||||||
|
* the re* CSS classes.
|
||||||
|
*/
|
||||||
|
pre.variable { padding: .5em; margin: 0;
|
||||||
|
background: #e4e4e4; color: #000000;
|
||||||
|
border: 1px solid #888888; }
|
||||||
|
.variable-linewrap { color: #404040; font-weight: bold; }
|
||||||
|
.variable-ellipsis { color: #404040; font-weight: bold; }
|
||||||
|
.variable-quote { color: #404040; font-weight: bold; }
|
||||||
|
.variable-group { color: #808080; font-weight: bold; }
|
||||||
|
.variable-op { color: #404040; font-weight: bold; }
|
||||||
|
.variable-string { color: #606060; }
|
||||||
|
.variable-unknown { color: #000000; font-weight: bold; }
|
||||||
|
.re { color: #000000; }
|
||||||
|
.re-char { color: #606060; }
|
||||||
|
.re-op { color: #000000; }
|
||||||
|
.re-group { color: #303030; }
|
||||||
|
.re-ref { color: #404040; }
|
||||||
|
|
||||||
|
/* Base tree
|
||||||
|
* - Used by class pages to display the base class hierarchy.
|
||||||
|
*/
|
||||||
|
pre.base-tree { font-size: 80%; margin: 0; }
|
||||||
|
|
||||||
|
/* Frames-based table of contents headers
|
||||||
|
* - Consists of two frames: one for selecting modules; and
|
||||||
|
* the other listing the contents of the selected module.
|
||||||
|
* - h1.toc is used for each frame's heading
|
||||||
|
* - h2.toc is used for subheadings within each frame.
|
||||||
|
*/
|
||||||
|
h1.toc { text-align: center; font-size: 105%;
|
||||||
|
margin: 0; font-weight: bold;
|
||||||
|
padding: 0; }
|
||||||
|
h2.toc { font-size: 100%; font-weight: bold;
|
||||||
|
margin: 0.5em 0 0 -0.3em; }
|
||||||
|
|
||||||
|
/* Syntax Highlighting for Source Code
|
||||||
|
* - doctest examples are displayed in a 'pre.py-doctest' block.
|
||||||
|
* If the example is in a details table entry, then it will use
|
||||||
|
* the colors specified by the 'table pre.py-doctest' line.
|
||||||
|
* - Source code listings are displayed in a 'pre.py-src' block.
|
||||||
|
* Each line is marked with 'span.py-line' (used to draw a line
|
||||||
|
* down the left margin, separating the code from the line
|
||||||
|
* numbers). Line numbers are displayed with 'span.py-lineno'.
|
||||||
|
* The expand/collapse block toggle button is displayed with
|
||||||
|
* 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not
|
||||||
|
* modify the font size of the text.)
|
||||||
|
* - If a source code page is opened with an anchor, then the
|
||||||
|
* corresponding code block will be highlighted. The code
|
||||||
|
* block's header is highlighted with 'py-highlight-hdr'; and
|
||||||
|
* the code block's body is highlighted with 'py-highlight'.
|
||||||
|
* - The remaining py-* classes are used to perform syntax
|
||||||
|
* highlighting (py-string for string literals, py-name for names,
|
||||||
|
* etc.)
|
||||||
|
*/
|
||||||
|
pre.py-doctest { padding: .5em; margin: 1em;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #888888; }
|
||||||
|
table pre.py-doctest { background: #e4e4e4;
|
||||||
|
color: #000000; }
|
||||||
|
pre.py-src { border: 2px solid #000000;
|
||||||
|
background: #f0f0f0; color: #000000; }
|
||||||
|
.py-line { border-left: 2px solid #000000;
|
||||||
|
margin-left: .2em; padding-left: .4em; }
|
||||||
|
.py-lineno { font-style: italic; font-size: 90%;
|
||||||
|
padding-left: .5em; }
|
||||||
|
a.py-toggle { text-decoration: none; }
|
||||||
|
div.py-highlight-hdr { border-top: 2px solid #000000;
|
||||||
|
border-bottom: 2px solid #000000;
|
||||||
|
background: #e8e8e8; }
|
||||||
|
div.py-highlight { border-bottom: 2px solid #000000;
|
||||||
|
background: #e0e0e0; }
|
||||||
|
.py-prompt { color: #505050; font-weight: bold;}
|
||||||
|
.py-more { color: #505050; font-weight: bold;}
|
||||||
|
.py-string { color: #606060; }
|
||||||
|
.py-comment { color: #303030; }
|
||||||
|
.py-keyword { color: #000000; }
|
||||||
|
.py-output { color: #404040; }
|
||||||
|
.py-name { color: #000000; }
|
||||||
|
.py-name:link { color: #000000 !important; }
|
||||||
|
.py-name:visited { color: #000000 !important; }
|
||||||
|
.py-number { color: #505050; }
|
||||||
|
.py-defname { color: #000000; font-weight: bold; }
|
||||||
|
.py-def-name { color: #000000; font-weight: bold; }
|
||||||
|
.py-base-class { color: #000000; }
|
||||||
|
.py-param { color: #000000; }
|
||||||
|
.py-docstring { color: #606060; }
|
||||||
|
.py-decorator { color: #404040; }
|
||||||
|
/* Use this if you don't want links to names underlined: */
|
||||||
|
/*a.py-name { text-decoration: none; }*/
|
||||||
|
|
||||||
|
/* Graphs & Diagrams
|
||||||
|
* - These CSS styles are used for graphs & diagrams generated using
|
||||||
|
* Graphviz dot. 'img.graph-without-title' is used for bare
|
||||||
|
* diagrams (to remove the border created by making the image
|
||||||
|
* clickable).
|
||||||
|
*/
|
||||||
|
img.graph-without-title { border: none; }
|
||||||
|
img.graph-with-title { border: 1px solid #000000; }
|
||||||
|
span.graph-title { font-weight: bold; }
|
||||||
|
span.graph-caption { }
|
||||||
|
|
||||||
|
/* General-purpose classes
|
||||||
|
* - 'p.indent-wrapped-lines' defines a paragraph whose first line
|
||||||
|
* is not indented, but whose subsequent lines are.
|
||||||
|
* - The 'nomargin-top' class is used to remove the top margin (e.g.
|
||||||
|
* from lists). The 'nomargin' class is used to remove both the
|
||||||
|
* top and bottom margin (but not the left or right margin --
|
||||||
|
* for lists, that would cause the bullets to disappear.)
|
||||||
|
*/
|
||||||
|
p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em;
|
||||||
|
margin: 0; }
|
||||||
|
.nomargin-top { margin-top: 0; }
|
||||||
|
.nomargin { margin-top: 0; margin-bottom: 0; }
|
||||||
|
|
||||||
|
/* HTML Log */
|
||||||
|
div.log-block { padding: 0; margin: .5em 0 .5em 0;
|
||||||
|
background: #f0f0f0; color: #000000;
|
||||||
|
border: 1px solid #000000; }
|
||||||
|
div.log-error { padding: .1em .3em .1em .3em; margin: 4px;
|
||||||
|
background: #b0b0b0; color: #000000;
|
||||||
|
border: 1px solid #000000; }
|
||||||
|
div.log-warning { padding: .1em .3em .1em .3em; margin: 4px;
|
||||||
|
background: #ffffff; color: #000000;
|
||||||
|
border: 1px solid #000000; }
|
||||||
|
div.log-info { padding: .1em .3em .1em .3em; margin: 4px;
|
||||||
|
background: #ffffff; color: #000000;
|
||||||
|
border: 1px solid #000000; }
|
||||||
|
h2.log-hdr { background: #b0b0b0; color: #000000;
|
||||||
|
margin: 0; padding: 0em 0.5em 0em 0.5em;
|
||||||
|
border-bottom: 1px solid #000000; font-size: 110%; }
|
||||||
|
p.log { font-weight: bold; margin: .5em 0 .5em 0; }
|
||||||
|
tr.opt-changed { color: #000000; font-weight: bold; }
|
||||||
|
tr.opt-default { color: #606060; }
|
||||||
|
pre.log { margin: 0; padding: 0; padding-left: 1em; }
|
|
@ -0,0 +1,293 @@
|
||||||
|
function toggle_private() {
|
||||||
|
// Search for any private/public links on this page. Store
|
||||||
|
// their old text in "cmd," so we will know what action to
|
||||||
|
// take; and change their text to the opposite action.
|
||||||
|
var cmd = "?";
|
||||||
|
var elts = document.getElementsByTagName("a");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "privatelink") {
|
||||||
|
cmd = elts[i].innerHTML;
|
||||||
|
elts[i].innerHTML = ((cmd && cmd.substr(0,4)=="show")?
|
||||||
|
"hide private":"show private");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update all DIVs containing private objects.
|
||||||
|
var elts = document.getElementsByTagName("div");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "private") {
|
||||||
|
elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"block");
|
||||||
|
}
|
||||||
|
else if (elts[i].className == "public") {
|
||||||
|
elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"block":"none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update all table rows containing private objects. Note, we
|
||||||
|
// use "" instead of "block" becaue IE & firefox disagree on what
|
||||||
|
// this should be (block vs table-row), and "" just gives the
|
||||||
|
// default for both browsers.
|
||||||
|
var elts = document.getElementsByTagName("tr");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "private") {
|
||||||
|
elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update all list items containing private objects.
|
||||||
|
var elts = document.getElementsByTagName("li");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "private") {
|
||||||
|
elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?
|
||||||
|
"none":"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update all list items containing private objects.
|
||||||
|
var elts = document.getElementsByTagName("ul");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "private") {
|
||||||
|
elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"block");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set a cookie to remember the current option.
|
||||||
|
document.cookie = "EpydocPrivate="+cmd;
|
||||||
|
}
|
||||||
|
function show_private() {
|
||||||
|
var elts = document.getElementsByTagName("a");
|
||||||
|
for(var i=0; i<elts.length; i++) {
|
||||||
|
if (elts[i].className == "privatelink") {
|
||||||
|
cmd = elts[i].innerHTML;
|
||||||
|
if (cmd && cmd.substr(0,4)=="show")
|
||||||
|
toggle_private();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getCookie(name) {
|
||||||
|
var dc = document.cookie;
|
||||||
|
var prefix = name + "=";
|
||||||
|
var begin = dc.indexOf("; " + prefix);
|
||||||
|
if (begin == -1) {
|
||||||
|
begin = dc.indexOf(prefix);
|
||||||
|
if (begin != 0) return null;
|
||||||
|
} else
|
||||||
|
{ begin += 2; }
|
||||||
|
var end = document.cookie.indexOf(";", begin);
|
||||||
|
if (end == -1)
|
||||||
|
{ end = dc.length; }
|
||||||
|
return unescape(dc.substring(begin + prefix.length, end));
|
||||||
|
}
|
||||||
|
function setFrame(url1, url2) {
|
||||||
|
parent.frames[1].location.href = url1;
|
||||||
|
parent.frames[2].location.href = url2;
|
||||||
|
}
|
||||||
|
function checkCookie() {
|
||||||
|
var cmd=getCookie("EpydocPrivate");
|
||||||
|
if (cmd && cmd.substr(0,4)!="show" && location.href.indexOf("#_") < 0)
|
||||||
|
toggle_private();
|
||||||
|
}
|
||||||
|
function toggleCallGraph(id) {
|
||||||
|
var elt = document.getElementById(id);
|
||||||
|
if (elt.style.display == "none")
|
||||||
|
elt.style.display = "block";
|
||||||
|
else
|
||||||
|
elt.style.display = "none";
|
||||||
|
}
|
||||||
|
function expand(id) {
|
||||||
|
var elt = document.getElementById(id+"-expanded");
|
||||||
|
if (elt) elt.style.display = "block";
|
||||||
|
var elt = document.getElementById(id+"-expanded-linenums");
|
||||||
|
if (elt) elt.style.display = "block";
|
||||||
|
var elt = document.getElementById(id+"-collapsed");
|
||||||
|
if (elt) { elt.innerHTML = ""; elt.style.display = "none"; }
|
||||||
|
var elt = document.getElementById(id+"-collapsed-linenums");
|
||||||
|
if (elt) { elt.innerHTML = ""; elt.style.display = "none"; }
|
||||||
|
var elt = document.getElementById(id+"-toggle");
|
||||||
|
if (elt) { elt.innerHTML = "-"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapse(id) {
|
||||||
|
var elt = document.getElementById(id+"-expanded");
|
||||||
|
if (elt) elt.style.display = "none";
|
||||||
|
var elt = document.getElementById(id+"-expanded-linenums");
|
||||||
|
if (elt) elt.style.display = "none";
|
||||||
|
var elt = document.getElementById(id+"-collapsed-linenums");
|
||||||
|
if (elt) { elt.innerHTML = "<br />"; elt.style.display="block"; }
|
||||||
|
var elt = document.getElementById(id+"-toggle");
|
||||||
|
if (elt) { elt.innerHTML = "+"; }
|
||||||
|
var elt = document.getElementById(id+"-collapsed");
|
||||||
|
if (elt) {
|
||||||
|
elt.style.display = "block";
|
||||||
|
|
||||||
|
var indent = elt.getAttribute("indent");
|
||||||
|
var pad = elt.getAttribute("pad");
|
||||||
|
var s = "<tt class='py-lineno'>";
|
||||||
|
for (var i=0; i<pad.length; i++) { s += " " }
|
||||||
|
s += "</tt>";
|
||||||
|
s += " <tt class='py-line'>";
|
||||||
|
for (var i=0; i<indent.length; i++) { s += " " }
|
||||||
|
s += "<a href='#' onclick='expand(\"" + id;
|
||||||
|
s += "\");return false'>...</a></tt><br />";
|
||||||
|
elt.innerHTML = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(id) {
|
||||||
|
elt = document.getElementById(id+"-toggle");
|
||||||
|
if (elt.innerHTML == "-")
|
||||||
|
collapse(id);
|
||||||
|
else
|
||||||
|
expand(id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlight(id) {
|
||||||
|
var elt = document.getElementById(id+"-def");
|
||||||
|
if (elt) elt.className = "py-highlight-hdr";
|
||||||
|
var elt = document.getElementById(id+"-expanded");
|
||||||
|
if (elt) elt.className = "py-highlight";
|
||||||
|
var elt = document.getElementById(id+"-collapsed");
|
||||||
|
if (elt) elt.className = "py-highlight";
|
||||||
|
}
|
||||||
|
|
||||||
|
function num_lines(s) {
|
||||||
|
var n = 1;
|
||||||
|
var pos = s.indexOf("\n");
|
||||||
|
while ( pos > 0) {
|
||||||
|
n += 1;
|
||||||
|
pos = s.indexOf("\n", pos+1);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse all blocks that mave more than `min_lines` lines.
|
||||||
|
function collapse_all(min_lines) {
|
||||||
|
var elts = document.getElementsByTagName("div");
|
||||||
|
for (var i=0; i<elts.length; i++) {
|
||||||
|
var elt = elts[i];
|
||||||
|
var split = elt.id.indexOf("-");
|
||||||
|
if (split > 0)
|
||||||
|
if (elt.id.substring(split, elt.id.length) == "-expanded")
|
||||||
|
if (num_lines(elt.innerHTML) > min_lines)
|
||||||
|
collapse(elt.id.substring(0, split));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandto(href) {
|
||||||
|
var start = href.indexOf("#")+1;
|
||||||
|
if (start != 0 && start != href.length) {
|
||||||
|
if (href.substring(start, href.length) != "-") {
|
||||||
|
collapse_all(4);
|
||||||
|
pos = href.indexOf(".", start);
|
||||||
|
while (pos != -1) {
|
||||||
|
var id = href.substring(start, pos);
|
||||||
|
expand(id);
|
||||||
|
pos = href.indexOf(".", pos+1);
|
||||||
|
}
|
||||||
|
var id = href.substring(start, href.length);
|
||||||
|
expand(id);
|
||||||
|
highlight(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function kill_doclink(id) {
|
||||||
|
var parent = document.getElementById(id);
|
||||||
|
parent.removeChild(parent.childNodes.item(0));
|
||||||
|
}
|
||||||
|
function auto_kill_doclink(ev) {
|
||||||
|
if (!ev) var ev = window.event;
|
||||||
|
if (!this.contains(ev.toElement)) {
|
||||||
|
var parent = document.getElementById(this.parentID);
|
||||||
|
parent.removeChild(parent.childNodes.item(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doclink(id, name, targets_id) {
|
||||||
|
var elt = document.getElementById(id);
|
||||||
|
|
||||||
|
// If we already opened the box, then destroy it.
|
||||||
|
// (This case should never occur, but leave it in just in case.)
|
||||||
|
if (elt.childNodes.length > 1) {
|
||||||
|
elt.removeChild(elt.childNodes.item(0));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The outer box: relative + inline positioning.
|
||||||
|
var box1 = document.createElement("div");
|
||||||
|
box1.style.position = "relative";
|
||||||
|
box1.style.display = "inline";
|
||||||
|
box1.style.top = 0;
|
||||||
|
box1.style.left = 0;
|
||||||
|
|
||||||
|
// A shadow for fun
|
||||||
|
var shadow = document.createElement("div");
|
||||||
|
shadow.style.position = "absolute";
|
||||||
|
shadow.style.left = "-1.3em";
|
||||||
|
shadow.style.top = "-1.3em";
|
||||||
|
shadow.style.background = "#404040";
|
||||||
|
|
||||||
|
// The inner box: absolute positioning.
|
||||||
|
var box2 = document.createElement("div");
|
||||||
|
box2.style.position = "relative";
|
||||||
|
box2.style.border = "1px solid #a0a0a0";
|
||||||
|
box2.style.left = "-.2em";
|
||||||
|
box2.style.top = "-.2em";
|
||||||
|
box2.style.background = "white";
|
||||||
|
box2.style.padding = ".3em .4em .3em .4em";
|
||||||
|
box2.style.fontStyle = "normal";
|
||||||
|
box2.onmouseout=auto_kill_doclink;
|
||||||
|
box2.parentID = id;
|
||||||
|
|
||||||
|
// Get the targets
|
||||||
|
var targets_elt = document.getElementById(targets_id);
|
||||||
|
var targets = targets_elt.getAttribute("targets");
|
||||||
|
var links = "";
|
||||||
|
target_list = targets.split(",");
|
||||||
|
for (var i=0; i<target_list.length; i++) {
|
||||||
|
var target = target_list[i].split("=");
|
||||||
|
links += "<li><a href='" + target[1] +
|
||||||
|
"' style='text-decoration:none'>" +
|
||||||
|
target[0] + "</a></li>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put it all together.
|
||||||
|
elt.insertBefore(box1, elt.childNodes.item(0));
|
||||||
|
//box1.appendChild(box2);
|
||||||
|
box1.appendChild(shadow);
|
||||||
|
shadow.appendChild(box2);
|
||||||
|
box2.innerHTML =
|
||||||
|
"Which <b>"+name+"</b> do you want to see documentation for?" +
|
||||||
|
"<ul style='margin-bottom: 0;'>" +
|
||||||
|
links +
|
||||||
|
"<li><a href='#' style='text-decoration:none' " +
|
||||||
|
"onclick='kill_doclink(\""+id+"\");return false;'>"+
|
||||||
|
"<i>None of the above</i></a></li></ul>";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_anchor() {
|
||||||
|
var href = location.href;
|
||||||
|
var start = href.indexOf("#")+1;
|
||||||
|
if ((start != 0) && (start != href.length))
|
||||||
|
return href.substring(start, href.length);
|
||||||
|
}
|
||||||
|
function redirect_url(dottedName) {
|
||||||
|
// Scan through each element of the "pages" list, and check
|
||||||
|
// if "name" matches with any of them.
|
||||||
|
for (var i=0; i<pages.length; i++) {
|
||||||
|
|
||||||
|
// Each page has the form "<pagename>-m" or "<pagename>-c";
|
||||||
|
// extract the <pagename> portion & compare it to dottedName.
|
||||||
|
var pagename = pages[i].substring(0, pages[i].length-2);
|
||||||
|
if (pagename == dottedName.substring(0,pagename.length)) {
|
||||||
|
|
||||||
|
// We've found a page that matches `dottedName`;
|
||||||
|
// construct its URL, using leftover `dottedName`
|
||||||
|
// content to form an anchor.
|
||||||
|
var pagetype = pages[i].charAt(pages[i].length-1);
|
||||||
|
var url = pagename + ((pagetype=="m")?"-module.html":
|
||||||
|
"-class.html");
|
||||||
|
if (dottedName.length > pagename.length)
|
||||||
|
url += "#" + dottedName.substring(pagename.length+1,
|
||||||
|
dottedName.length);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# unproudly borrowed from David Goodger's rst2html.py
|
||||||
|
|
||||||
|
"""
|
||||||
|
A minimal front end to the Docutils Publisher, producing HTML.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import locale
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from docutils.core import publish_cmdline, default_description
|
||||||
|
# ____________________________________________________________
|
||||||
|
from docutils import nodes, utils
|
||||||
|
from docutils.parsers.rst import roles
|
||||||
|
|
||||||
|
"""
|
||||||
|
description of the new roles:
|
||||||
|
|
||||||
|
`:api:` : link to the code
|
||||||
|
|
||||||
|
- code.py becomes api/code.html
|
||||||
|
- code.Code.code_test becomes api/code.Code.code_test.html
|
||||||
|
- code.Code() becomes api/code.Code.html
|
||||||
|
|
||||||
|
`:doc:`a link to an internal file
|
||||||
|
example become example.html
|
||||||
|
|
||||||
|
ref: link with anchor as in an external file
|
||||||
|
|
||||||
|
:ref:`toto#titi` becomes toto.html#titi
|
||||||
|
"""
|
||||||
|
from os.path import splitext
|
||||||
|
|
||||||
|
def api_reference_role(role, rawtext, text, lineno, inliner,
|
||||||
|
options={}, content=[]):
|
||||||
|
basename = text
|
||||||
|
if "(" in text:
|
||||||
|
basename = text.split("(")[0]
|
||||||
|
if ".py" in text:
|
||||||
|
basename = splitext(text)[0]
|
||||||
|
if "test_" in text:
|
||||||
|
refuri = "api/" + "tiramisu.test." + basename + '.html'
|
||||||
|
else:
|
||||||
|
refuri = "api/" + "tiramisu." + basename + '.html'
|
||||||
|
roles.set_classes(options)
|
||||||
|
node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
|
||||||
|
**options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
roles.register_local_role('api', api_reference_role)
|
||||||
|
|
||||||
|
def doc_reference_role(role, rawtext, text, lineno, inliner,
|
||||||
|
options={}, content=[]):
|
||||||
|
refuri = text + '.html'
|
||||||
|
roles.set_classes(options)
|
||||||
|
node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
|
||||||
|
**options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
roles.register_local_role('doc', doc_reference_role)
|
||||||
|
|
||||||
|
def ref_reference_role(role, rawtext, text, lineno, inliner,
|
||||||
|
options={}, content=[]):
|
||||||
|
fname, anchor = text.split('#')
|
||||||
|
refuri = fname + '.html#' + anchor
|
||||||
|
roles.set_classes(options)
|
||||||
|
node = nodes.reference(rawtext, utils.unescape(anchor), refuri=refuri,
|
||||||
|
**options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
roles.register_local_role('ref', ref_reference_role)
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
description = ('Generates (X)HTML documents from standalone reStructuredText '
|
||||||
|
'sources. ' + default_description)
|
||||||
|
|
||||||
|
publish_cmdline(writer_name='html', description=description)
|
||||||
|
|
|
@ -0,0 +1,181 @@
|
||||||
|
.. default-role:: literal
|
||||||
|
|
||||||
|
Configuration status
|
||||||
|
======================
|
||||||
|
|
||||||
|
:module: :api:`config.py`
|
||||||
|
:tests: - :api:`test_option_owner.py`
|
||||||
|
- :api:`test_option_type.py`
|
||||||
|
- :api:`test_option_default.py`
|
||||||
|
|
||||||
|
Available configuration statuses
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
These configuration statuses corresponds to specific global attributes :
|
||||||
|
|
||||||
|
**read write status**
|
||||||
|
|
||||||
|
The configuration can be accessed by `__get__` and `__set__`
|
||||||
|
properties, except for the `hidden` configuration options but, yes, it is
|
||||||
|
possible to modify a disabled option.
|
||||||
|
|
||||||
|
To enable read-write status, call
|
||||||
|
:api:`config.Config.cfgimpl_read_write()`
|
||||||
|
|
||||||
|
**read only status**
|
||||||
|
|
||||||
|
The whole configuration is `frozen`, that is modifiying a value is
|
||||||
|
forbidden. We can access to a configuration option only with the
|
||||||
|
`__getattr__` property.
|
||||||
|
|
||||||
|
The configuration has not an access to the hidden options
|
||||||
|
but can read the disabled options.
|
||||||
|
|
||||||
|
To enable read only status, call :api:`config.Config.cfgimpl_read_only()`
|
||||||
|
|
||||||
|
.. csv-table:: **Configuration's statuses summary**
|
||||||
|
:header: " ", "Hidden", "Disabled"
|
||||||
|
|
||||||
|
"read only status", `False`, `True`
|
||||||
|
"read-write status", `True`, `False`
|
||||||
|
|
||||||
|
Freezing a configuration
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
It is possible to *freeze* a single `Option` object with
|
||||||
|
:api:`option.Option.freeze()`. If you try to modify a frozen option, it
|
||||||
|
raises a `TypeError: trying to change a frozen option object`.
|
||||||
|
|
||||||
|
At the configuration level, :api:`config.Config.cfgimpl_freeze()` freeze
|
||||||
|
the whole configuration options.
|
||||||
|
|
||||||
|
- :api:`test_option_type.test_freeze_one_option()`
|
||||||
|
- :api:`test_option_type.test_frozen_value()`
|
||||||
|
- :api:`test_option_type.test_freeze()`
|
||||||
|
|
||||||
|
|
||||||
|
Restricted access to an `Option()`
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Configuration options access statuses are defined at configuration level
|
||||||
|
that corresponds to theses :api:`option.Option()`'s attribute:
|
||||||
|
|
||||||
|
**hidden**
|
||||||
|
|
||||||
|
This means that an option raises an `HiddenOptionError` if we try to access
|
||||||
|
the value of the option.
|
||||||
|
|
||||||
|
See `hide()` or `show()` in `Option()` that comes from
|
||||||
|
:api:`option.HiddenBaseType`
|
||||||
|
|
||||||
|
corresponding convenience API provided:
|
||||||
|
|
||||||
|
`hide()`:
|
||||||
|
set the `hidden` attribute to `True`
|
||||||
|
|
||||||
|
`show()`:
|
||||||
|
set the `hidden` attribute to `False`
|
||||||
|
|
||||||
|
**disabled**
|
||||||
|
|
||||||
|
This means that an option *doesn't exists* (doesn't say anything
|
||||||
|
much more thant an `AttibuteAccess` error)
|
||||||
|
|
||||||
|
See in :api:`option.DisabledBaseType` the origins of
|
||||||
|
`Option.enable()` or `Option.disable()`
|
||||||
|
|
||||||
|
corresponding convenience API provided:
|
||||||
|
|
||||||
|
`disable()`:
|
||||||
|
set the `disabled` attribute to `True`
|
||||||
|
|
||||||
|
`enable()`:
|
||||||
|
set the `disabled` attribute to `False`
|
||||||
|
|
||||||
|
mode
|
||||||
|
|
||||||
|
a mode is `normal` or `expert`, just a category of `Option()` or
|
||||||
|
group wich determines if an option is easy to choose or not,
|
||||||
|
available methods are:
|
||||||
|
|
||||||
|
`get_mode()`:
|
||||||
|
returns the current mode
|
||||||
|
|
||||||
|
`set_mode(mode)`:
|
||||||
|
sets a new mode
|
||||||
|
|
||||||
|
see it in :api:`option.ModeBaseType`
|
||||||
|
|
||||||
|
Value owners
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Every configuration option has a **owner**. When the option is
|
||||||
|
instanciated, the owner is `default` because a default value has been
|
||||||
|
set (including `None`, take a look at the tests).
|
||||||
|
|
||||||
|
The `value_owner` is the man who did it. Yes, the man who changed the value of the
|
||||||
|
configuration option.
|
||||||
|
|
||||||
|
- At the instance of the `Config` object, the value owner is `default` because
|
||||||
|
the default values are set at the instance of the configuration option object,
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# let's expect there is an option named 'name'
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
# the override method has been called
|
||||||
|
config._cfgimpl_value_owners['name'] == 'default'
|
||||||
|
|
||||||
|
- at the modification of an option, the owner is `default_owner`, (which is `user`)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# modification of the value by attribute access
|
||||||
|
config.gc.dummy = True
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
|
||||||
|
- the default owner can be set with the `set_owner()` method
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
config.set_owner('spam')
|
||||||
|
config.set(dummy=True)
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'spam'
|
||||||
|
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'spam'
|
||||||
|
|
||||||
|
Special owners
|
||||||
|
---------------
|
||||||
|
|
||||||
|
If the owner of a configuration option is `auto` or `fill` the behavior of the
|
||||||
|
access of the value changes. In fact, there is nothing in the value.
|
||||||
|
The value comes from somewhere else (typically, it is calculated by the
|
||||||
|
operation system).
|
||||||
|
|
||||||
|
**auto**
|
||||||
|
|
||||||
|
This means that it is a calculated value and therefore automatically
|
||||||
|
protected it cannot be modified by attribute access once the owner
|
||||||
|
is `auto`.
|
||||||
|
|
||||||
|
The configuration option is hidden and a fonction in a specific
|
||||||
|
library is called for the computation of the value.
|
||||||
|
|
||||||
|
**fill**
|
||||||
|
|
||||||
|
if the configuration option has a default value, the default is
|
||||||
|
returned, otherwise the value is calculated
|
||||||
|
|
||||||
|
The default values behavior
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Configuration options have default values that are stored in the
|
||||||
|
`Option()` object itself. Default values, the `default`, can be set in
|
||||||
|
various ways.
|
||||||
|
|
||||||
|
.. FIXME : ADD DETAILS HERE
|
||||||
|
|
||||||
|
If a default value is modified by overriding it, not only the value of
|
||||||
|
the option resets to the default that is proposed, but the owner is
|
||||||
|
modified too, it is reseted to `default`.
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
:date: 17 avril
|
||||||
|
|
||||||
|
- lever une exception parlante (pour l'instant, c'est une "KeyError")
|
||||||
|
lorsqu'on essaye d'affecter quelque chose
|
||||||
|
à un groupe, genre
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
cfg = Config(descr)
|
||||||
|
cfg.gc = "uvw"
|
||||||
|
|
||||||
|
alors que gc est un groupe
|
||||||
|
|
||||||
|
:date: 12 avril
|
||||||
|
|
||||||
|
- faire un mode dégradé avec des warnings
|
||||||
|
- validations de longueur des maitres/esclaves ailleurs à sortir des requires
|
||||||
|
et à mettre dans des validators
|
||||||
|
|
||||||
|
:date: 3 avril 2012
|
||||||
|
|
||||||
|
- hide sur les sous-sous groupe : il faut que ça hide **tout** les sous-groupe
|
||||||
|
récursivement
|
||||||
|
|
||||||
|
groupes `master/slaves`:
|
||||||
|
|
||||||
|
faut-il coder les multi avec des requires, ou bien simplement
|
||||||
|
un groupe avec comme variable le nom du groupe ?
|
||||||
|
|
||||||
|
auto, fill, obligatoire
|
||||||
|
|
||||||
|
2012-03-22
|
||||||
|
|
||||||
|
**groupe master**
|
||||||
|
|
||||||
|
faire une api du genre : `Option().is_master()`
|
||||||
|
pour cela, tester `if self.parent._name == self._name: return True`
|
||||||
|
|
||||||
|
- mettre un attribut `auto` aux options de configuration, de manière à
|
||||||
|
ce qu'elles sachent quelle fonction eos appeler (que ça soit une info
|
||||||
|
dans l'option ou bien au niveau de la config ?)
|
||||||
|
le fait de détecter un "auto" vient du owner, mais il faut savoir
|
||||||
|
quelle fonction appeler
|
||||||
|
|
||||||
|
A documenter
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- les variables multiples
|
||||||
|
- expliquer les urls du json dans la doc
|
||||||
|
- documenter le typage des options descriptions descr_type
|
||||||
|
|
||||||
|
A ajouter
|
||||||
|
---------
|
||||||
|
|
||||||
|
Option -> attribut help (en plus de doc)
|
||||||
|
get_help() (à mettre en class Type avec Doc aussi)
|
||||||
|
|
||||||
|
separator -> pas pour l'instant
|
||||||
|
|
||||||
|
fill, auto, obligatoire
|
||||||
|
|
||||||
|
nouveau type :
|
||||||
|
|
||||||
|
type option (dérivé de ChoiceOPtion) dans lequel il y a des nouvelles valeurs
|
||||||
|
possibles (pas de validations) ou plutôt une StringOption qui propose un choix
|
||||||
|
de valeurs par défault de type liste.
|
||||||
|
|
||||||
|
|
||||||
|
:date: 24 mars
|
||||||
|
|
||||||
|
- hide pour les sous-sous config (récursivement) et pas seulement une
|
||||||
|
seule sous-config (ou bien, quelque chose de réglable)
|
||||||
|
|
||||||
|
- validate global : vérifier à l'init de la conf qu'une variable
|
||||||
|
n'existe pas déjà, etc
|
||||||
|
|
||||||
|
:date: 26 janvier
|
||||||
|
|
||||||
|
- un attribut eosfunc pour auto + les paramètres à donner à la fonction
|
||||||
|
pareil pour le fill (function et paramètres)
|
||||||
|
|
||||||
|
reset
|
||||||
|
-------
|
||||||
|
|
||||||
|
**à discuter** : ça correspond exactement au override,
|
||||||
|
ou bien au opt.setoption(None, 'default')
|
||||||
|
|
||||||
|
**si la valeur par défaut est définie, un __get__ ne pourra jamais
|
||||||
|
renvoyer None.** ce qui est bloquant. Il faut pouvoir revenir à None.
|
||||||
|
|
||||||
|
pour supprimer la valeur d'une options (et revenir à la valeur par défault)
|
||||||
|
cfg.reset() (supprime _cfgimpl_value[name]) et _cfgimpl_value_owner[name])
|
||||||
|
|
||||||
|
reset()
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
class AmbigousOptionError(Exception):
|
||||||
|
pass
|
||||||
|
class NoMatchingOptionFound(AttributeError):
|
||||||
|
pass
|
||||||
|
class ConfigError(Exception):
|
||||||
|
pass
|
||||||
|
class ConflictConfigError(ConfigError):
|
||||||
|
pass
|
||||||
|
class HiddenOptionError(AttributeError):
|
||||||
|
pass
|
||||||
|
class DisabledOptionError(AttributeError):
|
||||||
|
pass
|
||||||
|
class NotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
class MethodCallError(Exception):
|
||||||
|
pass
|
||||||
|
class RequiresError(Exception):
|
||||||
|
pass
|
||||||
|
class MandatoryError(Exception):
|
||||||
|
pass
|
||||||
|
class SpecialOwnersError(Exception):
|
||||||
|
pass
|
||||||
|
class ModeOptionError(Exception):
|
||||||
|
pass
|
||||||
|
|
|
@ -0,0 +1,482 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"pretty small and local configuration management tool"
|
||||||
|
from error import (ConfigError, ConflictConfigError, NotFoundError,
|
||||||
|
RequiresError)
|
||||||
|
available_actions = ['hide', 'show', 'enable', 'disable']
|
||||||
|
reverse_actions = {'hide': 'show', 'show': 'hide',
|
||||||
|
'disable':'enable', 'enable': 'disable'}
|
||||||
|
# ____________________________________________________________
|
||||||
|
# OptionDescription authorized group_type values
|
||||||
|
group_types = ['default', 'family', 'group', 'master']
|
||||||
|
# Option and OptionDescription modes
|
||||||
|
modes = ['normal', 'expert']
|
||||||
|
# ____________________________________________________________
|
||||||
|
# interfaces
|
||||||
|
class HiddenBaseType(object):
|
||||||
|
hidden = False
|
||||||
|
def hide(self):
|
||||||
|
self.hidden = True
|
||||||
|
def show(self):
|
||||||
|
self.hidden = False
|
||||||
|
def _is_hidden(self):
|
||||||
|
# dangerous method: how an Option can determine its status by itself ?
|
||||||
|
return self.hidden
|
||||||
|
|
||||||
|
class DisabledBaseType(object):
|
||||||
|
disabled = False
|
||||||
|
def disable(self):
|
||||||
|
self.disabled = True
|
||||||
|
def enable(self):
|
||||||
|
self.disabled = False
|
||||||
|
def _is_disabled(self):
|
||||||
|
return self.disabled
|
||||||
|
|
||||||
|
class ModeBaseType(object):
|
||||||
|
mode = 'normal'
|
||||||
|
def get_mode(self):
|
||||||
|
return self.mode
|
||||||
|
def set_mode(self, mode):
|
||||||
|
if mode not in modes:
|
||||||
|
raise TypeError("Unknown mode: {0}".format(mode))
|
||||||
|
self.mode = mode
|
||||||
|
# ____________________________________________________________
|
||||||
|
class Option(HiddenBaseType, DisabledBaseType, ModeBaseType):
|
||||||
|
#reminder: an Option object is **not** a container for the value
|
||||||
|
_frozen = False
|
||||||
|
def __init__(self, name, doc, default=None, requires=None,
|
||||||
|
mandatory=False, multi=False, callback=None, mode='normal'):
|
||||||
|
self._name = name
|
||||||
|
self.doc = doc
|
||||||
|
self._requires = requires
|
||||||
|
self._mandatory = mandatory
|
||||||
|
self.multi = multi
|
||||||
|
self.callback = callback
|
||||||
|
if mode not in modes:
|
||||||
|
raise ConfigError("mode {0} not available".format(mode))
|
||||||
|
self.mode = mode
|
||||||
|
if default != None:
|
||||||
|
if not self.validate(default):
|
||||||
|
raise ConfigError("invalid default value {0} "
|
||||||
|
"for option {1}".format(default, name))
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
raise NotImplementedError('abstract base class')
|
||||||
|
|
||||||
|
def getdefault(self):
|
||||||
|
return self.default
|
||||||
|
|
||||||
|
def getdoc(self):
|
||||||
|
return self.doc
|
||||||
|
|
||||||
|
def getcallback(self):
|
||||||
|
return self.callback
|
||||||
|
|
||||||
|
def setowner(self, config, who):
|
||||||
|
name = self._name
|
||||||
|
if self._frozen:
|
||||||
|
raise TypeError("trying to change a frozen option's owner: %s" % name)
|
||||||
|
if who in ['auto', 'fill']: # XXX special_owners to be imported from config
|
||||||
|
if self.callback == None:
|
||||||
|
raise SpecialOwnersError("no callback specified for"
|
||||||
|
"option {0}".format(name))
|
||||||
|
config._cfgimpl_value_owners[name] = who
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
name = self._name
|
||||||
|
if self._frozen:
|
||||||
|
raise TypeError('trying to change a frozen option object: %s' % name)
|
||||||
|
# we want the possibility to reset everything
|
||||||
|
if who == "default" and value is None:
|
||||||
|
self.default = None
|
||||||
|
return
|
||||||
|
if not self.validate(value):
|
||||||
|
raise ConfigError('invalid value %s for option %s' % (value, name))
|
||||||
|
if who == "default":
|
||||||
|
# changes the default value (and therefore resets the previous value)
|
||||||
|
self.default = value
|
||||||
|
apply_requires(self, config)
|
||||||
|
# FIXME put the validation for the multi somewhere else
|
||||||
|
# # it is a multi **and** it has requires
|
||||||
|
# if self.multi == True:
|
||||||
|
# if type(value) != list:
|
||||||
|
# raise TypeError("value {0} must be a list".format(value))
|
||||||
|
# if self._requires is not None:
|
||||||
|
# for reqname in self._requires:
|
||||||
|
# # FIXME : verify that the slaves are all multi
|
||||||
|
# #option = getattr(config._cfgimpl_descr, reqname)
|
||||||
|
# # if not option.multi == True:
|
||||||
|
# # raise ConflictConfigError("an option with requires "
|
||||||
|
# # "has to be a list type : {0}".format(name))
|
||||||
|
# if len(config._cfgimpl_values[reqname]) != len(value):
|
||||||
|
# raise ConflictConfigError("an option with requires "
|
||||||
|
# "has not the same length of the others "
|
||||||
|
# "in the group : {0}".format(reqname))
|
||||||
|
config._cfgimpl_previous_values[name] = config._cfgimpl_values[name]
|
||||||
|
config._cfgimpl_values[name] = value
|
||||||
|
|
||||||
|
def getkey(self, value):
|
||||||
|
return value
|
||||||
|
|
||||||
|
def freeze(self):
|
||||||
|
self._frozen = True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def unfreeze(self):
|
||||||
|
self._frozen = False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def is_multi(self):
|
||||||
|
return self.multi
|
||||||
|
|
||||||
|
def is_mandatory(self):
|
||||||
|
return self._mandatory
|
||||||
|
|
||||||
|
class ChoiceOption(Option):
|
||||||
|
opt_type = 'string'
|
||||||
|
|
||||||
|
def __init__(self, name, doc, values, default=None, requires=None,
|
||||||
|
multi=False, mandatory=False):
|
||||||
|
self.values = values
|
||||||
|
super(ChoiceOption, self).__init__(name, doc, default=default,
|
||||||
|
requires=requires, multi=multi, mandatory=mandatory)
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
name = self._name
|
||||||
|
super(ChoiceOption, self).setoption(config, value, who)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if self.multi == False:
|
||||||
|
return value is None or value in self.values
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
if not (val is None or val in self.values):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
class BoolOption(Option):
|
||||||
|
opt_type = 'bool'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(BoolOption, self).__init__(*args, **kwargs)
|
||||||
|
# def __init__(self, name, doc, default=None, requires=None,
|
||||||
|
# validator=None, multi=False, mandatory=False):
|
||||||
|
# super(BoolOption, self).__init__(name, doc, default=default,
|
||||||
|
# requires=requires, multi=multi, mandatory=mandatory)
|
||||||
|
#self._validator = validator
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if self.multi == False:
|
||||||
|
return isinstance(value, bool)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
for val in value:
|
||||||
|
if not isinstance(val, bool):
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
# FIXME config level validator
|
||||||
|
# def setoption(self, config, value, who):
|
||||||
|
# name = self._name
|
||||||
|
# if value and self._validator is not None:
|
||||||
|
# toplevel = config._cfgimpl_get_toplevel()
|
||||||
|
# self._validator(toplevel)
|
||||||
|
# super(BoolOption, self).setoption(config, value, who)
|
||||||
|
|
||||||
|
class IntOption(Option):
|
||||||
|
opt_type = 'int'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(IntOption, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if self.multi == False:
|
||||||
|
try:
|
||||||
|
int(value)
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
try:
|
||||||
|
int(val)
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
super(IntOption, self).setoption(config, value, who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class FloatOption(Option):
|
||||||
|
opt_type = 'float'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(FloatOption, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if self.multi == False:
|
||||||
|
try:
|
||||||
|
float(value)
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
try:
|
||||||
|
float(val)
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
super(FloatOption, self).setoption(config, float(value), who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class StrOption(Option):
|
||||||
|
opt_type = 'string'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(StrOption, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
if self.multi == False:
|
||||||
|
return isinstance(value, str)
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
if not isinstance(val, str):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
super(StrOption, self).setoption(config, value, who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class SymLinkOption(object): #(HiddenBaseType, DisabledBaseType):
|
||||||
|
opt_type = 'symlink'
|
||||||
|
|
||||||
|
def __init__(self, name, path):
|
||||||
|
self._name = name
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
setattr(config, self.path, value) # .setoption(self.path, value, who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class IPOption(Option):
|
||||||
|
opt_type = 'ip'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(IPOption, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
# by now the validation is nothing but a string, use IPy instead
|
||||||
|
if self.multi == False:
|
||||||
|
return isinstance(value, str)
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
if not isinstance(val, str):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
super(IPOption, self).setoption(config, value, who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class NetmaskOption(Option):
|
||||||
|
opt_type = 'netmask'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(NetmaskOption, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
# by now the validation is nothing but a string, use IPy instead
|
||||||
|
if self.multi == False:
|
||||||
|
return isinstance(value, str)
|
||||||
|
else:
|
||||||
|
for val in value:
|
||||||
|
if not isinstance(val, str):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def setoption(self, config, value, who):
|
||||||
|
try:
|
||||||
|
super(NetmaskOption, self).setoption(config, value, who)
|
||||||
|
except TypeError, e:
|
||||||
|
raise ConfigError(*e.args)
|
||||||
|
|
||||||
|
class ArbitraryOption(Option):
|
||||||
|
def __init__(self, name, doc, default=None, defaultfactory=None,
|
||||||
|
requires=None, multi=False, mandatory=False):
|
||||||
|
super(ArbitraryOption, self).__init__(name, doc, requires=requires,
|
||||||
|
multi=multi, mandatory=mandatory)
|
||||||
|
self.defaultfactory = defaultfactory
|
||||||
|
if defaultfactory is not None:
|
||||||
|
assert default is None
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getdefault(self):
|
||||||
|
if self.defaultfactory is not None:
|
||||||
|
return self.defaultfactory()
|
||||||
|
return self.default
|
||||||
|
|
||||||
|
class OptionDescription(HiddenBaseType, DisabledBaseType, ModeBaseType):
|
||||||
|
group_type = 'default'
|
||||||
|
|
||||||
|
def __init__(self, name, doc, children, requires=None):
|
||||||
|
self._name = name
|
||||||
|
self.doc = doc
|
||||||
|
self._children = children
|
||||||
|
self._requires = requires
|
||||||
|
self._build()
|
||||||
|
|
||||||
|
def getdoc(self):
|
||||||
|
return self.doc
|
||||||
|
|
||||||
|
def _build(self):
|
||||||
|
for child in self._children:
|
||||||
|
setattr(self, child._name, child)
|
||||||
|
|
||||||
|
def add_child(self, child):
|
||||||
|
"dynamically adds a configuration option"
|
||||||
|
#Nothing is static. Even the Mona Lisa is falling apart.
|
||||||
|
for ch in self._children:
|
||||||
|
if isinstance(ch, Option):
|
||||||
|
if child._name == ch._name:
|
||||||
|
raise ConflictConfigError("existing option : {0}".format(
|
||||||
|
child._name))
|
||||||
|
self._children.append(child)
|
||||||
|
setattr(self, child._name, child)
|
||||||
|
|
||||||
|
def update_child(self, child):
|
||||||
|
"modification of an existing option"
|
||||||
|
# XXX : corresponds to the `redefine`, is it usefull
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getkey(self, config):
|
||||||
|
return tuple([child.getkey(getattr(config, child._name))
|
||||||
|
for child in self._children])
|
||||||
|
|
||||||
|
def getpaths(self, include_groups=False, currpath=None):
|
||||||
|
"""returns a list of all paths in self, recursively
|
||||||
|
currpath should not be provided (helps with recursion)
|
||||||
|
"""
|
||||||
|
if currpath is None:
|
||||||
|
currpath = []
|
||||||
|
paths = []
|
||||||
|
for option in self._children:
|
||||||
|
attr = option._name
|
||||||
|
if attr.startswith('_cfgimpl'):
|
||||||
|
continue
|
||||||
|
value = getattr(self, attr)
|
||||||
|
if isinstance(value, OptionDescription):
|
||||||
|
if include_groups:
|
||||||
|
paths.append('.'.join(currpath + [attr]))
|
||||||
|
currpath.append(attr)
|
||||||
|
paths += value.getpaths(include_groups=include_groups,
|
||||||
|
currpath=currpath)
|
||||||
|
currpath.pop()
|
||||||
|
else:
|
||||||
|
paths.append('.'.join(currpath + [attr]))
|
||||||
|
return paths
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def set_group_type(self, group_type):
|
||||||
|
if group_type in group_types:
|
||||||
|
self.group_type = group_type
|
||||||
|
else:
|
||||||
|
raise ConfigError('not allowed value for group_type : {0}'.format(
|
||||||
|
group_type))
|
||||||
|
|
||||||
|
def get_group_type(self):
|
||||||
|
return self.group_type
|
||||||
|
# ____________________________________________________________
|
||||||
|
def hide(self):
|
||||||
|
super(OptionDescription, self).hide()
|
||||||
|
# FIXME : AND THE SUBCHILDREN ?
|
||||||
|
for child in self._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
child.hide()
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
# FIXME : AND THE SUBCHILDREN ??
|
||||||
|
super(OptionDescription, self).show()
|
||||||
|
for child in self._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
child.show()
|
||||||
|
# ____________________________________________________________
|
||||||
|
def disable(self):
|
||||||
|
super(OptionDescription, self).disable()
|
||||||
|
# FIXME : AND THE SUBCHILDREN ?
|
||||||
|
for child in self._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
child.disable()
|
||||||
|
|
||||||
|
def enable(self):
|
||||||
|
# FIXME : AND THE SUBCHILDREN ?
|
||||||
|
super(OptionDescription, self).enable()
|
||||||
|
for child in self._children:
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
child.enable()
|
||||||
|
# ____________________________________________________________
|
||||||
|
def apply_requires(opt, config):
|
||||||
|
if hasattr(opt, '_requires'):
|
||||||
|
if opt._requires is not None:
|
||||||
|
# malformed requirements
|
||||||
|
rootconfig = config._cfgimpl_get_toplevel()
|
||||||
|
for req in opt._requires:
|
||||||
|
if not type(req) == tuple and len(req) in (3, 4):
|
||||||
|
raise RequiresError("malformed requirements for option:"
|
||||||
|
" {0}".format(opt._name))
|
||||||
|
# all actions **must** be identical
|
||||||
|
actions = [req[2] for req in opt._requires]
|
||||||
|
action = actions[0]
|
||||||
|
for act in actions:
|
||||||
|
if act != action:
|
||||||
|
raise RequiresError("malformed requirements for option:"
|
||||||
|
" {0}".format(opt._name))
|
||||||
|
# filters the callbacks
|
||||||
|
matches = False
|
||||||
|
for req in opt._requires:
|
||||||
|
if len(req) == 3:
|
||||||
|
name, expected, action = req
|
||||||
|
inverted = False
|
||||||
|
if len(req) == 4:
|
||||||
|
name, expected, action, inverted = req
|
||||||
|
if inverted == 'inverted':
|
||||||
|
inverted = True
|
||||||
|
homeconfig, shortname = \
|
||||||
|
rootconfig._cfgimpl_get_home_by_path(name)
|
||||||
|
# FIXME: doesn't work with 'auto' or 'fill' yet
|
||||||
|
# (copy the code from the __getattr__
|
||||||
|
if shortname in homeconfig._cfgimpl_values:
|
||||||
|
value = homeconfig._cfgimpl_values[shortname]
|
||||||
|
if (not inverted and value == expected) or \
|
||||||
|
(inverted and value != expected):
|
||||||
|
if action not in available_actions:
|
||||||
|
raise RequiresError("malformed requirements"
|
||||||
|
" for option: {0}".format(opt._name))
|
||||||
|
getattr(opt, action)() #.hide() or show() or...
|
||||||
|
matches = True
|
||||||
|
else: # option doesn't exist ! should not happen...
|
||||||
|
raise NotFoundError("required option not found: "
|
||||||
|
"{0}".format(name))
|
||||||
|
# no callback has been triggered, then just reverse the action
|
||||||
|
if not matches:
|
||||||
|
getattr(opt, reverse_actions[action])()
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: html
|
||||||
|
|
||||||
|
generate:
|
||||||
|
python ./generate.py
|
||||||
|
|
||||||
|
html: generate
|
||||||
|
make -C ./build all
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C ./build clean
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
SRC=$(wildcard *.txt)
|
||||||
|
HTMLFRAGMENT=$(addsuffix .html, $(basename $(SRC)))
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: html
|
||||||
|
|
||||||
|
html: $(HTMLFRAGMENT)
|
||||||
|
|
||||||
|
%.html: %.txt
|
||||||
|
./rst2html.py --stylesheet ./style.css $< > $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.html
|
||||||
|
rm -f *.txt
|
||||||
|
|
|
@ -0,0 +1,540 @@
|
||||||
|
/*
|
||||||
|
* basic.css
|
||||||
|
* ~~~~~~~~~
|
||||||
|
*
|
||||||
|
* Sphinx stylesheet -- basic theme.
|
||||||
|
*
|
||||||
|
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||||
|
* :license: BSD, see LICENSE for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -- main layout ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.clearer {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- relbar ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.related {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related h3 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 10px;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related li.right {
|
||||||
|
float: right;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- sidebar --------------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.sphinxsidebarwrapper {
|
||||||
|
padding: 10px 5px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar {
|
||||||
|
float: left;
|
||||||
|
width: 230px;
|
||||||
|
margin-left: -100%;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul ul,
|
||||||
|
div.sphinxsidebar ul.want-points {
|
||||||
|
margin-left: 20px;
|
||||||
|
list-style: square;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar form {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input {
|
||||||
|
border: 1px solid #98dbcc;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type="text"] {
|
||||||
|
width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type="submit"] {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- search page ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
ul.search {
|
||||||
|
margin: 10px 0 0 20px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.search li {
|
||||||
|
padding: 5px 0 5px 20px;
|
||||||
|
background-image: url(file.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.search li a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.search li div.context {
|
||||||
|
color: #888;
|
||||||
|
margin: 2px 0 0 30px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.keywordmatches li.goodmatch a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- index page ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
table.contentstable {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.contentstable p.biglink {
|
||||||
|
line-height: 150%;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.biglink {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.linkdescr {
|
||||||
|
font-style: italic;
|
||||||
|
padding-top: 5px;
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- general index --------------------------------------------------------- */
|
||||||
|
|
||||||
|
table.indextable {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.indextable td {
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.indextable dl, table.indextable dd {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.indextable tr.pcap {
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.indextable tr.cap {
|
||||||
|
margin-top: 10px;
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.toggler {
|
||||||
|
margin-right: 3px;
|
||||||
|
margin-top: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.modindex-jumpbox {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
margin: 1em 0 1em 0;
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.genindex-jumpbox {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
margin: 1em 0 1em 0;
|
||||||
|
padding: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- general body styles --------------------------------------------------- */
|
||||||
|
|
||||||
|
a.headerlink {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:hover > a.headerlink,
|
||||||
|
h2:hover > a.headerlink,
|
||||||
|
h3:hover > a.headerlink,
|
||||||
|
h4:hover > a.headerlink,
|
||||||
|
h5:hover > a.headerlink,
|
||||||
|
h6:hover > a.headerlink,
|
||||||
|
dt:hover > a.headerlink {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body p.caption {
|
||||||
|
text-align: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body td {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-list ul {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.first {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.rubric {
|
||||||
|
margin-top: 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.align-left, .figure.align-left, object.align-left {
|
||||||
|
clear: left;
|
||||||
|
float: left;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.align-right, .figure.align-right, object.align-right {
|
||||||
|
clear: right;
|
||||||
|
float: right;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.align-center, .figure.align-center, object.align-center {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- sidebars -------------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.sidebar {
|
||||||
|
margin: 0 0 0.5em 1em;
|
||||||
|
border: 1px solid #ddb;
|
||||||
|
padding: 7px 7px 0 7px;
|
||||||
|
background-color: #ffe;
|
||||||
|
width: 40%;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sidebar-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- topics ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 7px 7px 0 7px;
|
||||||
|
margin: 10px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.topic-title {
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- admonitions ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.admonition {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition dt {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition dl {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title {
|
||||||
|
margin: 0px 10px 5px 0px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body p.centered {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- tables ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
table.docutils {
|
||||||
|
border: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.docutils td, table.docutils th {
|
||||||
|
padding: 1px 8px 1px 5px;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
border-bottom: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.field-list td, table.field-list th {
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.footnote td, table.footnote th {
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.citation {
|
||||||
|
border-left: solid 1px gray;
|
||||||
|
margin-left: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.citation td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- other body styles ----------------------------------------------------- */
|
||||||
|
|
||||||
|
ol.arabic {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol.loweralpha {
|
||||||
|
list-style: lower-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol.upperalpha {
|
||||||
|
list-style: upper-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol.lowerroman {
|
||||||
|
list-style: lower-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol.upperroman {
|
||||||
|
list-style: upper-roman;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd p {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd ul, dd table {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd {
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt:target, .highlighted {
|
||||||
|
background-color: #fbe54e;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl.glossary dt {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-list ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-list p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refcount {
|
||||||
|
color: #060;
|
||||||
|
}
|
||||||
|
|
||||||
|
.optional {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versionmodified {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-message {
|
||||||
|
background-color: #fda;
|
||||||
|
padding: 5px;
|
||||||
|
border: 3px solid red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footnote:target {
|
||||||
|
background-color: #ffa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-block {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-block .line-block {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guilabel, .menuselection {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accelerator {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.classifier {
|
||||||
|
font-style: oblique;
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr, acronym {
|
||||||
|
border-bottom: dotted 1px;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- code displays --------------------------------------------------------- */
|
||||||
|
|
||||||
|
pre {
|
||||||
|
overflow: auto;
|
||||||
|
overflow-y: hidden; /* fixes display issues on Chrome browsers */
|
||||||
|
}
|
||||||
|
|
||||||
|
td.linenos pre {
|
||||||
|
padding: 5px 0px;
|
||||||
|
border: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.highlighttable {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.highlighttable td {
|
||||||
|
padding: 0 0.5em 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.descname {
|
||||||
|
background-color: transparent;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.descclassname {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.xref, a tt {
|
||||||
|
background-color: transparent;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewcode-link {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewcode-back {
|
||||||
|
float: right;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.viewcode-block:target {
|
||||||
|
margin: -1px -10px;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- math display ---------------------------------------------------------- */
|
||||||
|
|
||||||
|
img.math {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body div.math p {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.eqno {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- printout stylesheet --------------------------------------------------- */
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
div.document,
|
||||||
|
div.documentwrapper,
|
||||||
|
div.bodywrapper {
|
||||||
|
margin: 0 !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar,
|
||||||
|
div.related,
|
||||||
|
div.footer,
|
||||||
|
#top-link {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# unproudly borrowed from David Goodger's rst2html.py
|
||||||
|
|
||||||
|
""" A minimal front end to the Docutils Publisher, producing HTML with a
|
||||||
|
`config` role
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import locale
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
from docutils.core import publish_cmdline, default_description
|
||||||
|
# ____________________________________________________________
|
||||||
|
from docutils import nodes, utils
|
||||||
|
from docutils.parsers.rst import roles
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
#register a :config: ReST link role for use in documentation
|
||||||
|
def config_reference_role(role, rawtext, text, lineno, inliner,
|
||||||
|
options={}, content=[]):
|
||||||
|
basename = text
|
||||||
|
refuri = "report/build" + basename + '.html'
|
||||||
|
roles.set_classes(options)
|
||||||
|
node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
|
||||||
|
**options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
roles.register_local_role('config', config_reference_role)
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
|
||||||
|
description = ('Generates (X)HTML documents from standalone reStructuredText '
|
||||||
|
'sources. ' + default_description)
|
||||||
|
|
||||||
|
publish_cmdline(writer_name='html', description=description)
|
||||||
|
|
|
@ -0,0 +1,795 @@
|
||||||
|
/*
|
||||||
|
* rtd.css
|
||||||
|
* ~~~~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
|
||||||
|
* Armin Ronacher for Werkzeug.
|
||||||
|
*
|
||||||
|
* Customized for ReadTheDocs by Eric Pierce & Eric Holscher
|
||||||
|
*
|
||||||
|
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||||
|
* :license: BSD, see LICENSE for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* RTD colors
|
||||||
|
* light blue: #e8ecef
|
||||||
|
* medium blue: #8ca1af
|
||||||
|
* dark blue: #465158
|
||||||
|
* dark grey: #444444
|
||||||
|
*
|
||||||
|
* white hover: #d1d9df;
|
||||||
|
* medium blue hover: #697983;
|
||||||
|
* green highlight: #8ecc4c
|
||||||
|
* light blue (project bar): #e8ecef
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import url("basic.css");
|
||||||
|
|
||||||
|
/* PAGE LAYOUT -------------------------------------------------------------- */
|
||||||
|
|
||||||
|
body {
|
||||||
|
font: 100%/1.5 "ff-meta-web-pro-1","ff-meta-web-pro-2",Arial,"Helvetica Neue",sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: black;
|
||||||
|
background-color: #465158;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
text-align: left;
|
||||||
|
background-color: #e8ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
margin: 0 0 0 16em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.5em 1.3em;
|
||||||
|
min-width: 20em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related {
|
||||||
|
font-size: 1em;
|
||||||
|
background-color: #465158;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.documentwrapper {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #e8ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* HEADINGS --------------------------------------------------------------- */
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.7em 0 0.3em 0;
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 1.15;
|
||||||
|
color: #111;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 2em 0 0.2em 0;
|
||||||
|
font-size: 1.35em;
|
||||||
|
padding: 0;
|
||||||
|
color: #465158;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 1em 0 -0.3em 0;
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #6c818f;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
|
||||||
|
display: none;
|
||||||
|
margin: 0 0 0 0.3em;
|
||||||
|
padding: 0 0.2em 0 0.2em;
|
||||||
|
color: #aaa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
|
||||||
|
h5:hover a.anchor, h6:hover a.anchor {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
|
||||||
|
h5 a.anchor:hover, h6 a.anchor:hover {
|
||||||
|
color: #777;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* LINKS ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Normal links get a pseudo-underline */
|
||||||
|
a {
|
||||||
|
color: #444;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links in sidebar, TOC, index trees and tables have no underline */
|
||||||
|
.sphinxsidebar a,
|
||||||
|
.toctree-wrapper a,
|
||||||
|
.indextable a,
|
||||||
|
#indices-and-tables a {
|
||||||
|
color: #444;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Most links get an underline-effect when hovered */
|
||||||
|
a:hover,
|
||||||
|
div.toctree-wrapper a:hover,
|
||||||
|
.indextable a:hover,
|
||||||
|
#indices-and-tables a:hover {
|
||||||
|
color: #111;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 1px solid #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer links */
|
||||||
|
div.footer a {
|
||||||
|
color: #86989B;
|
||||||
|
text-decoration: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
div.footer a:hover {
|
||||||
|
color: #a6b8bb;
|
||||||
|
text-decoration: underline;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Permalink anchor (subtle grey with a red hover) */
|
||||||
|
div.body a.headerlink {
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 1em;
|
||||||
|
margin-left: 6px;
|
||||||
|
padding: 0 4px 0 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
div.body a.headerlink:hover {
|
||||||
|
color: #c60f0f;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* NAVIGATION BAR --------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.related ul {
|
||||||
|
height: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.65em 0;
|
||||||
|
float: left;
|
||||||
|
display: block;
|
||||||
|
color: white; /* For the >> separators */
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li.right {
|
||||||
|
float: right;
|
||||||
|
margin-right: 5px;
|
||||||
|
color: transparent; /* Hide the | separators */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Breadcrumb" links in nav bar */
|
||||||
|
div.related ul li a {
|
||||||
|
order: none;
|
||||||
|
background-color: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 6px 0 6px 4px;
|
||||||
|
line-height: 1.75em;
|
||||||
|
color: #ffffff;
|
||||||
|
padding: 0.4em 0.8em;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
/* previous / next / modules / index links look more like buttons */
|
||||||
|
div.related ul li.right a {
|
||||||
|
margin: 0.375em 0;
|
||||||
|
background-color: #697983;
|
||||||
|
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
}
|
||||||
|
/* All navbar links light up as buttons when hovered */
|
||||||
|
div.related ul li a:hover {
|
||||||
|
background-color: #8ca1af;
|
||||||
|
color: #ffffff;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
}
|
||||||
|
/* Take extra precautions for tt within links */
|
||||||
|
a tt,
|
||||||
|
div.related ul li a tt {
|
||||||
|
background: inherit !important;
|
||||||
|
color: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SIDEBAR ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
div.sphinxsidebarwrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar {
|
||||||
|
margin: 0;
|
||||||
|
margin-left: -100%;
|
||||||
|
float: left;
|
||||||
|
top: 3em;
|
||||||
|
left: 0;
|
||||||
|
padding: 0 1em;
|
||||||
|
width: 14em;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #e8ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar img {
|
||||||
|
max-width: 12em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3,
|
||||||
|
div.sphinxsidebar h4,
|
||||||
|
div.sphinxsidebar p.logo {
|
||||||
|
margin: 1.2em 0 0.3em 0;
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0;
|
||||||
|
color: #222222;
|
||||||
|
font-family: "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3 a {
|
||||||
|
color: #444444;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul,
|
||||||
|
div.sphinxsidebar p {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
line-height: 130%;
|
||||||
|
background-color: #e8ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No bullets for nested lists, but a little extra indentation */
|
||||||
|
div.sphinxsidebar ul ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A little top/bottom padding to prevent adjacent links' borders
|
||||||
|
* from overlapping each other */
|
||||||
|
div.sphinxsidebar ul li {
|
||||||
|
padding: 1px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A little left-padding to make these align with the ULs */
|
||||||
|
div.sphinxsidebar p.topless {
|
||||||
|
padding-left: 0 0 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make these into hidden one-liners */
|
||||||
|
div.sphinxsidebar ul li,
|
||||||
|
div.sphinxsidebar p.topless {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
/* ...which become visible when hovered */
|
||||||
|
div.sphinxsidebar ul li:hover,
|
||||||
|
div.sphinxsidebar p.topless:hover {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search text box and "Go" button */
|
||||||
|
#searchbox {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
background: #ddd;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
}
|
||||||
|
#searchbox h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make search box and button abut and have a border */
|
||||||
|
input,
|
||||||
|
div.sphinxsidebar input {
|
||||||
|
border: 1px solid #999;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search textbox */
|
||||||
|
input[type="text"] {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 3px;
|
||||||
|
height: 20px;
|
||||||
|
width: 144px;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-bottom-left-radius: 3px;
|
||||||
|
-moz-border-radius-topleft: 3px;
|
||||||
|
-moz-border-radius-bottomleft: 3px;
|
||||||
|
-webkit-border-top-left-radius: 3px;
|
||||||
|
-webkit-border-bottom-left-radius: 3px;
|
||||||
|
}
|
||||||
|
/* Search button */
|
||||||
|
input[type="submit"] {
|
||||||
|
margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */
|
||||||
|
height: 22px;
|
||||||
|
color: #444;
|
||||||
|
background-color: #e8ecef;
|
||||||
|
padding: 1px 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top-right-radius: 3px;
|
||||||
|
border-bottom-right-radius: 3px;
|
||||||
|
-moz-border-radius-topright: 3px;
|
||||||
|
-moz-border-radius-bottomright: 3px;
|
||||||
|
-webkit-border-top-right-radius: 3px;
|
||||||
|
-webkit-border-bottom-right-radius: 3px;
|
||||||
|
}
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
color: #ffffff;
|
||||||
|
background-color: #8ecc4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar p.searchtip {
|
||||||
|
clear: both;
|
||||||
|
padding: 0.5em 0 0 0;
|
||||||
|
background: #ddd;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar links are unusual */
|
||||||
|
div.sphinxsidebar li a,
|
||||||
|
div.sphinxsidebar p a {
|
||||||
|
background: #e8ecef; /* In case links overlap main content */
|
||||||
|
border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
border: 1px solid transparent; /* To prevent things jumping around on hover */
|
||||||
|
padding: 0 5px 0 5px;
|
||||||
|
}
|
||||||
|
div.sphinxsidebar li a:hover,
|
||||||
|
div.sphinxsidebar p a:hover {
|
||||||
|
color: #111;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid #888;
|
||||||
|
}
|
||||||
|
div.sphinxsidebar p.logo a {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tweak any link appearing in a heading */
|
||||||
|
div.sphinxsidebar h3 a {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* OTHER STUFF ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
cite, code, tt {
|
||||||
|
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||||
|
'Bitstream Vera Sans Mono', monospace;
|
||||||
|
font-size: 0.95em;
|
||||||
|
letter-spacing: 0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.descname, tt.descclassname, tt.xref {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px solid #abc;
|
||||||
|
margin: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pre, #_fontwidthtest {
|
||||||
|
font-family: 'Consolas', 'Deja Vu Sans Mono',
|
||||||
|
'Bitstream Vera Sans Mono', monospace;
|
||||||
|
margin: 1em 2em;
|
||||||
|
font-size: 0.95em;
|
||||||
|
letter-spacing: 0.015em;
|
||||||
|
line-height: 120%;
|
||||||
|
padding: 0.5em;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #eee;
|
||||||
|
border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.linenos pre {
|
||||||
|
margin: 1em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.code pre {
|
||||||
|
margin: 1em 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.quotebar {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
max-width: 250px;
|
||||||
|
float: right;
|
||||||
|
padding: 2px 7px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 0 -0.5em 0 -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td, table th {
|
||||||
|
padding: 0.2em 0.5em 0.2em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ADMONITIONS AND WARNINGS ------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Shared by admonitions, warnings and sidebars */
|
||||||
|
div.admonition,
|
||||||
|
div.warning,
|
||||||
|
div.sidebar {
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin: 2em;
|
||||||
|
padding: 0;
|
||||||
|
/*
|
||||||
|
border-radius: 6px;
|
||||||
|
-moz-border-radius: 6px;
|
||||||
|
-webkit-border-radius: 6px;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
div.admonition p,
|
||||||
|
div.warning p,
|
||||||
|
div.sidebar p {
|
||||||
|
margin: 0.5em 1em 0.5em 1em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
div.admonition pre,
|
||||||
|
div.warning pre,
|
||||||
|
div.sidebar pre {
|
||||||
|
margin: 0.4em 1em 0.4em 1em;
|
||||||
|
}
|
||||||
|
div.admonition p.admonition-title,
|
||||||
|
div.warning p.admonition-title,
|
||||||
|
div.sidebar p.sidebar-title {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.1em 0 0.1em 0.5em;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-shadow: 0 1px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
div.admonition ul, div.admonition ol,
|
||||||
|
div.warning ul, div.warning ol,
|
||||||
|
div.sidebar ul, div.sidebar ol {
|
||||||
|
margin: 0.1em 0.5em 0.5em 3em;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Admonitions and sidebars only */
|
||||||
|
div.admonition, div.sidebar {
|
||||||
|
border: 1px solid #609060;
|
||||||
|
background-color: #e9ffe9;
|
||||||
|
}
|
||||||
|
div.admonition p.admonition-title,
|
||||||
|
div.sidebar p.sidebar-title {
|
||||||
|
background-color: #70A070;
|
||||||
|
border-bottom: 1px solid #609060;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Warnings only */
|
||||||
|
div.warning {
|
||||||
|
border: 1px solid #900000;
|
||||||
|
background-color: #ffe9e9;
|
||||||
|
}
|
||||||
|
div.warning p.admonition-title {
|
||||||
|
background-color: #b04040;
|
||||||
|
border-bottom: 1px solid #900000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Sidebars only */
|
||||||
|
div.sidebar {
|
||||||
|
max-width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
div.versioninfo {
|
||||||
|
margin: 1em 0 0 0;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #DDEAF0;
|
||||||
|
padding: 8px;
|
||||||
|
line-height: 1.3em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewcode-back {
|
||||||
|
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
|
||||||
|
'Verdana', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.viewcode-block:target {
|
||||||
|
background-color: #f4debf;
|
||||||
|
border-top: 1px solid #ac9;
|
||||||
|
border-bottom: 1px solid #ac9;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl {
|
||||||
|
margin: 1em 0 2.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Highlight target when you click an internal link */
|
||||||
|
dt:target {
|
||||||
|
background: #ffe080;
|
||||||
|
}
|
||||||
|
/* Don't highlight whole divs */
|
||||||
|
div.highlight {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
/* But do highlight spans (so search results can be highlighted) */
|
||||||
|
span.highlight {
|
||||||
|
background: #ffe080;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer {
|
||||||
|
background-color: #465158;
|
||||||
|
color: #eeeeee;
|
||||||
|
padding: 0 2em 2em 2em;
|
||||||
|
clear: both;
|
||||||
|
font-size: 0.8em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0.8em 0 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section p img.math {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.section p img {
|
||||||
|
margin: 1em 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* MOBILE LAYOUT -------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5 {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding-left: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper a.headerlink, #indices-and-tables h1 a {
|
||||||
|
color: #e6e6e6;
|
||||||
|
font-size: 80%;
|
||||||
|
float: right;
|
||||||
|
line-height: 1.8;
|
||||||
|
position: absolute;
|
||||||
|
right: -0.7em;
|
||||||
|
visibility: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-size: 0.7em;
|
||||||
|
overflow: auto;
|
||||||
|
word-wrap: break-word;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul {
|
||||||
|
height: 2.5em;
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li {
|
||||||
|
clear: both;
|
||||||
|
color: #465158;
|
||||||
|
padding: 0.2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li:last-child {
|
||||||
|
border-bottom: 1px dotted #8ca1af;
|
||||||
|
padding-bottom: 0.4em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li a {
|
||||||
|
color: #465158;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li a:hover {
|
||||||
|
background: inherit;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li.right {
|
||||||
|
clear: none;
|
||||||
|
padding: 0.65em 0;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li.right a {
|
||||||
|
color: #fff;
|
||||||
|
padding-right: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related ul li.right a:hover {
|
||||||
|
background-color: #8ca1af;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body {
|
||||||
|
clear: both;
|
||||||
|
min-width: 0;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar {
|
||||||
|
float: none;
|
||||||
|
margin: 0;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type="text"] {
|
||||||
|
height: 2em;
|
||||||
|
line-height: 2em;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type="submit"] {
|
||||||
|
height: 2em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar p.searchtip {
|
||||||
|
background: inherit;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul li, div.sphinxsidebar p.topless {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodywrapper img {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.documentwrapper {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition, div.warning, pre, blockquote {
|
||||||
|
margin-left: 0em;
|
||||||
|
margin-right: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body p img {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchbox {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related:not(:first-child) li {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related:not(:first-child) li.right {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rtd_doc_footer .badge {
|
||||||
|
float: none;
|
||||||
|
margin: 1em auto;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rtd_doc_footer .badge.revsys-inline {
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.indextable {
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indextable tr {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indextable td {
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indextable td dt {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.search {
|
||||||
|
margin-left: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.search li div.context {
|
||||||
|
font-size: 90%;
|
||||||
|
line-height: 1.1;
|
||||||
|
margin-bottom: 1;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
from os.path import dirname, join
|
||||||
|
from rst import Rest, Paragraph, Strong, OrderedListItem, ListItem, Title, Link, Transition
|
||||||
|
from rst import Directive, Em, Quote, Text
|
||||||
|
from tiramisu.option import *
|
||||||
|
from tiramisu.config import *
|
||||||
|
#from makerestdoc import *
|
||||||
|
|
||||||
|
docdir = join(dirname(__file__), 'build')
|
||||||
|
|
||||||
|
def make_rst_file(filename, rstcontent):
|
||||||
|
fh = file(filename, 'w')
|
||||||
|
fh.write(rstcontent.text())
|
||||||
|
fh.close()
|
||||||
|
|
||||||
|
def descr_content(path, prefix, descr, root=False):
|
||||||
|
content = Rest()
|
||||||
|
title = Title(abovechar="", belowchar="=")
|
||||||
|
if root:
|
||||||
|
title.join(Text("Configuration's overview for: "), Quote(descr._name))
|
||||||
|
else:
|
||||||
|
title.join(Text("Group's overview for: "), Quote(descr._name))
|
||||||
|
content.add(title)
|
||||||
|
content.add(ListItem().join(Strong("name:"), Text(descr._name)))
|
||||||
|
if not root:
|
||||||
|
content.add(ListItem().join(Strong("path:"), Text(path)))
|
||||||
|
content.add(ListItem().join(Strong("description:"), Text(descr.doc)))
|
||||||
|
if not root:
|
||||||
|
content.add(ListItem().join(Strong("container:"), Text(prefix)))
|
||||||
|
if not root:
|
||||||
|
content.add(ListItem().join(Strong("type:"), Text(descr.group_type)))
|
||||||
|
if not root:
|
||||||
|
content.add(ListItem().join(Strong("requirements:"), Text(str(descr._requires))))
|
||||||
|
content.add(ListItem().join(Strong("is hidden:"), Text(str(descr._is_hidden()))))
|
||||||
|
content.add(ListItem().join(Strong("is disabled:"), Text(str(descr._is_disabled()))))
|
||||||
|
content.add(Transition())
|
||||||
|
content.add(Title(abovechar="", belowchar="-").join(Text("Ordered list of childrens for:"), Text(path)))
|
||||||
|
for opt in descr._children:
|
||||||
|
name = opt._name
|
||||||
|
link = Link(name + ":", join(path + '.' + name + ".html"))
|
||||||
|
# because of SympLink opt
|
||||||
|
if hasattr(opt, 'doc'):
|
||||||
|
doc = opt.doc
|
||||||
|
else:
|
||||||
|
doc = name
|
||||||
|
content.add(OrderedListItem(link, Text(opt.doc)))
|
||||||
|
content.add(Transition())
|
||||||
|
content.add(Paragraph(Link("back to index", "index.html")))
|
||||||
|
make_rst_file(join(docdir, path + '.txt'), content)
|
||||||
|
if root:
|
||||||
|
make_rst_file(join(docdir, 'index.txt'), content)
|
||||||
|
|
||||||
|
def opt_rst_content(path, prefix, descr, value):
|
||||||
|
content = Rest()
|
||||||
|
title = Title(abovechar="", belowchar="=")
|
||||||
|
title.join(Text("Configuration's option overview for: "), Quote(descr._name))
|
||||||
|
content.add(title)
|
||||||
|
content.add(ListItem().join(Strong("name:"), Text(descr._name)))
|
||||||
|
content.add(ListItem().join(Strong("value:"), Text(str(value))))
|
||||||
|
content.add(ListItem().join(Strong("path:"), Text(path)))
|
||||||
|
content.add(ListItem().join(Strong("container:"), Text(prefix)))
|
||||||
|
if isinstance(descr, ChoiceOption):
|
||||||
|
content.add(ListItem().join(Strong("possible values:"), Text(str(descr.values))))
|
||||||
|
if not isinstance(descr, SymLinkOption):
|
||||||
|
content.add(ListItem().join(Strong("type:"), Text(str(descr.opt_type))))
|
||||||
|
content.add(ListItem().join(Strong("default:"), Text(str(descr.getdefault()))))
|
||||||
|
content.add(ListItem().join(Strong("description:"), Text(str(descr.getdoc()))))
|
||||||
|
content.add(ListItem().join(Strong("requirements:"), Text(str(descr._requires))))
|
||||||
|
content.add(ListItem().join(Strong("is hidden:"), Text(str(descr._is_hidden()))))
|
||||||
|
content.add(ListItem().join(Strong("is disabled:"), Text(str(descr._is_disabled()))))
|
||||||
|
content.add(ListItem().join(Strong("is frozen:"), Text(str(descr._frozen))))
|
||||||
|
content.add(ListItem().join(Strong("is multi:"), Text(str(descr.multi))))
|
||||||
|
content.add(ListItem().join(Strong("is mandatory:"), Text(str(descr.is_mandatory()))))
|
||||||
|
else:
|
||||||
|
content.add(ListItem().join(Strong("links to:"), Text(str(descr.path))))
|
||||||
|
content.add(Transition())
|
||||||
|
content.add(Paragraph(Link("back to container", join(prefix + ".html"))))
|
||||||
|
make_rst_file(join(docdir, path + '.txt'), content)
|
||||||
|
|
||||||
|
def make_rest_overview(cfg, title=True):
|
||||||
|
rootname = cfg._cfgimpl_descr._name
|
||||||
|
descr_content(rootname, rootname, cfg._cfgimpl_descr, root=True)
|
||||||
|
#cfg.cfgimpl_read_write()
|
||||||
|
cfg._cfgimpl_disabled = False
|
||||||
|
cfg._cfgimpl_hidden = False
|
||||||
|
for path in cfg.getpaths(include_groups=True, allpaths=True):
|
||||||
|
child = cfg.unwrap_from_path(path)
|
||||||
|
fullpath = rootname + '.' + path
|
||||||
|
prefix = fullpath.rsplit(".", 1)[0]
|
||||||
|
if isinstance(child, OptionDescription):
|
||||||
|
descr_content(fullpath, prefix, child)
|
||||||
|
else:
|
||||||
|
value = getattr(cfg, path)
|
||||||
|
opt_rst_content(fullpath, prefix, child, value)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from test_config_big_example import get_example_config
|
||||||
|
make_rest_overview(get_example_config())
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
from tiramisu.config import Config
|
||||||
|
from tiramisu import option
|
||||||
|
# we shall keep extendable types out of the reach of unexceptional guys like us
|
||||||
|
# horror __metaclass__ = extendabletype
|
||||||
|
|
||||||
|
def get_fullpath(opt, path):
|
||||||
|
if path:
|
||||||
|
return "%s.%s" % (path, opt._name)
|
||||||
|
else:
|
||||||
|
return opt._name
|
||||||
|
|
||||||
|
class Option:
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
fullpath = get_fullpath(self, path)
|
||||||
|
result = Rest(
|
||||||
|
Title(fullpath, abovechar="=", belowchar="="),
|
||||||
|
ListItem(Strong("name:"), self._name),
|
||||||
|
ListItem(Strong("description:"), self.doc))
|
||||||
|
return result
|
||||||
|
|
||||||
|
class ChoiceOption(Option, option.ChoiceOption):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
content = super(ChoiceOption, self).make_rest_doc(path)
|
||||||
|
content.add(ListItem(Strong("option type:"), "choice option"))
|
||||||
|
content.add(ListItem(Strong("possible values:"),
|
||||||
|
*[ListItem(str(val)) for val in self.values]))
|
||||||
|
if self.default is not None:
|
||||||
|
content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
|
||||||
|
# requirements = []
|
||||||
|
#
|
||||||
|
# for val in self.values:
|
||||||
|
# if val not in self._requires:
|
||||||
|
# continue
|
||||||
|
# req = self._requires[val]
|
||||||
|
# requirements.append(ListItem("value '%s' requires:" % (val, ),
|
||||||
|
# *[ListItem(Link(opt, opt + ".html"),
|
||||||
|
# "to be set to '%s'" % (rval, ))
|
||||||
|
# for (opt, rval) in req]))
|
||||||
|
# if requirements:
|
||||||
|
# content.add(ListItem(Strong("requirements:"), *requirements))
|
||||||
|
return content
|
||||||
|
|
||||||
|
class BoolOption(Option, option.BoolOption):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
content = super(BoolOption, self).make_rest_doc(path)
|
||||||
|
fullpath = get_fullpath(self, path)
|
||||||
|
content.add(ListItem(Strong("option type:"), "boolean option"))
|
||||||
|
if self.default is not None:
|
||||||
|
content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
# if self._requires is not None:
|
||||||
|
# requirements = [ListItem(Link(opt, opt + ".html"),
|
||||||
|
# "must be set to '%s'" % (rval, ))
|
||||||
|
# for (opt, rval) in self._requires]
|
||||||
|
# if requirements:
|
||||||
|
# content.add(ListItem(Strong("requirements:"), *requirements))
|
||||||
|
return content
|
||||||
|
|
||||||
|
class IntOption(Option, option.IntOption):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
content = super(IntOption, self).make_rest_doc(path)
|
||||||
|
content.add(ListItem(Strong("option type:"), "integer option"))
|
||||||
|
if self.default is not None:
|
||||||
|
content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
return content
|
||||||
|
|
||||||
|
class FloatOption(Option, option.FloatOption):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
content = super(FloatOption, self).make_rest_doc(path)
|
||||||
|
content.add(ListItem(Strong("option type:"), "float option"))
|
||||||
|
if self.default is not None:
|
||||||
|
content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
return content
|
||||||
|
|
||||||
|
class StrOption(Option, option.StrOption):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
content = super(StrOption, self).make_rest_doc(path)
|
||||||
|
content.add(ListItem(Strong("option type:"), "string option"))
|
||||||
|
if self.default is not None:
|
||||||
|
content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
return content
|
||||||
|
|
||||||
|
#class ArbitraryOption:
|
||||||
|
# def make_rest_doc(self, path=""):
|
||||||
|
# content = super(ArbitraryOption, self).make_rest_doc(path)
|
||||||
|
# content.add(ListItem(Strong("option type:"),
|
||||||
|
# "arbitrary option (mostly internal)"))
|
||||||
|
# if self.default is not None:
|
||||||
|
# content.add(ListItem(Strong("default:"), str(self.default)))
|
||||||
|
# elif self.defaultfactory is not None:
|
||||||
|
# content.add(ListItem(Strong("factory for the default value:"),
|
||||||
|
# str(self.defaultfactory)))
|
||||||
|
# return content
|
||||||
|
|
||||||
|
class OptionDescription(option.OptionDescription):
|
||||||
|
def make_rest_doc(self, path=""):
|
||||||
|
fullpath = get_fullpath(self, path)
|
||||||
|
content = Rest(
|
||||||
|
Title(fullpath, abovechar="=", belowchar="="))
|
||||||
|
toctree = []
|
||||||
|
for child in self._children:
|
||||||
|
subpath = fullpath + "." + child._name
|
||||||
|
toctree.append(subpath)
|
||||||
|
content.add(Directive("toctree", *toctree, **{'maxdepth': 4}))
|
||||||
|
content.join(
|
||||||
|
ListItem(Strong("name:"), self._name),
|
||||||
|
ListItem(Strong("description:"), self.doc))
|
||||||
|
stack = []
|
||||||
|
curr = content
|
||||||
|
# config = Config(self)
|
||||||
|
return content
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,410 @@
|
||||||
|
# unproudly borrowed from pypy :
|
||||||
|
# http://codespeak.net/svn/pypy/trunk/pypy/tool/rest/rst.py
|
||||||
|
""" reStructuredText generation tools
|
||||||
|
|
||||||
|
provides an api to build a tree from nodes, which can be converted to
|
||||||
|
ReStructuredText on demand
|
||||||
|
|
||||||
|
note that not all of ReST is supported, a usable subset is offered, but
|
||||||
|
certain features aren't supported, and also certain details (like how links
|
||||||
|
are generated, or how escaping is done) can not be controlled
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
def escape(txt):
|
||||||
|
"""escape ReST markup"""
|
||||||
|
if not isinstance(txt, str) and not isinstance(txt, unicode):
|
||||||
|
txt = str(txt)
|
||||||
|
# XXX this takes a very naive approach to escaping, but it seems to be
|
||||||
|
# sufficient...
|
||||||
|
for c in '\\*`|:_':
|
||||||
|
txt = txt.replace(c, '\\%s' % (c,))
|
||||||
|
return txt
|
||||||
|
|
||||||
|
class RestError(Exception):
|
||||||
|
""" raised on containment errors (wrong parent) """
|
||||||
|
|
||||||
|
class AbstractMetaclass(type):
|
||||||
|
def __new__(cls, *args):
|
||||||
|
obj = super(AbstractMetaclass, cls).__new__(cls, *args)
|
||||||
|
parent_cls = obj.parentclass
|
||||||
|
if parent_cls is None:
|
||||||
|
return obj
|
||||||
|
if not isinstance(parent_cls, list):
|
||||||
|
class_list = [parent_cls]
|
||||||
|
else:
|
||||||
|
class_list = parent_cls
|
||||||
|
if obj.allow_nesting:
|
||||||
|
class_list.append(obj)
|
||||||
|
|
||||||
|
for _class in class_list:
|
||||||
|
if not _class.allowed_child:
|
||||||
|
_class.allowed_child = {obj:True}
|
||||||
|
else:
|
||||||
|
_class.allowed_child[obj] = True
|
||||||
|
return obj
|
||||||
|
|
||||||
|
class AbstractNode(object):
|
||||||
|
""" Base class implementing rest generation
|
||||||
|
"""
|
||||||
|
sep = ''
|
||||||
|
__metaclass__ = AbstractMetaclass
|
||||||
|
parentclass = None # this exists to allow parent to know what
|
||||||
|
# children can exist
|
||||||
|
allow_nesting = False
|
||||||
|
allowed_child = {}
|
||||||
|
defaults = {}
|
||||||
|
|
||||||
|
_reg_whitespace = re.compile('\s+')
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.parent = None
|
||||||
|
self.children = []
|
||||||
|
for child in args:
|
||||||
|
self._add(child)
|
||||||
|
for arg in kwargs:
|
||||||
|
setattr(self, arg, kwargs[arg])
|
||||||
|
|
||||||
|
def join(self, *children):
|
||||||
|
""" add child nodes
|
||||||
|
|
||||||
|
returns a reference to self
|
||||||
|
"""
|
||||||
|
for child in children:
|
||||||
|
self._add(child)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def add(self, child):
|
||||||
|
""" adds a child node
|
||||||
|
|
||||||
|
returns a reference to the child
|
||||||
|
"""
|
||||||
|
self._add(child)
|
||||||
|
return child
|
||||||
|
|
||||||
|
def _add(self, child):
|
||||||
|
if child.__class__ not in self.allowed_child:
|
||||||
|
raise RestError("%r cannot be child of %r" % \
|
||||||
|
(child.__class__, self.__class__))
|
||||||
|
self.children.append(child)
|
||||||
|
child.parent = self
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return self.children[item]
|
||||||
|
|
||||||
|
def __setitem__(self, item, value):
|
||||||
|
self.children[item] = value
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
""" return a ReST string representation of the node """
|
||||||
|
return self.sep.join([child.text() for child in self.children])
|
||||||
|
|
||||||
|
def wordlist(self):
|
||||||
|
""" return a list of ReST strings for this node and its children """
|
||||||
|
return [self.text()]
|
||||||
|
|
||||||
|
class Rest(AbstractNode):
|
||||||
|
""" Root node of a document """
|
||||||
|
|
||||||
|
sep = "\n\n"
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
AbstractNode.__init__(self, *args, **kwargs)
|
||||||
|
self.links = {}
|
||||||
|
|
||||||
|
def render_links(self, check=False):
|
||||||
|
"""render the link attachments of the document"""
|
||||||
|
assert not check, "Link checking not implemented"
|
||||||
|
if not self.links:
|
||||||
|
return ""
|
||||||
|
link_texts = []
|
||||||
|
# XXX this could check for duplicates and remove them...
|
||||||
|
for link, target in self.links.iteritems():
|
||||||
|
link_texts.append(".. _`%s`: %s" % (escape(link), target))
|
||||||
|
return "\n" + "\n".join(link_texts) + "\n\n"
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
outcome = []
|
||||||
|
if (isinstance(self.children[0], Transition) or
|
||||||
|
isinstance(self.children[-1], Transition)):
|
||||||
|
raise ValueError, ('document must not begin or end with a '
|
||||||
|
'transition')
|
||||||
|
for child in self.children:
|
||||||
|
outcome.append(child.text())
|
||||||
|
|
||||||
|
# always a trailing newline
|
||||||
|
text = self.sep.join([i for i in outcome if i]) + "\n"
|
||||||
|
return text + self.render_links()
|
||||||
|
|
||||||
|
class Transition(AbstractNode):
|
||||||
|
""" a horizontal line """
|
||||||
|
parentclass = Rest
|
||||||
|
|
||||||
|
def __init__(self, char='-', width=80, *args, **kwargs):
|
||||||
|
self.char = char
|
||||||
|
self.width = width
|
||||||
|
super(Transition, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
return (self.width - 1) * self.char
|
||||||
|
|
||||||
|
class Paragraph(AbstractNode):
|
||||||
|
""" simple paragraph """
|
||||||
|
|
||||||
|
parentclass = Rest
|
||||||
|
sep = " "
|
||||||
|
indent = ""
|
||||||
|
# FIXME
|
||||||
|
width = 880
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# make shortcut
|
||||||
|
args = list(args)
|
||||||
|
for num, arg in enumerate(args):
|
||||||
|
if isinstance(arg, str):
|
||||||
|
args[num] = Text(arg)
|
||||||
|
super(Paragraph, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
texts = []
|
||||||
|
for child in self.children:
|
||||||
|
texts += child.wordlist()
|
||||||
|
|
||||||
|
buf = []
|
||||||
|
outcome = []
|
||||||
|
lgt = len(self.indent)
|
||||||
|
|
||||||
|
def grab(buf):
|
||||||
|
outcome.append(self.indent + self.sep.join(buf))
|
||||||
|
|
||||||
|
texts.reverse()
|
||||||
|
while texts:
|
||||||
|
next = texts[-1]
|
||||||
|
if not next:
|
||||||
|
texts.pop()
|
||||||
|
continue
|
||||||
|
if lgt + len(self.sep) + len(next) <= self.width or not buf:
|
||||||
|
buf.append(next)
|
||||||
|
lgt += len(next) + len(self.sep)
|
||||||
|
texts.pop()
|
||||||
|
else:
|
||||||
|
grab(buf)
|
||||||
|
lgt = len(self.indent)
|
||||||
|
buf = []
|
||||||
|
grab(buf)
|
||||||
|
return "\n".join(outcome)
|
||||||
|
|
||||||
|
class SubParagraph(Paragraph):
|
||||||
|
""" indented sub paragraph """
|
||||||
|
|
||||||
|
indent = " "
|
||||||
|
|
||||||
|
class Title(Paragraph):
|
||||||
|
""" title element """
|
||||||
|
|
||||||
|
parentclass = Rest
|
||||||
|
belowchar = "="
|
||||||
|
abovechar = ""
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
txt = self._get_text()
|
||||||
|
lines = []
|
||||||
|
if self.abovechar:
|
||||||
|
lines.append(self.abovechar * len(txt))
|
||||||
|
lines.append(txt)
|
||||||
|
if self.belowchar:
|
||||||
|
lines.append(self.belowchar * len(txt))
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def _get_text(self):
|
||||||
|
txt = []
|
||||||
|
for node in self.children:
|
||||||
|
txt += node.wordlist()
|
||||||
|
return ' '.join(txt)
|
||||||
|
|
||||||
|
class AbstractText(AbstractNode):
|
||||||
|
parentclass = [Paragraph, Title]
|
||||||
|
start = ""
|
||||||
|
end = ""
|
||||||
|
def __init__(self, _text):
|
||||||
|
self._text = _text
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
text = self.escape(self._text)
|
||||||
|
return self.start + text + self.end
|
||||||
|
|
||||||
|
def escape(self, text):
|
||||||
|
if not isinstance(text, str) and not isinstance(text, unicode):
|
||||||
|
text = str(text)
|
||||||
|
if self.start:
|
||||||
|
text = text.replace(self.start, '\\%s' % (self.start,))
|
||||||
|
if self.end and self.end != self.start:
|
||||||
|
text = text.replace(self.end, '\\%s' % (self.end,))
|
||||||
|
return text
|
||||||
|
|
||||||
|
class Text(AbstractText):
|
||||||
|
def wordlist(self):
|
||||||
|
text = escape(self._text)
|
||||||
|
return self._reg_whitespace.split(text)
|
||||||
|
|
||||||
|
class LiteralBlock(AbstractText):
|
||||||
|
parentclass = Rest
|
||||||
|
start = '::\n\n'
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
if not self._text.strip():
|
||||||
|
return ''
|
||||||
|
text = self.escape(self._text).split('\n')
|
||||||
|
for i, line in enumerate(text):
|
||||||
|
if line.strip():
|
||||||
|
text[i] = ' %s' % (line,)
|
||||||
|
return self.start + '\n'.join(text)
|
||||||
|
|
||||||
|
class Em(AbstractText):
|
||||||
|
start = "*"
|
||||||
|
end = "*"
|
||||||
|
|
||||||
|
class Strong(AbstractText):
|
||||||
|
start = "**"
|
||||||
|
end = "**"
|
||||||
|
|
||||||
|
class Quote(AbstractText):
|
||||||
|
start = '``'
|
||||||
|
end = '``'
|
||||||
|
|
||||||
|
class Anchor(AbstractText):
|
||||||
|
start = '_`'
|
||||||
|
end = '`'
|
||||||
|
|
||||||
|
class Footnote(AbstractText):
|
||||||
|
def __init__(self, note, symbol=False):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class Citation(AbstractText):
|
||||||
|
def __init__(self, text, cite):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class ListItem(Paragraph):
|
||||||
|
allow_nesting = True
|
||||||
|
item_chars = '*+-'
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
idepth = self.get_indent_depth()
|
||||||
|
indent = self.indent + (idepth + 1) * ' '
|
||||||
|
txt = '\n\n'.join(self.render_children(indent))
|
||||||
|
ret = []
|
||||||
|
item_char = self.item_chars[idepth]
|
||||||
|
ret += [indent[len(item_char)+1:], item_char, ' ', txt[len(indent):]]
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
def render_children(self, indent):
|
||||||
|
txt = []
|
||||||
|
buffer = []
|
||||||
|
def render_buffer(fro, to):
|
||||||
|
if not fro:
|
||||||
|
return
|
||||||
|
p = Paragraph(indent=indent, *fro)
|
||||||
|
p.parent = self.parent
|
||||||
|
to.append(p.text())
|
||||||
|
for child in self.children:
|
||||||
|
if isinstance(child, AbstractText):
|
||||||
|
buffer.append(child)
|
||||||
|
else:
|
||||||
|
if buffer:
|
||||||
|
render_buffer(buffer, txt)
|
||||||
|
buffer = []
|
||||||
|
txt.append(child.text())
|
||||||
|
|
||||||
|
render_buffer(buffer, txt)
|
||||||
|
return txt
|
||||||
|
|
||||||
|
def get_indent_depth(self):
|
||||||
|
depth = 0
|
||||||
|
current = self
|
||||||
|
while (current.parent is not None and
|
||||||
|
isinstance(current.parent, ListItem)):
|
||||||
|
depth += 1
|
||||||
|
current = current.parent
|
||||||
|
return depth
|
||||||
|
|
||||||
|
class OrderedListItem(ListItem):
|
||||||
|
item_chars = ["#."] * 5
|
||||||
|
|
||||||
|
class DListItem(ListItem):
|
||||||
|
item_chars = None
|
||||||
|
def __init__(self, term, definition, *args, **kwargs):
|
||||||
|
self.term = term
|
||||||
|
super(DListItem, self).__init__(definition, *args, **kwargs)
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
idepth = self.get_indent_depth()
|
||||||
|
indent = self.indent + (idepth + 1) * ' '
|
||||||
|
txt = '\n\n'.join(self.render_children(indent))
|
||||||
|
ret = []
|
||||||
|
ret += [indent[2:], self.term, '\n', txt]
|
||||||
|
return ''.join(ret)
|
||||||
|
|
||||||
|
class Link(AbstractText):
|
||||||
|
start = '`'
|
||||||
|
end = '`_'
|
||||||
|
|
||||||
|
def __init__(self, _text, target):
|
||||||
|
self._text = _text
|
||||||
|
self.target = target
|
||||||
|
self.rest = None
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
if self.rest is None:
|
||||||
|
self.rest = self.find_rest()
|
||||||
|
if self.rest.links.get(self._text, self.target) != self.target:
|
||||||
|
raise ValueError('link name %r already in use for a different '
|
||||||
|
'target' % (self.target,))
|
||||||
|
self.rest.links[self._text] = self.target
|
||||||
|
return AbstractText.text(self)
|
||||||
|
|
||||||
|
def find_rest(self):
|
||||||
|
# XXX little overkill, but who cares...
|
||||||
|
next = self
|
||||||
|
while next.parent is not None:
|
||||||
|
next = next.parent
|
||||||
|
return next
|
||||||
|
|
||||||
|
class InternalLink(AbstractText):
|
||||||
|
start = '`'
|
||||||
|
end = '`_'
|
||||||
|
|
||||||
|
class LinkTarget(Paragraph):
|
||||||
|
def __init__(self, name, target):
|
||||||
|
self.name = name
|
||||||
|
self.target = target
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
return ".. _`%s`:%s\n" % (self.name, self.target)
|
||||||
|
|
||||||
|
class Substitution(AbstractText):
|
||||||
|
def __init__(self, text, **kwargs):
|
||||||
|
raise NotImplemented('XXX')
|
||||||
|
|
||||||
|
class Directive(Paragraph):
|
||||||
|
indent = ' '
|
||||||
|
def __init__(self, name, *args, **options):
|
||||||
|
self.name = name
|
||||||
|
self.content = args
|
||||||
|
super(Directive, self).__init__()
|
||||||
|
self.options = options
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
# XXX not very pretty...
|
||||||
|
txt = '.. %s::' % (self.name,)
|
||||||
|
options = '\n'.join([' :%s: %s' % (k, v) for (k, v) in
|
||||||
|
self.options.iteritems()])
|
||||||
|
if options:
|
||||||
|
txt += '\n%s' % (options,)
|
||||||
|
|
||||||
|
if self.content:
|
||||||
|
txt += '\n'
|
||||||
|
for item in self.content:
|
||||||
|
txt += '\n ' + item
|
||||||
|
|
||||||
|
return txt
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# coding: utf-8
|
||||||
|
from tiramisu.config import *
|
||||||
|
from tiramisu.option import *
|
||||||
|
|
||||||
|
all_modules = ['amon', 'sphynx', 'zephir']
|
||||||
|
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', 'doc pour gc', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('essai', 'une éééééé doc pour essai', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
|
||||||
|
def get_example_config():
|
||||||
|
return Config(descr)
|
|
@ -0,0 +1,13 @@
|
||||||
|
"""automatically sets the PYTHONPATH before running the unit tests
|
||||||
|
|
||||||
|
This is supposed to be used in development mode (i.e. testing from a fresh
|
||||||
|
checkout)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from os.path import dirname, abspath, join, normpath
|
||||||
|
import sys
|
||||||
|
|
||||||
|
HERE = dirname(abspath(__file__))
|
||||||
|
PATH = normpath(join(HERE, '..'))
|
||||||
|
if PATH not in sys.path:
|
||||||
|
sys.path.insert(1, PATH)
|
|
@ -0,0 +1,96 @@
|
||||||
|
#this test is much more to test that **it's there** and answers attribute access
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_base_config():
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcdummy])
|
||||||
|
cfg = Config(descr)
|
||||||
|
assert cfg.dummy == False
|
||||||
|
dm = cfg.unwrap_from_path('dummy')
|
||||||
|
assert dm._name == 'dummy'
|
||||||
|
|
||||||
|
def test_base_config_and_groups():
|
||||||
|
descr = make_description()
|
||||||
|
# overrides the booloption default value
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config.gc.name == 'ref'
|
||||||
|
assert config.bool == False
|
||||||
|
nm = config.unwrap_from_path('gc.name')
|
||||||
|
assert nm._name == 'name'
|
||||||
|
gc = config.unwrap_from_path('gc')
|
||||||
|
assert gc._name == 'gc'
|
||||||
|
nm = config.unwrap_from_name('name')
|
||||||
|
assert nm._name == 'name'
|
||||||
|
|
||||||
|
def test_base_config_in_a_tree():
|
||||||
|
"how options are organized into a tree"
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
|
||||||
|
assert config.gc.name == 'ref'
|
||||||
|
config.gc.name = 'framework'
|
||||||
|
assert config.gc.name == 'framework'
|
||||||
|
assert getattr(config, "gc.name") == 'framework'
|
||||||
|
|
||||||
|
assert config.objspace == 'std'
|
||||||
|
config.objspace = 'thunk'
|
||||||
|
assert config.objspace == 'thunk'
|
||||||
|
|
||||||
|
assert config.gc.float == 2.3
|
||||||
|
assert config.int == 0
|
||||||
|
config.gc.float = 3.4
|
||||||
|
config.int = 123
|
||||||
|
assert config.gc.float == 3.4
|
||||||
|
assert config.int == 123
|
||||||
|
|
||||||
|
assert not config.wantref
|
||||||
|
|
||||||
|
assert config.str == "abc"
|
||||||
|
config.str = "def"
|
||||||
|
assert config.str == "def"
|
||||||
|
|
||||||
|
raises(AttributeError, 'config.gc.foo = "bar"')
|
||||||
|
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config.gc.name == 'ref'
|
||||||
|
config.wantframework = True
|
||||||
|
|
||||||
|
def test_config_values():
|
||||||
|
"_cfgimpl_values appears to be a simple dict"
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
config.set(dummy=False)
|
||||||
|
assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
|
||||||
|
|
||||||
|
def test_cfgimpl_get_home_by_path():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config._cfgimpl_get_home_by_path('gc.dummy')[1] == 'dummy'
|
||||||
|
assert config._cfgimpl_get_home_by_path('dummy')[1] == 'dummy'
|
||||||
|
assert config.getpaths(include_groups=False) == ['gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
||||||
|
assert config.getpaths(include_groups=True) == ['gc', 'gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
|
@ -0,0 +1,167 @@
|
||||||
|
"configuration objects global API"
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Tests', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test', default=False)
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
|
||||||
|
def test_compare_configs():
|
||||||
|
"config object comparison"
|
||||||
|
descr = make_description()
|
||||||
|
conf1 = Config(descr)
|
||||||
|
conf2 = Config(descr, wantref=True)
|
||||||
|
assert conf1 != conf2
|
||||||
|
assert hash(conf1) != hash(conf2)
|
||||||
|
assert conf1.getkey() != conf2.getkey()
|
||||||
|
conf1.wantref = True
|
||||||
|
assert conf1 == conf2
|
||||||
|
assert hash(conf1) == hash(conf2)
|
||||||
|
assert conf1.getkey() == conf2.getkey()
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def test_iter_config():
|
||||||
|
"iteration on config object"
|
||||||
|
s = StrOption("string", "", default="string")
|
||||||
|
s2 = StrOption("string2", "", default="string2")
|
||||||
|
descr = OptionDescription("options", "", [s,s2])
|
||||||
|
config = Config(descr)
|
||||||
|
assert [(name, value) for name, value in config] == \
|
||||||
|
[('string', 'string'), ('string2', 'string2')]
|
||||||
|
|
||||||
|
def test_iter_subconfig():
|
||||||
|
"iteration on config sub object"
|
||||||
|
descr = make_description()
|
||||||
|
conf = Config(descr)
|
||||||
|
for (name, value), (gname, gvalue) in \
|
||||||
|
zip(conf.gc, [("name", "ref"), ("dummy", False)]):
|
||||||
|
assert name == gname
|
||||||
|
assert value == gvalue
|
||||||
|
#____________________________________________________________
|
||||||
|
def test_getpaths():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
|
||||||
|
assert config.getpaths() == ['gc.name', 'gc.dummy', 'gc.float', 'bool',
|
||||||
|
'objspace', 'wantref', 'str', 'wantframework',
|
||||||
|
'int', 'boolop']
|
||||||
|
assert config.getpaths() == descr.getpaths()
|
||||||
|
assert config.gc.getpaths() == ['name', 'dummy', 'float']
|
||||||
|
assert config.gc.getpaths() == descr.gc.getpaths()
|
||||||
|
assert config.getpaths(include_groups=True) == [
|
||||||
|
'gc', 'gc.name', 'gc.dummy', 'gc.float',
|
||||||
|
'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
||||||
|
|
||||||
|
assert config.getpaths(True) == descr.getpaths(True)
|
||||||
|
|
||||||
|
def test_getpaths_with_hidden():
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
booloption.hide()
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
descr = OptionDescription('tiramisu', '', [booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
|
||||||
|
config = Config(descr)
|
||||||
|
result = ['objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
||||||
|
assert config.getpaths() == result
|
||||||
|
r2 = ['bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
||||||
|
assert config.getpaths(allpaths=True) == r2
|
||||||
|
|
||||||
|
def test_str():
|
||||||
|
descr = make_description()
|
||||||
|
c = Config(descr)
|
||||||
|
print c # does not crash
|
||||||
|
|
||||||
|
def test_dir():
|
||||||
|
descr = make_description()
|
||||||
|
c = Config(descr)
|
||||||
|
print dir(c)
|
||||||
|
|
||||||
|
def test_make_dict():
|
||||||
|
"serialization of the whole config to a dict"
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("s1", "", [
|
||||||
|
BoolOption("a", "", default=False)]),
|
||||||
|
IntOption("int", "", default=42)])
|
||||||
|
config = Config(descr)
|
||||||
|
d = make_dict(config)
|
||||||
|
assert d == {"s1.a": False, "int": 42}
|
||||||
|
config.int = 43
|
||||||
|
config.s1.a = True
|
||||||
|
d = make_dict(config)
|
||||||
|
assert d == {"s1.a": True, "int": 43}
|
||||||
|
d2 = make_dict(config, flatten=True)
|
||||||
|
assert d2 == {'a': True, 'int': 43}
|
||||||
|
|
||||||
|
def test_delattr():
|
||||||
|
"delattr, means suppression of an option in a config"
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("s1", "", [
|
||||||
|
BoolOption("a", "", default=False)]),
|
||||||
|
IntOption("int", "", default=42)])
|
||||||
|
c = Config(descr)
|
||||||
|
c.int = 45
|
||||||
|
assert c.int == 45
|
||||||
|
del c.int
|
||||||
|
assert c.int == 42
|
||||||
|
c.int = 45
|
||||||
|
assert c.int == 45
|
||||||
|
|
||||||
|
#def test_validator():
|
||||||
|
# "validates the integrity of an option towards a whole configuration"
|
||||||
|
# def my_validator_1(config):
|
||||||
|
# assert config is c
|
||||||
|
|
||||||
|
# def my_validator_2(config):
|
||||||
|
# assert config is c
|
||||||
|
# raise ConflictConfigError
|
||||||
|
|
||||||
|
# descr = OptionDescription("opt", "", [
|
||||||
|
# BoolOption('booloption1', 'option test1', default=False,
|
||||||
|
# validator=my_validator_1),
|
||||||
|
# BoolOption('booloption2', 'option test2', default=False,
|
||||||
|
# validator=my_validator_2),
|
||||||
|
# BoolOption('booloption4', 'option test4', default=False,
|
||||||
|
# ),
|
||||||
|
# ])
|
||||||
|
# c = Config(descr)
|
||||||
|
# c.booloption1 = True
|
||||||
|
## raises(ConfigError, "c.booloption2 = True")
|
||||||
|
## assert c.booloption2 is False
|
||||||
|
## raises(ConfigError, "c.booloption3 = True")
|
||||||
|
# assert c.booloption2 is False
|
||||||
|
# c.booloption4 = True
|
||||||
|
# assert c.booloption2 is False
|
||||||
|
# c.booloption2 = False
|
||||||
|
# assert c.booloption2 is False
|
||||||
|
#
|
|
@ -0,0 +1,258 @@
|
||||||
|
#just a proof of concept with a lot of options and option groups
|
||||||
|
import autopath
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
all_modules = ['amon', 'sphynx', 'zephir']
|
||||||
|
|
||||||
|
example__optiondescription = OptionDescription("objspace", "Object Space Options", [
|
||||||
|
ChoiceOption("name", "Object Space name",
|
||||||
|
["std", "flow", "thunk", "dump", "taint"],
|
||||||
|
"std"),
|
||||||
|
|
||||||
|
OptionDescription("opcodes", "opcodes to enable in the interpreter", [
|
||||||
|
BoolOption("CALL_LIKELY_BUILTIN", "emit a special bytecode for likely calls to builtin functions",
|
||||||
|
default=False,
|
||||||
|
requires=[("translation.stackless", False)]),
|
||||||
|
BoolOption("CALL_METHOD", "emit a special bytecode for expr.name()",
|
||||||
|
default=False),
|
||||||
|
]),
|
||||||
|
|
||||||
|
BoolOption("nofaking", "disallow faking in the object space",
|
||||||
|
default=False,
|
||||||
|
requires=[
|
||||||
|
("objspace.usemodules.posix", True),
|
||||||
|
("objspace.usemodules.time", True),
|
||||||
|
("objspace.usemodules.errno", True)],
|
||||||
|
),
|
||||||
|
|
||||||
|
OptionDescription("usemodules", "Which Modules should be used", [
|
||||||
|
BoolOption(modname, "use module %s" % (modname, ),
|
||||||
|
default=True,
|
||||||
|
requires= ['amon'],
|
||||||
|
)
|
||||||
|
for modname in all_modules]),
|
||||||
|
|
||||||
|
BoolOption("allworkingmodules", "use as many working modules as possible",
|
||||||
|
default=True,
|
||||||
|
),
|
||||||
|
|
||||||
|
BoolOption("translationmodules",
|
||||||
|
"use only those modules that are needed to run translate.py on pypy",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
|
|
||||||
|
BoolOption("geninterp", "specify whether geninterp should be used",
|
||||||
|
default=True),
|
||||||
|
|
||||||
|
BoolOption("logbytecodes",
|
||||||
|
"keep track of bytecode usage",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("usepycfiles", "Write and read pyc files when importing",
|
||||||
|
default=True),
|
||||||
|
|
||||||
|
BoolOption("lonepycfiles", "Import pyc files with no matching py file",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.usepycfiles", True)]),
|
||||||
|
|
||||||
|
StrOption("soabi",
|
||||||
|
"Tag to differentiate extension modules built for different Python interpreters",
|
||||||
|
default=None),
|
||||||
|
|
||||||
|
BoolOption("honor__builtins__",
|
||||||
|
"Honor the __builtins__ key of a module dictionary",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("disable_call_speedhacks",
|
||||||
|
"make sure that all calls go through space.call_args",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("timing",
|
||||||
|
"timing of various parts of the interpreter (simple profiling)",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
OptionDescription("std", "Standard Object Space Options", [
|
||||||
|
BoolOption("withtproxy", "support transparent proxies",
|
||||||
|
default=True),
|
||||||
|
|
||||||
|
BoolOption("withsmallint", "use tagged integers",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.withprebuiltint", False),
|
||||||
|
("translation.taggedpointers", True)]),
|
||||||
|
|
||||||
|
BoolOption("withprebuiltint", "prebuild commonly used int objects",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
IntOption("prebuiltintfrom", "lowest integer which is prebuilt",
|
||||||
|
default=-5),
|
||||||
|
|
||||||
|
IntOption("prebuiltintto", "highest integer which is prebuilt",
|
||||||
|
default=100),
|
||||||
|
|
||||||
|
BoolOption("withstrjoin", "use strings optimized for addition",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withstrslice", "use strings optimized for slicing",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withstrbuf", "use strings optimized for addition (ver 2)",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withprebuiltchar",
|
||||||
|
"use prebuilt single-character string objects",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("sharesmallstr",
|
||||||
|
"always reuse the prebuilt string objects "
|
||||||
|
"(the empty string and potentially single-char strings)",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withrope", "use ropes as the string implementation",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.withstrslice", False),
|
||||||
|
("objspace.std.withstrjoin", False),
|
||||||
|
("objspace.std.withstrbuf", False)],
|
||||||
|
),
|
||||||
|
|
||||||
|
BoolOption("withropeunicode", "use ropes for the unicode implementation",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.withrope", True)]),
|
||||||
|
|
||||||
|
BoolOption("withcelldict",
|
||||||
|
"use dictionaries that are optimized for being used as module dicts",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.opcodes.CALL_LIKELY_BUILTIN", False),
|
||||||
|
("objspace.honor__builtins__", False)]),
|
||||||
|
|
||||||
|
BoolOption("withdictmeasurement",
|
||||||
|
"create huge files with masses of information "
|
||||||
|
"about dictionaries",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withmapdict",
|
||||||
|
"make instances really small but slow without the JIT",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.getattributeshortcut", True),
|
||||||
|
("objspace.std.withtypeversion", True),
|
||||||
|
]),
|
||||||
|
|
||||||
|
BoolOption("withrangelist",
|
||||||
|
"enable special range list implementation that does not "
|
||||||
|
"actually create the full list until the resulting "
|
||||||
|
"list is mutated",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("withtypeversion",
|
||||||
|
"version type objects when changing them",
|
||||||
|
default=False,
|
||||||
|
# weakrefs needed, because of get_subclasses()
|
||||||
|
requires=[("translation.rweakref", True)]),
|
||||||
|
|
||||||
|
BoolOption("withmethodcache",
|
||||||
|
"try to cache method lookups",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.withtypeversion", True),
|
||||||
|
("translation.rweakref", True)]),
|
||||||
|
BoolOption("withmethodcachecounter",
|
||||||
|
"try to cache methods and provide a counter in __pypy__. "
|
||||||
|
"for testing purposes only.",
|
||||||
|
default=False,
|
||||||
|
requires=[("objspace.std.withmethodcache", True)]),
|
||||||
|
IntOption("methodcachesizeexp",
|
||||||
|
" 2 ** methodcachesizeexp is the size of the of the method cache ",
|
||||||
|
default=11),
|
||||||
|
BoolOption("optimized_int_add",
|
||||||
|
"special case the addition of two integers in BINARY_ADD",
|
||||||
|
default=False),
|
||||||
|
BoolOption("optimized_comparison_op",
|
||||||
|
"special case the comparison of integers",
|
||||||
|
default=False),
|
||||||
|
BoolOption("optimized_list_getitem",
|
||||||
|
"special case the 'list[integer]' expressions",
|
||||||
|
default=False),
|
||||||
|
BoolOption("builtinshortcut",
|
||||||
|
"a shortcut for operations between built-in types",
|
||||||
|
default=False),
|
||||||
|
BoolOption("getattributeshortcut",
|
||||||
|
"track types that override __getattribute__",
|
||||||
|
default=False),
|
||||||
|
BoolOption("newshortcut",
|
||||||
|
"cache and shortcut calling __new__ from builtin types",
|
||||||
|
default=False),
|
||||||
|
|
||||||
|
BoolOption("logspaceoptypes",
|
||||||
|
"a instrumentation option: before exit, print the types seen by "
|
||||||
|
"certain simpler bytecodes",
|
||||||
|
default=False),
|
||||||
|
ChoiceOption("multimethods", "the multimethod implementation to use",
|
||||||
|
["doubledispatch", "mrd"],
|
||||||
|
default="mrd"),
|
||||||
|
BoolOption("immutable_builtintypes",
|
||||||
|
"Forbid the changing of builtin types", default=True),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def get_combined_translation_config(other_optdescr=None,
|
||||||
|
existing_config=None,
|
||||||
|
overrides=None,
|
||||||
|
translating=False):
|
||||||
|
if overrides is None:
|
||||||
|
overrides = {}
|
||||||
|
d = BoolOption("translating",
|
||||||
|
"indicates whether we are translating currently",
|
||||||
|
default=False)
|
||||||
|
if other_optdescr is None:
|
||||||
|
children = []
|
||||||
|
newname = ""
|
||||||
|
else:
|
||||||
|
children = [other_optdescr]
|
||||||
|
newname = other_optdescr._name
|
||||||
|
descr = OptionDescription("eole", "all options", children)
|
||||||
|
config = Config(descr, **overrides)
|
||||||
|
if translating:
|
||||||
|
config.translating = True
|
||||||
|
if existing_config is not None:
|
||||||
|
for child in existing_config._cfgimpl_descr._children:
|
||||||
|
if child._name == newname:
|
||||||
|
continue
|
||||||
|
value = getattr(existing_config, child._name)
|
||||||
|
config._cfgimpl_values[child._name] = value
|
||||||
|
return config
|
||||||
|
|
||||||
|
def get_example_config(overrides=None, translating=False):
|
||||||
|
return get_combined_translation_config(
|
||||||
|
example__optiondescription, overrides=overrides,
|
||||||
|
translating=translating)
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def test_example_option():
|
||||||
|
config = get_example_config()
|
||||||
|
result = ['objspace.name', 'objspace.opcodes.CALL_LIKELY_BUILTIN',
|
||||||
|
'objspace.opcodes.CALL_METHOD', 'objspace.nofaking',
|
||||||
|
'objspace.usemodules.amon', 'objspace.usemodules.sphynx',
|
||||||
|
'objspace.usemodules.zephir', 'objspace.allworkingmodules',
|
||||||
|
'objspace.translationmodules', 'objspace.geninterp',
|
||||||
|
'objspace.logbytecodes', 'objspace.usepycfiles', 'objspace.lonepycfiles',
|
||||||
|
'objspace.soabi', 'objspace.honor__builtins__',
|
||||||
|
'objspace.disable_call_speedhacks', 'objspace.timing',
|
||||||
|
'objspace.std.withtproxy', 'objspace.std.withsmallint',
|
||||||
|
'objspace.std.withprebuiltint', 'objspace.std.prebuiltintfrom',
|
||||||
|
'objspace.std.prebuiltintto', 'objspace.std.withstrjoin',
|
||||||
|
'objspace.std.withstrslice', 'objspace.std.withstrbuf',
|
||||||
|
'objspace.std.withprebuiltchar', 'objspace.std.sharesmallstr',
|
||||||
|
'objspace.std.withrope', 'objspace.std.withropeunicode',
|
||||||
|
'objspace.std.withcelldict', 'objspace.std.withdictmeasurement',
|
||||||
|
'objspace.std.withmapdict', 'objspace.std.withrangelist',
|
||||||
|
'objspace.std.withtypeversion', 'objspace.std.withmethodcache',
|
||||||
|
'objspace.std.withmethodcachecounter', 'objspace.std.methodcachesizeexp',
|
||||||
|
'objspace.std.optimized_int_add', 'objspace.std.optimized_comparison_op',
|
||||||
|
'objspace.std.optimized_list_getitem', 'objspace.std.builtinshortcut',
|
||||||
|
'objspace.std.getattributeshortcut', 'objspace.std.newshortcut',
|
||||||
|
'objspace.std.logspaceoptypes', 'objspace.std.multimethods',
|
||||||
|
'objspace.std.immutable_builtintypes']
|
||||||
|
|
||||||
|
assert config.getpaths(allpaths=True) == result
|
|
@ -0,0 +1,207 @@
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def make_description_duplicates():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
## dummy 1
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
# dummy2 (same name)
|
||||||
|
gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, gcdummy2, floatoption])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_identical_names():
|
||||||
|
"""If in the schema (the option description) there is something that
|
||||||
|
have the same name, an exection is raised
|
||||||
|
"""
|
||||||
|
descr = make_description_duplicates()
|
||||||
|
raises(ConflictConfigError, "cfg = Config(descr)")
|
||||||
|
|
||||||
|
def make_description2():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
# first multi
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
boolop.enable_multi()
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
# second multi
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option.enable_multi()
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
# FIXME: XXX would you mind putting the multi validations anywhere else
|
||||||
|
# than in the requires !!!
|
||||||
|
#def test_multi_constraints():
|
||||||
|
# "a multi in a constraint has to have the same length"
|
||||||
|
# descr = make_description2()
|
||||||
|
# cfg = Config(descr)
|
||||||
|
# cfg.boolop = [True, True, False]
|
||||||
|
# cfg.wantframework = [False, False, True]
|
||||||
|
#
|
||||||
|
#def test_multi_raise():
|
||||||
|
# "a multi in a constraint has to have the same length"
|
||||||
|
# # FIXME fusionner les deux tests, MAIS PROBLEME :
|
||||||
|
# # il ne devrait pas etre necessaire de refaire une config
|
||||||
|
# # si la valeur est modifiee une deuxieme fois ->
|
||||||
|
# #raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
|
||||||
|
# # ExceptionFailure: 'DID NOT RAISE'
|
||||||
|
# descr = make_description2()
|
||||||
|
# cfg = Config(descr)
|
||||||
|
# cfg.boolop = [True]
|
||||||
|
# raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
|
||||||
|
# ____________________________________________________________
|
||||||
|
# adding dynamically new options description schema
|
||||||
|
def test_newoption_add_in_descr():
|
||||||
|
descr = make_description()
|
||||||
|
newoption = BoolOption('newoption', 'dummy twoo', default=False)
|
||||||
|
descr.add_child(newoption)
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.newoption == False
|
||||||
|
|
||||||
|
def test_newoption_add_in_subdescr():
|
||||||
|
descr = make_description()
|
||||||
|
newoption = BoolOption('newoption', 'dummy twoo', default=False)
|
||||||
|
descr.gc.add_child(newoption)
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config.gc.newoption == False
|
||||||
|
|
||||||
|
def test_newoption_add_in_config():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
newoption = BoolOption('newoption', 'dummy twoo', default=False)
|
||||||
|
descr.add_child(newoption)
|
||||||
|
config.cfgimpl_update()
|
||||||
|
assert config.newoption == False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def make_description_requires():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide')])
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
stroption, intoption])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_hidden_if_in():
|
||||||
|
descr = make_description_requires()
|
||||||
|
cfg = Config(descr)
|
||||||
|
intoption = cfg.unwrap_from_path('int')
|
||||||
|
stroption = cfg.unwrap_from_path('str')
|
||||||
|
assert not stroption._is_hidden()
|
||||||
|
cfg.int = 1
|
||||||
|
raises(HiddenOptionError, "cfg.str")
|
||||||
|
raises(HiddenOptionError, 'cfg.str= "uvw"')
|
||||||
|
assert stroption._is_hidden()
|
||||||
|
|
||||||
|
def test_hidden_if_in_with_group():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
|
||||||
|
requires=[('int', 1, 'hide')])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption,
|
||||||
|
objspaceoption, stroption, intoption])
|
||||||
|
cfg = Config(descr)
|
||||||
|
assert not gcgroup._is_hidden()
|
||||||
|
cfg.int = 1
|
||||||
|
raises(HiddenOptionError, "cfg.gc.name")
|
||||||
|
# raises(HiddenOptionError, 'cfg.gc= "uvw"')
|
||||||
|
assert gcgroup._is_hidden()
|
||||||
|
|
||||||
|
def test_disabled_with_group():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
|
||||||
|
requires=[('int', 1, 'disable')])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption,
|
||||||
|
objspaceoption, stroption, intoption])
|
||||||
|
cfg = Config(descr)
|
||||||
|
assert not gcgroup._is_disabled()
|
||||||
|
cfg.int = 1
|
||||||
|
raises(DisabledOptionError, "cfg.gc.name")
|
||||||
|
# raises(HiddenOptionError, 'cfg.gc= "uvw"')
|
||||||
|
assert gcgroup._is_disabled()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
"test all types of option default values for options, add new option in a descr"
|
||||||
|
import autopath
|
||||||
|
|
||||||
|
from py.test import raises
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
from error import MandatoryError
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
# default values
|
||||||
|
def test_default_is_none():
|
||||||
|
"""
|
||||||
|
Most constructors take a ``default`` argument that specifies the default
|
||||||
|
value of the option. If this argument is not supplied the default value is
|
||||||
|
assumed to be ``None``.
|
||||||
|
"""
|
||||||
|
dummy1 = BoolOption('dummy1', 'doc dummy')
|
||||||
|
dummy2 = BoolOption('dummy2', 'doc dummy')
|
||||||
|
group = OptionDescription('group', '', [dummy1, dummy2])
|
||||||
|
config = Config(group)
|
||||||
|
# so when the default value is not set, there is actually a default value
|
||||||
|
assert config.dummy1 == None
|
||||||
|
assert config.dummy2 == None
|
||||||
|
|
||||||
|
def test_set_defaut_value_from_option_object():
|
||||||
|
"""Options have an available default setting and can give it back"""
|
||||||
|
b = BoolOption("boolean", "", default=False)
|
||||||
|
assert b.getdefault() == False
|
||||||
|
|
||||||
|
def test_mandatory():
|
||||||
|
dummy1 = BoolOption('dummy1', 'doc dummy', mandatory=True)
|
||||||
|
dummy2 = BoolOption('dummy2', 'doc dummy', mandatory=True)
|
||||||
|
group = OptionDescription('group', '', [dummy1, dummy2])
|
||||||
|
config = Config(group)
|
||||||
|
# config.setoption('dummy1', True)
|
||||||
|
raises(MandatoryError, 'config.dummy1')
|
||||||
|
config.dummy1 = True
|
||||||
|
assert config.dummy1 == True
|
||||||
|
raises(MandatoryError, 'config.dummy2 == None')
|
||||||
|
raises(MandatoryError, "config.override({'dummy2':None})")
|
||||||
|
config.set(dummy2=True)
|
||||||
|
config.dummy2 = False
|
||||||
|
assert config.dummy2 == False
|
||||||
|
|
||||||
|
def test_override_are_defaults():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
|
||||||
|
config.gc.dummy = True
|
||||||
|
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
#Options have an available default setting and can give it back
|
||||||
|
assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False
|
||||||
|
config.override({'gc.dummy':True})
|
||||||
|
#assert config.gc.dummy == True
|
||||||
|
#assert config._cfgimpl_descr._children[0]._children[1].getdefault() == True
|
||||||
|
#assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'default'
|
||||||
|
|
||||||
|
def test_overrides_changes_option_value():
|
||||||
|
"with config.override(), the default is changed and the value is changed"
|
||||||
|
descr = OptionDescription("test", "", [
|
||||||
|
BoolOption("b", "", default=False)])
|
||||||
|
config = Config(descr)
|
||||||
|
config.b = True
|
||||||
|
config.override({'b': False})
|
||||||
|
assert config.b == False
|
||||||
|
#____________________________________________________________
|
||||||
|
# test various option types
|
||||||
|
def test_choice_with_no_default():
|
||||||
|
descr = OptionDescription("test", "", [
|
||||||
|
ChoiceOption("backend", "", ["c", "cli"])])
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.backend is None
|
||||||
|
config.backend = "c"
|
||||||
|
|
||||||
|
def test_choice_with_default():
|
||||||
|
descr = OptionDescription("test", "", [
|
||||||
|
ChoiceOption("backend", "", ["c", "cli"], default="cli")])
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.backend == "cli"
|
||||||
|
|
||||||
|
def test_arbitrary_option():
|
||||||
|
descr = OptionDescription("top", "", [
|
||||||
|
ArbitraryOption("a", "no help", default=None)
|
||||||
|
])
|
||||||
|
config = Config(descr)
|
||||||
|
config.a = []
|
||||||
|
config.a.append(1)
|
||||||
|
assert config.a == [1]
|
||||||
|
|
||||||
|
descr = OptionDescription("top", "", [
|
||||||
|
ArbitraryOption("a", "no help", defaultfactory=list)
|
||||||
|
])
|
||||||
|
c1 = Config(descr)
|
||||||
|
c2 = Config(descr)
|
||||||
|
c1.a.append(1)
|
||||||
|
assert c2.a == []
|
||||||
|
assert c1.a == [1]
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
import autopath
|
||||||
|
|
||||||
|
from py.test import raises
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
from error import SpecialOwnersError
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
## dummy 1
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_override_are_default_owner():
|
||||||
|
"config.override() implies that the owner is 'default' again"
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
# defaut
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
|
||||||
|
# user
|
||||||
|
config.gc.dummy = True
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
#Options have an available default setting and can give it back
|
||||||
|
assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False
|
||||||
|
config.override({'gc.dummy':True})
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
|
||||||
|
# user again
|
||||||
|
config.gc.dummy = False
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
|
||||||
|
def test_change_owner():
|
||||||
|
descr = make_description()
|
||||||
|
# here the owner is 'default'
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
# the default owner is 'user' (which is not 'default')
|
||||||
|
# Still not getting it ? read the docs
|
||||||
|
config.gc.dummy = True
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||||
|
config.cfgimpl_set_owner('eggs')
|
||||||
|
config.set(dummy=False)
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'eggs'
|
||||||
|
config.cfgimpl_set_owner('spam')
|
||||||
|
gcdummy = config.unwrap_from_path('gc.dummy')
|
||||||
|
gcdummy.setowner(config.gc, 'blabla')
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'blabla'
|
||||||
|
config.gc.dummy = True
|
||||||
|
assert config.gc._cfgimpl_value_owners['dummy'] == 'spam'
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
# special owners
|
||||||
|
def test_auto_owner():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
config.gc.setoption('dummy', True, 'auto')
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy")
|
||||||
|
raises(ConflictConfigError, "config.gc.setoption('dummy', False, 'auto')")
|
||||||
|
# shall return an auto value...
|
||||||
|
#assert config.gc.dummy == 'auto_dummy_value'
|
||||||
|
|
||||||
|
def test_cannot_override_special_owners():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
config.gc.setoption('dummy', True, 'auto')
|
||||||
|
raises(SpecialOwnersError, "config.override({'gc.dummy': True})")
|
||||||
|
|
||||||
|
def test_fill_owner():
|
||||||
|
"fill option"
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config.bool == False
|
||||||
|
assert config.gc.dummy == False
|
||||||
|
# 'fill' special values
|
||||||
|
config.gc.setoption('dummy', True, 'fill')
|
||||||
|
assert config.gc.dummy == False
|
||||||
|
|
||||||
|
def test_auto_fill_and_override():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
booloption = config.unwrap_from_path('bool')
|
||||||
|
booloption.callback = 'identical'
|
||||||
|
booloption.setowner(config, 'auto')
|
||||||
|
assert config.bool == 'identicalbool'
|
||||||
|
gcdummy = config.unwrap_from_path('gc.dummy')
|
||||||
|
gcdummy.callback = 'identical'
|
||||||
|
gcdummy.setowner(config.gc, 'fill')
|
||||||
|
raises(SpecialOwnersError, "config.override({'gc.dummy':True})")
|
||||||
|
config.gc.setoption('dummy', False, 'fill')
|
||||||
|
# value is returned
|
||||||
|
assert config.gc.dummy == False
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,356 @@
|
||||||
|
"config.set() or config.setoption() or option.setoption()"
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
from error import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False)
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
# change with __setattr__
|
||||||
|
def test_attribute_access():
|
||||||
|
"Once set, option values can't be changed again by attribute access"
|
||||||
|
s = StrOption("string", "", default="string")
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
# let's try to change it again
|
||||||
|
config.string = "foo"
|
||||||
|
assert config.string == "foo"
|
||||||
|
# raises(ConflictConfigError, 'config.string = "bar"')
|
||||||
|
|
||||||
|
def test_idontexist():
|
||||||
|
descr = make_description()
|
||||||
|
cfg = Config(descr)
|
||||||
|
raises(AttributeError, "cfg.idontexist")
|
||||||
|
# ____________________________________________________________
|
||||||
|
def test_attribute_access_with_multi():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
config.string = ["foo", "bar"]
|
||||||
|
assert config.string == ["foo", "bar"]
|
||||||
|
|
||||||
|
def test_attribute_access_with_multi():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
config.string = ["foo", "bar"]
|
||||||
|
assert config.string == ["foo", "bar"]
|
||||||
|
|
||||||
|
def test_multi_with_requires():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide')], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s, intoption, stroption])
|
||||||
|
config = Config(descr)
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
config.int = 1
|
||||||
|
raises(HiddenOptionError, "config.str = ['a', 'b']")
|
||||||
|
assert stroption._is_hidden()
|
||||||
|
|
||||||
|
def test__requires_with_inverted():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide', 'inverted')], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s, intoption, stroption])
|
||||||
|
config = Config(descr)
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
config.int = 1
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
|
||||||
|
def test_multi_with_requires_in_another_group():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
descr = OptionDescription("options", "", [intoption])
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide')], multi=True)
|
||||||
|
descr = OptionDescription("opt", "", [stroption])
|
||||||
|
descr2 = OptionDescription("opt2", "", [intoption, s, descr])
|
||||||
|
config = Config(descr2)
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
config.int = 1
|
||||||
|
raises(HiddenOptionError, "config.opt.str = ['a', 'b']")
|
||||||
|
assert stroption._is_hidden()
|
||||||
|
|
||||||
|
def test_apply_requires_from_config():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
descr = OptionDescription("options", "", [intoption])
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'hide')], multi=True)
|
||||||
|
descr = OptionDescription("opt", "", [stroption])
|
||||||
|
descr2 = OptionDescription("opt2", "", [intoption, s, descr])
|
||||||
|
config = Config(descr2)
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
config.int = 1
|
||||||
|
try:
|
||||||
|
config.opt.str
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
assert stroption._is_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_apply_requires_with_disabled():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
descr = OptionDescription("options", "", [intoption])
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'disable')], multi=True)
|
||||||
|
descr = OptionDescription("opt", "", [stroption])
|
||||||
|
descr2 = OptionDescription("opt2", "", [intoption, s, descr])
|
||||||
|
config = Config(descr2)
|
||||||
|
assert stroption._is_disabled() == False
|
||||||
|
config.int = 1
|
||||||
|
try:
|
||||||
|
config.opt.str
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
assert stroption._is_disabled()
|
||||||
|
|
||||||
|
def test_multi_with_requires_with_disabled_in_another_group():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
descr = OptionDescription("options", "", [intoption])
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', 1, 'disable')], multi=True)
|
||||||
|
descr = OptionDescription("opt", "", [stroption])
|
||||||
|
descr2 = OptionDescription("opt2", "", [intoption, s, descr])
|
||||||
|
config = Config(descr2)
|
||||||
|
assert stroption._is_disabled() == False
|
||||||
|
config.int = 1
|
||||||
|
raises(DisabledOptionError, "config.opt.str = ['a', 'b']")
|
||||||
|
assert stroption._is_disabled()
|
||||||
|
|
||||||
|
def test_multi_with_requires_that_is_multi():
|
||||||
|
s = StrOption("string", "", default="string", multi=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=[0, 0], multi=True)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc",
|
||||||
|
requires=[('int', [1, 1], 'hide')], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s, intoption, stroption])
|
||||||
|
config = Config(descr)
|
||||||
|
assert stroption._is_hidden() == False
|
||||||
|
config.int = [1, 1]
|
||||||
|
raises(HiddenOptionError, "config.str = ['a', 'b']")
|
||||||
|
assert stroption._is_hidden()
|
||||||
|
|
||||||
|
def test_multi_with_bool():
|
||||||
|
s = BoolOption("bool", "", default=[False], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
assert descr.bool.multi == True
|
||||||
|
config.bool = [True, False]
|
||||||
|
assert config._cfgimpl_values['bool'] == [True, False]
|
||||||
|
assert config.bool == [True, False]
|
||||||
|
|
||||||
|
def test_multi_with_bool_two():
|
||||||
|
s = BoolOption("bool", "", default=[False], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
assert descr.bool.multi == True
|
||||||
|
raises(ConfigError, "config.bool = True")
|
||||||
|
|
||||||
|
def test_choice_access_with_multi():
|
||||||
|
ch = ChoiceOption("t1", "", ["a", "b"], default=["a", "a", "a"], multi=True)
|
||||||
|
descr = OptionDescription("options", "", [ch])
|
||||||
|
config = Config(descr)
|
||||||
|
config.t1 = ["a", "b", "a", "b"]
|
||||||
|
assert config.t1 == ["a", "b", "a", "b"]
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def test_setoption_from_option():
|
||||||
|
"a setoption directly from the option is **not** a good practice"
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
descr = OptionDescription('descr', '', [booloption])
|
||||||
|
cfg = Config(descr)
|
||||||
|
booloption.setoption(cfg, False, 'owner')
|
||||||
|
assert cfg.bool == False
|
||||||
|
# ____________________________________________________________
|
||||||
|
def test_set_mode_in_config():
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True,
|
||||||
|
mode='expert')
|
||||||
|
descr = OptionDescription('descr', '', [booloption])
|
||||||
|
cfg = Config(descr)
|
||||||
|
cfg.cfgimpl_set_mode('expert')
|
||||||
|
raises(ModeOptionError, "cfg.bool")
|
||||||
|
cfg.cfgimpl_set_mode('normal')
|
||||||
|
assert cfg.bool == True
|
||||||
|
#____________________________________________________________
|
||||||
|
def test_dwim_set():
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("sub", "", [
|
||||||
|
BoolOption("b1", ""),
|
||||||
|
ChoiceOption("c1", "", ['a', 'b', 'c'], 'a'),
|
||||||
|
BoolOption("d1", ""),
|
||||||
|
]),
|
||||||
|
BoolOption("b2", ""),
|
||||||
|
BoolOption("d1", ""),
|
||||||
|
])
|
||||||
|
c = Config(descr)
|
||||||
|
c.set(b1=False, c1='b')
|
||||||
|
assert not c.sub.b1
|
||||||
|
assert c.sub.c1 == 'b'
|
||||||
|
# new config, because you cannot change values once they are set
|
||||||
|
c = Config(descr)
|
||||||
|
c.set(b2=False, **{'sub.c1': 'c'})
|
||||||
|
assert not c.b2
|
||||||
|
assert c.sub.c1 == 'c'
|
||||||
|
raises(AmbigousOptionError, "c.set(d1=True)")
|
||||||
|
raises(NoMatchingOptionFound, "c.set(unknown='foo')")
|
||||||
|
|
||||||
|
def test_more_set():
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("s1", "", [
|
||||||
|
BoolOption("a", "", default=False)]),
|
||||||
|
IntOption("int", "", default=42)])
|
||||||
|
d = {'s1.a': True, 'int': 23}
|
||||||
|
config = Config(descr)
|
||||||
|
config.set(**d)
|
||||||
|
assert config.s1.a
|
||||||
|
assert config.int == 23
|
||||||
|
|
||||||
|
def test_set_with_hidden_option():
|
||||||
|
boolopt = BoolOption("a", "", default=False)
|
||||||
|
boolopt.hide()
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("s1", "", [boolopt]),
|
||||||
|
IntOption("int", "", default=42)])
|
||||||
|
d = {'s1.a': True, 'int': 23}
|
||||||
|
config = Config(descr)
|
||||||
|
raises(HiddenOptionError, "config.set(**d)")
|
||||||
|
|
||||||
|
def test_set_with_unknown_option():
|
||||||
|
boolopt = BoolOption("b", "", default=False)
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("s1", "", [boolopt]),
|
||||||
|
IntOption("int", "", default=42)])
|
||||||
|
d = {'s1.a': True, 'int': 23}
|
||||||
|
config = Config(descr)
|
||||||
|
raises(NoMatchingOptionFound, "config.set(**d)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_symlink_option():
|
||||||
|
boolopt = BoolOption("b", "", default=False)
|
||||||
|
linkopt = SymLinkOption("c", "s1.b")
|
||||||
|
descr = OptionDescription("opt", "",
|
||||||
|
[linkopt, OptionDescription("s1", "", [boolopt])])
|
||||||
|
config = Config(descr)
|
||||||
|
setattr(config, "s1.b", True)
|
||||||
|
setattr(config, "s1.b", False)
|
||||||
|
assert config.s1.b == False
|
||||||
|
assert config.c == False
|
||||||
|
config.c = True
|
||||||
|
assert config.s1.b == True
|
||||||
|
assert config.c == True
|
||||||
|
config.c = False
|
||||||
|
assert config.s1.b == False
|
||||||
|
assert config.c == False
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
def test_config_impl_values():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
# gcdummy.setoption(config, True, "user")
|
||||||
|
# config.setoption("gc.dummy", True, "user")
|
||||||
|
#config.gc.dummy = True
|
||||||
|
# config.setoption("bool", False, "user")
|
||||||
|
config.set(dummy=False)
|
||||||
|
assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
|
||||||
|
## acces to the option object
|
||||||
|
# config.gc._cfgimpl_descr.dummy.setoption(config, True, "user")
|
||||||
|
assert config.gc.dummy == False
|
||||||
|
# config.set(dummy=True)
|
||||||
|
# assert config.gc.dummy == True
|
||||||
|
|
||||||
|
#____________________________________________________________
|
||||||
|
def test_accepts_multiple_changes_from_option():
|
||||||
|
s = StrOption("string", "", default="string")
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
config.string = "egg"
|
||||||
|
assert s.getdefault() == "string"
|
||||||
|
assert config.string == "egg"
|
||||||
|
s.setoption(config, 'blah', "default")
|
||||||
|
assert s.getdefault() == "blah"
|
||||||
|
assert config.string == "blah"
|
||||||
|
s.setoption(config, 'bol', "user")
|
||||||
|
assert config.string == 'bol'
|
||||||
|
config.override({'string': "blurp"})
|
||||||
|
assert config.string == 'blurp'
|
||||||
|
assert s.getdefault() == 'blurp'
|
||||||
|
|
||||||
|
def test_allow_multiple_changes_from_config():
|
||||||
|
"""
|
||||||
|
a `setoption` from the config object is much like the attribute access,
|
||||||
|
except the fact that value owner can bet set
|
||||||
|
"""
|
||||||
|
s = StrOption("string", "", default="string")
|
||||||
|
s2 = StrOption("string2", "", default="string")
|
||||||
|
suboption = OptionDescription("bip", "", [s2])
|
||||||
|
descr = OptionDescription("options", "", [s, suboption])
|
||||||
|
config = Config(descr)
|
||||||
|
config.setoption("string", 'blah', "user")
|
||||||
|
config.setoption("string", "oh", "user")
|
||||||
|
assert config.string == "oh"
|
||||||
|
config.set(string2= 'blah')
|
||||||
|
assert config.bip.string2 == 'blah'
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
def test_overrides_are_defaults():
|
||||||
|
descr = OptionDescription("test", "", [
|
||||||
|
BoolOption("b1", "", default=False),
|
||||||
|
BoolOption("b2", "", default=False),
|
||||||
|
])
|
||||||
|
# overrides here
|
||||||
|
config = Config(descr, b2=True)
|
||||||
|
assert config.b2
|
||||||
|
# test with a require
|
||||||
|
config.b1 = True
|
||||||
|
assert config.b2
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
# accessing a value by the get method
|
||||||
|
def test_access_by_get():
|
||||||
|
descr = make_description()
|
||||||
|
cfg = Config(descr)
|
||||||
|
raises(NotFoundError, "cfg.get('idontexist')" )
|
||||||
|
assert cfg.get('wantref') == False
|
||||||
|
assert cfg.gc.dummy == False
|
||||||
|
assert cfg.get('dummy') == False
|
||||||
|
|
||||||
|
def test_access_by_get_whith_hide():
|
||||||
|
b1 = BoolOption("b1", "")
|
||||||
|
b1.hide()
|
||||||
|
descr = OptionDescription("opt", "", [
|
||||||
|
OptionDescription("sub", "", [
|
||||||
|
b1,
|
||||||
|
ChoiceOption("c1", "", ['a', 'b', 'c'], 'a'),
|
||||||
|
BoolOption("d1", ""),
|
||||||
|
]),
|
||||||
|
BoolOption("b2", ""),
|
||||||
|
BoolOption("d1", ""),
|
||||||
|
])
|
||||||
|
c = Config(descr)
|
||||||
|
raises(HiddenOptionError, "c.get('b1')")
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
# coding: utf-8
|
||||||
|
"frozen and hidden values"
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcoption.set_mode("expert")
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
# hidding dummy here
|
||||||
|
gcdummy.hide()
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=[('gc.name', 'ref')])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=[('gc.name', 'framework')])
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
booloptiontwo = BoolOption('booltwo', 'Test boolean option two', default=False)
|
||||||
|
subgroup = OptionDescription('subgroup', '', [booloptiontwo])
|
||||||
|
# ____________________________________________________________
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [subgroup, gcoption, gcdummy, floatoption])
|
||||||
|
gcgroup.set_mode("expert")
|
||||||
|
descr = OptionDescription('trs', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption])
|
||||||
|
return descr
|
||||||
|
#____________________________________________________________
|
||||||
|
#freeze
|
||||||
|
def make_description_freeze():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False,
|
||||||
|
requires=['boolop'])
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_freeze_one_option():
|
||||||
|
"freeze an option "
|
||||||
|
descr = make_description_freeze()
|
||||||
|
conf = Config(descr)
|
||||||
|
#freeze only one option
|
||||||
|
conf.gc._cfgimpl_descr.dummy.freeze()
|
||||||
|
assert conf.gc.dummy == False
|
||||||
|
raises(TypeError, "conf.gc.dummy = True")
|
||||||
|
|
||||||
|
def test_frozen_value():
|
||||||
|
"setattr a frozen value at the config level"
|
||||||
|
s = StrOption("string", "", default="string")
|
||||||
|
descr = OptionDescription("options", "", [s])
|
||||||
|
config = Config(descr)
|
||||||
|
s.freeze()
|
||||||
|
raises(ConfigError, 'config.string = "egg"')
|
||||||
|
|
||||||
|
def test_freeze():
|
||||||
|
"freeze a whole configuration object"
|
||||||
|
descr = make_description()
|
||||||
|
conf = Config(descr)
|
||||||
|
conf.cfgimpl_freeze()
|
||||||
|
raises(ConfigError, "conf.gc.name = 'try to modify'")
|
||||||
|
# ____________________________________________________________
|
||||||
|
def test_is_hidden():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.gc._cfgimpl_descr.dummy._is_hidden() == True
|
||||||
|
# setattr
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy == False")
|
||||||
|
# getattr
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy")
|
||||||
|
# I want to access to this option anyway
|
||||||
|
path = 'gc.dummy'
|
||||||
|
homeconfig, name = config._cfgimpl_get_home_by_path(path)
|
||||||
|
assert homeconfig._cfgimpl_values[name] == False
|
||||||
|
|
||||||
|
def test_group_is_hidden():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
gc = config.unwrap_from_path('gc')
|
||||||
|
gc.hide()
|
||||||
|
dummy = config.unwrap_from_path('gc.dummy')
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy")
|
||||||
|
assert gc._is_hidden()
|
||||||
|
raises(HiddenOptionError, "config.gc.float")
|
||||||
|
# manually set the subconfigs to "show"
|
||||||
|
gc.show()
|
||||||
|
assert gc._is_hidden() == False
|
||||||
|
assert config.gc.float == 2.3
|
||||||
|
#dummy est en hide
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy == False")
|
||||||
|
|
||||||
|
def test_global_show():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.gc._cfgimpl_descr.dummy._is_hidden() == True
|
||||||
|
raises(HiddenOptionError, "config.gc.dummy == False")
|
||||||
|
|
||||||
|
def test_with_many_subgroups():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.gc.subgroup._cfgimpl_descr.booltwo._is_hidden() == False
|
||||||
|
assert config.gc.subgroup.booltwo == False
|
||||||
|
config.gc.subgroup._cfgimpl_descr.booltwo.hide()
|
||||||
|
path = 'gc.subgroup.booltwo'
|
||||||
|
homeconfig, name = config._cfgimpl_get_home_by_path(path)
|
||||||
|
assert name == "booltwo"
|
||||||
|
option = getattr(homeconfig._cfgimpl_descr, name)
|
||||||
|
assert option._is_hidden()
|
||||||
|
|
||||||
|
def test_option_mode():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.gc._cfgimpl_descr.name.get_mode() == 'expert'
|
||||||
|
assert config._cfgimpl_descr.gc.get_mode() == 'expert'
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#this test is much more to test that **it's there** and answers attribute access
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
gcdummy2 = BoolOption('hide', 'dummy', default=True)
|
||||||
|
objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
['std', 'thunk'], 'std')
|
||||||
|
booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption, gcdummy2])
|
||||||
|
descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
wantref_option, stroption,
|
||||||
|
wantframework_option,
|
||||||
|
intoption, boolop])
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_base_config_and_groups():
|
||||||
|
descr = make_description()
|
||||||
|
# overrides the booloption default value
|
||||||
|
config = Config(descr, bool=False)
|
||||||
|
assert config.gc.hide == True
|
||||||
|
|
||||||
|
def test_root_config_answers_ok():
|
||||||
|
"if you hide the root config, the options in this namespace behave normally"
|
||||||
|
gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
descr = OptionDescription('tiramisu', '', [gcdummy, boolop])
|
||||||
|
cfg = Config(descr)
|
||||||
|
cfg.cfgimpl_hide()
|
||||||
|
assert cfg.dummy == False
|
||||||
|
assert cfg.boolop == True
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
# coding: utf-8
|
||||||
|
import autopath
|
||||||
|
from config import *
|
||||||
|
from option import *
|
||||||
|
|
||||||
|
def make_description():
|
||||||
|
numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
|
||||||
|
nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
|
||||||
|
nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
|
||||||
|
default=1)
|
||||||
|
activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
|
||||||
|
default=False)
|
||||||
|
mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
|
||||||
|
default=False)
|
||||||
|
# hidden (variable cachée)
|
||||||
|
# mode_conteneur_actif.taint()
|
||||||
|
adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
|
||||||
|
time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
|
||||||
|
['Paris', 'Londres'], 'Paris')
|
||||||
|
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||||
|
|
||||||
|
master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
interface1 = OptionDescription('interface1', '', [master])
|
||||||
|
interface1.set_group_type('group')
|
||||||
|
|
||||||
|
general = OptionDescription('general', '', [numero_etab, nom_machine,
|
||||||
|
nombre_interfaces, activer_proxy_client,
|
||||||
|
mode_conteneur_actif, adresse_serveur_ntp,
|
||||||
|
time_zone])
|
||||||
|
general.set_group_type('family')
|
||||||
|
creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
|
||||||
|
descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole] )
|
||||||
|
return descr
|
||||||
|
|
||||||
|
def test_base_config():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
assert config.creole.general.activer_proxy_client == False
|
||||||
|
assert config.creole.general.nom_machine == "eoleng"
|
||||||
|
assert config.get('nom_machine') == "eoleng"
|
||||||
|
result = {'general.numero_etab': None, 'general.nombre_interfaces': 1,
|
||||||
|
'general.serveur_ntp': None, 'interface1.ip_admin_eth0.ip_admin_eth0': None,
|
||||||
|
'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris',
|
||||||
|
'interface1.ip_admin_eth0.netmask_admin_eth0': None, 'general.nom_machine':
|
||||||
|
'eoleng', 'general.activer_proxy_client': False}
|
||||||
|
assert make_dict(config.creole) == result
|
||||||
|
result = {'serveur_ntp': None, 'mode_conteneur_actif': False,
|
||||||
|
'ip_admin_eth0': None, 'time_zone': 'Paris', 'numero_etab': None,
|
||||||
|
'netmask_admin_eth0': None, 'nom_machine': 'eoleng', 'activer_proxy_client':
|
||||||
|
False, 'nombre_interfaces': 1}
|
||||||
|
assert make_dict(config.creole, flatten=True) == result
|
||||||
|
|
||||||
|
def test_get_group_type():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
grp = config.unwrap_from_path('creole.general')
|
||||||
|
assert grp.get_group_type() == "family"
|
||||||
|
|
||||||
|
def test_iter_on_groups():
|
||||||
|
descr = make_description()
|
||||||
|
config = Config(descr)
|
||||||
|
result = list(config.creole.iter_groups(group_type= "family"))
|
||||||
|
group_names = [res[0] for res in result]
|
||||||
|
assert group_names == ['general']
|
||||||
|
result = list(config.creole.iter_groups())
|
||||||
|
group_names = [res[0] for res in result]
|
||||||
|
assert group_names == ['general', 'interface1']
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from tool import reverse_from_paths
|
||||||
|
|
||||||
|
#def make_description():
|
||||||
|
# gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||||
|
# gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||||
|
# objspaceoption = ChoiceOption('objspace', 'Object space',
|
||||||
|
# ['std', 'thunk'], 'std')
|
||||||
|
# booloption = BoolOption('bool', 'Test boolean option', default=True)
|
||||||
|
# intoption = IntOption('int', 'Test int option', default=0)
|
||||||
|
# floatoption = FloatOption('float', 'Test float option', default=2.3)
|
||||||
|
# stroption = StrOption('str', 'Test string option', default="abc")
|
||||||
|
# boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||||
|
# wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||||
|
# wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||||
|
# default=False)
|
||||||
|
#
|
||||||
|
# gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||||
|
# descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
|
||||||
|
# wantref_option, stroption,
|
||||||
|
# wantframework_option,
|
||||||
|
# intoption, boolop])
|
||||||
|
# return descr
|
||||||
|
|
||||||
|
def test_rebuild():
|
||||||
|
# pouvoir faire une comparaison avec equal
|
||||||
|
d = {"s1.s2.s3.s4.a": True, "int": 43, "s2.b":True, "s3.c": True, "s3.d":[1,2,3]}
|
||||||
|
cfg = reverse_from_paths(d)
|
||||||
|
assert cfg.s1.s2.s3.s4.a == True
|
||||||
|
assert cfg.int == 43
|
||||||
|
assert cfg.s2.b == True
|
||||||
|
assert cfg.s3.c == True
|
||||||
|
assert cfg.s3.d == [1,2,3]
|
||||||
|
|
||||||
|
# assert config.getpaths() == ['gc.name', 'gc.dummy', 'gc.float', 'bool',
|
||||||
|
# 'objspace', 'wantref', 'str', 'wantframework',
|
||||||
|
# 'int', 'boolop']
|
||||||
|
|
||||||
|
# assert config.getpaths(include_groups=False) == ['gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
||||||
|
# assert config.getpaths(include_groups=True) == ['gc', 'gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
|
|
@ -0,0 +1,26 @@
|
||||||
|
#this test is much more to test that **it's there** and answers attribute access
|
||||||
|
import autopath
|
||||||
|
from py.test import raises
|
||||||
|
|
||||||
|
from tool import extend
|
||||||
|
|
||||||
|
class A:
|
||||||
|
a = 'titi'
|
||||||
|
def tarte(self):
|
||||||
|
return "tart"
|
||||||
|
class B:
|
||||||
|
__metaclass__ = extend
|
||||||
|
|
||||||
|
def to_rst(self):
|
||||||
|
return "hello"
|
||||||
|
|
||||||
|
B.extend(A)
|
||||||
|
|
||||||
|
a = B()
|
||||||
|
|
||||||
|
def test_extendable():
|
||||||
|
assert a.a == 'titi'
|
||||||
|
assert a.tarte() == 'tart'
|
||||||
|
assert a.to_rst() == "hello"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
from config import Config
|
||||||
|
from option import (OptionDescription, Option, ChoiceOption, BoolOption,
|
||||||
|
FloatOption, StrOption, IntOption, IPOption, NetmaskOption,
|
||||||
|
ArbitraryOption, group_types, apply_requires)
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
# reverse factory
|
||||||
|
# XXX HAAAAAAAAAAAACK (but possibly a good one)
|
||||||
|
def reverse_from_paths(data):
|
||||||
|
"rebuilds a (fake) data structure from an unflatten `make_dict()` result"
|
||||||
|
# ____________________________________________________________
|
||||||
|
_build_map = {
|
||||||
|
bool: BoolOption,
|
||||||
|
int: IntOption,
|
||||||
|
float: FloatOption,
|
||||||
|
str: StrOption,
|
||||||
|
}
|
||||||
|
def option_factory(name, value):
|
||||||
|
"dummy -> Option('dummy')"
|
||||||
|
if type(value) == list:
|
||||||
|
return _build_map[type(value[0])](name, '', multi=True, default=value)
|
||||||
|
else:
|
||||||
|
return _build_map[type(value)](name, '', default=value)
|
||||||
|
|
||||||
|
def build_options(data):
|
||||||
|
"config.gc.dummy -> Option('dummy')"
|
||||||
|
for key, value in data.items():
|
||||||
|
name = key.split('.')[-1]
|
||||||
|
yield (key, option_factory(name, value))
|
||||||
|
# ____________________________________________________________
|
||||||
|
def parent(pathname):
|
||||||
|
"config.gc.dummy -> config.gc"
|
||||||
|
if "." in pathname:
|
||||||
|
return ".".join(pathname.split('.')[:-1])
|
||||||
|
# no parent except rootconfig, naturally returns None
|
||||||
|
|
||||||
|
def subgroups(pathname):
|
||||||
|
"config.gc.dummy.bool -> [config.gc, config.gc.dummy]"
|
||||||
|
group = parent(pathname)
|
||||||
|
parents =[]
|
||||||
|
while group is not None:
|
||||||
|
parents.append(group)
|
||||||
|
group = parent(group)
|
||||||
|
return parents
|
||||||
|
|
||||||
|
def build_option_descriptions(data):
|
||||||
|
all_groups = []
|
||||||
|
for key in data.keys():
|
||||||
|
for group in subgroups(key):
|
||||||
|
# so group is unique in the list
|
||||||
|
if group not in all_groups:
|
||||||
|
all_groups.append(group)
|
||||||
|
for group in all_groups:
|
||||||
|
name = group.split('.')[-1]
|
||||||
|
yield (group, OptionDescription(name, '', []))
|
||||||
|
# ____________________________________________________________
|
||||||
|
descr = OptionDescription('tiramisu', 'fake rebuild structure', [])
|
||||||
|
cfg = Config(descr)
|
||||||
|
# add descrs in cfg
|
||||||
|
def compare(a, b):
|
||||||
|
l1 = a.split(".")
|
||||||
|
l2 = b.split(".")
|
||||||
|
if len(l1) < len(l2):
|
||||||
|
return -1
|
||||||
|
elif len(l1) > len(l2):
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
grps = list(build_option_descriptions(data))
|
||||||
|
groups = dict(grps)
|
||||||
|
grp_paths = [pathname for pathname, opt_descr in grps]
|
||||||
|
grp_paths.sort(compare)
|
||||||
|
for grp in grp_paths:
|
||||||
|
if not "." in grp:
|
||||||
|
cfg._cfgimpl_descr.add_child(groups[grp])
|
||||||
|
cfg.cfgimpl_update()
|
||||||
|
else:
|
||||||
|
parentdescr = cfg.unwrap_from_path(parent(grp))
|
||||||
|
parentdescr.add_child(groups[grp])
|
||||||
|
getattr(cfg, parent(grp)).cfgimpl_update()
|
||||||
|
# add options in descrs
|
||||||
|
for pathname, opt in build_options(data):
|
||||||
|
current_group_name = parent(pathname)
|
||||||
|
if current_group_name == None:
|
||||||
|
cfg._cfgimpl_descr.add_child(opt)
|
||||||
|
cfg.cfgimpl_update()
|
||||||
|
else:
|
||||||
|
curr_grp = groups[current_group_name]
|
||||||
|
curr_grp.add_child(opt)
|
||||||
|
getattr(cfg, current_group_name).cfgimpl_update()
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
# ____________________________________________________________
|
||||||
|
# extendable type
|
||||||
|
class extend(type):
|
||||||
|
"""
|
||||||
|
A magic trick for classes, which lets you add methods or attributes to a
|
||||||
|
class
|
||||||
|
"""
|
||||||
|
def extend(cls, extclass):
|
||||||
|
bases = list(extclass.__bases__)
|
||||||
|
bases.append(extclass)
|
||||||
|
for cl in bases:
|
||||||
|
for key, value in cl.__dict__.items():
|
||||||
|
if key == '__module__':
|
||||||
|
continue
|
||||||
|
setattr(cls, key, value)
|
||||||
|
|
||||||
|
# ____________________________________________________________
|
||||||
|
|