Compare commits
17 Commits
release/3.
...
release/3.
Author | SHA1 | Date | |
---|---|---|---|
0e02ae3182 | |||
ac42fd509c | |||
4709ac5f01 | |||
cab8dae15a | |||
05abe76932 | |||
33c1666cc9 | |||
2a6df8c8d8 | |||
cc44cabf56 | |||
35ee424810 | |||
5c0ac75c52 | |||
7873910322 | |||
d25edd7dd7 | |||
e786b4068d | |||
da015d3af0 | |||
a248e114de | |||
74d367c731 | |||
0e20318a9b |
19
ChangeLog
19
ChangeLog
@ -1,4 +1,21 @@
|
||||
Sat Sep 8 22:54:12 2018 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||
Sun Mar 24 20:24:34 2019
|
||||
* version 3.0 rc3
|
||||
* corrections in debug logger
|
||||
* requirement can have callback
|
||||
* version 3.0 rc2
|
||||
* add cidr notation to domainnameoption if allow_ip is True (fixes #5)
|
||||
* safer option.type() (ref #4)
|
||||
|
||||
Tue Mar 5 08:22:12 2018 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||
* version 3.0 rc2
|
||||
* simplifying netmaskoption
|
||||
* multiple option call (fixes #1)
|
||||
* doesn't check follower requirement with an other follower or a leader if idx is None (fixes #3)
|
||||
|
||||
Mon Feb 25 10:12:35 2019 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||
* version 3.0 rc1
|
||||
|
||||
Sat Sep 8 22:54:12 2019 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||
* propose a new API to access to Tiramisu Option
|
||||
This new API is totally incompatible with older's one
|
||||
|
||||
|
153
doc/Makefile
153
doc/Makefile
@ -1,153 +0,0 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/tiramisu.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/tiramisu.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/tiramisu"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/tiramisu"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
6
doc/_templates/module.rst
vendored
6
doc/_templates/module.rst
vendored
@ -1,6 +0,0 @@
|
||||
{{ fullname }}
|
||||
{{ underline }}
|
||||
|
||||
.. automodule:: {{ fullname }}
|
||||
:members:
|
||||
:noindex:
|
15
doc/api.txt
15
doc/api.txt
@ -1,15 +0,0 @@
|
||||
Auto generated library's API
|
||||
================================
|
||||
|
||||
.. autosummary::
|
||||
:toctree: api
|
||||
:template: module.rst
|
||||
|
||||
tiramisu.option
|
||||
tiramisu.setting
|
||||
tiramisu.config
|
||||
tiramisu.value
|
||||
tiramisu.autolib
|
||||
tiramisu.error
|
||||
tiramisu.storage
|
||||
|
@ -1,6 +0,0 @@
|
||||
tiramisu.autolib
|
||||
================
|
||||
|
||||
.. automodule:: tiramisu.autolib
|
||||
:members:
|
||||
:noindex:
|
@ -1,6 +0,0 @@
|
||||
tiramisu.config
|
||||
===============
|
||||
|
||||
.. automodule:: tiramisu.config
|
||||
:members:
|
||||
:noindex:
|
@ -1,6 +0,0 @@
|
||||
tiramisu.error
|
||||
==============
|
||||
|
||||
.. automodule:: tiramisu.error
|
||||
:members:
|
||||
:noindex:
|
@ -1,6 +0,0 @@
|
||||
tiramisu.option
|
||||
===============
|
||||
|
||||
.. automodule:: tiramisu.option
|
||||
:members:
|
||||
:noindex:
|
@ -1,5 +0,0 @@
|
||||
tiramisu.setting
|
||||
================
|
||||
|
||||
.. automodule:: tiramisu.setting
|
||||
:members:
|
@ -1,6 +0,0 @@
|
||||
tiramisu.storage
|
||||
================
|
||||
|
||||
.. automodule:: tiramisu.storage
|
||||
:members:
|
||||
:noindex:
|
@ -1,5 +0,0 @@
|
||||
tiramisu.value
|
||||
==============
|
||||
|
||||
.. automodule:: tiramisu.value
|
||||
:members:
|
295
doc/conf.py
295
doc/conf.py
@ -1,295 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# tiramisu documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue Nov 20 14:29:31 2012.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', 'sphinx.ext.extlinks']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.txt'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'tiramisu'
|
||||
copyright = u'2013, tiramisu team'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'traditional'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'tiramisudoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'tiramisu.tex', u'tiramisu Documentation',
|
||||
u'gwen', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'tiramisu', u'tiramisu Documentation',
|
||||
[u'gwen'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'tiramisu', u'tiramisu Documentation',
|
||||
u'gwen', 'tiramisu', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
|
||||
# -- Options for Epub output ---------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = u'tiramisu'
|
||||
epub_author = u'gwen'
|
||||
epub_publisher = u'gwen'
|
||||
epub_copyright = u'2012, gwen'
|
||||
|
||||
# The language of the text. It defaults to the language option
|
||||
# or en if the language is not set.
|
||||
#epub_language = ''
|
||||
|
||||
# The scheme of the identifier. Typical schemes are ISBN or URL.
|
||||
#epub_scheme = ''
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#epub_uid = ''
|
||||
|
||||
# A tuple containing the cover image and cover page html template filenames.
|
||||
#epub_cover = ()
|
||||
|
||||
# HTML files that should be inserted before the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_pre_files = []
|
||||
|
||||
# HTML files shat should be inserted after the pages created by sphinx.
|
||||
# The format is a list of tuples containing the path and title.
|
||||
#epub_post_files = []
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
#epub_exclude_files = []
|
||||
|
||||
# The depth of the table of contents in toc.ncx.
|
||||
#epub_tocdepth = 3
|
||||
|
||||
# Allow duplicate toc entries.
|
||||
#epub_tocdup = True
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
extlinks = {'api': ('./api/tiramisu.%s', ""),
|
||||
'test': ('./api/test.%s', "")}
|
||||
|
||||
|
||||
autosummary_generate = True
|
||||
|
||||
|
BIN
doc/config.png
BIN
doc/config.png
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
257
doc/config.svg
257
doc/config.svg
@ -1,257 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="400"
|
||||
height="200"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="test.svg"
|
||||
inkscape:export-filename="/home/gnunux/git/tiramisu/doc/storage.png"
|
||||
inkscape:export-xdpi="135"
|
||||
inkscape:export-ydpi="135">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3827" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="73.881208"
|
||||
inkscape:cy="154.11692"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="841"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-852.36218)">
|
||||
<g
|
||||
id="g4206"
|
||||
transform="translate(32.34835,646.56497)">
|
||||
<text
|
||||
sodipodi:linespacing="686.00001%"
|
||||
id="text2985"
|
||||
y="368.36218"
|
||||
x="98"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;line-height:686.00001335%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="368.36218"
|
||||
x="98"
|
||||
id="tspan2987"
|
||||
sodipodi:role="line">Config</tspan></text>
|
||||
<rect
|
||||
y="351.36218"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4211"
|
||||
transform="translate(-21.922096,643.64303)">
|
||||
<rect
|
||||
y="312.36218"
|
||||
x="189.5"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-2"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3777"
|
||||
y="325.76599"
|
||||
x="220.51762"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="325.76599"
|
||||
x="220.51762"
|
||||
id="tspan3779"
|
||||
sodipodi:role="line">Option</tspan><tspan
|
||||
y="335.76599"
|
||||
x="220.51762"
|
||||
sodipodi:role="line"
|
||||
id="tspan3022">Description</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g4201"
|
||||
transform="translate(11,622)">
|
||||
<rect
|
||||
y="293.42468"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-5"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text4190"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan4194"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
sodipodi:role="line">Option</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g4201-9"
|
||||
transform="translate(85.749784,621.95117)">
|
||||
<rect
|
||||
y="293.42468"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-5-1"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text4190-0"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan4194-2"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
sodipodi:role="line">Option</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g4211-4"
|
||||
transform="translate(52.525433,602.85429)">
|
||||
<rect
|
||||
y="312.36218"
|
||||
x="189.5"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-2-3"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3777-0"
|
||||
y="325.76599"
|
||||
x="220.51762"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="325.76599"
|
||||
x="220.51762"
|
||||
id="tspan3779-1"
|
||||
sodipodi:role="line">Option</tspan><tspan
|
||||
y="335.76599"
|
||||
x="220.51762"
|
||||
sodipodi:role="line"
|
||||
id="tspan3022-7">Description</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g4201-1"
|
||||
transform="translate(123.6527,582.89051)">
|
||||
<rect
|
||||
y="293.42468"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-5-7"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text4190-2"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan4194-8"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
sodipodi:role="line">Option</tspan></text>
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 151.43627,945.42468 19.70537,10.58053"
|
||||
id="path3110"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4201"
|
||||
inkscape:connection-start-point="d4"
|
||||
inkscape:connection-end="#g4211"
|
||||
inkscape:connection-end-point="d4" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 198.77217,956.00521 -0.21665,-10.62936"
|
||||
id="path3112"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4211"
|
||||
inkscape:connection-start-point="d4"
|
||||
inkscape:connection-end="#g4201-9"
|
||||
inkscape:connection-end-point="d4" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 226.45587,956.00521 19.69159,-10.78874"
|
||||
id="path3114"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4211"
|
||||
inkscape:connection-start-point="d4"
|
||||
inkscape:connection-end="#g4211-4"
|
||||
inkscape:connection-end-point="d4" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 259.11483,915.21647 -8.55152,-8.90128"
|
||||
id="path3116"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4211-4"
|
||||
inkscape:connection-start-point="d4"
|
||||
inkscape:connection-end="#g4201-1"
|
||||
inkscape:connection-end-point="d4" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 164.25211,997.92715 15.42203,-11.92194"
|
||||
id="path3118"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4206"
|
||||
inkscape:connection-start-point="d4"
|
||||
inkscape:connection-end="#g4211"
|
||||
inkscape:connection-end-point="d4" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.0 KiB |
570
doc/config.txt
570
doc/config.txt
@ -1,570 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
===============================
|
||||
Options handling basics
|
||||
===============================
|
||||
|
||||
Tiramisu is made of almost three main objects :
|
||||
|
||||
- :class:`tiramisu.option.Option` stands for the option types
|
||||
- :class:`tiramisu.option.OptionDescription` is the shema, the option's structure
|
||||
- :class:`tiramisu.config.Config` which is the whole configuration entry point
|
||||
|
||||
Accessing the `Option`'s
|
||||
-------------------------
|
||||
|
||||
The :class:`~tiramisu.config.Config` object attribute access notation stands for
|
||||
the value of the configuration's :class:`~tiramisu.option.Option`.
|
||||
:class:`~tiramisu.config.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.
|
||||
|
||||
::
|
||||
|
||||
>>> from tiramisu.config import Config
|
||||
>>> from tiramisu.option import BoolOption, OptionDescription
|
||||
>>>
|
||||
>>> gcdummy = BoolOption('dummy', 'dummy', default=False)
|
||||
>>> gcdummy.impl_getdefault()
|
||||
False
|
||||
>>> cfg.dummy
|
||||
False
|
||||
>>> descr = OptionDescription('tiramisu', '', [gcdummy])
|
||||
>>> cfg = Config(descr)
|
||||
>>> cfg.dummy = True
|
||||
>>> cfg.dummy
|
||||
True
|
||||
>>> cfg.idontexist
|
||||
AttributeError: 'OptionDescription' object has no attribute 'idontexist'
|
||||
|
||||
The `Option` objects (in this case the :class:`~tiramisu.option.BoolOption`),
|
||||
are organized into a tree into nested
|
||||
:class:`~tiramisu.option.OptionDescription` objects.
|
||||
|
||||
.. image:: config.png
|
||||
|
||||
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.
|
||||
``cfg.optgroup.optname``.
|
||||
|
||||
Let's make the protocol of accessing a `Config`'s attribute explicit
|
||||
(because explicit is better than implicit):
|
||||
|
||||
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.
|
||||
|
||||
But there are special exceptions. We will see later on that an option can be a
|
||||
:term:`mandatory option`. A mandatory option is an option that must have a value
|
||||
defined.
|
||||
|
||||
Setting the value of an option
|
||||
------------------------------
|
||||
|
||||
An important part of the setting's configuration consists of setting the
|
||||
value's option. There are different ways of setting values,
|
||||
the first one is of course the `__setattr__` method
|
||||
|
||||
::
|
||||
|
||||
cfg.name = value
|
||||
|
||||
And if you wanna come back to a default value, use the builtin `del()` function::
|
||||
|
||||
del(cfg.name)
|
||||
|
||||
.. module:: tiramisu.config
|
||||
|
||||
.. _`tree`:
|
||||
|
||||
The handling of options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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).
|
||||
|
||||
Common manipulations
|
||||
------------------------
|
||||
|
||||
Let's perform some common manipulation on some options
|
||||
|
||||
>>> from tiramisu.config import Config
|
||||
>>> from tiramisu.option import UnicodeOption, OptionDescription
|
||||
>>> #
|
||||
>>> var1 = UnicodeOption('var1', 'first variable')
|
||||
>>> var2 = UnicodeOption('var2', '', u'value')
|
||||
>>> #
|
||||
>>> od1 = OptionDescription('od1', 'first OD', [var1, var2])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
|
||||
let's set somme access rules on the main namespace
|
||||
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
let's travel the namespaces
|
||||
|
||||
>>> print c
|
||||
[od1]
|
||||
>>> print c.od1
|
||||
var1 = None
|
||||
var2 = value
|
||||
>>> print c.od1.var1
|
||||
None
|
||||
>>> print c.od1.var2
|
||||
value
|
||||
|
||||
let's modify a value (be careful to the value's type...)
|
||||
|
||||
>>> c.od1.var1 = 'value'
|
||||
Traceback (most recent call last):
|
||||
ValueError: invalid value value for option var1
|
||||
>>> c.od1.var1 = u'value'
|
||||
>>> print c.od1.var1
|
||||
value
|
||||
>>> c.od1.var2 = u'value2'
|
||||
>>> print c.od1.var2
|
||||
value2
|
||||
|
||||
let's come back to the default value
|
||||
|
||||
>>> del(c.od1.var2)
|
||||
>>> print c.od1.var2
|
||||
value
|
||||
|
||||
The value is saved in a :class:`~tiramisu.value.Value` object. It is on this
|
||||
object that we have to trigger the `reset`, which take the option itself
|
||||
(`var2`) as a parameter.
|
||||
|
||||
On the other side, in the `read_only` mode, it is not possible to modify the value
|
||||
|
||||
>>> c.read_only()
|
||||
>>> c.od1.var2 = u'value2'
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: cannot change the value for option var2 this option is frozen
|
||||
|
||||
|
||||
let's retrieve the option `var1` description
|
||||
|
||||
>>> var1.impl_get_information('doc')
|
||||
'first variable'
|
||||
|
||||
And if the option has been lost, it is possible to retrieve it again:
|
||||
|
||||
>>> c.unwrap_from_path('od1.var1').impl_get_information('doc')
|
||||
'first variable'
|
||||
|
||||
Searching for an option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In an application, knowing the path of an option is not always feasible.
|
||||
That's why a tree of options can easily be searched. First, let's build such a tree::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '')
|
||||
>>> var2 = UnicodeOption('var2', '')
|
||||
>>> var3 = UnicodeOption('var3', '')
|
||||
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
||||
>>> var4 = UnicodeOption('var4', '')
|
||||
>>> var5 = UnicodeOption('var5', '')
|
||||
>>> var6 = UnicodeOption('var6', '')
|
||||
>>> var7 = UnicodeOption('var1', '', u'value')
|
||||
>>> od2 = OptionDescription('od2', '', [var4, var5, var6, var7])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
Second, let's find an option by it's name::
|
||||
|
||||
>>> print c.find(byname='var1')
|
||||
[<tiramisu.option.UnicodeOption object at 0x7ff1bf7d6ef0>,
|
||||
<tiramisu.option.UnicodeOption object at 0x7ff1b90c7290>]
|
||||
|
||||
If the option name is unique, the search can be stopped once one matched option
|
||||
has been found:
|
||||
|
||||
>>> print c.find_first(byname='var1')
|
||||
<tiramisu.option.UnicodeOption object at 0x7ff1bf7d6ef0>
|
||||
|
||||
Instead of the option's object, the value or path can be retrieved:
|
||||
|
||||
>>> print c.find(byname='var1', type_='value')
|
||||
[None, u'value']
|
||||
>>> print c.find(byname='var1', type_='path')
|
||||
['od1.var1', 'od2.var1']
|
||||
|
||||
Finaly, a search can be performed on the values, the type or even a combination
|
||||
of all these criteria:
|
||||
|
||||
|
||||
>>> print c.find(byvalue=u'value', type_='path')
|
||||
['od2.var1']
|
||||
>>> print c.find(bytype=UnicodeOption, type_='path')
|
||||
['od1.var1', 'od1.var2', 'od1.var3', 'od2.var4', 'od2.var5', 'od2.var6', 'od2.var1']
|
||||
>>> print c.find(byvalue=u'value', byname='var1', bytype=UnicodeOption, type_='path')
|
||||
['od2.var1']
|
||||
|
||||
The search can be performed in a subtree:
|
||||
|
||||
>>> print c.od1.find(byname='var1', type_='path')
|
||||
['od1.var1']
|
||||
|
||||
In a root tree or in a subtree, all option can be retrieved in a dict container:
|
||||
|
||||
>>> print c.make_dict()
|
||||
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value',
|
||||
'od1.var1': None, 'od1.var3': None, 'od1.var2': None}
|
||||
|
||||
If the organisation in a tree is not important,
|
||||
:meth:`~config.SubConfig.make_dict()` results can be flattened
|
||||
|
||||
>>> print c.make_dict(flatten=True)
|
||||
{'var5': None, 'var4': None, 'var6': None, 'var1': u'value', 'var3': None,
|
||||
'var2': None}
|
||||
|
||||
.. note:: be carefull with this `flatten` parameter, here we have just lost
|
||||
two options named `var1`
|
||||
|
||||
One can export only interesting parts of a tree of options into a dict, for
|
||||
example the options that are in the same group that a given `var1` option::
|
||||
|
||||
>>> print c.make_dict(withoption='var1')
|
||||
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value',
|
||||
'od1.var1': None, 'od1.var3': None, 'od1.var2': None}
|
||||
>>> print c.make_dict(withoption='var1', withvalue=u'value')
|
||||
{'od2.var4': None, 'od2.var5': None, 'od2.var6': None, 'od2.var1': u'value'}
|
||||
|
||||
and of course, :meth:`~config.SubConfig.make_dict()` can be called in a subtree:
|
||||
|
||||
>>> print c.od1.make_dict(withoption='var1')
|
||||
{'var1': None, 'var3': None, 'var2': None}
|
||||
|
||||
The owners
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
owner
|
||||
|
||||
When a value is set on an option, an owner is set too, that's why one can know
|
||||
at any time if a value is a default value or not. Let's create a tree::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '', u'oui')
|
||||
>>> od1 = OptionDescription('od1', '', [var1])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
Then let's retrieve the owner associated to an option::
|
||||
|
||||
>>> print c.getowner(var1)
|
||||
default
|
||||
>>> c.od1.var1 = u'no'
|
||||
>>> print c.getowner(var1)
|
||||
user
|
||||
>>> del(c.var1)
|
||||
>>> print c.getowner(var1)
|
||||
default
|
||||
|
||||
You can create your own owner, for example to distinguish modification made by
|
||||
one user to an other one's.
|
||||
|
||||
>>> from tiramisu.setting import owners
|
||||
>>> owners.addowner('toto')
|
||||
>>> c.cfgimpl_get_settings().setowner(owners.toto)
|
||||
>>> print c.getowner(var1)
|
||||
default
|
||||
>>> c.od1.var1 = u'no'
|
||||
>>> print c.getowner(var1)
|
||||
toto
|
||||
|
||||
The properties
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
A property is an information on an option's state.
|
||||
Let's create options with properties::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '', u'value', properties=('hidden',))
|
||||
>>> var2 = UnicodeOption('var2', '', properties=('mandatory',))
|
||||
>>> var3 = UnicodeOption('var3', '', u'value', properties=('frozen', 'unknown'))
|
||||
>>> var4 = UnicodeOption('var4', '', u'value')
|
||||
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
||||
>>> od2 = OptionDescription('od2', '', [var4], properties=('hidden',))
|
||||
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
A hidden value is a value that cannot be accessed in read/write mode. This
|
||||
option cannot be modified any more. Let's try to access to an option's value
|
||||
with a hidden option::
|
||||
|
||||
>>> print c.od1.var1
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named: var1
|
||||
with properties ['hidden']
|
||||
>>> c.read_only()
|
||||
>>> print c.od1.var1
|
||||
value
|
||||
|
||||
A mandatory option is an option with a value that shall not be `None`. The
|
||||
value has to be defined. Accessing to such an option is easy in read/write
|
||||
mode. But in read only mode, an error is raised if no value has been defined::
|
||||
|
||||
>>> c.read_write()
|
||||
>>> print c.od1.var2
|
||||
None
|
||||
>>> c.read_only()
|
||||
>>> print c.od1.var2
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named: var2
|
||||
with properties ['mandatory']
|
||||
>>> c.read_write()
|
||||
>>> c.od1.var2 = u'value'
|
||||
>>> c.read_only()
|
||||
>>> print c.od1.var2
|
||||
value
|
||||
|
||||
A frozen option, is an option that cannot be modified by a user.
|
||||
Let's try to modify a frozen option::
|
||||
|
||||
>>> c.read_write()
|
||||
>>> print c.od1.var3
|
||||
value
|
||||
>>> c.od1.var3 = u'value2'
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: cannot change the value for option var3 this option is frozen
|
||||
>>> c.read_only()
|
||||
>>> print c.od1.var3
|
||||
value
|
||||
|
||||
Tiramisu allows us to use user defined properties. Let's define and use one in
|
||||
read/write or read only mode::
|
||||
|
||||
>>> c.cfgimpl_get_settings().append('unknown')
|
||||
>>> print c.od1.var3
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
||||
var3 with properties ['unknown']
|
||||
>>> c.cfgimpl_get_settings().remove('unknown')
|
||||
>>> print c.od1.var3
|
||||
value
|
||||
|
||||
Many properties can be defined at the same time on an option::
|
||||
|
||||
>>> c.cfgimpl_get_settings().extend(['unknown1', 'unknown2'])
|
||||
|
||||
Properties can also be defined on an option group (that is, on an
|
||||
:term:`option description`) let's hide a group and try to access to it::
|
||||
|
||||
>>> c.read_write()
|
||||
>>> print c.od2.var4
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named: od2
|
||||
with properties ['hidden']
|
||||
>>> c.read_only()
|
||||
>>> print c.od2.var4
|
||||
value
|
||||
|
||||
Furthermore, let's retrieve the properties, delete and add the `hidden` property::
|
||||
|
||||
>>> c.read_write()
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
['hidden']
|
||||
>>> print c.od1.var1
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
||||
var1 with properties ['hidden']
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('hidden')
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
[]
|
||||
>>> print c.od1.var1
|
||||
value
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('hidden')
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
['hidden']
|
||||
>>> print c.od1.var1
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
||||
var1 with properties ['hidden']
|
||||
|
||||
|
||||
.. _multi-option:
|
||||
|
||||
The multi-options
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. glossary::
|
||||
|
||||
multi-option
|
||||
|
||||
Multi-options are normal options that have list of values (multiple values)
|
||||
instead of values::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '', [u'val1', u'val2'], multi=True)
|
||||
>>> od1 = OptionDescription('od1', '', [var1])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
A multi-option's value can be manipulated like a list::
|
||||
|
||||
>>> print c.od1.var1
|
||||
[u'val1', u'val2']
|
||||
>>> c.od1.var1 = [u'var1']
|
||||
>>> print c.od1.var1
|
||||
[u'var1']
|
||||
>>> c.od1.var1.append(u'val3')
|
||||
>>> print c.od1.var1
|
||||
[u'var1', u'val3']
|
||||
>>> c.od1.var1.pop(1)
|
||||
u'val3'
|
||||
>>> print c.od1.var1
|
||||
[u'var1']
|
||||
|
||||
But it is not possible to set a value to a multi-option which is not a list::
|
||||
|
||||
>>> c.od1.var1 = u'error'
|
||||
Traceback (most recent call last):
|
||||
ValueError: invalid value error for option var1 which must be a list
|
||||
|
||||
|
||||
The master/slave groups
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
.. glossary::
|
||||
|
||||
master/slave
|
||||
|
||||
A master/slave group is an :class:`~tiramisu.option.OptionDescription` and the
|
||||
options that lives inside.
|
||||
|
||||
Inside this group, a special option, named master option, has the same name as
|
||||
the group. The group (the option description) is set to type `master`.
|
||||
All options in a master group is a multi-option (see :ref:`multi-option`).
|
||||
The slave options have a `default_multi` attribute set to `True`::
|
||||
|
||||
>>> from tiramisu.setting import groups
|
||||
>>> from tiramisu.config import Config
|
||||
>>> from tiramisu.option import UnicodeOption, OptionDescription
|
||||
>>>
|
||||
>>> var1 = UnicodeOption('master', '', multi=True)
|
||||
>>> var2 = UnicodeOption('slave1', '', multi=True)
|
||||
>>> var3 = UnicodeOption('slave2', '', multi=True, default_multi=u"default")
|
||||
>>>
|
||||
>>> od1 = OptionDescription('master', '', [var1, var2, var3])
|
||||
>>> od1.impl_set_group_type(groups.master)
|
||||
>>>
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
The length of the lists can be modified::
|
||||
|
||||
>>> print c.master
|
||||
master = []
|
||||
slave1 = []
|
||||
slave2 = []
|
||||
>>> c.master.master.append(u'oui')
|
||||
>>> print c.master
|
||||
master = [u'oui']
|
||||
slave1 = [None]
|
||||
slave2 = [u'default']
|
||||
>>> c.master.master = [u'non']
|
||||
>>> print c.master
|
||||
master = [u'non']
|
||||
slave1 = [None]
|
||||
slave2 = [u'default']
|
||||
>>>
|
||||
>>> c.master.master = [u'oui', u'non']
|
||||
>>> print c.master
|
||||
master = [u'oui', u'non']
|
||||
slave1 = [None, None]
|
||||
slave2 = [u'default', u'default']
|
||||
|
||||
But it is forbidden to change the lenght of a slave::
|
||||
|
||||
>>> c.master.slave1[0] = u'super'
|
||||
>>> print c.master
|
||||
master = [u'oui', u'non']
|
||||
slave1 = [u'super', None]
|
||||
slave2 = [u'default', u'default']
|
||||
>>> c.master.slave1 = [u'new1', u'new2']
|
||||
>>> print c.master
|
||||
master = [u'oui', u'non']
|
||||
slave1 = [u'new1', u'new2']
|
||||
slave2 = [u'default', u'default']
|
||||
>>> c.master.slave1 = [u'new1']
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.SlaveError: invalid len for the slave: slave1 which has master.master as master
|
||||
>>> c.master.slave1 = [u'new1', u'new2', u'new3']
|
||||
tiramisu.error.SlaveError: invalid len for the slave: slave1 which has master.master as master
|
||||
|
||||
you have to call the `pop` function on the master::
|
||||
|
||||
>>> c.master.master = [u'oui']
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.SlaveError: invalid len for the master: master which has slave1 as slave with greater len
|
||||
>>> c.master.master.pop(0)
|
||||
u'oui'
|
||||
>>> print c.master
|
||||
master = [u'non']
|
||||
slave1 = [u'new2']
|
||||
slave2 = [u'default']
|
||||
|
||||
Configuration's interesting methods
|
||||
------------------------------------------
|
||||
|
||||
A `Config` object is informed by an `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`` (or `SubConfig`).
|
||||
|
||||
.. currentmodule:: tiramisu.config
|
||||
|
||||
.. class:: Config
|
||||
|
||||
.. autoclass:: SubConfig
|
||||
:members: find, find_first, __iter__, iter_groups, iter_all, make_dict
|
||||
|
||||
.. automethod:: __init__
|
||||
|
||||
.. rubric:: Summary
|
||||
|
||||
.. autosummary::
|
||||
|
||||
find
|
||||
find_first
|
||||
|
||||
__iter__
|
||||
iter_groups
|
||||
iter_all
|
||||
|
||||
make_dict
|
||||
|
||||
.. rubric:: Methods
|
||||
|
||||
|
||||
A :class:`~config.CommonConfig` is a abstract base class. A
|
||||
:class:`~config.SubConfig` is an just in time created objects that wraps an
|
||||
::class:`~option.OptionDescription`. A SubConfig differs from a Config in the
|
||||
fact that a config is a root object and has an environnement, a context which
|
||||
defines the different properties, access rules, vs... There is generally only
|
||||
one Config, and many SubConfigs.
|
@ -1,306 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
.. currentmodule:: tiramisu
|
||||
|
||||
The global consistency
|
||||
===========================
|
||||
|
||||
Identical option names
|
||||
----------------------
|
||||
|
||||
If an :class:`~option.Option()` happens to be defined twice in the
|
||||
:term:`schema` (e.g. the :class:`~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.
|
||||
|
||||
Option's values type validation
|
||||
--------------------------------
|
||||
|
||||
When a value is set to the option, the value is validated by the
|
||||
option's :class:`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.
|
||||
|
||||
For example, an :class:`option.IntOption` validator waits for an `int` object of
|
||||
course, an :class:`option.StrOption` validator waits for an `str`, vs...
|
||||
|
||||
Where are located the values
|
||||
-------------------------------
|
||||
|
||||
The entry point of the acces to the values is the :class:`setting.Setting()` of
|
||||
the root configuration object, but the values are actually located in the
|
||||
:class:`value.Values()` object, in order to be delegated in some kind of a
|
||||
`tiramisu.storage`, which can be a in-memory storage, or a persistent (for the
|
||||
time being, a sqlite3) storage.
|
||||
|
||||
:class:`value.Values()` is also responsible of the owners and the calculation
|
||||
of the options that have callbacks.
|
||||
|
||||
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, the possibilities are hudge.
|
||||
|
||||
A requirement is a list of dictionaries that have fairly this form::
|
||||
|
||||
[{'option': a, 'expected': False, 'action': 'disabled', 'inverse': True,
|
||||
'transitive':True, 'same_action': True}]
|
||||
|
||||
Actually a transformation is made to this dictionary during the validation of
|
||||
this requires at the :class:`~option.Option()`'s init. The dictionary becomes
|
||||
a tuple, wich is passed to the :meth:`~setting.Settings.apply_requires()`
|
||||
method. Take a look at the code to fully understand the exact meaning of the
|
||||
requirements:
|
||||
|
||||
.. automethod:: tiramisu.setting.Settings.apply_requires
|
||||
|
||||
|
||||
The path of the option is required, the second element is the value wich is
|
||||
expected to trigger the callback, it is required too, and the third one is the
|
||||
callback's action name (`hide`, `show`...), wich is a
|
||||
:class:`~setting.Property()`. Requirements are validated in
|
||||
:class:`setting.Setting`.
|
||||
|
||||
|
||||
Let's create an option wich has requirements::
|
||||
|
||||
>>> from tiramisu.option import *
|
||||
>>> from tiramisu.config import *
|
||||
>>> var2 = UnicodeOption('var2', '', u'oui')
|
||||
>>> var1 = UnicodeOption('var1', '', u'value', requires=[{'option':var2, 'expected':u'non', 'action':'hidden'}])
|
||||
>>> var3 = UnicodeOption('var3', '', u'value', requires=[{'option':var2, 'expected':u'non', 'action':'hidden'}, {'option':var2, 'expected':u'non', 'action':'disabled'}])
|
||||
>>> var4 = UnicodeOption('var4', '', u'oui')
|
||||
>>> od1 = OptionDescription('od1', '', [var1, var2, var3])
|
||||
>>> od2 = OptionDescription('od2', '', [var4], requires=[{'option':od1.var2, 'expected':u'oui', 'action':'hidden', 'inverse':True}])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1, od2])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
The requirement here is the dict `{'option':var2, 'expected':u'non',
|
||||
'action':'hidden'}` wich means that is the option `'od1.var2'` is set to
|
||||
`'non'`, the option `'od1.var1'` is gonna be hidden. On the other hand, if the
|
||||
option `'od1.var2'` is different from `'non'`, the option `'od1.var1'` is not
|
||||
hidden any more::
|
||||
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
[]
|
||||
>>> print c.od1.var1
|
||||
value
|
||||
>>> print c.od1.var2
|
||||
oui
|
||||
>>> c.od1.var2 = u'non'
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
['hidden']
|
||||
>>> print c.od1.var1
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named:
|
||||
var1 with properties ['hidden']
|
||||
>>> c.od1.var2 = u'oui'
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var1]
|
||||
[]
|
||||
>>> print c.od1.var1
|
||||
value
|
||||
|
||||
The requirement on `od2` is `{'option':od1.var2, 'expected':u'oui',
|
||||
'action':'hidden', 'inverse':True}`, which means that if the option `od1.var2`
|
||||
is set to `oui`, the option is not hidden (because of the `True` at the end of
|
||||
the tuple wich means 'inverted', take a look at the :doc:`consistency`
|
||||
document.)::
|
||||
|
||||
>>> print c.od2.var4
|
||||
oui
|
||||
>>> c.od1.var2 = u'non'
|
||||
>>> print c.od2.var4
|
||||
Traceback (most recent call last):
|
||||
tiramisu.error.PropertiesOptionError: trying to access to an option named: od2 with properties ['hidden']
|
||||
>>> c.od1.var2 = u'oui'
|
||||
>>> print c.od2.var4
|
||||
oui
|
||||
|
||||
Requirements can be accumulated
|
||||
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
||||
[]
|
||||
>>> c.od1.var2 = u'non'
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
||||
['disabled', 'hidden']
|
||||
>>> c.od1.var2 = u'oui'
|
||||
>>> print c.cfgimpl_get_settings()[rootod.od1.var3]
|
||||
[]
|
||||
|
||||
Requirements can be accumulated for different or identical properties (inverted
|
||||
or not)::
|
||||
|
||||
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
||||
... 'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'expected':'oui',
|
||||
... 'action':'hidden'}])
|
||||
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
||||
... 'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'excepted':'oui',
|
||||
... 'action':'disabled', 'inverse':True}])
|
||||
|
||||
But it is not possible to have inverted requirements on the same property.
|
||||
Here is an impossible situation::
|
||||
|
||||
>>> a = UnicodeOption('var3', '', u'value', requires=[{'option':od1.var2,
|
||||
... 'expected':'non', 'action':'hidden'}, {'option':od1.var1, 'expected':'oui',
|
||||
... 'hidden', True}])
|
||||
|
||||
Traceback (most recent call last):
|
||||
ValueError: inconsistency in action types for option: var3 action: hidden
|
||||
|
||||
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.
|
||||
|
||||
.. currentmodule:: tiramisu.option
|
||||
|
||||
Other hooks are availables to validate upon a whole configuration at any time,
|
||||
for example the consistency between two options (typically, an
|
||||
:class:`IPOption` and a :class:`NetworkOption`).
|
||||
|
||||
Let's define validator (wich is a normal python function)::
|
||||
|
||||
>>> def valid_a(value, letter=''):
|
||||
... return value.startswith(letter)
|
||||
|
||||
Here is an option wich uses this validator::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '', u'oui', validator=valid_a, validator_args={'letter': 'o'})
|
||||
>>> od1 = OptionDescription('od1', '', [var1])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
The validation is applied at the modification time::
|
||||
|
||||
>>> c.od1.var1 = u'non'
|
||||
Traceback (most recent call last):
|
||||
ValueError: invalid value non for option var1
|
||||
>>> c.od1.var1 = u'oh non'
|
||||
|
||||
You can disabled this validation::
|
||||
|
||||
>>> c.cfgimpl_get_settings().remove('validator')
|
||||
>>> c.od1.var1 = u'non'
|
||||
|
||||
|
||||
Values that are calculated
|
||||
--------------------------------
|
||||
|
||||
An option that have a callback is considered to have a value that is to be
|
||||
calculated.
|
||||
|
||||
An option's property with a `force_store_value` attribute is considered to be
|
||||
modified at the first calculation.
|
||||
|
||||
.. automodule:: tiramisu.autolib
|
||||
:members:
|
||||
|
||||
This is the typically protocol for accessing a option's for a calculated value,
|
||||
but some twisted ways are also possible, take a look at the `force_store_value`
|
||||
attribute.
|
||||
|
||||
.. glossary::
|
||||
|
||||
force store value
|
||||
|
||||
A calculated value (that is, an option that has a callback) with the
|
||||
attribute `force_store_value` enabled is considered to be modified at
|
||||
the first calculation
|
||||
|
||||
Let's create four calculation functions::
|
||||
|
||||
def return_calc():
|
||||
#return an unicode value
|
||||
return u'calc'
|
||||
|
||||
def return_value(value):
|
||||
return value
|
||||
|
||||
def return_value_param(param=u''):
|
||||
return param
|
||||
|
||||
def return_no_value_if_non(value):
|
||||
#if value is not u'non' return value
|
||||
if value == u'non':
|
||||
return None
|
||||
else:
|
||||
return value
|
||||
|
||||
Then we create four options using theses functions::
|
||||
|
||||
>>> var1 = UnicodeOption('var1', '', callback=return_calc)
|
||||
>>> var2 = UnicodeOption('var2', '', callback=return_value, callback_params={'': (u'value',)})
|
||||
>>> var3 = UnicodeOption('var3', '', callback=return_value_param, callback_params={'param': (u'value_param',)})
|
||||
>>> var4 = UnicodeOption('var4', '', callback=return_no_value_if_non, callback_params={'': (('od1.var5', False),)})
|
||||
>>> var5 = UnicodeOption('var5', '', u'oui')
|
||||
>>> od1 = OptionDescription('od1', '', [var1, var2, var3, var4, var5])
|
||||
>>> rootod = OptionDescription('rootod', '', [od1])
|
||||
>>> c = Config(rootod)
|
||||
>>> c.read_write()
|
||||
|
||||
The first option `var1` returns the result of the `return_calc` function, wich
|
||||
is `u'calc'`::
|
||||
|
||||
>>> print c.od1.var1
|
||||
calc
|
||||
|
||||
The second option `var2` returns the result of the `return_value` fucntion,
|
||||
wich is `value`. The parameter `u'value'` is passed to this function::
|
||||
|
||||
>>> print c.od1.var2
|
||||
value
|
||||
|
||||
The third option `var3` returns the result of the function `return_value_param`
|
||||
with the named parameter `param` and the value `u'value_param'`::
|
||||
|
||||
>>> print c.od1.var3
|
||||
value_param
|
||||
|
||||
The fourth option `var4` returns the reslut of the function `return_no_value_if_non`
|
||||
that is the value of `od1.var5` exceptif the value is u`non`::
|
||||
|
||||
>>> print c.od1.var4
|
||||
oui
|
||||
>>> c.od1.var5 = u'new'
|
||||
>>> print c.od1.var4
|
||||
new
|
||||
>>> c.od1.var5 = u'non'
|
||||
>>> print c.od1.var4
|
||||
None
|
||||
|
||||
The calculation replaces the default value.
|
||||
If we modify the value, the calculation is not carried out any more::
|
||||
|
||||
>>> print c.od1.var1
|
||||
calc
|
||||
>>> c.od1.var1 = u'new_value'
|
||||
>>> print c.od1.var1
|
||||
new_value
|
||||
|
||||
To force the calculation to be carried out in some cases, one must add the
|
||||
`frozen` and the `force_default_on_freeze` properties::
|
||||
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('frozen')
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].append('force_default_on_freeze')
|
||||
>>> print c.od1.var1
|
||||
calc
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('frozen')
|
||||
>>> c.cfgimpl_get_settings()[rootod.od1.var1].remove('force_default_on_freeze')
|
||||
>>> print c.od1.var1
|
||||
new_value
|
@ -1,92 +0,0 @@
|
||||
Test framework
|
||||
==================
|
||||
|
||||
Have a look at the :file:`test` subdirectory of the project.
|
||||
We are using py.test_
|
||||
|
||||
.. _py.test: http://pytest.org/latest/
|
||||
|
||||
|
||||
config APIs
|
||||
-----------------
|
||||
|
||||
.. automodule:: test.test_config
|
||||
:members:
|
||||
|
||||
option APIs
|
||||
---------------
|
||||
|
||||
.. automodule:: test.test_option
|
||||
:members:
|
||||
|
||||
|
||||
others
|
||||
----------
|
||||
|
||||
.. automodule:: test.test_mandatory
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_config_big_example
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_default
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_consistency
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_cache
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_setting
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_freeze
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_config_ip
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_slots
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_reverse_from_path
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_requires
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_owner
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_permissive
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_type
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_dereference
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_storage
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_calculation
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_option_with_special_name
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_config_domain
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_symlink
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_metaconfig
|
||||
:members:
|
||||
|
||||
.. automodule:: test.test_parsing_group
|
||||
:members:
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
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
|
||||
|
@ -1,69 +0,0 @@
|
||||
\begin{frame}
|
||||
\frametitle{Comparaison entre le noyau de Créole et Tiramisu}
|
||||
\begin{itemize}
|
||||
\item \emph{Tiramisu} a pour objectif de
|
||||
\begin{itemize}
|
||||
\item remplacer le noyau \emph{Creole} (\texttt{EoleDict}) de manière transparente ;
|
||||
\item résoudre les problèmes inhérents à \texttt{CreoleServ} ;
|
||||
\end{itemize}
|
||||
\item au niveau du code, il y a enfin une vraie séparation du c\oe ur et du fonctionnel ;
|
||||
\item valide le type \emph{et la structure}, l'ajout de types est aisé.
|
||||
\item \emph{Creole} : \texttt{EoleDict, EoleVars} $ \Leftrightarrow $ \texttt{Config, Option}\\
|
||||
cf \texttt{tiramisu/doc/build/pydoc/index.html}
|
||||
\item intégré à \texttt{gen\_config}, \texttt{cheetah}, \texttt{DTD Creole}, syntaxe \texttt{Creole} \dots
|
||||
\item \texttt{eole-report/D02CoherenceVariables.pdf}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Gestionnaire de configuration existants}
|
||||
\begin{itemize}
|
||||
\item Le gestionnaire de conf de Victor Stinner $\Rightarrow$ \emph{NuFw};
|
||||
\item puppet, cfgengine... $\Rightarrow$ intéressant, de nombreux comportements peuvent être repris, mais tel quel difficilement compatible avec \emph{Creole};
|
||||
\item \emph{Creole} $\Leftrightarrow$ \texttt{tiramisu/doc/build/glossary.html}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Un "vrai" serveur de config}
|
||||
\begin{itemize}
|
||||
\item un 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 de la conf $ \Rightarrow $ Tiramisu.
|
||||
\item \texttt{doc/getting-started.html}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Qu'est-ce qu'un gestionnaire de conf moderne ?}
|
||||
\begin{itemize}
|
||||
\item c'est une organisation arborescente des données (les données sont imbriquées) ;
|
||||
\item c'est un accès facile aux données (typiquement une interface de type \emph{dictionnaire}) ;
|
||||
\item clefs-valeurs, mais quelles valeurs exactement ? $ \Rightarrow $ calcul JIT (just in time) ;
|
||||
\item \texttt{eole-report/D01AccesVariables.pdf}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Définition d'un gestionnaire de configuration}
|
||||
\begin{itemize}
|
||||
\item les families, groups, master \dots~ ce sont des \emph{schémas} de données (\texttt{OptionDescription}) ;
|
||||
\item c'est la configuration (\texttt{Config}) qui est responsable de l'accès aux valeurs ;
|
||||
\item la configuration est aisément manipulable, et a un point d'entrée unique ;
|
||||
\item l'accès aux valeurs des \texttt{Options} de configuration ne peut se faire \emph{que} depuis la conf racine.
|
||||
\item \texttt{eole-report/D01AccesVariables.pdf}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\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 \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}
|
||||
|
@ -1,61 +0,0 @@
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{Etats ("status") de la configuration}
|
||||
\begin{itemize}
|
||||
\item système d'états de la configuration par \emph{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{un peu de mathématiques : prévenir les deadlocks}
|
||||
\begin{itemize}
|
||||
\item sûreté : prévention des deadlocks ;
|
||||
\item dans tiramisu, le modèle est suffisamment abstrait pour que son exploitation mathématique soit
|
||||
réalisable par les techniques de \emph{Model Checking} ;
|
||||
\item soit on a besoin de ne connaître que l'ensemble des états, pas leurs liens $\Rightarrow$ espace d'états ;
|
||||
\item soit on a besoin de connaître toutes les relations $\Rightarrow$ graphe d'accessibilité ;
|
||||
\item la configuration est modélisable en une structure de \emph{Kripe} ;
|
||||
\item déjà le parsing de la conf est facile, la preuve : \texttt{tiramisu/report/build/index.html}
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{un peu de mathématiques (suite) CreoleLint}
|
||||
\begin{itemize}
|
||||
\item exemple : $ P = 3 \wedge Q = 1 \triangleleft \langle P = 1 \hookleftarrow Q = 0 \rangle$
|
||||
\item la propriété \og dans aucun état on a $P = 3$ et $Q = 1$ \fg~ est-elle vraie ?
|
||||
Pour vérifier cette propriété, on a besoin de connaître l'espace d'états ;
|
||||
\item la propriété \og chaque chemin débutant dans un état accessible $P=1$ passe par un état où $Q=3$ et $P=2$ \fg~
|
||||
est-elle vraie ? Cela demande de connaître le graphe d'accessibilité ;
|
||||
\item les structures de \emph{Kripe} sont des machines à états étiquetées par les valuations de toutes les variables propositionnelles ;
|
||||
\item une compliation statique devient possible dans \emph{CreoleLint} \dots
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}
|
||||
\frametitle{compatibilité Créole : ce qui reste à faire}
|
||||
\begin{itemize}
|
||||
\item les options spéciales sont implémentées (auto, fill, obligatoire, \dots) reste la librairie des fonctions pour les variables automatiques \texttt{eosfunc} ;
|
||||
\item tous les états sont implémentés (hidden, disabled, mode (normal/expert), \dots), il faut fixer les comportement \texttt{read write} ;
|
||||
\item les "valprec" (valeur précédentes) et une mémoire de \emph{tous} les états antérieurs ;
|
||||
\item fixer les comportement des hides (sous-groupes récursifs, \dots) ;
|
||||
\item validations master/slaves, validations globales au regard de la configuration entière puisque c'est possible maintenant.
|
||||
\end{itemize}
|
||||
|
||||
\end{frame}
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
%%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}
|
||||
\usepackage{alltt}
|
||||
\usecolortheme{crane}
|
||||
\beamertemplatetransparentcovered
|
||||
%\logo{\includegraphics[height=1cm]{ban.png}}
|
||||
|
||||
\title{Tiramisu}
|
||||
\subtitle{gestionnaire de configuration}
|
||||
\author{Gwen}
|
||||
\institute{\texttt{git clone git://git.labs.libre-entreprise.org/tiramisu.git} \\
|
||||
\texttt{firefox tiramisu/doc/build/index.html}}
|
||||
|
||||
\date{\today}
|
||||
|
||||
\begin{document}
|
||||
\frame{\titlepage}
|
||||
|
||||
\include{definition}
|
||||
\include{statut}
|
||||
|
||||
\end{document}
|
||||
|
@ -1,19 +0,0 @@
|
||||
Errors that may be encountered
|
||||
==================================
|
||||
|
||||
Three builtins exceptions are used :
|
||||
-----------------------------------------
|
||||
|
||||
- **ValueError** : Validation error, parameters error, a list instead
|
||||
of a Multi, or if the value does not make sense
|
||||
|
||||
- **TypeError** : type error in a parameter
|
||||
|
||||
- **AttributeError** : wrong path or unknownd option or optiondescription
|
||||
|
||||
And five other exceptions :
|
||||
------------------------------
|
||||
|
||||
.. automodule:: tiramisu.error
|
||||
:members:
|
||||
|
@ -1,86 +0,0 @@
|
||||
==================================
|
||||
Getting started
|
||||
==================================
|
||||
|
||||
What is options handling ?
|
||||
=================================
|
||||
|
||||
Due to more and more available options required to set up an operating system,
|
||||
compiler options or whatever, 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 control was
|
||||
introduced...
|
||||
|
||||
What is Tiramisu ?
|
||||
===================
|
||||
|
||||
Tiramisu is an options handler and an options controller, which aims at
|
||||
producing flexible and fast options access. The main advantages are its access
|
||||
rules and the fact that the whole consistency is preserved at any time, see
|
||||
:doc:`consistency`. There is of course type and structure validations, but also
|
||||
validations towards the whole options. Furthermore, options can be reached and
|
||||
changed according to the access rules from nearly everywhere in your appliance.
|
||||
|
||||
Just the facts
|
||||
==============
|
||||
|
||||
.. _gettingtiramisu:
|
||||
|
||||
`tiramisu`\ 's home page is here_
|
||||
|
||||
.. _here: https://forge.cadoles.com/Cadoles/tiramisu
|
||||
|
||||
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 to the current developments.
|
||||
|
||||
::
|
||||
|
||||
git clone https://forge.cadoles.com/Cadoles/tiramisu.git
|
||||
|
||||
This will get you a fresh checkout of the code repository in a local directory
|
||||
named ``tiramisu``.
|
||||
|
||||
Getting started
|
||||
-------------------
|
||||
|
||||
Option objects can be created in different ways. Let's perform very basic
|
||||
:class:`~tiramisu.option.Option` and :class:`~tiramisu.config.Config` object
|
||||
manipulations:
|
||||
|
||||
::
|
||||
|
||||
>>> from tiramisu.config import Config
|
||||
>>> from tiramisu.option import OptionDescription, BoolOption
|
||||
>>> # let's create a group of options... with only one option inside
|
||||
>>> descr = OptionDescription("optgroup", "", [
|
||||
... BoolOption("bool", "", default=False)])
|
||||
>>> # c is a namespace as well as a container for the options
|
||||
>>> c = Config(descr)
|
||||
>>> c.bool
|
||||
False
|
||||
>>> c.bool = True
|
||||
>>> c.bool
|
||||
True
|
||||
|
||||
So by now, we have:
|
||||
|
||||
- a namespace (which is `c` here)
|
||||
- the access of an option's value by the
|
||||
attribute access way (here `bool`, which is a boolean option
|
||||
:class:`~tiramisu.option.BoolOption()`.
|
||||
|
||||
So, option objects are produced at the entry point `c` and then handed down to
|
||||
where they are actually used when `c.bool` is triggered. This keeps options
|
||||
local but available at any timer and consistent.
|
||||
|
||||
Once the namespace is created, we can set a
|
||||
:meth:`~config.CommonConfig.read_write()` access to the options::
|
||||
|
||||
>>> c.read_write()
|
||||
|
||||
which enables us to set a bunch of access rules that we wil explain later in
|
||||
:doc:`status`.
|
@ -1,86 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
Glossary
|
||||
==========
|
||||
|
||||
.. glossary::
|
||||
|
||||
configuration
|
||||
|
||||
Global configuration object, wich contains the whole configuration
|
||||
options *and* their descriptions (option types and group)
|
||||
|
||||
schema
|
||||
option description
|
||||
|
||||
see :class:`tiramisu.option.OptionDescription`
|
||||
|
||||
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.
|
||||
|
||||
configuration option
|
||||
|
||||
An option object wich has a name and a value and can be accessed
|
||||
from the configuration object
|
||||
|
||||
access rules
|
||||
|
||||
Global access rules are : :meth:`~config.CommonConfig.read_write()` or
|
||||
:meth:`~config.Config.read_only()`, see :doc:`status`
|
||||
|
||||
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`
|
||||
|
||||
freeze
|
||||
|
||||
A whole configuration can be frozen (used in read only access). See
|
||||
:ref:`frozen` for details.
|
||||
|
||||
A single option can be frozen too.
|
||||
|
||||
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.
|
||||
|
||||
option with properties
|
||||
|
||||
an option wich has property like 'hidden' or 'disabled' is an option
|
||||
wich has restricted acces rules
|
||||
|
||||
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
|
||||
|
||||
a disabled option has a different behaviour on regards to the access
|
||||
of the value in the configuration, see :doc:`status` for more details.
|
||||
|
||||
mandatory option
|
||||
|
||||
A mandatory option is a configuration option wich value has to be
|
||||
set, that is the default value cannot be `None`.
|
||||
|
||||
consistency
|
||||
|
||||
Preserving the consistency in a whole configuration is a tricky thing,
|
||||
tiramisu takes care of it for you, see :doc:`consistency` for details.
|
||||
|
||||
context
|
||||
|
||||
The context is a :class:`tiramisu.setting.Setting()` object in the
|
||||
configuration that enables us to access to the global properties
|
||||
|
||||
for example the `read_write` or `read_only` :term:`access rules`
|
||||
|
||||
|
@ -1,62 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
.. meta::
|
||||
|
||||
:description: configuration management
|
||||
:keywords: config, configuration
|
||||
|
||||
.. title:: tiramisu
|
||||
|
||||
The tasting of `Tiramisu`
|
||||
=========================
|
||||
|
||||
.. image:: logo.png
|
||||
:height: 150px
|
||||
|
||||
`Tiramisu`
|
||||
|
||||
is a cool, refreshing Italian dessert,
|
||||
|
||||
it is also an `options controller tool`_.
|
||||
|
||||
.. _`options controller tool`: http://en.wikipedia.org/wiki/Configuration_management#Overview
|
||||
|
||||
|
||||
It's a pretty small, local (that is, straight on the operating system) options
|
||||
handler and controller.
|
||||
|
||||
controlling options explanations
|
||||
--------------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
getting-started
|
||||
config
|
||||
option
|
||||
storage
|
||||
status
|
||||
consistency
|
||||
error
|
||||
glossary
|
||||
api
|
||||
doctest
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. note:: The tiramisu code is licensed under the `LGPL licence`_
|
||||
and this documentation is licensed under the `Creative Commons
|
||||
Attribution-ShareAlike 3.0 Unported License`_\ .
|
||||
|
||||
|
||||
|
||||
.. _`Creative Commons Attribution-ShareAlike 3.0 Unported License`: http://creativecommons.org/licenses/by-sa/3.0/deed.en_US
|
||||
|
||||
.. _`LGPL licence`: http://www.gnu.org/licenses/lgpl.html
|
||||
|
||||
.. todolist::
|
BIN
doc/logo.png
BIN
doc/logo.png
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
125
doc/option.txt
125
doc/option.txt
@ -1,125 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
.. module:: tiramisu.option
|
||||
|
||||
The options types
|
||||
===================
|
||||
|
||||
Description of Options
|
||||
----------------------
|
||||
|
||||
All the constructors take a ``name`` and a ``doc`` argument as first
|
||||
arguments to give to the option or option description a name and a description document.
|
||||
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``.
|
||||
|
||||
The `Option` base class
|
||||
-------------------------
|
||||
|
||||
It's the abstract base class for almost all options (except the symlink).
|
||||
|
||||
.. _optioninit:
|
||||
|
||||
.. autoclass:: Option
|
||||
:special-members:
|
||||
:members:
|
||||
|
||||
All option types
|
||||
------------------
|
||||
|
||||
BoolOption
|
||||
~~~~~~~~~~
|
||||
|
||||
.. autoclass:: BoolOption
|
||||
:private-members:
|
||||
|
||||
IntOption
|
||||
~~~~~~~~~
|
||||
|
||||
.. autoclass:: IntOption
|
||||
:private-members:
|
||||
|
||||
FloatOption
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: FloatOption
|
||||
:private-members:
|
||||
|
||||
StrOption
|
||||
~~~~~~~~~
|
||||
|
||||
.. autoclass:: StrOption
|
||||
:private-members:
|
||||
|
||||
UnicodeOption
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: UnicodeOption
|
||||
:private-members:
|
||||
|
||||
SymLinkOption
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: SymLinkOption
|
||||
:private-members:
|
||||
|
||||
|
||||
``SymLinkOption`` redirects to another configuration option in the
|
||||
configuration, that is :
|
||||
|
||||
- retrieves the value of the target,
|
||||
- can set the value of the target too
|
||||
|
||||
IPOption
|
||||
~~~~~~~~
|
||||
|
||||
.. autoclass:: IPOption
|
||||
:private-members:
|
||||
|
||||
PortOption
|
||||
~~~~~~~~~~
|
||||
|
||||
.. autoclass:: PortOption
|
||||
:private-members:
|
||||
|
||||
NetmaskOption
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: NetmaskOption
|
||||
:private-members:
|
||||
|
||||
NetworkOption
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: NetworkOption
|
||||
:private-members:
|
||||
|
||||
DomainnameOption
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: DomainnameOption
|
||||
:private-members:
|
||||
|
||||
ChoiceOption
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. autoclass:: ChoiceOption
|
||||
:private-members:
|
||||
|
||||
|
||||
.. _optdescr:
|
||||
|
||||
The `OptionDescription` class
|
||||
-------------------------------
|
||||
|
||||
.. autoclass:: OptionDescription
|
||||
:special-members:
|
||||
:members:
|
||||
|
||||
|
||||
If you need to access to 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. The option objects are in the `_children`
|
||||
`OptionDescription`'s attribute.
|
155
doc/status.txt
155
doc/status.txt
@ -1,155 +0,0 @@
|
||||
.. default-role:: literal
|
||||
|
||||
Local statuses and global settings
|
||||
=====================================
|
||||
|
||||
Available configuration statuses
|
||||
----------------------------------
|
||||
|
||||
.. currentmodule:: tiramisu
|
||||
|
||||
The configuration's status lives in an :class:`setting.Setting()` object.
|
||||
This configuration status corresponds to specific attributes or bunch of
|
||||
attributes that can be accessed together with some `setting.Setting`
|
||||
method:
|
||||
|
||||
**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
|
||||
:class:`~config.CommonConfig.read_write()` on the config.
|
||||
|
||||
**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 :class:`~config.SubConfig.read_only()` on
|
||||
the config.
|
||||
|
||||
.. csv-table:: **Configuration's statuses summary**
|
||||
:header: " ", "Hidden", "Disabled", "Mandatory"
|
||||
|
||||
"read only status", `False`, `True`, `True`
|
||||
"read-write status", `True`, `False`, `False`
|
||||
|
||||
.. _`frozen`:
|
||||
|
||||
Freezing a configuration
|
||||
---------------------------
|
||||
|
||||
At the configuration level, :class:`~setting.Setting()` enables us to freeze the
|
||||
whole configuration, wich means that the frozen :class:`~option.Option()`'s
|
||||
values cannot be modified.
|
||||
|
||||
It is possible to *freeze* a single :class:`~option.Option()` object with
|
||||
:meth:`~config.SubConfig.cfgimpl_get_settings()`. If you try to modify a frozen
|
||||
option, it raises a `TypeError: trying to change a frozen option object`.
|
||||
|
||||
To find out if an option `myoption` is frozen, just make an assertion on the
|
||||
settings like that::
|
||||
|
||||
'frozen' in cfg.cfgimpl_get_settings()[myoption]
|
||||
|
||||
Moreover, frozen option can return their default values if
|
||||
:meth:`~option.Option.force_default()` is called on this option.
|
||||
|
||||
.. glossary::
|
||||
|
||||
force default on freeze
|
||||
|
||||
A single option is frozen and we want the option to return something
|
||||
else than his value, typically it is his default value.
|
||||
|
||||
In the option's values, an attribute can be set
|
||||
:attr:`force_default_on_freeze`, that forces this behavior.
|
||||
|
||||
Restricted access to an `Option()`
|
||||
-----------------------------------
|
||||
|
||||
.. autoclass:: tiramisu.setting.Property
|
||||
|
||||
The `properties` attribute is in charge of the access rules' option's value.
|
||||
|
||||
Configuration options access statuses are defined at configuration level
|
||||
that corresponds to the `option.Option()`'s `properties` attribute,
|
||||
for example: hidden, disabled.
|
||||
|
||||
Use the pythonic way to know if a property is there::
|
||||
|
||||
'hidden' in c.cfgimpl_get_settings()
|
||||
'frozen' in c.cfgimpl_get_settings()[opt]
|
||||
|
||||
To access to the global settings::
|
||||
|
||||
cfg.cfgimpl_get_settings()
|
||||
cfg.cfgimpl_get_settings()[option1]
|
||||
|
||||
to add, or suppress a global property::
|
||||
|
||||
cfg.cfgimpl_get_settings()[option1].append('hidden')
|
||||
cfg.cfgimpl_get_settings()[option1].remove('hidden')
|
||||
|
||||
to activate, deactivate properties::
|
||||
|
||||
cfg.cfgimpl_get_settings().append('hidden')
|
||||
cfg.cfgimpl_get_settings().remove('hidden')
|
||||
|
||||
The global properties are living in e :class:`~setting.Setting` object. A
|
||||
`Setting` object also takes care of the way to access option values and the
|
||||
storage in the cache.
|
||||
|
||||
Value owners
|
||||
-------------
|
||||
|
||||
Every configuration option has a **owner**. When the option is instanciated,
|
||||
the owner is :obj:`setting.owners.default` because a default value has been set
|
||||
(including `None`, wich means that no value has been set yet).
|
||||
|
||||
.. method:: config.CommonConfig.getowner()
|
||||
|
||||
This method can retrieve an Option's owner.
|
||||
|
||||
- At the instance of the `Config` object, the value owner is
|
||||
:obj:`setting.owners.default` because
|
||||
the default values are set at the instance of the configuration option
|
||||
object,
|
||||
|
||||
- at the modification of an option, the owner is `owners.default`, (which is
|
||||
:obj:`owners.user`)
|
||||
|
||||
Special behaviors for an option
|
||||
---------------------------------
|
||||
|
||||
**mandatory**
|
||||
|
||||
A mandatory option shall return a value. If a value, or a default value
|
||||
has not been set, a error is raised.
|
||||
|
||||
**has a callback**
|
||||
|
||||
This means that it is a calculated value and therefore automatically
|
||||
protected it cannot be modified by attribute access.
|
||||
|
||||
**force_store_value**
|
||||
|
||||
if the configuration option has a default value, the default is
|
||||
returned, otherwise the value is calculated.
|
||||
|
||||
Its inner state is represented by `option.Option.force_default()`
|
||||
|
||||
Configuration options have default values that are stored in the
|
||||
`Option()` object itself. Default values, the `default`, can be set in
|
||||
various ways.
|
||||
|
||||
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 `owners.default`.
|
||||
|
BIN
doc/storage.png
BIN
doc/storage.png
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
265
doc/storage.svg
265
doc/storage.svg
@ -1,265 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="400"
|
||||
height="200"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="test.svg"
|
||||
inkscape:export-filename="/home/gnunux/git/tiramisu/doc/storage.png"
|
||||
inkscape:export-xdpi="135"
|
||||
inkscape:export-ydpi="135">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3827" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="106.95445"
|
||||
inkscape:cy="208.15932"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="841"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-852.36218)">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 235.5,78.588237 306,109"
|
||||
id="path4403"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4211"
|
||||
inkscape:connection-start-point="d4"
|
||||
transform="translate(0,852.36218)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 235.5,131.08416 305,107"
|
||||
id="path4405"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:connection-start="#g4216"
|
||||
inkscape:connection-start-point="d4"
|
||||
transform="translate(0,852.36218)" />
|
||||
<g
|
||||
id="g4206"
|
||||
transform="translate(-17,590)">
|
||||
<text
|
||||
sodipodi:linespacing="686.00001%"
|
||||
id="text2985"
|
||||
y="368.36218"
|
||||
x="98"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;line-height:686.00001335%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="368.36218"
|
||||
x="98"
|
||||
id="tspan2987"
|
||||
sodipodi:role="line">Config</tspan></text>
|
||||
<rect
|
||||
y="351.36218"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g4211"
|
||||
transform="translate(-17,590)">
|
||||
<rect
|
||||
y="312.36218"
|
||||
x="189.5"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-2"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="686.00001%"
|
||||
id="text3777"
|
||||
y="330.36218"
|
||||
x="206"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;line-height:686.00001335%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="330.36218"
|
||||
x="206"
|
||||
id="tspan3779"
|
||||
sodipodi:role="line">Values</tspan></text>
|
||||
</g>
|
||||
<g
|
||||
id="g4216"
|
||||
transform="translate(-17,590)">
|
||||
<rect
|
||||
y="389.36218"
|
||||
x="189.5"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-4"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="686.00001%"
|
||||
id="text3799"
|
||||
y="407.36218"
|
||||
x="200"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;line-height:686.00001335%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
y="407.36218"
|
||||
x="200"
|
||||
id="tspan3801"
|
||||
sodipodi:role="line">Settings</tspan></text>
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 127,967.39444 45.5,15.93548"
|
||||
id="path4028"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 127,945.0396 45.5,-16.35484"
|
||||
id="path4030"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
id="rect4161"
|
||||
width="55.5"
|
||||
height="26"
|
||||
x="277.5"
|
||||
y="946.36218" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1.96347165;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3843"
|
||||
sodipodi:cx="401"
|
||||
sodipodi:cy="334.86218"
|
||||
sodipodi:rx="38"
|
||||
sodipodi:ry="10.5"
|
||||
d="m 439,334.86218 a 38,10.5 0 1 1 -76,0 38,10.5 0 1 1 76,0 z"
|
||||
transform="matrix(0.71325325,0,0,0.57998971,18.66254,749.17042)" />
|
||||
<path
|
||||
transform="matrix(0.71325325,0,0,0.57998971,18.57337,775.05247)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1.96347165;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3843-3"
|
||||
sodipodi:cx="401"
|
||||
sodipodi:cy="334.86218"
|
||||
sodipodi:rx="38"
|
||||
sodipodi:ry="10.5"
|
||||
d="m 439,334.86218 a 38,10.5 0 1 1 -76,0 38,10.5 0 1 1 76,0 z" />
|
||||
<path
|
||||
transform="matrix(0.71325325,0,0,0.57998971,18.52879,762.07519)"
|
||||
sodipodi:type="arc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1.96347165;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3843-3-0"
|
||||
sodipodi:cx="401"
|
||||
sodipodi:cy="334.86218"
|
||||
sodipodi:rx="38"
|
||||
sodipodi:ry="10.5"
|
||||
d="m 439,334.86218 a 38,10.5 0 1 1 -76,0 38,10.5 0 1 1 76,0 z" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
id="rect3883"
|
||||
width="62.989182"
|
||||
height="6.7061315"
|
||||
x="274.72043"
|
||||
y="949.91193" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
id="rect3883-3"
|
||||
width="58.087975"
|
||||
height="6.4161367"
|
||||
x="277.34818"
|
||||
y="962.78046" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1.26286423;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
d="m 277.52869,943.35095 -0.0442,26.02673"
|
||||
id="path3917"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1.26286423;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
d="m 331.64698,969.26909 0.13377,-26.17203"
|
||||
id="path3921"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;line-height:686.00001335%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="286.33643"
|
||||
y="958.32324"
|
||||
id="text3821"
|
||||
sodipodi:linespacing="686.00001%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3823"
|
||||
x="286.33643"
|
||||
y="958.32324">Storage</tspan></text>
|
||||
<g
|
||||
id="g4201"
|
||||
transform="translate(-17,590)">
|
||||
<rect
|
||||
y="293.42468"
|
||||
x="81"
|
||||
height="30"
|
||||
width="63"
|
||||
id="rect3757-5"
|
||||
style="fill:none;stroke:#000000;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text4190"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
style="font-size:10px;font-style:normal;font-weight:normal;text-align:center;line-height:100%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan4194"
|
||||
y="309.42468"
|
||||
x="110.27588"
|
||||
sodipodi:role="line">Option</tspan></text>
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 95.5,913.42468 0,27.9375"
|
||||
id="path4199"
|
||||
inkscape:connector-type="polyline"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 9.4 KiB |
@ -1,52 +0,0 @@
|
||||
Storage
|
||||
=======
|
||||
|
||||
.. automodule:: tiramisu.storage
|
||||
|
||||
.. automethod:: tiramisu.storage.set_storage
|
||||
|
||||
.. image:: storage.png
|
||||
|
||||
Dictionary
|
||||
~~~~~~~~~~
|
||||
|
||||
.. automodule:: tiramisu.storage.dictionary
|
||||
|
||||
Dictionary settings:
|
||||
|
||||
.. automethod:: tiramisu.storage.dictionary.storage.Setting
|
||||
|
||||
Sqlite3
|
||||
~~~~~~~
|
||||
|
||||
.. automodule:: tiramisu.storage.sqlite3
|
||||
|
||||
Sqlite3 settings:
|
||||
|
||||
.. automethod:: tiramisu.storage.sqlite3.storage.Setting
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
>>> from tiramisu.option import StrOption, OptionDescription
|
||||
>>> from tiramisu.config import Config
|
||||
>>> from tiramisu.storage import set_storage
|
||||
>>> set_storage('sqlite3', dir_database='/tmp/tiramisu')
|
||||
>>> s = StrOption('str', '')
|
||||
>>> o = OptionDescription('od', '', [s])
|
||||
>>> c1 = Config(o, persistent=True, session_id='xxxx')
|
||||
>>> c1.str
|
||||
>>> c1.str = 'yes'
|
||||
>>> c1.str
|
||||
'yes'
|
||||
>>> del(c1)
|
||||
>>> c2 = Config(o, persistent=True, session_id='xxxx')
|
||||
>>> c2.str
|
||||
'yes'
|
||||
>>> del(c2)
|
||||
>>> list_sessions()
|
||||
['xxxx']
|
||||
>>> delete_session('xxxx')
|
||||
>>> c3 = Config(o, persistent=True, session_id='xxxx')
|
||||
>>> c3.str
|
||||
|
@ -83,30 +83,34 @@ def _autocheck_default_value(cfg, path, conf, **kwargs):
|
||||
|
||||
# test default value (should be empty)
|
||||
# cannot test for follower (we cannot get all values for a follower)
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(path).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(path).value.get() == empty_value
|
||||
assert cfg_.option(path).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(path).value.get() == empty_value
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(path).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(path).value.get() == empty_value
|
||||
raises(PropertiesOptionError, "cfg_.option(path).value.get()")
|
||||
assert cfg_.forcepermissive.option(path).value.get() == empty_value
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(path).value.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(path).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(path).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(path).value.get()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(path, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).option(path, 1).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(path, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(path, 1).value.get() == empty_value
|
||||
assert cfg_.option(path, 0).value.get() == empty_value
|
||||
assert cfg_.option(path, 1).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(path, 0).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(path, 1).value.get() == empty_value
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(path, 0).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(path, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(path, 1).value.get() == empty_value
|
||||
raises(PropertiesOptionError, "cfg_.option(path, 0).value.get()")
|
||||
assert cfg_.forcepermissive.option(path, 0).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(path, 1).value.get() == empty_value
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(path, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(path, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(path, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(path, 0).value.get()")
|
||||
|
||||
|
||||
def _set_value(cfg, pathwrite, conf, **kwargs):
|
||||
@ -131,52 +135,56 @@ def _set_value(cfg, pathwrite, conf, **kwargs):
|
||||
|
||||
# for follower should have an index and good length
|
||||
# for leader must append, not set
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if isleader:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
raises(APIError, "cfg.config(conf).option(pathwrite, 0).value.set(first_value[0])")
|
||||
raises(APIError, "cfg_.option(pathwrite, 0).value.set(first_value[0])")
|
||||
if not set_permissive:
|
||||
cfg.config(conf).option(pathwrite).value.set([first_value[0]])
|
||||
cfg_.option(pathwrite).value.set([first_value[0]])
|
||||
else:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite).value.set([first_value[0]])
|
||||
cfg_.forcepermissive.option(pathwrite).value.set([first_value[0]])
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite).value.set([first_value[0]])")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite).value.set([first_value[0]])")
|
||||
if set_permissive:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite).value.set([first_value[0]])
|
||||
cfg_.forcepermissive.option(pathwrite).value.set([first_value[0]])
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite).value.set([first_value[0]])")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathwrite).value.set([first_value[0]])")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite).value.set([first_value[0]])")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathwrite).value.set([first_value[0]])")
|
||||
if len(first_value) > 1:
|
||||
raises(APIError, "cfg.config(conf).unrestraint.option(pathwrite).value.set(first_value[1])")
|
||||
raises(APIError, "cfg_.unrestraint.option(pathwrite).value.set(first_value[1])")
|
||||
elif isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
if not set_permissive:
|
||||
cfg.config(conf).option(pathwrite, 1).value.set(second_value)
|
||||
cfg_.option(pathwrite, 1).value.set(second_value)
|
||||
else:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite, 1).value.set(second_value)
|
||||
cfg_.forcepermissive.option(pathwrite, 1).value.set(second_value)
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite, 1).value.set(second_value)")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite, 1).value.set(second_value)")
|
||||
if set_permissive:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite, 1).value.set(second_value)
|
||||
cfg_.forcepermissive.option(pathwrite, 1).value.set(second_value)
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite, 1).value.set(second_value)")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathwrite, 1).value.set(second_value)")
|
||||
raises(APIError, "cfg.config(conf).unrestraint.option(pathwrite).value.set([second_value, second_value])")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite, 1).value.set(second_value)")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathwrite, 1).value.set(second_value)")
|
||||
raises(APIError, "cfg_.unrestraint.option(pathwrite).value.set([second_value, second_value])")
|
||||
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
if not set_permissive:
|
||||
cfg.config(conf).option(pathwrite).value.set(first_value)
|
||||
cfg_.option(pathwrite).value.set(first_value)
|
||||
else:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite).value.set(first_value)
|
||||
cfg_.forcepermissive.option(pathwrite).value.set(first_value)
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite).value.set(first_value)")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite).value.set(first_value)")
|
||||
if set_permissive:
|
||||
cfg.config(conf).forcepermissive.option(pathwrite).value.set(first_value)
|
||||
cfg_.forcepermissive.option(pathwrite).value.set(first_value)
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathwrite).value.set(first_value)")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathwrite).value.set(first_value)")
|
||||
#FIXME raises(APIError, "cfg.config(conf).unrestraint.option(pathwrite).value.set(first_value)")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathwrite).value.set(first_value)")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathwrite).value.set(first_value)")
|
||||
#FIXME raises(APIError, "cfg_.unrestraint.option(pathwrite).value.set(first_value)")
|
||||
|
||||
|
||||
def _getproperties(multi, isfollower, kwargs):
|
||||
@ -195,37 +203,41 @@ def _getproperties(multi, isfollower, kwargs):
|
||||
|
||||
|
||||
def _check_properties(cfg, mcfg, pathread, conf, kwargs, props_permissive, props):
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if not cfg.unrestraint.option(pathread).option.isfollower():
|
||||
if not kwargs.get('permissive_od', False):
|
||||
assert set(cfg.config(conf).option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).option(pathread).property.get()) == set(props)
|
||||
assert set(cfg_.option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.option(pathread).property.get()) == set(props)
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).property.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).property.get()")
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread).property.get()) == set(props)
|
||||
assert set(cfg.config(conf).unrestraint.option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).unrestraint.option(pathread).property.get()) == set(props)
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).property.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).property.get()")
|
||||
assert set(cfg_.forcepermissive.option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.forcepermissive.option(pathread).property.get()) == set(props)
|
||||
assert set(cfg_.unrestraint.option(pathread).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.unrestraint.option(pathread).property.get()) == set(props)
|
||||
else:
|
||||
if not kwargs.get('permissive_od', False):
|
||||
assert set(cfg.config(conf).option(pathread, 0).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).option(pathread, 0).property.get()) == set(props)
|
||||
assert set(cfg_.option(pathread, 0).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.option(pathread, 0).property.get()) == set(props)
|
||||
#
|
||||
assert set(cfg.config(conf).option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).option(pathread, 1).property.get()) == set(props)
|
||||
assert set(cfg_.option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.option(pathread, 1).property.get()) == set(props)
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).property.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).property.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).property.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).property.get()")
|
||||
#
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 1).property.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 1).property.get()")
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread, 0).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread, 0).property.get()) == set(props)
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 1).property.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 1).property.get()")
|
||||
assert set(cfg_.forcepermissive.option(pathread, 0).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.forcepermissive.option(pathread, 0).property.get()) == set(props)
|
||||
#
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).forcepermissive.option(pathread, 1).property.get()) == set(props)
|
||||
assert set(cfg.config(conf).unrestraint.option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg.config(conf).unrestraint.option(pathread, 1).property.get()) == set(props)
|
||||
assert set(cfg_.forcepermissive.option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.forcepermissive.option(pathread, 1).property.get()) == set(props)
|
||||
assert set(cfg_.unrestraint.option(pathread, 1).property.get()) == set(props_permissive)
|
||||
assert set(cfg_.unrestraint.option(pathread, 1).property.get()) == set(props)
|
||||
|
||||
|
||||
def _property_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs):
|
||||
@ -253,12 +265,16 @@ def _property_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
|
||||
# set properties with permissive
|
||||
for prop in properties:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
cfg.config(confread).option(pathwrite).property.add(prop)
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
cfg.config(confread).forcepermissive.option(pathwrite).property.add(prop)
|
||||
if confread is not None:
|
||||
cfg_ = cfg.config(confread)
|
||||
else:
|
||||
cfg.config(confread).unrestraint.option(pathwrite).property.add(prop)
|
||||
cfg_ = cfg
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
cfg_.option(pathwrite).property.add(prop)
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
cfg_.forcepermissive.option(pathwrite).property.add(prop)
|
||||
else:
|
||||
cfg_.unrestraint.option(pathwrite).property.add(prop)
|
||||
if confwrite == confread:
|
||||
_check_properties(cfg, mcfg, pathread, confwrite, kwargs, properties, properties)
|
||||
else:
|
||||
@ -286,64 +302,72 @@ def _autocheck_get_value(cfg, pathread, conf, **kwargs):
|
||||
second_value = SUBLIST_SECOND_VALUE[1]
|
||||
|
||||
# get value after set value without permissive
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).option(pathread, 1).value.get() == second_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == second_value
|
||||
assert cfg_.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.option(pathread, 1).value.get() == second_value
|
||||
assert cfg_.forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == second_value
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).value.get()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
if set_permissive:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == second_value
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == second_value
|
||||
else:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == empty_value
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread, 0).value.get()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread).value.get() == first_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == first_value
|
||||
assert cfg_.option(pathread).value.get() == first_value
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == first_value
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).value.get()")
|
||||
if set_permissive:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == first_value
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == first_value
|
||||
else:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == empty_value
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread).value.get()")
|
||||
|
||||
|
||||
def _check_owner(cfg, pathread, conf, kwargs, owner, permissive_owner):
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread).owner.get() == owner
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.get() == owner
|
||||
assert cfg_.option(pathread).owner.get() == owner
|
||||
assert cfg_.forcepermissive.option(pathread).owner.get() == owner
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.get() == permissive_owner
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.get()")
|
||||
assert cfg_.forcepermissive.option(pathread).owner.get() == permissive_owner
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread).owner.get()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg.config(conf).option(pathread, 1).owner.get() == owner
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).owner.get() == owner
|
||||
assert cfg_.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.option(pathread, 1).owner.get() == owner
|
||||
assert cfg_.forcepermissive.option(pathread, 1).owner.get() == owner
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 1).owner.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).owner.get() == permissive_owner
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 1).owner.get()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.forcepermissive.option(pathread, 1).owner.get() == permissive_owner
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread, 0).owner.get()")
|
||||
|
||||
|
||||
@autocheck
|
||||
@ -373,49 +397,53 @@ def autocheck_default_owner(cfg, mcfg, pathread, pathwrite, confread, confwrite,
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
# check if owner is a string "default" and 'isdefault'
|
||||
def do(conf):
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread).owner.get() == 'default'
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.get() == 'default'
|
||||
assert cfg_.option(pathread).owner.get() == 'default'
|
||||
assert cfg_.forcepermissive.option(pathread).owner.get() == 'default'
|
||||
#
|
||||
assert cfg.config(conf).option(pathread).owner.isdefault()
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.isdefault()
|
||||
assert cfg_.option(pathread).owner.isdefault()
|
||||
assert cfg_.forcepermissive.option(pathread).owner.isdefault()
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.get() == 'default'
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.get()")
|
||||
assert cfg_.forcepermissive.option(pathread).owner.get() == 'default'
|
||||
#
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.isdefault()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.isdefault()
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.isdefault()")
|
||||
assert cfg_.forcepermissive.option(pathread).owner.isdefault()
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread).owner.get()")
|
||||
#
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).owner.isdefault()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).owner.isdefault()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).owner.isdefault()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread).owner.isdefault()")
|
||||
#
|
||||
assert cfg.config(conf).unrestraint.option(pathread).owner.get() == 'default'
|
||||
assert cfg.config(conf).unrestraint.option(pathread).owner.isdefault()
|
||||
assert cfg_.unrestraint.option(pathread).owner.get() == 'default'
|
||||
assert cfg_.unrestraint.option(pathread).owner.isdefault()
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
#
|
||||
assert cfg.config(conf).option(pathread, 0).owner.isdefault()
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.isdefault()
|
||||
assert cfg_.option(pathread, 0).owner.isdefault()
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.isdefault()
|
||||
elif not kwargs.get('propertyerror', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.get()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.get() == 'default'
|
||||
#
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.isdefault()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.isdefault()
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.isdefault()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.isdefault()
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread, 0).owner.get()")
|
||||
#
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).owner.isdefault()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread, 0).owner.isdefault()")
|
||||
assert cfg.config(conf).unrestraint.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg.config(conf).unrestraint.option(pathread, 0).owner.isdefault()
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).owner.isdefault()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread, 0).owner.isdefault()")
|
||||
assert cfg_.unrestraint.option(pathread, 0).owner.get() == 'default'
|
||||
assert cfg_.unrestraint.option(pathread, 0).owner.isdefault()
|
||||
do(confread)
|
||||
if confread != confwrite:
|
||||
do(confwrite)
|
||||
@ -450,40 +478,44 @@ def autocheck_get_value_permissive(cfg, mcfg, pathread, pathwrite, confread, con
|
||||
|
||||
def do(conf):
|
||||
# get value after set value without permissive
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
if submulti_:
|
||||
assert cfg.config(conf).option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
assert cfg_.option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
else:
|
||||
assert cfg.config(conf).option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
assert cfg_.option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).option(pathread, 1).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
raises(PropertiesOptionError, "assert cfg_.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg_.option(pathread, 1).value.get()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
if submulti_:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == SUBLIST_SECOND_VALUE[1]
|
||||
else:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == LIST_SECOND_VALUE[1]
|
||||
else:
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).option(pathread, 1).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg_.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg_.option(pathread, 1).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg_.forcepermissive.option(pathread, 0).value.get()")
|
||||
raises(PropertiesOptionError, "assert cfg_.forcepermissive.option(pathread, 1).value.get()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
assert cfg.config(conf).option(pathread).value.get() == first_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == first_value
|
||||
assert cfg_.option(pathread).value.get() == first_value
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == first_value
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == first_value
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).value.get()")
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == first_value
|
||||
else:
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).value.get()")
|
||||
raises(PropertiesOptionError, "cfg_.forcepermissive.option(pathread).value.get()")
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
do(confread)
|
||||
if confread != confwrite:
|
||||
@ -515,8 +547,12 @@ def autocheck_value_follower(cfg, mcfg, pathread, pathwrite, confread, confwrite
|
||||
empty_value = kwargs['default']
|
||||
|
||||
def do(conf):
|
||||
length = cfg.config(conf).option(pathread).value.len()
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.len() == length
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
length = cfg_.option(pathread).value.len()
|
||||
assert cfg_.forcepermissive.option(pathread).value.len() == length
|
||||
assert length == 2
|
||||
do(confread)
|
||||
if confread != confwrite:
|
||||
@ -567,33 +603,41 @@ def autocheck_reset_value(cfg, mcfg, pathread, pathwrite, confread, confwrite, *
|
||||
|
||||
# reset value without permissive
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
cfg.config(confwrite).option(pathwrite).value.reset()
|
||||
cfg_.option(pathwrite).value.reset()
|
||||
#else:
|
||||
#FIXME raises(PropertiesOptionError, "cfg.config(confwrite).option(pathwrite).value.reset()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
cfg.config(confwrite).option(pathwrite, 0).value.reset()
|
||||
cfg_.option(pathwrite, 0).value.reset()
|
||||
#else:
|
||||
#FIXME raises(PropertiesOptionError, "cfg.config(confwrite).option(pathwrite, 0).value.reset()")
|
||||
|
||||
# get value after reset value without permissive
|
||||
def do(conf):
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).option(pathread, 1).value.get() == second_value[1]
|
||||
assert cfg_.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.option(pathread, 1).value.get() == second_value[1]
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread, 0).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).value.get() == second_value[1]
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread, 0).value.get()")
|
||||
assert cfg_.forcepermissive.option(pathread, 0).value.get() == empty_value
|
||||
assert cfg_.forcepermissive.option(pathread, 1).value.get() == second_value[1]
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(conf).option(pathread).value.get() == empty_value
|
||||
assert cfg_.option(pathread).value.get() == empty_value
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(PropertiesOptionError, "cfg.config(conf).option(pathread).value.get()")
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).value.get() == first_value
|
||||
raises(PropertiesOptionError, "cfg_.option(pathread).value.get()")
|
||||
assert cfg_.forcepermissive.option(pathread).value.get() == first_value
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
do(confread)
|
||||
if confread != confwrite:
|
||||
@ -606,16 +650,24 @@ def autocheck_append_value(cfg, mcfg, pathread, pathwrite, confread, confwrite,
|
||||
submulti_ = cfg.unrestraint.option(pathread).option.issubmulti()
|
||||
if not isleader:
|
||||
return
|
||||
if confread is not None:
|
||||
cfg_ = cfg.config(confread)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if confwrite is not None:
|
||||
cfg2_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg2_ = cfg
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if not kwargs.get('propertyerror', False):
|
||||
leader_value = cfg.config(confread).forcepermissive.option(pathread).value.get()
|
||||
leader_value = cfg_.forcepermissive.option(pathread).value.get()
|
||||
len_value = len(leader_value)
|
||||
leader_value.append(undefined)
|
||||
assert len(cfg.config(confread).forcepermissive.option(pathread).value.get()) == len_value
|
||||
assert len(cfg_.forcepermissive.option(pathread).value.get()) == len_value
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.set(leader_value)
|
||||
new_leader_value = cfg.config(confread).forcepermissive.option(pathread).value.get()
|
||||
cfg2_.forcepermissive.option(pathread).value.set(leader_value)
|
||||
new_leader_value = cfg_.forcepermissive.option(pathread).value.get()
|
||||
len_new = len(new_leader_value)
|
||||
assert len_value + 1 == len_new
|
||||
assert new_leader_value[-1] == kwargs['default_multi']
|
||||
@ -625,16 +677,16 @@ def autocheck_append_value(cfg, mcfg, pathread, pathwrite, confread, confwrite,
|
||||
else:
|
||||
follower_path += '.third'
|
||||
for idx in range(len_new):
|
||||
assert cfg.config(confread).forcepermissive.option(follower_path, idx).value.get() == kwargs['default_multi']
|
||||
assert cfg_.forcepermissive.option(follower_path, idx).value.get() == kwargs['default_multi']
|
||||
#
|
||||
if not submulti_:
|
||||
value = 'value'
|
||||
else:
|
||||
value = ['value']
|
||||
leader_value.append(value)
|
||||
assert len(cfg.config(confread).forcepermissive.option(pathread).value.get()) == len(new_leader_value)
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.set(leader_value)
|
||||
assert cfg.config(confread).forcepermissive.option(pathread).value.get()[-1] == value
|
||||
assert len(cfg_.forcepermissive.option(pathread).value.get()) == len(new_leader_value)
|
||||
cfg2_.forcepermissive.option(pathread).value.set(leader_value)
|
||||
assert cfg_.forcepermissive.option(pathread).value.get()[-1] == value
|
||||
|
||||
|
||||
@autocheck
|
||||
@ -644,6 +696,14 @@ def autocheck_pop_value(cfg, mcfg, pathread, pathwrite, confread, confwrite, **k
|
||||
if not isleader:
|
||||
return
|
||||
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if confread is not None:
|
||||
cfg2_ = cfg.config(confread)
|
||||
else:
|
||||
cfg2_ = cfg
|
||||
if not kwargs.get('propertyerror', False):
|
||||
if not submulti_:
|
||||
values = ['value1', 'value2', 'value3', 'value4']
|
||||
@ -658,34 +718,34 @@ def autocheck_pop_value(cfg, mcfg, pathread, pathwrite, confread, confwrite, **k
|
||||
else:
|
||||
a_follower += '.third'
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.set(values)
|
||||
cfg.forcepermissive.config(confwrite).option(a_follower, 1).value.set(follower_value)
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 1).value.get() == follower_value
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 1).owner.isdefault() is False
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 2).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 2).owner.isdefault() is True
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 3).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 3).owner.isdefault() is True
|
||||
cfg_.forcepermissive.option(pathread).value.set(values)
|
||||
cfg_.forcepermissive.option(a_follower, 1).value.set(follower_value)
|
||||
cfg2_.forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
cfg2_.forcepermissive.option(a_follower, 1).value.get() == follower_value
|
||||
assert cfg2_.forcepermissive.option(a_follower, 1).owner.isdefault() is False
|
||||
cfg2_.forcepermissive.option(a_follower, 2).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 2).owner.isdefault() is True
|
||||
cfg2_.forcepermissive.option(a_follower, 3).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 3).owner.isdefault() is True
|
||||
#
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.pop(3)
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 1).value.get() == follower_value
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 1).owner.isdefault() is False
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 2).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 2).owner.isdefault() is True
|
||||
cfg_.forcepermissive.option(pathread).value.pop(3)
|
||||
cfg2_.forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
cfg2_.forcepermissive.option(a_follower, 1).value.get() == follower_value
|
||||
assert cfg2_.forcepermissive.option(a_follower, 1).owner.isdefault() is False
|
||||
cfg2_.forcepermissive.option(a_follower, 2).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 2).owner.isdefault() is True
|
||||
#
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.pop(0)
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 0).value.get() == follower_value
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 0).owner.isdefault() is False
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 1).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 1).owner.isdefault() is True
|
||||
cfg_.forcepermissive.option(pathread).value.pop(0)
|
||||
cfg2_.forcepermissive.option(a_follower, 0).value.get() == follower_value
|
||||
assert cfg2_.forcepermissive.option(a_follower, 0).owner.isdefault() is False
|
||||
cfg2_.forcepermissive.option(a_follower, 1).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 1).owner.isdefault() is True
|
||||
#
|
||||
cfg.forcepermissive.config(confwrite).option(pathread).value.pop(0)
|
||||
cfg.config(confread).forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg.config(confread).forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
cfg_.forcepermissive.option(pathread).value.pop(0)
|
||||
cfg2_.forcepermissive.option(a_follower, 0).value.get() == kwargs['default_multi']
|
||||
assert cfg2_.forcepermissive.option(a_follower, 0).owner.isdefault() is True
|
||||
|
||||
|
||||
@autocheck
|
||||
@ -697,12 +757,20 @@ def autocheck_reset_value_permissive(cfg, mcfg, pathread, pathwrite, confread, c
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
if not isfollower:
|
||||
cfg.forcepermissive.config(confwrite).option(pathwrite).value.reset()
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.forcepermissive.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.forcepermissive
|
||||
cfg_.option(pathwrite).value.reset()
|
||||
else:
|
||||
cfg.forcepermissive.option(pathwrite, 1).value.reset()
|
||||
elif kwargs.get('permissive', False):
|
||||
if not isfollower:
|
||||
cfg.forcepermissive.config(confwrite).option(pathwrite).value.reset()
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.forcepermissive.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.forcepermissive
|
||||
cfg_.option(pathwrite).value.reset()
|
||||
else:
|
||||
cfg.forcepermissive.option(pathwrite, 1).value.reset()
|
||||
#FIXME else:
|
||||
@ -723,13 +791,21 @@ def autocheck_display(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwa
|
||||
return
|
||||
make_dict = kwargs['make_dict']
|
||||
make_dict_value = kwargs['make_dict_value']
|
||||
assert cfg.config(confread).value.dict() == make_dict
|
||||
if confread is not None:
|
||||
cfg_ = cfg.config(confread)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if confwrite is not None:
|
||||
cfg2_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg2_ = cfg
|
||||
assert cfg_.value.dict() == make_dict
|
||||
if confread != confwrite:
|
||||
assert(cfg.config(confwrite).value.dict()) == make_dict
|
||||
assert(cfg2_.value.dict()) == make_dict
|
||||
_set_value(cfg, pathwrite, confwrite, **kwargs)
|
||||
assert cfg.config(confread).value.dict() == make_dict_value
|
||||
assert cfg_.value.dict() == make_dict_value
|
||||
if confread != confwrite:
|
||||
assert(cfg.config(confwrite).value.dict()) == make_dict_value
|
||||
assert(cfg2_.value.dict()) == make_dict_value
|
||||
|
||||
|
||||
@autocheck
|
||||
@ -749,7 +825,11 @@ def autocheck_property(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kw
|
||||
|
||||
# set properties without permissive
|
||||
for prop in properties:
|
||||
cfg.unrestraint.config(confwrite).option(pathwrite).property.add(prop)
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.unrestraint.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.unrestraint
|
||||
cfg_.option(pathwrite).property.add(prop)
|
||||
if confread == confwrite:
|
||||
_check_properties(cfg, mcfg, pathread, confread, kwargs, properties, properties)
|
||||
else:
|
||||
@ -774,7 +854,11 @@ def autocheck_reset_property(cfg, mcfg, pathread, pathwrite, confread, confwrite
|
||||
_property_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs)
|
||||
|
||||
# reset properties without permissive
|
||||
cfg.unrestraint.config(confwrite).option(pathwrite).property.reset()
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.unrestraint.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.unrestraint
|
||||
cfg_.option(pathwrite).property.reset()
|
||||
|
||||
if confread == confwrite:
|
||||
_check_properties(cfg, mcfg, pathread, confread, kwargs, default_props, default_props)
|
||||
@ -819,22 +903,28 @@ def autocheck_default_owner_with_value(cfg, mcfg, pathread, pathwrite, confread,
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
_set_value(cfg, pathwrite, confwrite, **kwargs)
|
||||
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.config(confread)
|
||||
cfg2_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
cfg2_ = cfg
|
||||
# test if is default owner without permissive
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(confwrite).option(pathread).owner.isdefault() is False
|
||||
assert cfg_.option(pathread).owner.isdefault() is False
|
||||
if confwrite != confread:
|
||||
assert cfg.config(confread).option(pathread).owner.isdefault() is False
|
||||
assert cfg2_.option(pathread).owner.isdefault() is False
|
||||
#FIXME else:
|
||||
# raises(PropertiesOptionError, "cfg.config(confwrite).option(pathread).owner.isdefault()")
|
||||
# raises(PropertiesOptionError, "cfg.config(confread).option(pathread).owner.isdefault()")
|
||||
else:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert cfg.config(confwrite).option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg.config(confwrite).option(pathread, 1).owner.isdefault() is False
|
||||
assert cfg2_.option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg2_.option(pathread, 1).owner.isdefault() is False
|
||||
if confwrite != confread:
|
||||
assert cfg.config(confread).option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg.config(confread).option(pathread, 1).owner.isdefault() is False
|
||||
assert cfg_.option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg_.option(pathread, 1).owner.isdefault() is False
|
||||
#FIXME else:
|
||||
# raises(PropertiesOptionError, "cfg.config(confwrite).option(pathread, 0).owner.isdefault()")
|
||||
# raises(PropertiesOptionError, "cfg.config(confread).option(pathread, 0).owner.isdefault()")
|
||||
@ -849,12 +939,16 @@ def autocheck_default_owner_with_value_permissive(cfg, mcfg, pathread, pathwrite
|
||||
|
||||
def do(conf):
|
||||
# test if is default owner with permissive
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
if not kwargs.get('propertyerror', False):
|
||||
if not isfollower:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread).owner.isdefault() is False
|
||||
assert cfg_.forcepermissive.option(pathread).owner.isdefault() is False
|
||||
else:
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg.config(conf).forcepermissive.option(pathread, 1).owner.isdefault() is False
|
||||
assert cfg_.forcepermissive.option(pathread, 0).owner.isdefault() is True
|
||||
assert cfg_.forcepermissive.option(pathread, 1).owner.isdefault() is False
|
||||
#FIXME else:
|
||||
# raises(PropertiesOptionError, "cfg.config(conf).forcepermissive.option(pathread).owner.isdefault()")
|
||||
do(confwrite)
|
||||
@ -865,11 +959,15 @@ def autocheck_default_owner_with_value_permissive(cfg, mcfg, pathread, pathwrite
|
||||
@autocheck
|
||||
def autocheck_set_owner_no_value(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs):
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.forcepermissive.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.forcepermissive
|
||||
if not kwargs.get('propertyerror', False):
|
||||
if not isfollower:
|
||||
raises(ConfigError, "cfg.forcepermissive.config(confwrite).option(pathwrite).owner.set('new_user')")
|
||||
raises(ConfigError, "cfg_.option(pathwrite).owner.set('new_user')")
|
||||
else:
|
||||
raises(ConfigError, "cfg.forcepermissive.option(pathwrite, 1).owner.set('new_user')")
|
||||
raises(ConfigError, "cfg_.option(pathwrite, 1).owner.set('new_user')")
|
||||
|
||||
|
||||
@autocheck
|
||||
@ -878,13 +976,17 @@ def autocheck_set_owner(cfg, mcfg, pathread, pathwrite, confread, confwrite, **k
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
|
||||
_set_value(cfg, pathwrite, confwrite, **kwargs)
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg
|
||||
|
||||
# set owner without permissive
|
||||
if not isfollower:
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
cfg.config(confwrite).option(pathwrite).owner.set('new_user')
|
||||
raises(ValueError, "cfg.config(confwrite).option(pathwrite).owner.set('default')")
|
||||
raises(ValueError, "cfg.config(confwrite).option(pathwrite).owner.set('forced')")
|
||||
cfg_.option(pathwrite).owner.set('new_user')
|
||||
raises(ValueError, "cfg_.option(pathwrite).owner.set('default')")
|
||||
raises(ValueError, "cfg_.option(pathwrite).owner.set('forced')")
|
||||
#FIXME else:
|
||||
# raises(PropertiesOptionError, "cfg.config(confwrite).option(pathwrite).owner.set('new_user')")
|
||||
else:
|
||||
@ -903,11 +1005,15 @@ def autocheck_set_owner_permissive(cfg, mcfg, pathread, pathwrite, confread, con
|
||||
isfollower = cfg.unrestraint.option(pathread).option.isfollower()
|
||||
|
||||
_set_value(cfg, pathwrite, confwrite, **kwargs)
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.forcepermissive.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.forcepermissive
|
||||
|
||||
# set owner with permissive
|
||||
if not kwargs.get('propertyerror', False):
|
||||
if not isfollower:
|
||||
cfg.forcepermissive.config(confwrite).option(pathwrite).owner.set('new_user1')
|
||||
cfg_.option(pathwrite).owner.set('new_user1')
|
||||
else:
|
||||
cfg.forcepermissive.option(pathwrite, 1).owner.set('new_user1')
|
||||
#FIXME else:
|
||||
@ -961,9 +1067,17 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
"""test permissive for hidden and disabled value
|
||||
"""
|
||||
# no permissive before
|
||||
assert cfg.unrestraint.config(confwrite).option(pathread).permissive.get() == frozenset()
|
||||
if confwrite is not None:
|
||||
cfg_ = cfg.unrestraint.config(confwrite)
|
||||
else:
|
||||
cfg_ = cfg.unrestraint
|
||||
if confread is not None:
|
||||
cfg2_ = cfg.config(confread).unrestraint
|
||||
else:
|
||||
cfg2_ = cfg.unrestraint
|
||||
assert cfg_.option(pathread).permissive.get() == frozenset()
|
||||
if kwargs.get('permissive_od', False):
|
||||
assert cfg.unrestraint.config(confwrite).option(pathread.rsplit('.', 1)[0]).permissive.get() == frozenset()
|
||||
assert cfg_.option(pathread.rsplit('.', 1)[0]).permissive.get() == frozenset()
|
||||
|
||||
# cannot access to hidden value without forcepermissive
|
||||
# and to disabled value (with forcepermissive too)
|
||||
@ -972,17 +1086,17 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
_autocheck_default_value(cfg, pathread, confread, **kwargs)
|
||||
|
||||
# set permissive
|
||||
cfg.unrestraint.config(confwrite).option(pathwrite).permissive.set(frozenset(['disabled']))
|
||||
cfg_.option(pathwrite).permissive.set(frozenset(['disabled']))
|
||||
callback = kwargs['callback']
|
||||
if callback:
|
||||
if pathread.endswith('val1') or pathread.endswith('val2'):
|
||||
call_path = pathread[:-4] + 'call' + pathread[-4:]
|
||||
else:
|
||||
call_path = pathread + 'call'
|
||||
cfg.unrestraint.config(confwrite).option(call_path).permissive.set(frozenset(['disabled']))
|
||||
cfg_.option(call_path).permissive.set(frozenset(['disabled']))
|
||||
|
||||
# have permissive?
|
||||
assert cfg.unrestraint.config(confwrite).option(pathread).permissive.get() == frozenset(['disabled'])
|
||||
assert cfg_.option(pathread).permissive.get() == frozenset(['disabled'])
|
||||
#if confwrite != confread:
|
||||
# assert cfg.config(confread).unrestraint.option(pathread).permissive.get() == frozenset(['disabled'])
|
||||
|
||||
@ -991,9 +1105,9 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
ckwargs['propertyerror'] = False
|
||||
_autocheck_default_value(cfg, pathread, confwrite, **ckwargs)
|
||||
|
||||
cfg.config(confread).unrestraint.option(pathwrite).permissive.set(frozenset(['disabled', 'hidden']))
|
||||
cfg2_.option(pathwrite).permissive.set(frozenset(['disabled', 'hidden']))
|
||||
if kwargs['callback']:
|
||||
cfg.config(confread).unrestraint.option(call_path).permissive.set(frozenset(['disabled', 'hidden']))
|
||||
cfg2_.option(call_path).permissive.set(frozenset(['disabled', 'hidden']))
|
||||
|
||||
# can access to all value except when optiondescript have hidden
|
||||
if not ckwargs.get('permissive_od', False):
|
||||
@ -1002,7 +1116,7 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
|
||||
if ckwargs.get('permissive_od', False):
|
||||
# set permissive to OptionDescription
|
||||
cfg.config(confread).unrestraint.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset(['disabled',
|
||||
cfg2_.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset(['disabled',
|
||||
'hidden']))
|
||||
ckwargs['permissive'] = False
|
||||
_autocheck_default_value(cfg, pathread, confread, **ckwargs)
|
||||
@ -1010,23 +1124,23 @@ def autocheck_permissive(cfg, mcfg, pathread, pathwrite, confread, confwrite, **
|
||||
# _autocheck_default_value(cfg, pathread, confwrite, **ckwargs)
|
||||
|
||||
# only hidden
|
||||
cfg.config(confread).unrestraint.option(pathwrite).permissive.set(frozenset(['hidden']))
|
||||
cfg2_.option(pathwrite).permissive.set(frozenset(['hidden']))
|
||||
if callback:
|
||||
cfg.config(confread).unrestraint.option(call_path).permissive.set(frozenset(['hidden']))
|
||||
cfg2_.option(call_path).permissive.set(frozenset(['hidden']))
|
||||
if ckwargs.get('permissive_od', False):
|
||||
_autocheck_default_value(cfg, pathread, confread, **ckwargs)
|
||||
cfg.config(confread).unrestraint.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset(['hidden']))
|
||||
cfg2_.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset(['hidden']))
|
||||
ckwargs = copy(kwargs)
|
||||
ckwargs['permissive'] = False
|
||||
_autocheck_default_value(cfg, pathread, confread, **ckwargs)
|
||||
|
||||
# no permissive
|
||||
cfg.config(confread).unrestraint.option(pathwrite).permissive.set(frozenset())
|
||||
cfg2_.option(pathwrite).permissive.set(frozenset())
|
||||
if callback:
|
||||
cfg.config(confread).unrestraint.option(call_path).permissive.set(frozenset())
|
||||
cfg2_.option(call_path).permissive.set(frozenset())
|
||||
if ckwargs.get('permissive_od', False):
|
||||
_autocheck_default_value(cfg, pathread, confread, **ckwargs)
|
||||
cfg.config(confread).unrestraint.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset())
|
||||
cfg2_.option(pathwrite.rsplit('.', 1)[0]).permissive.set(frozenset())
|
||||
_autocheck_default_value(cfg, pathread, confread, **kwargs)
|
||||
|
||||
|
||||
@ -1060,17 +1174,21 @@ def autocheck_find(cfg, mcfg, pathread, pathwrite, confread, confwrite, **kwargs
|
||||
option = _getoption(cfg.unrestraint.option(pathread))
|
||||
|
||||
def do(conf):
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert option == _getoption(cfg.config(conf).option.find(name, first=True))
|
||||
assert option == _getoption(cfg.config(conf).forcepermissive.option.find(name, first=True))
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(AttributeError, "cfg.config(conf).option.find(name, first=True)")
|
||||
assert option == _getoption(cfg.config(conf).forcepermissive.option.find(name, first=True))
|
||||
if conf is not None:
|
||||
cfg_ = cfg.config(conf)
|
||||
else:
|
||||
raises(AttributeError, "cfg.config(conf).option.find(name, first=True)")
|
||||
raises(AttributeError, "cfg.config(conf).forcepermissive.option.find(name, first=True)")
|
||||
assert option == _getoption(cfg.config(conf).unrestraint.option.find(name, first=True))
|
||||
assert [option] == _getoptions(cfg.config(conf).unrestraint.option.find(name))
|
||||
cfg_ = cfg
|
||||
if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False):
|
||||
assert option == _getoption(cfg_.option.find(name, first=True))
|
||||
assert option == _getoption(cfg_.forcepermissive.option.find(name, first=True))
|
||||
elif kwargs.get('permissive', False):
|
||||
raises(AttributeError, "cfg_.option.find(name, first=True)")
|
||||
assert option == _getoption(cfg_.forcepermissive.option.find(name, first=True))
|
||||
else:
|
||||
raises(AttributeError, "cfg_.option.find(name, first=True)")
|
||||
raises(AttributeError, "cfg_.forcepermissive.option.find(name, first=True)")
|
||||
assert option == _getoption(cfg_.unrestraint.option.find(name, first=True))
|
||||
assert [option] == _getoptions(cfg_.unrestraint.option.find(name))
|
||||
do(confread)
|
||||
if confread != confwrite:
|
||||
do(confwrite)
|
||||
|
@ -264,6 +264,23 @@ def test_config_multi():
|
||||
assert config.option('test3').value.get() == [2, 1]
|
||||
|
||||
|
||||
def test_prefix_error():
|
||||
i1 = IntOption('test1', '')
|
||||
od = OptionDescription('test', '', [i1])
|
||||
config = Config(od)
|
||||
config.property.read_write()
|
||||
config.option('test1').value.set(1)
|
||||
try:
|
||||
config.option('test1').value.set('yes')
|
||||
except Exception as err:
|
||||
assert str(err) == '"yes" is an invalid integer for "test1"'
|
||||
try:
|
||||
config.option('test1').value.set('yes')
|
||||
except Exception as err:
|
||||
err.prefix = ''
|
||||
assert str(err) == 'invalid value'
|
||||
|
||||
|
||||
def test_no_validation():
|
||||
i1 = IntOption('test1', '')
|
||||
od = OptionDescription('test', '', [i1])
|
||||
|
@ -4,8 +4,7 @@ do_autopath()
|
||||
import warnings, sys
|
||||
from py.test import raises
|
||||
|
||||
from tiramisu import Config
|
||||
from tiramisu.option import DomainnameOption, EmailOption, URLOption, OptionDescription
|
||||
from tiramisu import Config, DomainnameOption, EmailOption, URLOption, OptionDescription
|
||||
from tiramisu.error import ValueWarning
|
||||
from tiramisu.i18n import _
|
||||
from tiramisu.storage import list_sessions
|
||||
@ -19,9 +18,11 @@ def test_domainname():
|
||||
d = DomainnameOption('d', '')
|
||||
f = DomainnameOption('f', '', allow_without_dot=True)
|
||||
g = DomainnameOption('g', '', allow_ip=True)
|
||||
od = OptionDescription('a', '', [d, f, g])
|
||||
h = DomainnameOption('h', '', allow_ip=True, cidr=True)
|
||||
od = OptionDescription('a', '', [d, f, g, h])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
#
|
||||
cfg.option('d').value.set('toto.com')
|
||||
raises(ValueError, "cfg.option('d').value.set('toto')")
|
||||
cfg.option('d').value.set('toto3.com')
|
||||
@ -40,9 +41,17 @@ def test_domainname():
|
||||
cfg.option('f').value.set('d.t')
|
||||
#
|
||||
raises(ValueError, "cfg.option('f').value.set('192.168.1.1')")
|
||||
raises(ValueError, "cfg.option('f').value.set('192.168.1.0/24')")
|
||||
#
|
||||
cfg.option('g').value.set('toto.com')
|
||||
cfg.option('g').value.set('192.168.1.0')
|
||||
cfg.option('g').value.set('192.168.1.29')
|
||||
raises(ValueError, "cfg.option('g').value.set('192.168.1.0/24')")
|
||||
#
|
||||
cfg.option('h').value.set('toto.com')
|
||||
raises(ValueError, "cfg.option('h').value.set('192.168.1.0')")
|
||||
raises(ValueError, "cfg.option('h').value.set('192.168.1.29')")
|
||||
cfg.option('h').value.set('192.168.1.0/24')
|
||||
|
||||
|
||||
def test_domainname_upper():
|
||||
|
@ -417,6 +417,7 @@ def test_mandatory_leader():
|
||||
api = Config(descr)
|
||||
api.property.read_only()
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "api.value.dict()")
|
||||
|
||||
|
||||
def test_mandatory_warnings_leader():
|
||||
|
@ -63,6 +63,12 @@ def test_unknown_config():
|
||||
raises(ConfigError, "meta.config('unknown')")
|
||||
|
||||
|
||||
def test_error_metaconfig():
|
||||
od2 = make_description()
|
||||
conf1 = Config(od2, session_id='conf1')
|
||||
raises(TypeError, "MetaConfig([GroupConfig([conf1])], session_id='meta')")
|
||||
|
||||
|
||||
def test_path():
|
||||
meta = make_metaconfig()
|
||||
assert meta.config.path() == 'meta'
|
||||
|
@ -98,6 +98,16 @@ def test_option_isoptiondescription():
|
||||
assert not cfg.option('od.test').option.isoptiondescription()
|
||||
|
||||
|
||||
def test_option_double():
|
||||
i = IntOption('test', '')
|
||||
od = OptionDescription('od1', '', [i])
|
||||
od = OptionDescription('od2', '', [od])
|
||||
od = OptionDescription('od3', '', [od])
|
||||
cfg = Config(od)
|
||||
assert cfg.option('od2.od1.test').value.get() is None
|
||||
assert cfg.option('od2').option('od1').option('test').value.get() is None
|
||||
|
||||
|
||||
def test_option_multi():
|
||||
IntOption('test', '', multi=True)
|
||||
IntOption('test', '', multi=True, default_multi=1)
|
||||
@ -227,3 +237,8 @@ def test_intoption():
|
||||
def test_get_display_type():
|
||||
i1 = IntOption('test1', 'description', min_number=3)
|
||||
assert i1.get_display_type() == 'integer'
|
||||
|
||||
|
||||
def test_option_not_in_config():
|
||||
i1 = IntOption('test1', 'description', min_number=3)
|
||||
raises(AttributeError, "i1.impl_getpath()")
|
||||
|
@ -8,7 +8,7 @@ from tiramisu.config import KernelConfig
|
||||
from tiramisu.setting import groups, owners
|
||||
from tiramisu import ChoiceOption, BoolOption, IntOption, FloatOption, \
|
||||
StrOption, OptionDescription, SymLinkOption, IPOption, NetmaskOption, Leadership, \
|
||||
undefined, Params, ParamOption, ParamValue, ParamContext
|
||||
undefined, Params, ParamOption, ParamValue, ParamContext, calc_value
|
||||
from tiramisu.api import TIRAMISU_VERSION
|
||||
from tiramisu.error import PropertiesOptionError, ConflictError, LeadershipError, ConfigError
|
||||
from tiramisu.i18n import _
|
||||
@ -1194,3 +1194,95 @@ def test_callback_raise():
|
||||
api.option('od2.opt2').value.get()
|
||||
except ConfigError as err:
|
||||
assert '"Option 2"' in str(err)
|
||||
|
||||
|
||||
def test_calc_value_simple():
|
||||
val1 = StrOption('val1', '', 'val1')
|
||||
val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1)))
|
||||
od = OptionDescription('root', '', [val1, val2])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val1'}
|
||||
|
||||
|
||||
def test_calc_value_multi():
|
||||
val1 = StrOption('val1', "", 'val1')
|
||||
val2 = StrOption('val2', "", 'val2')
|
||||
val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True)))
|
||||
od = OptionDescription('root', '', [val1, val2, val3])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
|
||||
|
||||
|
||||
def test_calc_value_disabled():
|
||||
val1 = StrOption('val1', '', 'val1')
|
||||
val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True), default=ParamValue('default_value')))
|
||||
od = OptionDescription('root', '', [val1, val2])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val1'}
|
||||
cfg.option('val1').property.add('disabled')
|
||||
assert cfg.value.dict() == {'val2': 'default_value'}
|
||||
|
||||
|
||||
def test_calc_value_condition():
|
||||
boolean = BoolOption('boolean', '', True)
|
||||
val1 = StrOption('val1', '', 'val1')
|
||||
val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True),
|
||||
default=ParamValue('default_value'),
|
||||
condition=ParamOption(boolean),
|
||||
expected=ParamValue(True)))
|
||||
od = OptionDescription('root', '', [boolean, val1, val2])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
assert cfg.value.dict() == {'boolean': True, 'val1': 'val1', 'val2': 'val1'}
|
||||
cfg.option('boolean').value.set(False)
|
||||
assert cfg.value.dict() == {'boolean': False, 'val1': 'val1', 'val2': 'default_value'}
|
||||
|
||||
|
||||
def test_calc_value_allow_none():
|
||||
val1 = StrOption('val1', "", 'val1')
|
||||
val2 = StrOption('val2', "")
|
||||
val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), allow_none=ParamValue(True)))
|
||||
od = OptionDescription('root', '', [val1, val2, val3])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': None, 'val3': ['val1', None]}
|
||||
|
||||
|
||||
def test_calc_value_remove_duplicate():
|
||||
val1 = StrOption('val1', "", 'val1')
|
||||
val2 = StrOption('val2', "", 'val1')
|
||||
val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), remove_duplicate_value=ParamValue(True)))
|
||||
od = OptionDescription('root', '', [val1, val2, val3])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val1', 'val3': ['val1']}
|
||||
|
||||
|
||||
def test_calc_value_join():
|
||||
val1 = StrOption('val1', "", 'val1')
|
||||
val2 = StrOption('val2', "", 'val2')
|
||||
val3 = StrOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), join=ParamValue('.')))
|
||||
od = OptionDescription('root', '', [val1, val2, val3])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val2', 'val3': 'val1.val2'}
|
||||
|
||||
|
||||
def test_calc_value_min():
|
||||
val1 = StrOption('val1', "", 'val1')
|
||||
val2 = StrOption('val2', "", 'val2')
|
||||
val3 = StrOption('val3', "", 'val3')
|
||||
val4 = StrOption('val4', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2), ParamOption(val3, True)), join=ParamValue('.'), min_args_len=ParamValue(3)))
|
||||
od = OptionDescription('root', '', [val1, val2, val3, val4])
|
||||
cfg = Config(od)
|
||||
cfg.property.read_write()
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val2', 'val3': 'val3', 'val4': 'val1.val2.val3'}
|
||||
cfg.option('val3').property.add('disabled')
|
||||
assert cfg.value.dict() == {'val1': 'val1', 'val2': 'val2', 'val4': ''}
|
||||
|
||||
|
||||
def test_calc_value_add():
|
||||
val1 = IntOption('val1', "", 1)
|
||||
val2 = IntOption('val2', "", 2)
|
||||
val3 = IntOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), operator=ParamValue('add')))
|
||||
od = OptionDescription('root', '', [val1, val2, val3])
|
||||
cfg = Config(od)
|
||||
assert cfg.value.dict() == {'val1': 1, 'val2': 2, 'val3': 3}
|
||||
|
@ -88,6 +88,24 @@ def test_consistency_warnings_only_more_option():
|
||||
assert len(w) == 1
|
||||
|
||||
|
||||
def test_consistency_error_prefix():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '')
|
||||
od = OptionDescription('od', '', [a, b])
|
||||
a.impl_add_consistency('not_equal', b)
|
||||
api = Config(od)
|
||||
api.option('a').value.set(1)
|
||||
try:
|
||||
api.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
assert str(err) == '"1" is an invalid integer for "b", must be different from the value of "a"'
|
||||
try:
|
||||
api.option('b').value.set(1)
|
||||
except Exception as err:
|
||||
err.prefix = ''
|
||||
assert str(err) == 'must be different from the value of "a"'
|
||||
|
||||
|
||||
def test_consistency_warnings_only_option():
|
||||
a = IntOption('a', '')
|
||||
b = IntOption('b', '', warnings_only=True)
|
||||
|
@ -8,7 +8,7 @@ from tiramisu.setting import groups
|
||||
from tiramisu import setting
|
||||
setting.expires_time = 1
|
||||
from tiramisu import IPOption, OptionDescription, BoolOption, IntOption, StrOption, \
|
||||
Leadership, Config
|
||||
Leadership, Config, calc_value, Params, ParamOption
|
||||
from tiramisu.error import PropertiesOptionError, RequirementError
|
||||
from py.test import raises
|
||||
from tiramisu.storage import list_sessions, delete_session
|
||||
@ -65,6 +65,27 @@ def test_requires():
|
||||
api.option('ip_address_service').value.get()
|
||||
|
||||
|
||||
def test_requires_callback():
|
||||
a = BoolOption('activate_service', '', True)
|
||||
b = IPOption('ip_address_service', '',
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(a)), 'expected': False, 'action': 'disabled'}])
|
||||
od = OptionDescription('service', '', [a, b])
|
||||
api = Config(od)
|
||||
api.property.read_write()
|
||||
assert not api.option('activate_service').option.requires()
|
||||
assert api.option('ip_address_service').option.requires()
|
||||
api.option('ip_address_service').value.get()
|
||||
api.option('activate_service').value.set(False)
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
api.option('activate_service').value.set(True)
|
||||
api.option('ip_address_service').value.get()
|
||||
|
||||
|
||||
def test_requires_inverse():
|
||||
a = BoolOption('activate_service', '', True)
|
||||
b = IPOption('ip_address_service', '',
|
||||
@ -179,6 +200,44 @@ def test_requires_same_action():
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_requires_same_action_callback():
|
||||
activate_service = BoolOption('activate_service', '', True)
|
||||
activate_service_web = BoolOption('activate_service_web', '', True,
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(activate_service)), 'expected': False,
|
||||
'action': 'new'}])
|
||||
|
||||
ip_address_service_web = IPOption('ip_address_service_web', '',
|
||||
requires=[{'option': activate_service_web, 'expected': False,
|
||||
'action': 'disabled', 'inverse': False,
|
||||
'transitive': True, 'same_action': False}])
|
||||
od1 = OptionDescription('service', '', [activate_service, activate_service_web, ip_address_service_web])
|
||||
api = Config(od1)
|
||||
api.property.read_write()
|
||||
api.property.add('new')
|
||||
api.option('activate_service').value.get()
|
||||
api.option('activate_service_web').value.get()
|
||||
api.option('ip_address_service_web').value.get()
|
||||
api.option('activate_service').value.set(False)
|
||||
#
|
||||
props = []
|
||||
try:
|
||||
api.option('activate_service_web').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['new'])
|
||||
#
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service_web').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
submsg = '"disabled" (' + _('the calculated value is {0}').format('"False"') + ')'
|
||||
assert str(err) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'ip_address_service_web', 'property', submsg))
|
||||
#access to cache
|
||||
assert str(err) == str(_('cannot access to {0} "{1}" because has {2} {3}').format('option', 'ip_address_service_web', 'property', submsg))
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_multiple_requires():
|
||||
a = StrOption('activate_service', '')
|
||||
b = IPOption('ip_address_service', '',
|
||||
@ -326,6 +385,36 @@ def test_requires_transitive():
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_requires_transitive_callback():
|
||||
a = BoolOption('activate_service', '', True)
|
||||
b = BoolOption('activate_service_web', '', True,
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(a)), 'expected': False, 'action': 'disabled'}])
|
||||
|
||||
d = IPOption('ip_address_service_web', '',
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(b)), 'expected': False, 'action': 'disabled'}])
|
||||
od = OptionDescription('service', '', [a, b, d])
|
||||
api = Config(od)
|
||||
api.property.read_write()
|
||||
api.option('activate_service').value.get()
|
||||
api.option('activate_service_web').value.get()
|
||||
api.option('ip_address_service_web').value.get()
|
||||
api.option('activate_service').value.set(False)
|
||||
#
|
||||
props = []
|
||||
try:
|
||||
api.option('activate_service_web').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
#
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service_web').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_requires_transitive_unrestraint():
|
||||
a = BoolOption('activate_service', '', True)
|
||||
b = BoolOption('activate_service_web', '', True,
|
||||
@ -589,6 +678,46 @@ def test_requires_multi_disabled():
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_requires_multi_disabled_callback():
|
||||
a = BoolOption('activate_service', '')
|
||||
b = IntOption('num_service', '')
|
||||
c = IPOption('ip_address_service', '',
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(a)), 'expected': True, 'action': 'disabled'},
|
||||
{'callback': calc_value, 'callback_params': Params(ParamOption(b)), 'expected': 1, 'action': 'disabled'}])
|
||||
od = OptionDescription('service', '', [a, b, c])
|
||||
api = Config(od)
|
||||
api.property.read_write()
|
||||
|
||||
api.option('ip_address_service').value.get()
|
||||
|
||||
api.option('activate_service').value.set(True)
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
api.option('activate_service').value.set(False)
|
||||
api.option('ip_address_service').value.get()
|
||||
|
||||
api.option('num_service').value.set(1)
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
api.option('activate_service').value.set(True)
|
||||
props = []
|
||||
try:
|
||||
api.option('ip_address_service').value.get()
|
||||
except PropertiesOptionError as err:
|
||||
props = err.proptype
|
||||
assert frozenset(props) == frozenset(['disabled'])
|
||||
|
||||
|
||||
def test_requires_multi_disabled_new_format():
|
||||
a = BoolOption('activate_service', '')
|
||||
b = IntOption('num_service', '')
|
||||
@ -1006,6 +1135,56 @@ def test_leadership_requires():
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0']
|
||||
|
||||
|
||||
def test_leadership_requires_callback():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True,
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(ip_admin_eth0)), 'expected': '192.168.1.1', 'action': 'disabled'}])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
maconfig = OptionDescription('toto', '', [interface1])
|
||||
api = Config(maconfig)
|
||||
api.property.read_write()
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
|
||||
#
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()")
|
||||
#
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.2'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() is None
|
||||
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.255')
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == '255.255.255.255'
|
||||
assert api.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['192.168.1.2', '192.168.1.2'],
|
||||
'ip_admin_eth0.netmask_admin_eth0': [None, '255.255.255.255']}
|
||||
#
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()")
|
||||
ret = api.value.dict()
|
||||
assert set(ret.keys()) == set(['ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert ret['ip_admin_eth0.ip_admin_eth0'] == ['192.168.1.2', '192.168.1.1']
|
||||
assert len(ret['ip_admin_eth0.netmask_admin_eth0']) == 2
|
||||
assert ret['ip_admin_eth0.netmask_admin_eth0'][0] is None
|
||||
assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError)
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0'][1]
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0'][0]
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0']
|
||||
#
|
||||
api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.set('255.255.255.255')
|
||||
ret = api.value.dict()
|
||||
assert set(ret.keys()) == set(['ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'])
|
||||
assert ret['ip_admin_eth0.ip_admin_eth0'] == ['192.168.1.2', '192.168.1.1']
|
||||
assert len(ret['ip_admin_eth0.netmask_admin_eth0']) == 2
|
||||
assert ret['ip_admin_eth0.netmask_admin_eth0'][0] == '255.255.255.255'
|
||||
assert isinstance(ret['ip_admin_eth0.netmask_admin_eth0'][1], PropertiesOptionError)
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0'][1]
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0'][0]
|
||||
del ret['ip_admin_eth0.netmask_admin_eth0']
|
||||
|
||||
|
||||
def test_leadership_requires_both():
|
||||
ip_admin = StrOption('ip_admin_eth0', "ip réseau autorisé")
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True,
|
||||
@ -1037,7 +1216,7 @@ def test_leadership_requires_properties():
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True,
|
||||
requires=[{'option': ip_admin_eth0, 'expected': '192.168.1.1', 'action': 'disabled'}])
|
||||
Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0], properties=('hidden',),
|
||||
requires=[{'option': ip_admin, 'expected': '192.168.1.1', 'action': 'disabled'}])
|
||||
requires=[{'option': ip_admin, 'expected': '192.168.1.1', 'action': 'disabled'}])
|
||||
|
||||
|
||||
def test_leadership_requires_leader():
|
||||
@ -1068,6 +1247,34 @@ def test_leadership_requires_leader():
|
||||
assert api.value.dict() == {'activate': False}
|
||||
|
||||
|
||||
def test_leadership_requires_leader_callback():
|
||||
activate = BoolOption('activate', "Activer l'accès au réseau", True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True,
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(activate)), 'expected': False, 'action': 'disabled'}])
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
maconfig = OptionDescription('toto', '', [activate, interface1])
|
||||
api = Config(maconfig)
|
||||
api.property.read_write()
|
||||
#
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
|
||||
#
|
||||
api.option('activate').value.set(False)
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
#
|
||||
api.option('activate').value.set(True)
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
#
|
||||
api.option('activate').value.set(False)
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
assert api.value.dict() == {'activate': False}
|
||||
|
||||
|
||||
def test_leadership_requires_leadership():
|
||||
activate = BoolOption('activate', "Activer l'accès au réseau", True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
@ -1096,6 +1303,34 @@ def test_leadership_requires_leadership():
|
||||
assert api.value.dict() == {'activate': False}
|
||||
|
||||
|
||||
def test_leadership_requires_leadership_callback():
|
||||
activate = BoolOption('activate', "Activer l'accès au réseau", True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0],
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(activate)), 'expected': False, 'action': 'disabled'}])
|
||||
maconfig = OptionDescription('toto', '', [activate, interface1])
|
||||
api = Config(maconfig)
|
||||
api.property.read_write()
|
||||
#
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
|
||||
#
|
||||
api.option('activate').value.set(False)
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
#
|
||||
api.option('activate').value.set(True)
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
#
|
||||
api.option('activate').value.set(False)
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.ip_admin_eth0').value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
assert api.value.dict() == {'activate': False}
|
||||
|
||||
|
||||
def test_leadership_requires_no_leader():
|
||||
activate = BoolOption('activate', "Activer l'accès au réseau", True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
@ -1123,3 +1358,460 @@ def test_leadership_requires_no_leader():
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()")
|
||||
assert api.value.dict() == {'ip_admin_eth0.ip_admin_eth0': ['192.168.1.2', '192.168.1.1'], 'activate': False}
|
||||
|
||||
|
||||
def test_leadership_requires_no_leader_callback():
|
||||
activate = BoolOption('activate', "Activer l'accès au réseau", True)
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True,
|
||||
requires=[{'callback': calc_value, 'callback_params': Params(ParamOption(activate)), 'expected': False, 'action': 'disabled'}])
|
||||
interface1 = Leadership('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
maconfig = OptionDescription('toto', '', [activate, interface1])
|
||||
api = Config(maconfig)
|
||||
api.property.read_write()
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == []
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2'])
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2']
|
||||
api.option('activate').value.set(False)
|
||||
api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1'])
|
||||
assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2', '192.168.1.1']
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()")
|
||||
api.option('activate').value.set(True)
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() is None
|
||||
api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.255')
|
||||
assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == '255.255.255.255'
|
||||
api.option('activate').value.set(False)
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()")
|
||||
raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()")
|
||||
dico = api.value.dict()
|
||||
assert set(dico.keys()) == {'activate', 'ip_admin_eth0.ip_admin_eth0', 'ip_admin_eth0.netmask_admin_eth0'}
|
||||
dico['ip_admin_eth0.ip_admin_eth0'] == ['192.168.1.2', '192.168.1.1']
|
||||
dico['activate'] == False
|
||||
del dico['ip_admin_eth0.netmask_admin_eth0'][1]
|
||||
del dico['ip_admin_eth0.netmask_admin_eth0'][0]
|
||||
|
||||
|
||||
def test_leadership_requires_complet():
|
||||
optiontoto = StrOption('unicodetoto', "Unicode leader")
|
||||
option = StrOption('unicode', "Unicode leader", multi=True)
|
||||
option1 = StrOption('unicode1', "Unicode follower 1", multi=True)
|
||||
option2 = StrOption('unicode2', "Values 'test' must show 'Unicode follower 3'", multi=True)
|
||||
option3 = StrOption('unicode3', "Unicode follower 3", requires=[{'option': option,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option4 = StrOption('unicode4', "Unicode follower 4", requires=[{'option': option2,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option5 = StrOption('unicode5', "Unicode follower 5", requires=[{'option': optiontoto,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option6 = StrOption('unicode6', "Unicode follower 6", requires=[{'option': optiontoto,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True},
|
||||
{'option': option2,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option7 = StrOption('unicode7', "Unicode follower 7", requires=[{'option': option2,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True},
|
||||
{'option': optiontoto,
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
descr1 = Leadership("unicode", "Common configuration 1",
|
||||
[option, option1, option2, option3, option4, option5, option6, option7])
|
||||
descr = OptionDescription("options", "Common configuration 2", [descr1, optiontoto])
|
||||
descr = OptionDescription("unicode1_leadership_requires", "Leader followers with Unicode follower 3 hidden when Unicode follower 2 is test", [descr])
|
||||
config = Config(descr)
|
||||
config.property.read_write()
|
||||
config.option('options.unicode.unicode').value.set(['test', 'trah'])
|
||||
config.option('options.unicode.unicode2', 0).value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto'])
|
||||
assert dico['options.unicode.unicode'] == ['test', 'trah']
|
||||
assert dico['options.unicode.unicode1'] == [None, None]
|
||||
assert dico['options.unicode.unicode2'] == ['test', None]
|
||||
assert dico['options.unicode.unicode3'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert dico['options.unicodetoto'] is None
|
||||
del dico['options.unicode.unicode3'][1]
|
||||
del dico['options.unicode.unicode3']
|
||||
del dico['options.unicode.unicode4'][1]
|
||||
del dico['options.unicode.unicode4']
|
||||
#
|
||||
config.option('options.unicodetoto').value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicode.unicode5', 'options.unicode.unicode6', 'options.unicode.unicode7', 'options.unicodetoto'])
|
||||
assert dico['options.unicode.unicode'] == ['test', 'trah']
|
||||
assert dico['options.unicode.unicode1'] == [None, None]
|
||||
assert dico['options.unicode.unicode2'] == ['test', None]
|
||||
assert dico['options.unicode.unicode3'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode5'] == [None, None]
|
||||
assert dico['options.unicode.unicode6'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode6'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode7'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode7'][1], PropertiesOptionError)
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
del dico['options.unicode.unicode3'][1]
|
||||
del dico['options.unicode.unicode3']
|
||||
del dico['options.unicode.unicode4'][1]
|
||||
del dico['options.unicode.unicode4']
|
||||
del dico['options.unicode.unicode6'][1]
|
||||
del dico['options.unicode.unicode6']
|
||||
del dico['options.unicode.unicode7'][1]
|
||||
del dico['options.unicode.unicode7']
|
||||
|
||||
|
||||
def test_leadership_requires_complet_callback():
|
||||
optiontoto = StrOption('unicodetoto', "Unicode leader")
|
||||
option = StrOption('unicode', "Unicode leader", multi=True)
|
||||
option1 = StrOption('unicode1', "Unicode follower 1", multi=True)
|
||||
option2 = StrOption('unicode2', "Values 'test' must show 'Unicode follower 3'", multi=True)
|
||||
option3 = StrOption('unicode3', "Unicode follower 3", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option4 = StrOption('unicode4', "Unicode follower 4", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option2)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option5 = StrOption('unicode5', "Unicode follower 5", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(optiontoto)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option6 = StrOption('unicode6', "Unicode follower 6", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(optiontoto)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True},
|
||||
{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option2)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option7 = StrOption('unicode7', "Unicode follower 7", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option2)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True},
|
||||
{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(optiontoto)),
|
||||
'expected': u'test',
|
||||
'action': 'hidden',
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
descr1 = Leadership("unicode", "Common configuration 1",
|
||||
[option, option1, option2, option3, option4, option5, option6, option7])
|
||||
descr = OptionDescription("options", "Common configuration 2", [descr1, optiontoto])
|
||||
descr = OptionDescription("unicode1_leadership_requires", "Leader followers with Unicode follower 3 hidden when Unicode follower 2 is test", [descr])
|
||||
config = Config(descr)
|
||||
config.property.read_write()
|
||||
config.option('options.unicode.unicode').value.set(['test', 'trah'])
|
||||
config.option('options.unicode.unicode2', 0).value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicode.unicode5', 'options.unicode.unicode6', 'options.unicode.unicode7', 'options.unicodetoto'])
|
||||
assert dico['options.unicode.unicode'] == ['test', 'trah']
|
||||
assert dico['options.unicode.unicode1'] == [None, None]
|
||||
assert dico['options.unicode.unicode2'] == ['test', None]
|
||||
assert dico['options.unicode.unicode3'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert dico['options.unicodetoto'] is None
|
||||
del dico['options.unicode.unicode3'][1]
|
||||
del dico['options.unicode.unicode3']
|
||||
del dico['options.unicode.unicode4'][1]
|
||||
del dico['options.unicode.unicode4']
|
||||
del dico['options.unicode.unicode5'][0]
|
||||
del dico['options.unicode.unicode5'][0]
|
||||
del dico['options.unicode.unicode6'][0]
|
||||
del dico['options.unicode.unicode6'][0]
|
||||
del dico['options.unicode.unicode7'][0]
|
||||
del dico['options.unicode.unicode7'][0]
|
||||
#
|
||||
config.option('options.unicodetoto').value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert dico.keys() == set(['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicode.unicode5', 'options.unicode.unicode6', 'options.unicode.unicode7', 'options.unicodetoto'])
|
||||
assert dico['options.unicode.unicode'] == ['test', 'trah']
|
||||
assert dico['options.unicode.unicode1'] == [None, None]
|
||||
assert dico['options.unicode.unicode2'] == ['test', None]
|
||||
assert dico['options.unicode.unicode3'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode5'] == [None, None]
|
||||
assert dico['options.unicode.unicode6'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode6'][1], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode7'][0] is None
|
||||
assert isinstance(dico['options.unicode.unicode7'][1], PropertiesOptionError)
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
del dico['options.unicode.unicode3'][1]
|
||||
del dico['options.unicode.unicode3']
|
||||
del dico['options.unicode.unicode4'][1]
|
||||
del dico['options.unicode.unicode4']
|
||||
del dico['options.unicode.unicode6'][1]
|
||||
del dico['options.unicode.unicode6']
|
||||
del dico['options.unicode.unicode7'][1]
|
||||
del dico['options.unicode.unicode7']
|
||||
|
||||
|
||||
def test_leadership_requires_transitive():
|
||||
optiontoto = StrOption('unicodetoto', "Unicode leader")
|
||||
option = StrOption('unicode', "Unicode leader", multi=True)
|
||||
option1 = StrOption('unicode1', "Unicode follower 1", multi=True)
|
||||
option2 = StrOption('unicode2', "Unicode follower 2", requires=[{'option': optiontoto,
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option3 = StrOption('unicode3', "Unicode follower 3", requires=[{'option': option2,
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option4 = StrOption('unicode4', "Unicode follower 4", requires=[{'option': option3,
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
descr1 = Leadership("unicode", "Common configuration 1",
|
||||
[option, option1, option2, option3, option4])
|
||||
descr = OptionDescription("options", "Common configuration 2", [descr1, optiontoto])
|
||||
descr = OptionDescription("unicode1", "", [descr])
|
||||
config = Config(descr)
|
||||
config.property.read_write()
|
||||
assert config.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': None}
|
||||
#
|
||||
config.option('options.unicodetoto').value.set('test')
|
||||
assert config.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode2': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': 'test'}
|
||||
#
|
||||
config.option('options.unicode.unicode').value.set(['a', 'b', 'c'])
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, None, None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('test')
|
||||
config.option('options.unicode.unicode3', 1).value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, 'test', None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode3'][1] == 'test'
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][1] == None
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('rah')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, 'rah', None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('test')
|
||||
config.option('options.unicodetoto').value.set('rah')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'rah'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
|
||||
|
||||
def test_leadership_requires_transitive_callback():
|
||||
optiontoto = StrOption('unicodetoto', "Unicode leader")
|
||||
option = StrOption('unicode', "Unicode leader", multi=True)
|
||||
option1 = StrOption('unicode1', "Unicode follower 1", multi=True)
|
||||
option2 = StrOption('unicode2', "Unicode follower 2", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(optiontoto)),
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option3 = StrOption('unicode3', "Unicode follower 3", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option2)),
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
option4 = StrOption('unicode4', "Unicode follower 4", requires=[{'callback': calc_value,
|
||||
'callback_params': Params(ParamOption(option3)),
|
||||
'expected': u'test',
|
||||
'action': 'disabled',
|
||||
'transitive': True,
|
||||
'inverse': True}],
|
||||
multi=True)
|
||||
descr1 = Leadership("unicode", "Common configuration 1",
|
||||
[option, option1, option2, option3, option4])
|
||||
descr = OptionDescription("options", "Common configuration 2", [descr1, optiontoto])
|
||||
descr = OptionDescription("unicode1", "", [descr])
|
||||
config = Config(descr)
|
||||
config.property.read_write()
|
||||
assert config.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode2': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': None}
|
||||
#
|
||||
config.option('options.unicodetoto').value.set('test')
|
||||
assert config.value.dict() == {'options.unicode.unicode': [], 'options.unicode.unicode1': [], 'options.unicode.unicode2': [], 'options.unicode.unicode3': [], 'options.unicode.unicode4': [], 'options.unicodetoto': 'test'}
|
||||
#
|
||||
config.option('options.unicode.unicode').value.set(['a', 'b', 'c'])
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, None, None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('test')
|
||||
config.option('options.unicode.unicode3', 1).value.set('test')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, 'test', None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode3'][1] == 'test'
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert dico['options.unicode.unicode4'][1] == None
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('rah')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'test'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert dico['options.unicode.unicode2'] == [None, 'rah', None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
#
|
||||
config.option('options.unicode.unicode2', 1).value.set('test')
|
||||
config.option('options.unicodetoto').value.set('rah')
|
||||
dico = config.value.dict()
|
||||
assert list(dico.keys()) == ['options.unicode.unicode', 'options.unicode.unicode1', 'options.unicode.unicode2', 'options.unicode.unicode3', 'options.unicode.unicode4', 'options.unicodetoto']
|
||||
assert dico['options.unicodetoto'] == 'rah'
|
||||
assert dico['options.unicode.unicode'] == ['a', 'b', 'c']
|
||||
assert dico['options.unicode.unicode1'] == [None, None, None]
|
||||
assert isinstance(dico['options.unicode.unicode3'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode3'][2], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][0], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][1], PropertiesOptionError)
|
||||
assert isinstance(dico['options.unicode.unicode4'][2], PropertiesOptionError)
|
||||
del (dico['options.unicode.unicode2'][2])
|
||||
del (dico['options.unicode.unicode2'][1])
|
||||
del (dico['options.unicode.unicode2'][0])
|
||||
del (dico['options.unicode.unicode3'][2])
|
||||
del (dico['options.unicode.unicode3'][1])
|
||||
del (dico['options.unicode.unicode3'][0])
|
||||
del (dico['options.unicode.unicode4'][2])
|
||||
del (dico['options.unicode.unicode4'][1])
|
||||
del (dico['options.unicode.unicode4'][0])
|
||||
|
@ -13,7 +13,7 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from .function import Params, ParamOption, ParamValue, ParamContext, \
|
||||
tiramisu_copy
|
||||
tiramisu_copy, calc_value
|
||||
from .option import *
|
||||
from .error import APIError
|
||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||
@ -37,7 +37,8 @@ allfuncs = ['Params',
|
||||
'Storage',
|
||||
'list_sessions',
|
||||
'delete_session',
|
||||
'tiramisu_copy']
|
||||
'tiramisu_copy',
|
||||
'calc_value']
|
||||
allfuncs.extend(all_options)
|
||||
del(all_options)
|
||||
__all__ = tuple(allfuncs)
|
||||
|
@ -148,7 +148,7 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||
return self._option_bag.option
|
||||
|
||||
def type(self):
|
||||
return self._option_bag.option.get_display_type()
|
||||
return self._option_bag.option.get_type()
|
||||
|
||||
def isleadership(self):
|
||||
"""Test if option is a leader or a follower"""
|
||||
@ -203,6 +203,20 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||
settings.get_context_properties(),
|
||||
settings.get_context_properties())
|
||||
|
||||
def __call__(self,
|
||||
path: str,
|
||||
index: Optional[int]=None) -> 'TiramisuOption':
|
||||
"""Select an option by path"""
|
||||
subpath = self._option_bag.option.impl_getname() + '.' + path
|
||||
subconfig, name = self._subconfig.cfgimpl_get_home_by_path(subpath,
|
||||
self._option_bag.config_bag)
|
||||
path = self._option_bag.path + '.' + path
|
||||
return TiramisuOption(name,
|
||||
path,
|
||||
index,
|
||||
subconfig,
|
||||
self._option_bag.config_bag)
|
||||
|
||||
|
||||
class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||
"""Manage option"""
|
||||
@ -451,8 +465,9 @@ class _TiramisuOptionValueOption:
|
||||
if isinstance(value, list):
|
||||
while undefined in value:
|
||||
idx = value.index(undefined)
|
||||
value[idx] = values.getdefaultvalue(self._option_bag,
|
||||
force_index=idx)
|
||||
soption_bag = self._option_bag.copy()
|
||||
soption_bag.index = idx
|
||||
value[idx] = values.getdefaultvalue(soption_bag)
|
||||
elif value == undefined:
|
||||
value = values.getdefaultvalue(self._option_bag)
|
||||
self._subconfig.setattr(value,
|
||||
@ -738,17 +753,9 @@ class TiramisuOption(CommonTiramisuOption):
|
||||
subconfig=subconfig,
|
||||
config_bag=config_bag)
|
||||
|
||||
|
||||
#__________________________________________________________________________________________________
|
||||
#
|
||||
# First part of API:
|
||||
# - contexts informations:
|
||||
# - context owner
|
||||
# - context information
|
||||
# - context property
|
||||
# - context permissive
|
||||
# - forcepermissive
|
||||
# - unrestraint
|
||||
# - manage MetaConfig or GroupConfig
|
||||
|
||||
|
||||
class TiramisuContext(TiramisuHelp):
|
||||
|
@ -90,11 +90,11 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
|
||||
return value[index]
|
||||
return value
|
||||
except PropertiesOptionError as err:
|
||||
# raise because must not add value None in carry_out_calculation
|
||||
# raise PropertiesOptionError (which is catched) because must not add value None in carry_out_calculation
|
||||
if callbk.notraisepropertyerror:
|
||||
raise err
|
||||
raise ConfigError(_('unable to carry out a calculation for "{}"'
|
||||
', {}').format(option.impl_get_display_name(), err))
|
||||
', {}').format(option.impl_get_display_name(), err), err)
|
||||
|
||||
|
||||
def carry_out_calculation(option,
|
||||
|
@ -1198,12 +1198,13 @@ class KernelMetaConfig(KernelMixConfig):
|
||||
if not isinstance(child, _CommonConfig):
|
||||
try:
|
||||
child = child._config
|
||||
except:
|
||||
except Exception:
|
||||
raise TypeError(_("{}config's children "
|
||||
"should be config, not {}"
|
||||
).format(self.impl_type,
|
||||
type(child)))
|
||||
if not isinstance(child, (KernelConfig, KernelMetaConfig)):
|
||||
if __debug__ and not isinstance(child, (KernelConfig,
|
||||
KernelMetaConfig)):
|
||||
raise TypeError(_("child must be a Config or MetaConfig"))
|
||||
if descr is None:
|
||||
descr = child.cfgimpl_get_description()
|
||||
|
@ -116,7 +116,7 @@ class PropertiesOptionError(AttributeError):
|
||||
self._name,
|
||||
prop_msg,
|
||||
msg))
|
||||
del self._requires, self._opt_type, self._name, self._option_bag
|
||||
del self._requires, self._opt_type, self._name
|
||||
del self._settings, self._orig_opt
|
||||
return self.msg
|
||||
|
||||
@ -127,7 +127,11 @@ class ConfigError(Exception):
|
||||
"""attempt to change an option's owner without a value
|
||||
or in case of `_cfgimpl_descr` is None
|
||||
or if a calculation cannot be carried out"""
|
||||
pass
|
||||
def __init__(self,
|
||||
exp,
|
||||
ori_err=None):
|
||||
super().__init__(exp)
|
||||
self.ori_err = ori_err
|
||||
|
||||
|
||||
class ConflictError(Exception):
|
||||
|
@ -12,6 +12,9 @@
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
from typing import Any, List, Optional
|
||||
from operator import add, mul, sub, truediv
|
||||
from .setting import undefined
|
||||
from .i18n import _
|
||||
|
||||
|
||||
@ -46,9 +49,12 @@ class Param:
|
||||
|
||||
|
||||
class ParamOption(Param):
|
||||
__slots__ = ('option', 'notraisepropertyerror')
|
||||
def __init__(self, option, notraisepropertyerror=False):
|
||||
if not hasattr(option, 'impl_is_symlinkoption'):
|
||||
__slots__ = ('option',
|
||||
'notraisepropertyerror')
|
||||
def __init__(self,
|
||||
option: 'Option',
|
||||
notraisepropertyerror: bool=False) -> None:
|
||||
if __debug__ and not hasattr(option, 'impl_is_symlinkoption'):
|
||||
raise ValueError(_('paramoption needs an option not {}').format(type(option)))
|
||||
if option.impl_is_symlinkoption():
|
||||
cur_opt = option.impl_getopt()
|
||||
@ -79,3 +85,240 @@ class ParamIndex(Param):
|
||||
|
||||
def tiramisu_copy(val): # pragma: no cover
|
||||
return val
|
||||
|
||||
|
||||
def calc_value(*args: List[Any],
|
||||
multi: bool=False,
|
||||
default: Any=undefined,
|
||||
condition: Any=undefined,
|
||||
expected: Any=undefined,
|
||||
condition_operator: str='AND',
|
||||
allow_none: bool=False,
|
||||
remove_duplicate_value: bool=False,
|
||||
join: Optional[str]=None,
|
||||
min_args_len: Optional[int]=None,
|
||||
operator: Optional[str]=None,
|
||||
index: Optional[int]=None,
|
||||
**kwargs) -> Any:
|
||||
"""calculate value
|
||||
:param multi: value returns must be a list of value
|
||||
:param default: default value if condition is not matched or if args is empty
|
||||
if there is more than one default value, set default_0, default_1, ...
|
||||
:param condition: test if condition is equal to expected value
|
||||
if there is more than one condition, set condition_0, condition_1, ...
|
||||
:param expected: value expected for all conditions
|
||||
if expected value is different between condition, set expected_0, expected_1, ...
|
||||
:param condition_operator: OR or AND operator for condition
|
||||
:param allow_none: if False, do not return list in None is present in list
|
||||
:param remove_duplicate_value: if True, remote duplicated value
|
||||
:param join: join all args with specified characters
|
||||
:param min_args_len: if number of arguments is smaller than this value, return default value
|
||||
:param operator: operator
|
||||
|
||||
examples:
|
||||
* you want to copy value from an option to an other option:
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption
|
||||
>>> val1 = StrOption('val1', '', 'val1')
|
||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1)))
|
||||
>>> od = OptionDescription('root', '', [val1, val2])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val1'}
|
||||
|
||||
* you want to copy values from two options in one multi option
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', "", 'val1')
|
||||
>>> val2 = StrOption('val2', "", 'val2')
|
||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True)))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val2', 'val3': ['val1', 'val2']}
|
||||
|
||||
* you want to copy a value from an option is it not disabled, otherwise set 'default_value'
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', '', 'val1')
|
||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True), default=ParamValue('default_value')))
|
||||
>>> od = OptionDescription('root', '', [val1, val2])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.property.read_write()
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val1'}
|
||||
>>> cfg.option('val1').property.add('disabled')
|
||||
>>> cfg.value.dict()
|
||||
{'val2': 'default_value'}
|
||||
|
||||
* you want to copy value from an option is an other is True, otherwise set 'default_value'
|
||||
>>> from tiramisu import calc_value, BoolOption, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> boolean = BoolOption('boolean', '', True)
|
||||
>>> val1 = StrOption('val1', '', 'val1')
|
||||
>>> val2 = StrOption('val2', '', callback=calc_value, callback_params=Params(ParamOption(val1, True),
|
||||
... default=ParamValue('default_value'),
|
||||
... condition=ParamOption(boolean),
|
||||
... expected=ParamValue(True)))
|
||||
>>> od = OptionDescription('root', '', [boolean, val1, val2])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.property.read_write()
|
||||
>>> cfg.value.dict()
|
||||
{'boolean': True, 'val1': 'val1', 'val2': 'val1'}
|
||||
>>> cfg.option('boolean').value.set(False)
|
||||
>>> cfg.value.dict()
|
||||
{'boolean': False, 'val1': 'val1', 'val2': 'default_value'}
|
||||
|
||||
* you want to copy option even if None is present
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', "", 'val1')
|
||||
>>> val2 = StrOption('val2', "")
|
||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), allow_none=ParamValue(True)))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': None, 'val3': ['val1', None]}
|
||||
|
||||
* you want uniq value
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', "", 'val1')
|
||||
>>> val2 = StrOption('val2', "", 'val1')
|
||||
>>> val3 = StrOption('val3', "", multi=True, callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), multi=ParamValue(True), remove_duplicate_value=ParamValue(True)))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val1', 'val3': ['val1']}
|
||||
|
||||
* you want to join two values with '.'
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', "", 'val1')
|
||||
>>> val2 = StrOption('val2', "", 'val2')
|
||||
>>> val3 = StrOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), join=ParamValue('.')))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val2', 'val3': 'val1.val2'}
|
||||
|
||||
* you want join three values, only if almost three values are set
|
||||
>>> from tiramisu import calc_value, StrOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = StrOption('val1', "", 'val1')
|
||||
>>> val2 = StrOption('val2', "", 'val2')
|
||||
>>> val3 = StrOption('val3', "", 'val3')
|
||||
>>> val4 = StrOption('val4', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2), ParamOption(val3, True)), join=ParamValue('.'), min_args_len=ParamValue(3)))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3, val4])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.property.read_write()
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val2', 'val3': 'val3', 'val4': 'val1.val2.val3'}
|
||||
>>> cfg.option('val3').property.add('disabled')
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 'val1', 'val2': 'val2', 'val4': ''}
|
||||
|
||||
* you want to add all values
|
||||
>>> from tiramisu import calc_value, IntOption, OptionDescription, Config, Params, ParamOption, ParamValue
|
||||
>>> val1 = IntOption('val1', "", 1)
|
||||
>>> val2 = IntOption('val2', "", 2)
|
||||
>>> val3 = IntOption('val3', "", callback=calc_value, callback_params=Params((ParamOption(val1), ParamOption(val2)), operator=ParamValue('add')))
|
||||
>>> od = OptionDescription('root', '', [val1, val2, val3])
|
||||
>>> cfg = Config(od)
|
||||
>>> cfg.value.dict()
|
||||
{'val1': 1, 'val2': 2, 'val3': 3}
|
||||
|
||||
"""
|
||||
def value_from_kwargs(value: Any, pattern: str, to_dict: bool=False) -> Any:
|
||||
# if value attribute exist return it's value
|
||||
# otherwise pattern_0, pattern_1, ...
|
||||
# otherwise undefined
|
||||
if value is not undefined:
|
||||
if to_dict == 'all':
|
||||
returns = {0: value}
|
||||
else:
|
||||
returns = value
|
||||
else:
|
||||
kwargs_matches = {}
|
||||
len_pattern = len(pattern)
|
||||
for key in kwargs.keys():
|
||||
if key.startswith(pattern):
|
||||
index = int(key[len_pattern:])
|
||||
kwargs_matches[index] = kwargs[key]
|
||||
if not kwargs_matches:
|
||||
return undefined
|
||||
keys = sorted(kwargs_matches)
|
||||
if to_dict:
|
||||
returns = {}
|
||||
else:
|
||||
returns = []
|
||||
for key in keys:
|
||||
if to_dict:
|
||||
returns[key] = kwargs_matches[key]
|
||||
else:
|
||||
returns.append(kwargs_matches[key])
|
||||
return returns
|
||||
|
||||
def is_condition_matches():
|
||||
calculated_conditions = value_from_kwargs(condition, 'condition_', to_dict='all')
|
||||
if condition is not undefined:
|
||||
is_matches = None
|
||||
calculated_expected = value_from_kwargs(expected, 'expected_', to_dict=True)
|
||||
for idx, calculated_condition in calculated_conditions.items():
|
||||
if isinstance(calculated_expected, dict):
|
||||
current_matches = calculated_condition == calculated_expected[idx]
|
||||
else:
|
||||
current_matches = calculated_condition == calculated_expected
|
||||
if is_matches is None:
|
||||
is_matches = current_matches
|
||||
elif condition_operator == 'AND':
|
||||
is_matches = is_matches and current_matches
|
||||
elif condition_operator == 'OR':
|
||||
is_matches = is_matches or current_matches
|
||||
else:
|
||||
raise ValueError(_('unexpected {} condition_operator in calc_value').format(condition_operator))
|
||||
else:
|
||||
is_matches = True
|
||||
return is_matches
|
||||
|
||||
def get_value():
|
||||
if not is_condition_matches():
|
||||
# force to default
|
||||
value = []
|
||||
else:
|
||||
value = list(args)
|
||||
if min_args_len and not len(value) >= min_args_len:
|
||||
value = []
|
||||
if value == []:
|
||||
# default value
|
||||
new_default = value_from_kwargs(default, 'default_')
|
||||
if new_default is not undefined:
|
||||
if not isinstance(new_default, list):
|
||||
value = [new_default]
|
||||
else:
|
||||
value = new_default
|
||||
return value
|
||||
|
||||
value = get_value()
|
||||
if not multi:
|
||||
if join is not None:
|
||||
value = join.join(value)
|
||||
elif value and operator:
|
||||
new_value = value[0]
|
||||
op = {'mul': mul,
|
||||
'add': add,
|
||||
'div': truediv,
|
||||
'sub': sub}[operator]
|
||||
for val in value[1:]:
|
||||
new_value = op(new_value, val)
|
||||
value = new_value
|
||||
elif value == []:
|
||||
value = None
|
||||
else:
|
||||
value = value[0]
|
||||
if isinstance(value, list) and index is not None:
|
||||
if len(value) > index:
|
||||
value = value[index]
|
||||
else:
|
||||
value = None
|
||||
elif None in value and not allow_none:
|
||||
value = []
|
||||
elif remove_duplicate_value:
|
||||
new_value = []
|
||||
for val in value:
|
||||
if val not in new_value:
|
||||
new_value.append(val)
|
||||
value = new_value
|
||||
return value
|
||||
|
@ -15,9 +15,16 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ____________________________________________________________
|
||||
from logging import getLogger
|
||||
from logging import getLogger, DEBUG, basicConfig, StreamHandler, Formatter
|
||||
import os
|
||||
|
||||
|
||||
log = getLogger('tiramisu')
|
||||
# import logging
|
||||
# logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
|
||||
if os.environ.get('TIRAMISU_DEBUG') == 'True':
|
||||
log.setLevel(DEBUG)
|
||||
handler = StreamHandler()
|
||||
handler.setLevel(DEBUG)
|
||||
formatter = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
log.addHandler(handler)
|
||||
|
@ -170,7 +170,7 @@ class Base:
|
||||
param.option._add_dependency(self)
|
||||
if type_ == 'validator':
|
||||
self._has_dependency = True
|
||||
is_multi = self.impl_is_dynoptiondescription() or self.impl_is_multi()
|
||||
is_multi = self.impl_is_optiondescription() or self.impl_is_multi()
|
||||
func_args, func_kwargs, func_positional, func_keyword = self._get_function_args(calculator)
|
||||
calculator_args, calculator_kwargs = self._get_parameters_args(calculator_params, add_value)
|
||||
# remove knowned kwargs
|
||||
@ -253,13 +253,14 @@ class Base:
|
||||
def _impl_set_callback(self,
|
||||
callback: Callable,
|
||||
callback_params: Optional[Params]=None) -> None:
|
||||
if callback is None and callback_params is not None:
|
||||
raise ValueError(_("params defined for a callback function but "
|
||||
"no callback defined"
|
||||
' yet for option "{0}"').format(
|
||||
self.impl_getname()))
|
||||
self._validate_calculator(callback,
|
||||
callback_params)
|
||||
if __debug__:
|
||||
if callback is None and callback_params is not None:
|
||||
raise ValueError(_("params defined for a callback function but "
|
||||
"no callback defined"
|
||||
' yet for option "{0}"').format(
|
||||
self.impl_getname()))
|
||||
self._validate_calculator(callback,
|
||||
callback_params)
|
||||
if callback is not None:
|
||||
callback_params = self._build_calculator_params(callback,
|
||||
callback_params,
|
||||
@ -397,7 +398,10 @@ class BaseOption(Base):
|
||||
super(BaseOption, self).__setattr__(name, value)
|
||||
|
||||
def impl_getpath(self) -> str:
|
||||
return self._path
|
||||
try:
|
||||
return self._path
|
||||
except AttributeError:
|
||||
raise AttributeError(_('"{}" not part of any Config').format(self.impl_get_display_name()))
|
||||
|
||||
def impl_has_callback(self) -> bool:
|
||||
"to know if a callback has been defined or not"
|
||||
@ -440,17 +444,25 @@ def validate_requires_arg(new_option: BaseOption,
|
||||
the description of the requires dictionary
|
||||
"""
|
||||
def get_option(require):
|
||||
option = require['option']
|
||||
if option == 'self':
|
||||
option = new_option
|
||||
if not isinstance(option, BaseOption):
|
||||
raise ValueError(_('malformed requirements '
|
||||
'must be an option in option {0}').format(name))
|
||||
if not multi and option.impl_is_multi():
|
||||
raise ValueError(_('malformed requirements '
|
||||
'multi option must not set '
|
||||
'as requires of non multi option {0}').format(name))
|
||||
option._add_dependency(new_option)
|
||||
if 'option' in require:
|
||||
option = require['option']
|
||||
if option == 'self':
|
||||
option = new_option
|
||||
if __debug__:
|
||||
if not isinstance(option, BaseOption):
|
||||
raise ValueError(_('malformed requirements '
|
||||
'must be an option in option {0}').format(name))
|
||||
if not multi and option.impl_is_multi():
|
||||
raise ValueError(_('malformed requirements '
|
||||
'multi option must not set '
|
||||
'as requires of non multi option {0}').format(name))
|
||||
option._add_dependency(new_option)
|
||||
else:
|
||||
callback = require['callback']
|
||||
callback_params = new_option._build_calculator_params(callback,
|
||||
require.get('callback_params'),
|
||||
'callback')
|
||||
option = (callback, callback_params)
|
||||
return option
|
||||
|
||||
def _set_expected(action,
|
||||
@ -479,11 +491,11 @@ def validate_requires_arg(new_option: BaseOption,
|
||||
operator = get_operator(require)
|
||||
if isinstance(expected, list):
|
||||
for exp in expected:
|
||||
if set(exp.keys()) != {'option', 'value'}:
|
||||
if __debug__ and set(exp.keys()) != {'option', 'value'}:
|
||||
raise ValueError(_('malformed requirements expected must have '
|
||||
'option and value for option {0}').format(name))
|
||||
option = get_option(exp)
|
||||
if option is not None:
|
||||
if __debug__:
|
||||
try:
|
||||
option._validate(exp['value'], undefined)
|
||||
except ValueError as err:
|
||||
@ -499,7 +511,7 @@ def validate_requires_arg(new_option: BaseOption,
|
||||
operator)
|
||||
else:
|
||||
option = get_option(require)
|
||||
if expected is not None:
|
||||
if __debug__ and not isinstance(option, tuple) and expected is not None:
|
||||
try:
|
||||
option._validate(expected, undefined)
|
||||
except ValueError as err:
|
||||
@ -557,25 +569,29 @@ def validate_requires_arg(new_option: BaseOption,
|
||||
# start parsing all requires given by user (has dict)
|
||||
# transforme it to a tuple
|
||||
for require in requires:
|
||||
if not isinstance(require, dict):
|
||||
raise ValueError(_("malformed requirements type for option:"
|
||||
" {0}, must be a dict").format(name))
|
||||
valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive',
|
||||
'same_action', 'operator')
|
||||
unknown_keys = frozenset(require.keys()) - frozenset(valid_keys)
|
||||
if unknown_keys != frozenset():
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' unknown keys {1}, must only '
|
||||
'{2}').format(name,
|
||||
unknown_keys,
|
||||
valid_keys))
|
||||
# prepare all attributes
|
||||
if not ('expected' in require and isinstance(require['expected'], list)) and \
|
||||
not ('option' in require and 'expected' in require) or \
|
||||
'action' not in require:
|
||||
raise ValueError(_("malformed requirements for option: {0}"
|
||||
" require must have option, expected and"
|
||||
" action keys").format(name))
|
||||
if __debug__:
|
||||
if not isinstance(require, dict):
|
||||
raise ValueError(_("malformed requirements type for option:"
|
||||
" {0}, must be a dict").format(name))
|
||||
valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive',
|
||||
'same_action', 'operator', 'callback', 'callback_params')
|
||||
unknown_keys = frozenset(require.keys()) - frozenset(valid_keys)
|
||||
if unknown_keys != frozenset():
|
||||
raise ValueError(_('malformed requirements for option: {0}'
|
||||
' unknown keys {1}, must only '
|
||||
'{2}').format(name,
|
||||
unknown_keys,
|
||||
valid_keys))
|
||||
# {'expected': ..., 'option': ..., 'action': ...}
|
||||
# {'expected': [{'option': ..., 'value': ...}, ...}], 'action': ...}
|
||||
# {'expected': ..., 'callback': ..., 'action': ...}
|
||||
if not 'expected' in require or not 'action' in require or \
|
||||
not (isinstance(require['expected'], list) or \
|
||||
'option' in require or \
|
||||
'callback' in require):
|
||||
raise ValueError(_("malformed requirements for option: {0}"
|
||||
" require must have option, expected and"
|
||||
" action keys").format(name))
|
||||
action = get_action(require)
|
||||
config_action.add(action)
|
||||
if action not in ret_requires:
|
||||
|
@ -27,6 +27,7 @@ from .option import Option
|
||||
class BoolOption(Option):
|
||||
"represents a choice between ``True`` and ``False``"
|
||||
__slots__ = tuple()
|
||||
_type = 'boolean'
|
||||
_display_name = _('boolean')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -28,6 +28,7 @@ from .option import Option
|
||||
|
||||
class BroadcastOption(Option):
|
||||
__slots__ = tuple()
|
||||
_type = 'broadcast_address'
|
||||
_display_name = _('broadcast address')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -33,6 +33,7 @@ class ChoiceOption(Option):
|
||||
The option can also have the value ``None``
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'choice'
|
||||
_display_name = _('choice')
|
||||
|
||||
def __init__(self,
|
||||
|
@ -27,6 +27,7 @@ from .option import Option
|
||||
|
||||
class DateOption(Option):
|
||||
__slots__ = tuple()
|
||||
_type = 'date'
|
||||
_display_name = _('date')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -19,15 +19,14 @@
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
import re
|
||||
from ipaddress import ip_address, IPv4Address
|
||||
|
||||
from ipaddress import ip_address
|
||||
from ..setting import undefined, Undefined, OptionBag
|
||||
from ..i18n import _
|
||||
from .option import Option
|
||||
from .stroption import StrOption
|
||||
from .ipoption import IPOption
|
||||
|
||||
|
||||
class DomainnameOption(StrOption):
|
||||
class DomainnameOption(IPOption):
|
||||
"""represents the choice of a domain name
|
||||
netbios: for MS domain
|
||||
hostname: to identify the device
|
||||
@ -35,6 +34,7 @@ class DomainnameOption(StrOption):
|
||||
fqdn: with tld, not supported yet
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
_type = 'domainname'
|
||||
_display_name = _('domain name')
|
||||
|
||||
def __init__(self,
|
||||
@ -43,16 +43,17 @@ class DomainnameOption(StrOption):
|
||||
default=None,
|
||||
default_multi=None,
|
||||
requires=None,
|
||||
multi=False,
|
||||
multi: bool=False,
|
||||
callback=None,
|
||||
callback_params=None,
|
||||
validator=None,
|
||||
validator_params=None,
|
||||
properties=None,
|
||||
allow_ip=False,
|
||||
type_='domainname',
|
||||
warnings_only=False,
|
||||
allow_without_dot=False):
|
||||
allow_ip: bool=False,
|
||||
cidr: bool=False,
|
||||
type_: str='domainname',
|
||||
warnings_only: bool=False,
|
||||
allow_without_dot=False) -> None:
|
||||
|
||||
if type_ not in ['netbios', 'hostname', 'domainname']:
|
||||
raise ValueError(_('unknown type_ {0} for hostname').format(type_))
|
||||
@ -72,25 +73,29 @@ class DomainnameOption(StrOption):
|
||||
else:
|
||||
regexp = r'((?!-)[a-z0-9-]{{1,{0}}})'.format(self._get_len(type_))
|
||||
if allow_ip:
|
||||
regexp = r'^(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))$'.format(regexp)
|
||||
if not cidr:
|
||||
regexp = r'^(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)))$'.format(regexp)
|
||||
else:
|
||||
regexp = r'^(?:{0}|(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){{3}}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9][0-9]))$'.format(regexp)
|
||||
else:
|
||||
regexp = r'^{0}$'.format(regexp)
|
||||
extra['_domain_re'] = re.compile(regexp)
|
||||
extra['_has_upper'] = re.compile('[A-Z]')
|
||||
|
||||
super(DomainnameOption, self).__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
extra=extra)
|
||||
super().__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
default_multi=default_multi,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
requires=requires,
|
||||
multi=multi,
|
||||
validator=validator,
|
||||
validator_params=validator_params,
|
||||
properties=properties,
|
||||
warnings_only=warnings_only,
|
||||
cidr=cidr,
|
||||
_extra=extra)
|
||||
|
||||
def _get_len(self, type_):
|
||||
if type_ == 'netbios':
|
||||
@ -116,9 +121,10 @@ class DomainnameOption(StrOption):
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if self.impl_get_extra('_allow_ip') is True:
|
||||
return
|
||||
raise ValueError(_('must not be an IP'))
|
||||
if self.impl_get_extra('_allow_ip') is False:
|
||||
raise ValueError(_('must not be an IP'))
|
||||
# it's an IP so validate with IPOption
|
||||
return super()._validate(value, option_bag, current_opt)
|
||||
part_name_length = self._get_len(self.impl_get_extra('_dom_type'))
|
||||
if self.impl_get_extra('_dom_type') == 'domainname':
|
||||
if not self.impl_get_extra('_allow_without_dot') and not "." in value:
|
||||
|
@ -28,4 +28,5 @@ class EmailOption(RegexpOption):
|
||||
__slots__ = tuple()
|
||||
#https://www.w3.org/TR/html-markup/input.email.html#input.email.attrs.value.single.
|
||||
_regexp = re.compile(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
||||
_type = 'email'
|
||||
_display_name = _('email address')
|
||||
|
@ -27,4 +27,5 @@ from .stroption import RegexpOption
|
||||
class FilenameOption(RegexpOption):
|
||||
__slots__ = tuple()
|
||||
_regexp = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
|
||||
_type = 'filename'
|
||||
_display_name = _('file name')
|
||||
|
@ -27,6 +27,7 @@ from .option import Option
|
||||
class FloatOption(Option):
|
||||
"represents a choice of a floating point number"
|
||||
__slots__ = tuple()
|
||||
_type = 'float'
|
||||
_display_name = _('float')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -27,6 +27,7 @@ from .option import Option
|
||||
class IntOption(Option):
|
||||
"represents a choice of an integer"
|
||||
__slots__ = tuple()
|
||||
_type = 'integer'
|
||||
_display_name = _('integer')
|
||||
|
||||
def __init__(self,
|
||||
|
@ -32,6 +32,7 @@ from .networkoption import NetworkOption
|
||||
class IPOption(StrOption):
|
||||
"represents the choice of an ip"
|
||||
__slots__ = tuple()
|
||||
_type = 'ip'
|
||||
_display_name = _('IP')
|
||||
|
||||
def __init__(self,
|
||||
@ -49,10 +50,15 @@ class IPOption(StrOption):
|
||||
private_only=False,
|
||||
allow_reserved=False,
|
||||
warnings_only=False,
|
||||
cidr=False):
|
||||
extra = {'_private_only': private_only,
|
||||
'_allow_reserved': allow_reserved,
|
||||
'_cidr': cidr}
|
||||
cidr=False,
|
||||
_extra=None):
|
||||
if _extra is None:
|
||||
extra = {}
|
||||
else:
|
||||
extra = _extra
|
||||
extra['_private_only'] = private_only
|
||||
extra['_allow_reserved'] = allow_reserved
|
||||
extra['_cidr'] = cidr
|
||||
super().__init__(name,
|
||||
doc,
|
||||
default=default,
|
||||
|
@ -109,7 +109,7 @@ class Leadership(OptionDescription):
|
||||
for requires_ in getattr(self, '_requires', ()):
|
||||
for require in requires_:
|
||||
for require_opt, values in require[0]:
|
||||
if require_opt.impl_is_multi() and require_opt.impl_get_leadership():
|
||||
if not isinstance(require_opt, tuple) and require_opt.impl_is_multi() and require_opt.impl_get_leadership():
|
||||
raise ValueError(_('malformed requirements option "{0}" '
|
||||
'must not be in follower for "{1}"').format(
|
||||
require_opt.impl_getname(),
|
||||
|
@ -19,6 +19,7 @@
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
from ipaddress import ip_interface, ip_network
|
||||
from typing import List
|
||||
|
||||
from ..error import ConfigError
|
||||
from ..setting import undefined, OptionBag, Undefined
|
||||
@ -30,6 +31,7 @@ from .stroption import StrOption
|
||||
class NetmaskOption(StrOption):
|
||||
"represents the choice of a netmask"
|
||||
__slots__ = tuple()
|
||||
_type = 'netmask'
|
||||
_display_name = _('netmask address')
|
||||
|
||||
def _validate(self,
|
||||
@ -49,57 +51,56 @@ class NetmaskOption(StrOption):
|
||||
raise ValueError()
|
||||
|
||||
def _cons_network_netmask(self,
|
||||
current_opt,
|
||||
opts,
|
||||
vals,
|
||||
warnings_only,
|
||||
context):
|
||||
#opts must be (netmask, network) options
|
||||
current_opt: Option,
|
||||
opts: List[Option],
|
||||
vals: List[str],
|
||||
warnings_only: bool,
|
||||
context: 'Config'):
|
||||
if context is undefined and len(vals) != 2:
|
||||
raise ConfigError(_('network_netmask needs a network and a netmask'))
|
||||
if None in vals or len(vals) != 2:
|
||||
return
|
||||
val_netmask, val_network = vals
|
||||
opt_netmask, opt_network = opts
|
||||
try:
|
||||
ip_network('{0}/{1}'.format(val_network, val_netmask))
|
||||
except ValueError:
|
||||
if current_opt == opts[1]:
|
||||
if current_opt == opt_network:
|
||||
raise ValueError(_('with netmask "{0}" ("{1}")').format(val_netmask,
|
||||
opts[0].impl_get_display_name()))
|
||||
opt_netmask.impl_get_display_name()))
|
||||
else:
|
||||
raise ValueError(_('with network "{0}" ("{1}")').format(val_network,
|
||||
opts[1].impl_get_display_name()))
|
||||
opt_network.impl_get_display_name()))
|
||||
|
||||
def _cons_ip_netmask(self,
|
||||
current_opt,
|
||||
opts,
|
||||
vals,
|
||||
warnings_only,
|
||||
context,
|
||||
_cidr=False):
|
||||
# opts must be (netmask, ip) options
|
||||
current_opt: Option,
|
||||
opts: List[Option],
|
||||
vals: List[str],
|
||||
warnings_only: bool,
|
||||
context: 'config',
|
||||
_cidr: bool=False):
|
||||
if context is undefined and len(vals) != 2:
|
||||
raise ConfigError(_('ip_netmask needs an IP and a netmask'))
|
||||
if None in vals or len(vals) != 2:
|
||||
return
|
||||
msg = None
|
||||
val_netmask, val_ip = vals
|
||||
opt_netmask, opt_ip = opts
|
||||
ip = ip_interface('{0}/{1}'.format(val_ip, val_netmask))
|
||||
network = ip.network
|
||||
if ip.ip == network.network_address:
|
||||
if not _cidr and current_opt == opts[1]:
|
||||
msg = _('this is a network with netmask "{0}" ("{1}")')
|
||||
else:
|
||||
msg = _('IP "{0}" ("{1}") is the network')
|
||||
elif ip.ip == network.broadcast_address:
|
||||
if not _cidr and current_opt == opts[1]:
|
||||
msg = _('this is a broadcast with netmask "{0}" ("{1}")')
|
||||
else:
|
||||
msg = _('IP "{0}" ("{1}") is the broadcast')
|
||||
if msg is not None:
|
||||
if not _cidr and current_opt == opts[1]:
|
||||
raise ValueError(msg.format(val_netmask,
|
||||
opts[0].impl_get_display_name()))
|
||||
else:
|
||||
raise ValueError(msg.format(val_ip,
|
||||
opts[1].impl_get_display_name()))
|
||||
if not _cidr and current_opt == opt_ip:
|
||||
if ip.ip == ip.network.network_address:
|
||||
raise ValueError( _('this is a network with netmask "{0}" ("{1}")'
|
||||
'').format(val_netmask,
|
||||
opt_netmask.impl_get_display_name()))
|
||||
elif ip.ip == ip.network.broadcast_address:
|
||||
raise ValueError(_('this is a broadcast with netmask "{0}" ("{1}")'
|
||||
'').format(val_netmask,
|
||||
opt_netmask.impl_get_display_name()))
|
||||
else:
|
||||
if ip.ip == ip.network.network_address:
|
||||
raise ValueError(_('IP "{0}" ("{1}") is the network'
|
||||
'').format(val_ip,
|
||||
opt_ip.impl_get_display_name()))
|
||||
elif ip.ip == ip.network.broadcast_address:
|
||||
raise ValueError(_('IP "{0}" ("{1}") is the broadcast'
|
||||
'').format(val_ip,
|
||||
opt_ip.impl_get_display_name()))
|
||||
|
@ -28,6 +28,7 @@ from .option import Option
|
||||
class NetworkOption(Option):
|
||||
"represents the choice of a network"
|
||||
__slots__ = tuple()
|
||||
_type = 'network'
|
||||
_display_name = _('network address')
|
||||
|
||||
def __init__(self,
|
||||
|
@ -179,6 +179,10 @@ class Option(BaseOption):
|
||||
def impl_is_dynsymlinkoption(self) -> bool:
|
||||
return False
|
||||
|
||||
def get_type(self) -> str:
|
||||
# _display_name for compatibility with older version than 3.0rc3
|
||||
return getattr(self, '_type', self._display_name)
|
||||
|
||||
def get_display_type(self) -> str:
|
||||
return self._display_name
|
||||
|
||||
@ -388,13 +392,13 @@ class Option(BaseOption):
|
||||
def impl_is_leader(self):
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return leadership
|
||||
return self.impl_get_leadership().is_leader(self)
|
||||
return False
|
||||
return leadership.is_leader(self)
|
||||
|
||||
def impl_is_follower(self):
|
||||
leadership = self.impl_get_leadership()
|
||||
if leadership is None:
|
||||
return leadership
|
||||
return False
|
||||
return not leadership.is_leader(self)
|
||||
|
||||
def impl_get_leadership(self):
|
||||
|
@ -139,7 +139,7 @@ class CacheOptionDescription(BaseOption):
|
||||
# * current option must be a follower (and only a follower)
|
||||
# * option in require and current option must be in same leadership
|
||||
for require_opt, values in require[0]:
|
||||
if require_opt.impl_is_multi():
|
||||
if not isinstance(require_opt, tuple) and require_opt.impl_is_multi():
|
||||
if is_follower is None:
|
||||
is_follower = option.impl_is_follower()
|
||||
if is_follower:
|
||||
|
@ -28,6 +28,7 @@ from .stroption import StrOption
|
||||
class PasswordOption(StrOption):
|
||||
"represents the choice of a password"
|
||||
__slots__ = tuple()
|
||||
_type = 'password'
|
||||
_display_name = _('password')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -40,6 +40,7 @@ class PortOption(StrOption):
|
||||
"""
|
||||
__slots__ = tuple()
|
||||
port_re = re.compile(r"^[0-9]*$")
|
||||
_type = 'port'
|
||||
_display_name = _('port')
|
||||
|
||||
def __init__(self,
|
||||
|
@ -29,6 +29,7 @@ from .option import Option
|
||||
class StrOption(Option):
|
||||
"represents the choice of a string"
|
||||
__slots__ = tuple()
|
||||
_type = 'string'
|
||||
_display_name = _('string')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -30,6 +30,7 @@ class URLOption(DomainnameOption):
|
||||
__slots__ = tuple()
|
||||
proto_re = re.compile(r'(http|https)://')
|
||||
path_re = re.compile(r"^[A-Za-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
|
||||
_type = 'url'
|
||||
_display_name = _('URL')
|
||||
|
||||
def _validate(self,
|
||||
|
@ -28,4 +28,5 @@ class UsernameOption(RegexpOption):
|
||||
__slots__ = tuple()
|
||||
#regexp build with 'man 8 adduser' informations
|
||||
_regexp = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
|
||||
_type = 'username'
|
||||
_display_name = _('username')
|
||||
|
@ -509,39 +509,59 @@ class Settings(object):
|
||||
exps, action, inverse, transitive, same_action, operator = require
|
||||
breaked = False
|
||||
for option, expected in exps:
|
||||
if option.issubdyn():
|
||||
option = option.to_dynoption(option_bag.option.rootpath,
|
||||
option_bag.option.impl_getsuffix())
|
||||
reqpath = option.impl_getpath()
|
||||
#FIXME too later!
|
||||
if reqpath.startswith(option_bag.path + '.'):
|
||||
raise RequirementError(_("malformed requirements "
|
||||
"imbrication detected for option:"
|
||||
" '{0}' with requirement on: "
|
||||
"'{1}'").format(option_bag.path, reqpath))
|
||||
idx = None
|
||||
is_indexed = False
|
||||
if option.impl_is_follower():
|
||||
idx = option_bag.index
|
||||
elif option.impl_is_multi() and option_bag.index is not None:
|
||||
is_indexed = True
|
||||
config_bag = option_bag.config_bag.copy()
|
||||
soption_bag = OptionBag()
|
||||
soption_bag.set_option(option,
|
||||
reqpath,
|
||||
idx,
|
||||
config_bag)
|
||||
if option_bag.option == option:
|
||||
soption_bag.config_bag.unrestraint()
|
||||
soption_bag.config_bag.remove_validation()
|
||||
soption_bag.apply_requires = False
|
||||
if not isinstance(option, tuple):
|
||||
if option.issubdyn():
|
||||
option = option.to_dynoption(option_bag.option.rootpath,
|
||||
option_bag.option.impl_getsuffix())
|
||||
reqpath = option.impl_getpath()
|
||||
if __debug__ and reqpath.startswith(option_bag.path + '.'):
|
||||
# FIXME too later!
|
||||
raise RequirementError(_("malformed requirements "
|
||||
"imbrication detected for option:"
|
||||
" '{0}' with requirement on: "
|
||||
"'{1}'").format(option_bag.path, reqpath))
|
||||
idx = None
|
||||
is_indexed = False
|
||||
if option.impl_is_follower():
|
||||
idx = option_bag.index
|
||||
if idx is None:
|
||||
continue
|
||||
elif option.impl_is_leader() and option_bag.index is None:
|
||||
continue
|
||||
elif option.impl_is_multi() and option_bag.index is not None:
|
||||
is_indexed = True
|
||||
config_bag = option_bag.config_bag.copy()
|
||||
soption_bag = OptionBag()
|
||||
soption_bag.set_option(option,
|
||||
reqpath,
|
||||
idx,
|
||||
config_bag)
|
||||
if option_bag.option == option:
|
||||
soption_bag.config_bag.unrestraint()
|
||||
soption_bag.config_bag.remove_validation()
|
||||
soption_bag.apply_requires = False
|
||||
else:
|
||||
soption_bag.config_bag.properties = soption_bag.config_bag.true_properties
|
||||
soption_bag.config_bag.set_permissive()
|
||||
else:
|
||||
soption_bag.config_bag.properties = soption_bag.config_bag.true_properties
|
||||
soption_bag.config_bag.set_permissive()
|
||||
if not option_bag.option.impl_is_optiondescription() and option_bag.option.impl_is_follower():
|
||||
idx = option_bag.index
|
||||
if idx is None:
|
||||
continue
|
||||
is_indexed = False
|
||||
try:
|
||||
value = context.getattr(reqpath,
|
||||
soption_bag)
|
||||
except PropertiesOptionError as err:
|
||||
if not isinstance(option, tuple):
|
||||
value = context.getattr(reqpath,
|
||||
soption_bag)
|
||||
else:
|
||||
value = context.cfgimpl_get_values().carry_out_calculation(option_bag,
|
||||
option[0],
|
||||
option[1])
|
||||
except (PropertiesOptionError, ConfigError) as err:
|
||||
if isinstance(err, ConfigError):
|
||||
if not isinstance(err.ori_err, PropertiesOptionError):
|
||||
raise err
|
||||
err = err.ori_err
|
||||
properties = err.proptype
|
||||
# if not transitive, properties must be verify in current requires
|
||||
# otherwise if same_action, property must be in properties
|
||||
@ -582,13 +602,19 @@ class Settings(object):
|
||||
inverse and value not in expected):
|
||||
if operator != 'and':
|
||||
if readable:
|
||||
if not inverse:
|
||||
msg = _('the value of "{0}" is {1}')
|
||||
display_value = display_list(expected, 'or', add_quote=True)
|
||||
if isinstance(option, tuple):
|
||||
if not inverse:
|
||||
msg = _('the calculated value is {0}').format(display_value)
|
||||
else:
|
||||
msg = _('the calculated value is not {0}').format(display_value)
|
||||
else:
|
||||
msg = _('the value of "{0}" is not {1}')
|
||||
calc_properties.setdefault(action, []).append(
|
||||
msg.format(option.impl_get_display_name(),
|
||||
display_list(expected, 'or', add_quote=True)))
|
||||
name = option.impl_get_display_name()
|
||||
if not inverse:
|
||||
msg = _('the value of "{0}" is {1}').format(name, display_value)
|
||||
else:
|
||||
msg = _('the value of "{0}" is not {1}').format(name, display_value)
|
||||
calc_properties.setdefault(action, []).append(msg)
|
||||
else:
|
||||
calc_properties.add(action)
|
||||
breaked = True
|
||||
|
@ -32,16 +32,16 @@ class Properties(Cache):
|
||||
|
||||
# properties
|
||||
def setproperties(self, path, properties):
|
||||
log.debug('setproperties', path, properties)
|
||||
log.debug('setproperties %s %s', path, properties)
|
||||
self._properties[path] = properties
|
||||
|
||||
def getproperties(self, path, default_properties):
|
||||
ret = self._properties.get(path, frozenset(default_properties))
|
||||
log.debug('getproperties', path, ret)
|
||||
log.debug('getproperties %s %s', path, ret)
|
||||
return ret
|
||||
|
||||
def delproperties(self, path):
|
||||
log.debug('delproperties', path)
|
||||
log.debug('delproperties %s', path)
|
||||
if path in self._properties:
|
||||
del(self._properties[path])
|
||||
|
||||
@ -64,7 +64,7 @@ class Permissives(Cache):
|
||||
super(Permissives, self).__init__(storage)
|
||||
|
||||
def setpermissives(self, path, permissives):
|
||||
log.debug('setpermissives', path, permissives)
|
||||
log.debug('setpermissives %s %s', path, permissives)
|
||||
if not permissives:
|
||||
if path in self._permissives:
|
||||
del self._permissives[path]
|
||||
@ -73,7 +73,7 @@ class Permissives(Cache):
|
||||
|
||||
def getpermissives(self, path=None):
|
||||
ret = self._permissives.get(path, frozenset())
|
||||
log.debug('getpermissives', path, ret)
|
||||
log.debug('getpermissives %s %s', path, ret)
|
||||
return ret
|
||||
|
||||
def exportation(self):
|
||||
@ -86,6 +86,6 @@ class Permissives(Cache):
|
||||
self._permissives = permissives
|
||||
|
||||
def delpermissive(self, path):
|
||||
log.debug('delpermissive', path)
|
||||
log.debug('delpermissive %s', path)
|
||||
if path in self._permissives:
|
||||
del(self._permissives[path])
|
||||
|
@ -76,7 +76,7 @@ class Values(Cache):
|
||||
"""set value for a path
|
||||
a specified value must be associated to an owner
|
||||
"""
|
||||
log.debug('setvalue', path, value, owner, index, id(self))
|
||||
log.debug('setvalue %s %s %s %s %s', path, value, owner, index, id(self))
|
||||
values = []
|
||||
vidx = None
|
||||
|
||||
@ -97,7 +97,7 @@ class Values(Cache):
|
||||
return: boolean
|
||||
"""
|
||||
has_path = path in self._values[0]
|
||||
log.debug('hasvalue', path, index, has_path, id(self))
|
||||
log.debug('hasvalue %s %s %s %s', path, index, has_path, id(self))
|
||||
if index is None:
|
||||
return has_path
|
||||
elif has_path:
|
||||
@ -110,7 +110,7 @@ class Values(Cache):
|
||||
"""
|
||||
_values == ((path1, path2), ((idx1_1, idx1_2), None), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2))
|
||||
"""
|
||||
log.debug('reduce_index', path, index, id(self))
|
||||
log.debug('reduce_index %s %s %s', path, index, id(self))
|
||||
path_idx = self._values[0].index(path)
|
||||
# get the "index" position
|
||||
subidx = self._values[1][path_idx].index(index)
|
||||
@ -129,7 +129,7 @@ class Values(Cache):
|
||||
path,
|
||||
index,
|
||||
commit):
|
||||
log.debug('resetvalue_index', path, index, id(self))
|
||||
log.debug('resetvalue_index %s %s %s', path, index, id(self))
|
||||
def _resetvalue(nb):
|
||||
values_idx = list(values[nb])
|
||||
del(values_idx[path_idx])
|
||||
@ -163,7 +163,7 @@ class Values(Cache):
|
||||
commit):
|
||||
"""remove value means delete value in storage
|
||||
"""
|
||||
log.debug('resetvalue', path, id(self))
|
||||
log.debug('resetvalue %s %s', path, id(self))
|
||||
def _resetvalue(nb):
|
||||
lst = list(self._values[nb])
|
||||
lst.pop(idx)
|
||||
@ -216,7 +216,7 @@ class Values(Cache):
|
||||
with_value)
|
||||
if owner is undefined:
|
||||
owner = default
|
||||
log.debug('getvalue', path, index, value, owner, id(self))
|
||||
log.debug('getvalue %s %s %s %s %s', path, index, value, owner, id(self))
|
||||
if with_value:
|
||||
return owner, value
|
||||
else:
|
||||
|
@ -81,7 +81,7 @@ class Permissives(Sqlite3DB):
|
||||
# permissive
|
||||
def setpermissives(self, path, permissive):
|
||||
path = self._sqlite_encode_path(path)
|
||||
log.debug('setpermissive', path, permissive, id(self))
|
||||
log.debug('setpermissive %s %s %s', path, permissive, id(self))
|
||||
self._storage.execute("DELETE FROM permissive WHERE path = ? AND session_id = ?",
|
||||
(path, self._session_id),
|
||||
False)
|
||||
@ -99,7 +99,7 @@ class Permissives(Sqlite3DB):
|
||||
ret = frozenset()
|
||||
else:
|
||||
ret = frozenset(self._sqlite_decode(permissives[0]))
|
||||
log.debug('getpermissive', path, ret, id(self))
|
||||
log.debug('getpermissive %s %s %s', path, ret, id(self))
|
||||
return ret
|
||||
|
||||
def delpermissive(self, path):
|
||||
|
@ -54,7 +54,7 @@ class Values(Sqlite3DB):
|
||||
"""set value for an option
|
||||
a specified value must be associated to an owner
|
||||
"""
|
||||
log.debug('setvalue', path, value, owner, index, commit)
|
||||
log.debug('setvalue %s %s %s %s %s', path, value, owner, index, commit)
|
||||
path = self._sqlite_encode_path(path)
|
||||
if index is not None:
|
||||
self.resetvalue_index(path,
|
||||
@ -81,7 +81,7 @@ class Values(Sqlite3DB):
|
||||
"""if opt has a value
|
||||
return: boolean
|
||||
"""
|
||||
log.debug('hasvalue', path, index)
|
||||
log.debug('hasvalue %s %s', path, index)
|
||||
path = self._sqlite_encode_path(path)
|
||||
return self._sqlite_select(path, index) is not None
|
||||
|
||||
@ -91,7 +91,7 @@ class Values(Sqlite3DB):
|
||||
_values == ((path1, path2), ((idx1_1, idx1_2), None),
|
||||
((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2))
|
||||
"""
|
||||
log.debug('reduce_index', path, index, id(self))
|
||||
log.debug('reduce_index %s %s %s', path, index, id(self))
|
||||
self._storage.execute("UPDATE value SET idx = ? WHERE path = ? and idx = ? "
|
||||
"AND session_id = ?",
|
||||
(index - 1, path, index, self._session_id))
|
||||
@ -102,7 +102,7 @@ class Values(Sqlite3DB):
|
||||
commit=True):
|
||||
"""remove value means delete value in storage
|
||||
"""
|
||||
log.debug('resetvalue_index', path, index, commit)
|
||||
log.debug('resetvalue_index %s %s %s', path, index, commit)
|
||||
path = self._sqlite_encode_path(path)
|
||||
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ? AND idx = ?",
|
||||
(path, self._session_id, index),
|
||||
@ -113,7 +113,7 @@ class Values(Sqlite3DB):
|
||||
commit):
|
||||
"""remove value means delete value in storage
|
||||
"""
|
||||
log.debug('resetvalue', path, commit)
|
||||
log.debug('resetvalue %s %s', path, commit)
|
||||
path = self._sqlite_encode_path(path)
|
||||
self._storage.execute("DELETE FROM value WHERE path = ? AND session_id = ?",
|
||||
(path, self._session_id),
|
||||
@ -126,7 +126,7 @@ class Values(Sqlite3DB):
|
||||
index=None):
|
||||
"""change owner for an option
|
||||
"""
|
||||
log.debug('setowner', path, owner, index)
|
||||
log.debug('setowner %s %s %s', path, owner, index)
|
||||
path = self._sqlite_encode_path(path)
|
||||
if index is None:
|
||||
self._storage.execute("UPDATE value SET owner = ? WHERE path = ? AND session_id = ?",
|
||||
@ -143,7 +143,7 @@ class Values(Sqlite3DB):
|
||||
"""get owner for an option
|
||||
return: owner object
|
||||
"""
|
||||
log.debug('getowner', path, default, index, with_value)
|
||||
log.debug('getowner %s %s %s %s', path, default, index, with_value)
|
||||
path = self._sqlite_encode_path(path)
|
||||
request = "SELECT owner, value FROM value WHERE path = ? AND session_id = ?"
|
||||
if index is not None:
|
||||
@ -178,7 +178,7 @@ class Values(Sqlite3DB):
|
||||
:param key: information's key (ex: "help", "doc"
|
||||
:param value: information's value (ex: "the help string")
|
||||
"""
|
||||
log.debug('set_information', key, value)
|
||||
log.debug('set_information %s %s', key, value)
|
||||
path = self._sqlite_encode_path(path)
|
||||
self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?",
|
||||
(key, self._session_id, path),
|
||||
@ -191,7 +191,7 @@ class Values(Sqlite3DB):
|
||||
|
||||
:param key: the item string (ex: "help")
|
||||
"""
|
||||
log.debug('get_information', key, default)
|
||||
log.debug('get_information %s %s', key, default)
|
||||
path = self._sqlite_encode_path(path)
|
||||
value = self._storage.select("SELECT value FROM information WHERE key = ? AND "
|
||||
"session_id = ? AND path = ?",
|
||||
@ -205,7 +205,7 @@ class Values(Sqlite3DB):
|
||||
return self._sqlite_decode(value[0])
|
||||
|
||||
def del_information(self, path, key, raises):
|
||||
log.debug('del_information', key, raises)
|
||||
log.debug('del_information %s %s', key, raises)
|
||||
path = self._sqlite_encode_path(path)
|
||||
if raises and self._storage.select("SELECT value FROM information WHERE key = ? "
|
||||
"AND session_id = ? AND path = ?",
|
||||
@ -282,7 +282,7 @@ class Values(Sqlite3DB):
|
||||
|
||||
def get_max_length(self,
|
||||
path):
|
||||
log.debug('get_max_length', path)
|
||||
log.debug('get_max_length %s', path)
|
||||
val_max = self._storage.select("SELECT max(idx) FROM value WHERE path = ? AND session_id = ?",
|
||||
(path, self._session_id), False)
|
||||
if val_max[0][0] is None:
|
||||
|
@ -75,16 +75,16 @@ class Cache(DictCache):
|
||||
'expire' in self_props):
|
||||
ntime = int(time())
|
||||
if timestamp + expiration_time >= ntime:
|
||||
log.debug('getcache in cache (1)', path, value, _display_classname(self),
|
||||
log.debug('getcache in cache (1) %s %s %s %s %s', path, value, _display_classname(self),
|
||||
id(self), index)
|
||||
return True, value
|
||||
else:
|
||||
log.debug('getcache expired value for path {} < {}'.format(
|
||||
timestamp + expiration_time, ntime))
|
||||
# if expired, remove from cache
|
||||
#self.delcache(path)
|
||||
#else:
|
||||
# log.debug('getcache expired value for path {} < {}'.format(
|
||||
# timestamp + expiration_time, ntime))
|
||||
# # if expired, remove from cache
|
||||
# #self.delcache(path)
|
||||
else:
|
||||
log.debug('getcache in cache (2)', path, value, _display_classname(self),
|
||||
log.debug('getcache in cache (2) %s %s %s %s %s', path, value, _display_classname(self),
|
||||
id(self), index)
|
||||
return True, value
|
||||
log.debug('getcache {} with index {} not in {} cache'.format(path, index,
|
||||
@ -94,13 +94,13 @@ class Cache(DictCache):
|
||||
def delcache(self, path):
|
||||
"""remove cache for a specified path
|
||||
"""
|
||||
log.debug('delcache', path, _display_classname(self), id(self))
|
||||
log.debug('delcache %s %s %s', path, _display_classname(self), id(self))
|
||||
if path in self._cache:
|
||||
self._delcache(path)
|
||||
|
||||
def reset_all_cache(self):
|
||||
"empty the cache"
|
||||
log.debug('reset_all_cache', _display_classname(self), id(self))
|
||||
log.debug('reset_all_cache %s %s', _display_classname(self), id(self))
|
||||
self._reset_all_cache()
|
||||
|
||||
def get_cached(self):
|
||||
|
@ -16,10 +16,11 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ____________________________________________________________
|
||||
import weakref
|
||||
from typing import Optional
|
||||
from typing import Optional, Any, Callable
|
||||
from .error import ConfigError, PropertiesOptionError
|
||||
from .setting import owners, undefined, forbidden_owners, OptionBag, ConfigBag
|
||||
from .autolib import carry_out_calculation
|
||||
from .function import Params
|
||||
from .i18n import _
|
||||
|
||||
|
||||
@ -135,26 +136,48 @@ class Values(object):
|
||||
return self.getdefaultvalue(option_bag)
|
||||
|
||||
def getdefaultvalue(self,
|
||||
option_bag,
|
||||
force_index: Optional[int]=None):
|
||||
option_bag):
|
||||
"""get default value:
|
||||
- get meta config value or
|
||||
- get calculated value or
|
||||
- get default value
|
||||
:param opt: the `option.Option()` object
|
||||
:param path: path for `option.Option()` object
|
||||
:type path: str
|
||||
:param index: index of a multi/submulti
|
||||
:type index: int
|
||||
:returns: default value
|
||||
"""
|
||||
moption_bag = self._get_meta(option_bag)
|
||||
if moption_bag:
|
||||
# retrieved value from meta config
|
||||
return moption_bag.config_bag.context.cfgimpl_get_values().get_cached_value(moption_bag)
|
||||
|
||||
if option_bag.option.impl_has_callback():
|
||||
# default value is a calculated value
|
||||
value = self.calculate_value(option_bag)
|
||||
if value is not undefined:
|
||||
return value
|
||||
|
||||
# now try to get default value:
|
||||
value = option_bag.option.impl_getdefault()
|
||||
|
||||
# - if option is a submulti, return a list a list
|
||||
# - if option is a multi, return a list
|
||||
# - default value
|
||||
if option_bag.option.impl_is_multi() and option_bag.index is not None:
|
||||
# if index, must return good value for this index
|
||||
if len(value) > option_bag.index:
|
||||
value = value[option_bag.index]
|
||||
else:
|
||||
# no value for this index, retrieve default multi value
|
||||
# default_multi is already a list for submulti
|
||||
value = option_bag.option.impl_getdefault_multi()
|
||||
return value
|
||||
|
||||
def calculate_value(self,
|
||||
option_bag: OptionBag) -> Any:
|
||||
def _reset_cache(_value):
|
||||
if not 'expire' in option_bag.properties:
|
||||
return
|
||||
is_cache, cache_value = self._p_.getcache(option_bag.path,
|
||||
None,
|
||||
index,
|
||||
config_bag.properties,
|
||||
option_bag.index,
|
||||
option_bag.config_bag.properties,
|
||||
option_bag.properties,
|
||||
'value')
|
||||
if not is_cache or cache_value == _value:
|
||||
@ -162,75 +185,55 @@ class Values(object):
|
||||
# so do not invalidate cache
|
||||
return
|
||||
# calculated value is a new value, so reset cache
|
||||
config_bag.context.cfgimpl_reset_cache(option_bag)
|
||||
option_bag.config_bag.context.cfgimpl_reset_cache(option_bag)
|
||||
|
||||
config_bag = option_bag.config_bag
|
||||
opt = option_bag.option
|
||||
if force_index is not None:
|
||||
index = force_index
|
||||
else:
|
||||
index = option_bag.index
|
||||
moption_bag = self._get_meta(option_bag)
|
||||
if moption_bag:
|
||||
# retrieved value from meta config
|
||||
return moption_bag.config_bag.context.cfgimpl_get_values().get_cached_value(moption_bag)
|
||||
|
||||
if opt.impl_has_callback():
|
||||
# if value has callback, calculate value
|
||||
callback, callback_params = opt.impl_get_callback()
|
||||
value = carry_out_calculation(opt,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
index=index,
|
||||
config_bag=config_bag,
|
||||
fromconsistency=option_bag.fromconsistency)
|
||||
if isinstance(value, list) and index is not None:
|
||||
# if value is a list and index is set
|
||||
if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
|
||||
# return value only if it's a submulti and not a list of list
|
||||
_reset_cache(value)
|
||||
return value
|
||||
|
||||
if len(value) > index:
|
||||
# return the value for specified index if found
|
||||
_reset_cache(value[index])
|
||||
return value[index]
|
||||
# there is no calculate value for this index,
|
||||
# so return an other default value
|
||||
else:
|
||||
if opt.impl_is_submulti():
|
||||
if isinstance(value, list):
|
||||
# value is a list, but no index specified
|
||||
if (value != [] and not isinstance(value[0], list)):
|
||||
# if submulti, return a list of value
|
||||
value = [value]
|
||||
elif index is not None:
|
||||
# if submulti, return a list of value
|
||||
value = [value]
|
||||
else:
|
||||
# return a list of list for a submulti
|
||||
value = [[value]]
|
||||
elif opt.impl_is_multi() and not isinstance(value, list) and index is None:
|
||||
# return a list for a multi
|
||||
value = [value]
|
||||
# if value has callback, calculate value
|
||||
callback, callback_params = option_bag.option.impl_get_callback()
|
||||
value = self.carry_out_calculation(option_bag,
|
||||
callback,
|
||||
callback_params)
|
||||
if isinstance(value, list) and option_bag.index is not None:
|
||||
# if value is a list and index is set
|
||||
if option_bag.option.impl_is_submulti() and (value == [] or not isinstance(value[0], list)):
|
||||
# return value only if it's a submulti and not a list of list
|
||||
_reset_cache(value)
|
||||
return value
|
||||
if len(value) > option_bag.index:
|
||||
# return the value for specified index if found
|
||||
_reset_cache(value[option_bag.index])
|
||||
return value[option_bag.index]
|
||||
# there is no calculate value for this index,
|
||||
# so return an other default value
|
||||
else:
|
||||
if option_bag.option.impl_is_submulti():
|
||||
if isinstance(value, list):
|
||||
# value is a list, but no index specified
|
||||
if (value != [] and not isinstance(value[0], list)):
|
||||
# if submulti, return a list of value
|
||||
value = [value]
|
||||
elif option_bag.index is not None:
|
||||
# if submulti, return a list of value
|
||||
value = [value]
|
||||
else:
|
||||
# return a list of list for a submulti
|
||||
value = [[value]]
|
||||
elif option_bag.option.impl_is_multi() and not isinstance(value, list) and option_bag.index is None:
|
||||
# return a list for a multi
|
||||
value = [value]
|
||||
_reset_cache(value)
|
||||
return value
|
||||
return undefined
|
||||
|
||||
# now try to get default value:
|
||||
# - if opt is a submulti, return a list a list
|
||||
# - if opt is a multi, return a list
|
||||
# - default value
|
||||
value = opt.impl_getdefault()
|
||||
if opt.impl_is_multi() and index is not None:
|
||||
# if index, must return good value for this index
|
||||
if len(value) > index:
|
||||
value = value[index]
|
||||
else:
|
||||
# no value for this index, retrieve default multi value
|
||||
# default_multi is already a list for submulti
|
||||
value = opt.impl_getdefault_multi()
|
||||
return value
|
||||
|
||||
def carry_out_calculation(self,
|
||||
option_bag: OptionBag,
|
||||
callback: Callable,
|
||||
callback_params: Optional[Params]) -> Any:
|
||||
return carry_out_calculation(option_bag.option,
|
||||
callback=callback,
|
||||
callback_params=callback_params,
|
||||
index=option_bag.index,
|
||||
config_bag=option_bag.config_bag,
|
||||
fromconsistency=option_bag.fromconsistency)
|
||||
def isempty(self,
|
||||
opt,
|
||||
value,
|
||||
|
@ -2,7 +2,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Tiramisu\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-02-25 08:47+CET\n"
|
||||
"POT-Creation-Date: 2019-03-05 08:46+CET\n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: Emmanuel Garette <egarette@cadoles.com>\n"
|
||||
"Language-Team: Tiramisu's team <egarette@cadoles.com>\n"
|
||||
@ -53,35 +53,35 @@ msgstr "l'index est obligatoire pour l'option suiveuse \"{}\""
|
||||
msgid "unknown method {}"
|
||||
msgstr "méthode {} inconnue"
|
||||
|
||||
#: tiramisu/api.py:346
|
||||
#: tiramisu/api.py:360
|
||||
msgid "cannot add this property: \"{0}\""
|
||||
msgstr "ne peut pas ajouter cette propriété : \"{0}\""
|
||||
|
||||
#: tiramisu/api.py:489 tiramisu/config.py:252
|
||||
#: tiramisu/api.py:503 tiramisu/config.py:252
|
||||
msgid "can't delete a SymLinkOption"
|
||||
msgstr "ne peut supprimer une valeur à une SymLinkOption"
|
||||
|
||||
#: tiramisu/api.py:622 tiramisu/api.py:1316
|
||||
#: tiramisu/api.py:636 tiramisu/api.py:1322
|
||||
msgid "please specify a valid sub function ({})"
|
||||
msgstr "veuillez spécifier une sous fonction valide ({})"
|
||||
|
||||
#: tiramisu/api.py:685 tiramisu/api.py:1139
|
||||
#: tiramisu/api.py:699 tiramisu/api.py:1145
|
||||
msgid "unknown list type {}"
|
||||
msgstr "type de liste inconnue {}"
|
||||
|
||||
#: tiramisu/api.py:687 tiramisu/api.py:1141
|
||||
#: tiramisu/api.py:701 tiramisu/api.py:1147
|
||||
msgid "unknown group_type: {0}"
|
||||
msgstr "group_type inconnu: {0}"
|
||||
|
||||
#: tiramisu/api.py:968
|
||||
#: tiramisu/api.py:974
|
||||
msgid "properties must be a set"
|
||||
msgstr "une propriété doit être de type set"
|
||||
|
||||
#: tiramisu/api.py:974 tiramisu/api.py:996
|
||||
#: tiramisu/api.py:980 tiramisu/api.py:1002
|
||||
msgid "unknown when {} (must be in append or remove)"
|
||||
msgstr "value {} inconsistent (doit être append ou remove)"
|
||||
|
||||
#: tiramisu/api.py:986 tiramisu/api.py:1008 tiramisu/config.py:1226
|
||||
#: tiramisu/api.py:992 tiramisu/api.py:1014 tiramisu/config.py:1227
|
||||
msgid "unknown type {}"
|
||||
msgstr "type inconnu {}"
|
||||
|
||||
@ -221,20 +221,20 @@ msgid "MetaConfig with optiondescription must have string has child, not {}"
|
||||
msgstr ""
|
||||
"MetaConfig avec une optiondescription doit avoir un nom comme enfant, pas {}"
|
||||
|
||||
#: tiramisu/config.py:1207
|
||||
#: tiramisu/config.py:1208
|
||||
msgid "child must be a Config or MetaConfig"
|
||||
msgstr "enfant doit être une une Config ou une MetaConfig"
|
||||
|
||||
#: tiramisu/config.py:1211
|
||||
#: tiramisu/config.py:1212
|
||||
msgid "all config in metaconfig must have the same optiondescription"
|
||||
msgstr ""
|
||||
"toutes les configs d'une metaconfig doivent avoir la même optiondescription"
|
||||
|
||||
#: tiramisu/config.py:1224
|
||||
#: tiramisu/config.py:1225
|
||||
msgid "config name must be uniq in groupconfig for {0}"
|
||||
msgstr "le nom de la config doit être unique dans un groupconfig pour {0}"
|
||||
|
||||
#: tiramisu/config.py:1249
|
||||
#: tiramisu/config.py:1250
|
||||
msgid "cannot find the config {}"
|
||||
msgstr "ne peut pas trouver la config {0}"
|
||||
|
||||
@ -250,11 +250,11 @@ msgstr "ou"
|
||||
msgid " {} "
|
||||
msgstr " {} "
|
||||
|
||||
#: tiramisu/error.py:103 tiramisu/setting.py:559
|
||||
#: tiramisu/error.py:103 tiramisu/setting.py:563
|
||||
msgid "property"
|
||||
msgstr "de la propriété"
|
||||
|
||||
#: tiramisu/error.py:105 tiramisu/setting.py:561
|
||||
#: tiramisu/error.py:105 tiramisu/setting.py:565
|
||||
msgid "properties"
|
||||
msgstr "des propriétés"
|
||||
|
||||
@ -349,11 +349,15 @@ msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule"
|
||||
msgid "\"{}\" ({}) object attribute \"{}\" is read-only"
|
||||
msgstr "\"{}\" ({}) l'attribut de l'objet \"{}\" est en lecture seule"
|
||||
|
||||
#: tiramisu/option/baseoption.py:447
|
||||
#: tiramisu/option/baseoption.py:403
|
||||
msgid "\"{}\" not part of any Config"
|
||||
msgstr "\"{}\" ne fait pas parti d'une Config"
|
||||
|
||||
#: tiramisu/option/baseoption.py:450
|
||||
msgid "malformed requirements must be an option in option {0}"
|
||||
msgstr "requirements mal formés doit être une option dans l'option {0}"
|
||||
|
||||
#: tiramisu/option/baseoption.py:450
|
||||
#: tiramisu/option/baseoption.py:453
|
||||
msgid ""
|
||||
"malformed requirements multi option must not set as requires of non multi "
|
||||
"option {0}"
|
||||
@ -361,59 +365,59 @@ msgstr ""
|
||||
"requirements mal formés une option multiple ne doit pas être spécifié comme "
|
||||
"pré-requis à l'option non multiple {0}"
|
||||
|
||||
#: tiramisu/option/baseoption.py:483
|
||||
#: tiramisu/option/baseoption.py:486
|
||||
msgid ""
|
||||
"malformed requirements expected must have option and value for option {0}"
|
||||
msgstr ""
|
||||
"expected mal formés pour le requirements, doit avoir une option et une "
|
||||
"valeur pour l'option {0}"
|
||||
|
||||
#: tiramisu/option/baseoption.py:490 tiramisu/option/baseoption.py:506
|
||||
#: tiramisu/option/baseoption.py:493 tiramisu/option/baseoption.py:509
|
||||
msgid "malformed requirements expected value must be valid for option {0}: {1}"
|
||||
msgstr ""
|
||||
"valeur de \"expected\" malformé, doit être valide pour l'option {0} : {1}"
|
||||
|
||||
#: tiramisu/option/baseoption.py:520
|
||||
#: tiramisu/option/baseoption.py:523
|
||||
msgid ""
|
||||
"malformed requirements for option: {0} action cannot be force_store_value"
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : {0} action ne peut pas être "
|
||||
"force_store_value"
|
||||
|
||||
#: tiramisu/option/baseoption.py:528
|
||||
#: tiramisu/option/baseoption.py:531
|
||||
msgid "malformed requirements for option: {0} inverse must be boolean"
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : {0} inverse doit être un booléen"
|
||||
|
||||
#: tiramisu/option/baseoption.py:535
|
||||
#: tiramisu/option/baseoption.py:538
|
||||
msgid "malformed requirements for option: {0} transitive must be boolean"
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : {0} transitive doit être booléen"
|
||||
|
||||
#: tiramisu/option/baseoption.py:542
|
||||
#: tiramisu/option/baseoption.py:545
|
||||
msgid "malformed requirements for option: {0} same_action must be boolean"
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : {0} same_action doit être un booléen"
|
||||
|
||||
#: tiramisu/option/baseoption.py:549
|
||||
#: tiramisu/option/baseoption.py:552
|
||||
msgid ""
|
||||
"malformed requirements for option: \"{0}\" operator must be \"or\" or \"and\""
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : \"{0}\" l'opérateur doit être \"or\" "
|
||||
"ou \"and\""
|
||||
|
||||
#: tiramisu/option/baseoption.py:561
|
||||
#: tiramisu/option/baseoption.py:564
|
||||
msgid "malformed requirements type for option: {0}, must be a dict"
|
||||
msgstr ""
|
||||
"type requirements malformé pour l'option : {0}, doit être un dictionnaire"
|
||||
|
||||
#: tiramisu/option/baseoption.py:567
|
||||
#: tiramisu/option/baseoption.py:570
|
||||
msgid "malformed requirements for option: {0} unknown keys {1}, must only {2}"
|
||||
msgstr ""
|
||||
"requirements mal formés pour l'option : {0} clefs inconnues {1}, doit "
|
||||
"seulement avoir {2}"
|
||||
|
||||
#: tiramisu/option/baseoption.py:576
|
||||
#: tiramisu/option/baseoption.py:579
|
||||
msgid ""
|
||||
"malformed requirements for option: {0} require must have option, expected "
|
||||
"and action keys"
|
||||
@ -431,7 +435,7 @@ msgstr "adresse broadcast"
|
||||
|
||||
#: tiramisu/option/broadcastoption.py:38 tiramisu/option/dateoption.py:37
|
||||
#: tiramisu/option/domainnameoption.py:113 tiramisu/option/ipoption.py:77
|
||||
#: tiramisu/option/netmaskoption.py:40 tiramisu/option/networkoption.py:67
|
||||
#: tiramisu/option/netmaskoption.py:41 tiramisu/option/networkoption.py:67
|
||||
#: tiramisu/option/passwordoption.py:38 tiramisu/option/portoption.py:106
|
||||
#: tiramisu/option/urloption.py:40
|
||||
msgid "invalid string"
|
||||
@ -653,7 +657,7 @@ msgstr ""
|
||||
"requirement mal formé pour l'option \"{0}\" ne doit pas être dans une "
|
||||
"suiveuse pour \"{1}\""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:33
|
||||
#: tiramisu/option/netmaskoption.py:34
|
||||
msgid "netmask address"
|
||||
msgstr "adresse netmask"
|
||||
|
||||
@ -661,11 +665,11 @@ msgstr "adresse netmask"
|
||||
msgid "network_netmask needs a network and a netmask"
|
||||
msgstr "network_netmask nécessite un réseau et un masque de réseau"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:67
|
||||
#: tiramisu/option/netmaskoption.py:68
|
||||
msgid "with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr "avec le masque \"{0}\" (\"{1}\")"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:70
|
||||
#: tiramisu/option/netmaskoption.py:71
|
||||
msgid "with network \"{0}\" (\"{1}\")"
|
||||
msgstr "avec le réseau \"{0}\" (\"{1}\")"
|
||||
|
||||
@ -673,19 +677,19 @@ msgstr "avec le réseau \"{0}\" (\"{1}\")"
|
||||
msgid "ip_netmask needs an IP and a netmask"
|
||||
msgstr "ip_netmask nécessite une IP et un masque de réseau"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:91
|
||||
#: tiramisu/option/netmaskoption.py:90
|
||||
msgid "this is a network with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr "c'est une adresse réseau avec le masque \"{0}\" (\"{1}\")"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:93
|
||||
msgid "IP \"{0}\" (\"{1}\") is the network"
|
||||
msgstr "IP \"{0}\" (\"{1}\") est le réseau"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:96
|
||||
#: tiramisu/option/netmaskoption.py:94
|
||||
msgid "this is a broadcast with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr "c'est une adresse broadcast avec le masque \"{0}\" (\"{1}\")"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:98
|
||||
#: tiramisu/option/netmaskoption.py:99
|
||||
msgid "IP \"{0}\" (\"{1}\") is the network"
|
||||
msgstr "IP \"{0}\" (\"{1}\") est le réseau"
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:103
|
||||
msgid "IP \"{0}\" (\"{1}\") is the broadcast"
|
||||
msgstr "IP \"{0}\" (\"{1}\") est l'adresse de broadcast"
|
||||
|
||||
@ -831,7 +835,7 @@ msgstr ""
|
||||
msgid "the dynoption \"{0}\" cannot have \"force_store_value\" property"
|
||||
msgstr "la dynoption \"{0}\" ne peut avoir la propriété \"force_store_value\""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:97 tiramisu/setting.py:639
|
||||
#: tiramisu/option/optiondescription.py:97 tiramisu/setting.py:643
|
||||
msgid ""
|
||||
"a leader ({0}) cannot have \"force_default_on_freeze\" or "
|
||||
"\"force_metaconfig_on_freeze\" property without \"frozen\""
|
||||
@ -982,48 +986,48 @@ msgstr ""
|
||||
"imbrication de requirements mal formés detectée pour l'option : '{0}' avec "
|
||||
"requirement sur : '{1}'"
|
||||
|
||||
#: tiramisu/setting.py:562
|
||||
#: tiramisu/setting.py:566
|
||||
msgid ""
|
||||
"cannot access to option \"{0}\" because required option \"{1}\" has {2} {3}"
|
||||
msgstr ""
|
||||
"ne peut accéder à l'option \"{0}\" parce que l'option requise \"{1}\" a {2} "
|
||||
"{3}"
|
||||
|
||||
#: tiramisu/setting.py:586
|
||||
#: tiramisu/setting.py:590
|
||||
msgid "the value of \"{0}\" is {1}"
|
||||
msgstr "la valeur de \"{0}\" est {1}"
|
||||
|
||||
#: tiramisu/setting.py:588
|
||||
#: tiramisu/setting.py:592
|
||||
msgid "the value of \"{0}\" is not {1}"
|
||||
msgstr "la valeur de \"{0}\" n'est pas {1}"
|
||||
|
||||
#: tiramisu/setting.py:629
|
||||
#: tiramisu/setting.py:633
|
||||
msgid "cannot set property {} for option \"{}\" this property is calculated"
|
||||
msgstr ""
|
||||
"ne peut ajouter la propriété {} pour l'option \"{}\" cette propriété est "
|
||||
"calculée"
|
||||
|
||||
#: tiramisu/setting.py:634
|
||||
#: tiramisu/setting.py:638
|
||||
msgid "can't assign property to the symlinkoption \"{}\""
|
||||
msgstr "ne peut assigner une propriété à une symlinkoption \"{}\""
|
||||
|
||||
#: tiramisu/setting.py:666
|
||||
#: tiramisu/setting.py:670
|
||||
msgid "permissive must be a frozenset"
|
||||
msgstr "une permissive doit être de type frozenset"
|
||||
|
||||
#: tiramisu/setting.py:670
|
||||
#: tiramisu/setting.py:674
|
||||
msgid "can't assign permissive to the symlinkoption \"{}\""
|
||||
msgstr "ne peut assigner une permissive à la symlinkoption \"{}\""
|
||||
|
||||
#: tiramisu/setting.py:677
|
||||
#: tiramisu/setting.py:681
|
||||
msgid "cannot add those permissives: {0}"
|
||||
msgstr "ne peut ajouter ces permissives : {0}"
|
||||
|
||||
#: tiramisu/setting.py:694
|
||||
#: tiramisu/setting.py:698
|
||||
msgid "can't reset properties to the symlinkoption \"{}\""
|
||||
msgstr "ne peut réinitialiser les propriétés de la symlinkoption \"{}\""
|
||||
|
||||
#: tiramisu/setting.py:709
|
||||
#: tiramisu/setting.py:713
|
||||
msgid "can't reset permissives to the symlinkoption \"{}\""
|
||||
msgstr "ne peut réinitialiser les permissive de la symlinkoption \"{}\""
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2019-02-25 08:47+CET\n"
|
||||
"POT-Creation-Date: 2019-03-05 08:46+CET\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@ -51,35 +51,35 @@ msgstr ""
|
||||
msgid "unknown method {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:346
|
||||
#: tiramisu/api.py:360
|
||||
msgid "cannot add this property: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:489 tiramisu/config.py:252
|
||||
#: tiramisu/api.py:503 tiramisu/config.py:252
|
||||
msgid "can't delete a SymLinkOption"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:622 tiramisu/api.py:1316
|
||||
#: tiramisu/api.py:636 tiramisu/api.py:1322
|
||||
msgid "please specify a valid sub function ({})"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:685 tiramisu/api.py:1139
|
||||
#: tiramisu/api.py:699 tiramisu/api.py:1145
|
||||
msgid "unknown list type {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:687 tiramisu/api.py:1141
|
||||
#: tiramisu/api.py:701 tiramisu/api.py:1147
|
||||
msgid "unknown group_type: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:968
|
||||
#: tiramisu/api.py:974
|
||||
msgid "properties must be a set"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:974 tiramisu/api.py:996
|
||||
#: tiramisu/api.py:980 tiramisu/api.py:1002
|
||||
msgid "unknown when {} (must be in append or remove)"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/api.py:986 tiramisu/api.py:1008 tiramisu/config.py:1226
|
||||
#: tiramisu/api.py:992 tiramisu/api.py:1014 tiramisu/config.py:1227
|
||||
msgid "unknown type {}"
|
||||
msgstr ""
|
||||
|
||||
@ -195,19 +195,19 @@ msgstr ""
|
||||
msgid "MetaConfig with optiondescription must have string has child, not {}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1207
|
||||
#: tiramisu/config.py:1208
|
||||
msgid "child must be a Config or MetaConfig"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1211
|
||||
#: tiramisu/config.py:1212
|
||||
msgid "all config in metaconfig must have the same optiondescription"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1224
|
||||
#: tiramisu/config.py:1225
|
||||
msgid "config name must be uniq in groupconfig for {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/config.py:1249
|
||||
#: tiramisu/config.py:1250
|
||||
msgid "cannot find the config {}"
|
||||
msgstr ""
|
||||
|
||||
@ -223,11 +223,11 @@ msgstr ""
|
||||
msgid " {} "
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:103 tiramisu/setting.py:559
|
||||
#: tiramisu/error.py:103 tiramisu/setting.py:563
|
||||
msgid "property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/error.py:105 tiramisu/setting.py:561
|
||||
#: tiramisu/error.py:105 tiramisu/setting.py:565
|
||||
msgid "properties"
|
||||
msgstr ""
|
||||
|
||||
@ -316,51 +316,55 @@ msgstr ""
|
||||
msgid "\"{}\" ({}) object attribute \"{}\" is read-only"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:447
|
||||
msgid "malformed requirements must be an option in option {0}"
|
||||
#: tiramisu/option/baseoption.py:403
|
||||
msgid "\"{}\" not part of any Config"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:450
|
||||
msgid "malformed requirements must be an option in option {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:453
|
||||
msgid "malformed requirements multi option must not set as requires of non multi option {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:483
|
||||
#: tiramisu/option/baseoption.py:486
|
||||
msgid "malformed requirements expected must have option and value for option {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:490 tiramisu/option/baseoption.py:506
|
||||
#: tiramisu/option/baseoption.py:493 tiramisu/option/baseoption.py:509
|
||||
msgid "malformed requirements expected value must be valid for option {0}: {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:520
|
||||
#: tiramisu/option/baseoption.py:523
|
||||
msgid "malformed requirements for option: {0} action cannot be force_store_value"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:528
|
||||
#: tiramisu/option/baseoption.py:531
|
||||
msgid "malformed requirements for option: {0} inverse must be boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:535
|
||||
#: tiramisu/option/baseoption.py:538
|
||||
msgid "malformed requirements for option: {0} transitive must be boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:542
|
||||
#: tiramisu/option/baseoption.py:545
|
||||
msgid "malformed requirements for option: {0} same_action must be boolean"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:549
|
||||
#: tiramisu/option/baseoption.py:552
|
||||
msgid "malformed requirements for option: \"{0}\" operator must be \"or\" or \"and\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:561
|
||||
#: tiramisu/option/baseoption.py:564
|
||||
msgid "malformed requirements type for option: {0}, must be a dict"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:567
|
||||
#: tiramisu/option/baseoption.py:570
|
||||
msgid "malformed requirements for option: {0} unknown keys {1}, must only {2}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/baseoption.py:576
|
||||
#: tiramisu/option/baseoption.py:579
|
||||
msgid "malformed requirements for option: {0} require must have option, expected and action keys"
|
||||
msgstr ""
|
||||
|
||||
@ -374,7 +378,7 @@ msgstr ""
|
||||
|
||||
#: tiramisu/option/broadcastoption.py:38 tiramisu/option/dateoption.py:37
|
||||
#: tiramisu/option/domainnameoption.py:113 tiramisu/option/ipoption.py:77
|
||||
#: tiramisu/option/netmaskoption.py:40 tiramisu/option/networkoption.py:67
|
||||
#: tiramisu/option/netmaskoption.py:41 tiramisu/option/networkoption.py:67
|
||||
#: tiramisu/option/passwordoption.py:38 tiramisu/option/portoption.py:106
|
||||
#: tiramisu/option/urloption.py:40
|
||||
msgid "invalid string"
|
||||
@ -576,7 +580,7 @@ msgstr ""
|
||||
msgid "malformed requirements option \"{0}\" must not be in follower for \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:33
|
||||
#: tiramisu/option/netmaskoption.py:34
|
||||
msgid "netmask address"
|
||||
msgstr ""
|
||||
|
||||
@ -584,11 +588,11 @@ msgstr ""
|
||||
msgid "network_netmask needs a network and a netmask"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:67
|
||||
#: tiramisu/option/netmaskoption.py:68
|
||||
msgid "with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:70
|
||||
#: tiramisu/option/netmaskoption.py:71
|
||||
msgid "with network \"{0}\" (\"{1}\")"
|
||||
msgstr ""
|
||||
|
||||
@ -596,19 +600,19 @@ msgstr ""
|
||||
msgid "ip_netmask needs an IP and a netmask"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:91
|
||||
#: tiramisu/option/netmaskoption.py:90
|
||||
msgid "this is a network with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:93
|
||||
msgid "IP \"{0}\" (\"{1}\") is the network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:96
|
||||
#: tiramisu/option/netmaskoption.py:94
|
||||
msgid "this is a broadcast with netmask \"{0}\" (\"{1}\")"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:98
|
||||
#: tiramisu/option/netmaskoption.py:99
|
||||
msgid "IP \"{0}\" (\"{1}\") is the network"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/netmaskoption.py:103
|
||||
msgid "IP \"{0}\" (\"{1}\") is the broadcast"
|
||||
msgstr ""
|
||||
|
||||
@ -737,7 +741,7 @@ msgstr ""
|
||||
msgid "the dynoption \"{0}\" cannot have \"force_store_value\" property"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/option/optiondescription.py:97 tiramisu/setting.py:639
|
||||
#: tiramisu/option/optiondescription.py:97 tiramisu/setting.py:643
|
||||
msgid "a leader ({0}) cannot have \"force_default_on_freeze\" or \"force_metaconfig_on_freeze\" property without \"frozen\""
|
||||
msgstr ""
|
||||
|
||||
@ -865,43 +869,43 @@ msgstr ""
|
||||
msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:562
|
||||
#: tiramisu/setting.py:566
|
||||
msgid "cannot access to option \"{0}\" because required option \"{1}\" has {2} {3}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:586
|
||||
#: tiramisu/setting.py:590
|
||||
msgid "the value of \"{0}\" is {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:588
|
||||
#: tiramisu/setting.py:592
|
||||
msgid "the value of \"{0}\" is not {1}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:629
|
||||
#: tiramisu/setting.py:633
|
||||
msgid "cannot set property {} for option \"{}\" this property is calculated"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:634
|
||||
#: tiramisu/setting.py:638
|
||||
msgid "can't assign property to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:666
|
||||
#: tiramisu/setting.py:670
|
||||
msgid "permissive must be a frozenset"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:670
|
||||
#: tiramisu/setting.py:674
|
||||
msgid "can't assign permissive to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:677
|
||||
#: tiramisu/setting.py:681
|
||||
msgid "cannot add those permissives: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:694
|
||||
#: tiramisu/setting.py:698
|
||||
msgid "can't reset properties to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: tiramisu/setting.py:709
|
||||
#: tiramisu/setting.py:713
|
||||
msgid "can't reset permissives to the symlinkoption \"{}\""
|
||||
msgstr ""
|
||||
|
||||
|
Reference in New Issue
Block a user