Compare commits

...

7 commits

540 changed files with 1677 additions and 523 deletions

13
CHANGELOG.md Normal file
View file

@ -0,0 +1,13 @@
## 1.0.2 (2024-01-28)
### Fix
- 2023 => 2024
- correction for calculated variable with a variable in a dynamic family
## 1.0.1 (2024-01-28)
### Feat
- documentation
- new format 1.0

View file

@ -15,7 +15,7 @@ What is a consistency handling system ?
Tiramisu
|Tiramisu| is a consistency handling system that was initially designed
|Tiramisu| is a consistency handling system that has initially been designed
in the configuration management scope. To put it more simply,
this library is generally used to handle configuration options.
@ -44,16 +44,16 @@ The dictionaries
.. image:: images/schema.png
The main advantage is that declaring variables and writing consistency is a simple
as writing YAML. It is not necessary to write :term:`Tiramisu` code.
The main advantage is that declaring variables and writing consistency is as simple
as writing YAML. With Rougail it is not necessary to write :term:`Tiramisu` code any more.
It simplifies a lot of things.
And rather than writing :term:`Tiramisu` code, we can declare variables and describe the relationships between variables in a declarative mode.
And rather than writing :term:`Tiramisu` code, we can declare variables and describe the relationships between variables in a declarative mode (that is, in a YAML file).
Once the dictionaries are loaded by Rougail, we find all the power of the :term:`Tiramisu` configuration management tool.
The dictionaries YAML format
---------------------------------
The YAML dictionaries format
-----------------------------
Before getting started with Rougail we need to learn the specifics of the YAML dictionaries file format (as well as some templating concepts).
@ -78,14 +78,13 @@ The variables
variable
Here is a second definition of a :term:`variable`: it is a declaration unit that represents a business domain metaphor,
the most common example is that a variable represents a configuration option
the most common example is that a variable that represents a configuration option
in a application, but a variable represents something more that a configuration option.
It provides a business domain specific representation unit.
.. note:: dictionaries can just define a list of variables, but we will see that
.. note:: Dictionaries can just define a list of variables, but we will see that
we can specify a lot more. We can define variables **and** their relations,
and the consistency between them.
**and** the consistency between them.
In the next step, we will explain through a tutorial how to construct a list of variables.
@ -176,7 +175,7 @@ Let's continuing on our "Hello world" theme and add a :term:`family` container.
description: Somebody to say hello
default: rougail
Here, we have a family named `world`.
Here, we have a family named `world`.
This family contains a variable named `name`
Again, let's validate this YAML file against Rougail's API:
@ -188,5 +187,5 @@ Again, let's validate this YAML file against Rougail's API:
We then have the output:
.. code-block:: python
{'rougail.world.name': 'rougail'}

View file

@ -3,7 +3,8 @@
Rougail is a configuration management library that allows you to load variables in a simple and convenient way.
In the following examples, we will use a specific configuration of Rougail. You will find all the options to :doc:`customize the directories structure used <configuration>`.
In the following examples, we will use a specific configuration of Rougail.
You will find all the configuraiton options in :doc:`configuration`.
To load the configuration you must import the `RougailConfig` class and set the `dictionaries_dir` values:
@ -31,16 +32,16 @@ Here is a first :file:`dict/00-base.yml` dictionary:
Then, let's create the :term:`Tiramisu` objects via the following script:
.. code-block:: python
.. code-block:: python
:caption: the `script.py` file content
from rougail import Rougail, RougailConfig
RougailConfig['dictionaries_dir'] = ['dict']
rougail = Rougail()
config = rougail.get_config()
print(config.value.get())
Let's execute `script.py`:
.. code-block:: bash
@ -76,9 +77,9 @@ Then let's create an extra :term:`dictionary` :file:`extras/00-base.yml`:
Then, let's create the :term:`Tiramisu` objects via the following :file:`script.py` script:
.. code-block:: python
:caption: the :file:`script.py` file content
.. code-block:: python
:caption: the :file:`script.py` file content
from rougail import Rougail, RougailConfig
RougailConfig['dictionaries_dir'] = ['dict']
@ -105,21 +106,21 @@ We create the complementary :term:`dictionary` named :file:`dict/01-function.yml
version: '1.0'
my_variable_jinja:
type: "string"
default:
default:
type: jinja
jinja: "{{ return_no() }}"
Then let's define the :func:`return_no` function in :file:`functions.py`:
.. code-block:: python
.. code-block:: python
:caption: the :file:`functions.py` content
def return_no():
return 'no'
Then, let's create the :term:`Tiramisu` objects via the following script:
.. code-block:: python
.. code-block:: python
:caption: the `script.py` file content
from rougail import Rougail, RougailConfig
@ -139,3 +140,54 @@ Let's execute `script.py`:
{'rougail.my_variable': 'my_value', 'rougail.my_variable_jinja': 'no', 'example.my_variable_extra': 'my_value_extra'}
The value of the `my_variable_extra` variable is calculated, and it's value comes from the :func:`return_no` function.
Create your own type
----------------------
A variable has a type. This type enables the variable to define the values that are accepted by this variable.
There is a series of default types, but obviously not all cases are taken.
It's possible to create your own type.
Here an example to a lipogram option (in a string, we cannot use "e" character):
.. code-block:: python
:caption: the `lipogram.py` file content
from tiramisu import StrOption
class LipogramOption(StrOption):
__slots__ = tuple()
_type = 'lipogram'
def validate(self,
value):
super().validate(value)
# verify that there is any 'e' in the sentense
if 'e' in value:
raise ValueError('Perec wrote a book without any "e", you could not do it in a simple sentence?')
To add the new lipogram type in Rougail:
.. code-block:: python
>>> from rougail import Rougail, RougailConfig
>>> RougailConfig['dictionaries_dir'] = ['dict']
>>> RougailConfig['custom_types']['lipogram'] = LipogramOption
Now, we can use lipogram type.
Here is a :file:`dict/00-base.yml` dictionary:
.. code-block:: yaml
---
version: '1.0'
var:
type: lipogram
.. code-block:: python
>>> rougail = Rougail()
>>> config = rougail.get_config()
>>> config.option('rougail.var').value.set('blah')
>>> config.option('rougail.var').value.set('I just want to add a quality string that has no bad characters')
[...]
tiramisu.error.ValueOptionError: "I just want to add a quality string that has no bad characters" is an invalid lipogram for "var", Perec wrote a book without any "e", you could not do it in a simple sentence?

View file

@ -271,9 +271,12 @@ Let's look at what happens if we try to access the `rougail.proxy.manual` variab
We have an error (with the message defined in the Jinja template):
.. code-block:: python
.. code-block:: shell
tiramisu.error.PropertiesOptionError: cannot access to
optiondescription "Manual proxy configuration" because
has property "disabled" (the mode proxy is not manual)
tiramisu.error.PropertiesOptionError: cannot access to optiondescription "Manual proxy configuration" because has property "disabled" (the mode proxy is not manual)
Let's configure the proxy in manual mode
@ -291,7 +294,7 @@ We can see that the returned variables does have the desired values:
'rougail.proxy.manual.http_proxy.port': '8080',
'rougail.proxy.manual.use_for_https': True}
Let's set the `read_only` mode:
Let's set the `read_only` mode and have a look at the configuration again:
.. code-block:: python
@ -307,7 +310,7 @@ Let's set the `read_only` mode:
In the `read_only` mode, we can see that the HTTPS configuration appears.
.. note:: We can see that `rougail.proxy.manual.http_proxy` values have been copied
in `rougail.proxy.manual.ssl_proxy` too...
in `rougail.proxy.manual.ssl_proxy` too.
Changing values programmatically
--------------------------------------

40
pyproject.toml Normal file
View file

@ -0,0 +1,40 @@
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.8.0,<4"]
[project]
name = "rougail"
version = "1.0.2"
authors = [
{name = "Emmanuel Garette", email = "gnunux@gnunux.info"},
]
description = "A consistency handling system that was initially designed in the configuration management"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Natural Language :: English",
"Natural Language :: French",
]
dependencies = [
"pyyaml ~= 6.0.1",
"pydantic ~= 2.5.2",
"jinja2 ~= 3.1.2",
]
[project.optional-dependancies]
dev = [
"pylint ~= 3.0.3",
]
[tool.commitizen]
name = "cz_conventional_commits"
tag_format = "$version"
version_scheme = "semver"
version_provider = "pep621"
update_changelog_on_bump = true

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -28,10 +28,12 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from tiramisu import Config
from copy import copy
from .convert import RougailConvert
from .config import RougailConfig
from .update import RougailUpgrade
from .object_model import CONVERT_OPTION
def tiramisu_display_name(kls) -> str:
@ -46,7 +48,7 @@ class Rougail:
def __init__(
self,
rougailconfig = None,
rougailconfig=None,
) -> None:
if rougailconfig is None:
rougailconfig = RougailConfig
@ -66,7 +68,8 @@ class Rougail:
if not self.config:
tiram_obj = self.converted.save(self.rougailconfig["tiramisu_cache"])
optiondescription = {}
exec(tiram_obj, None, optiondescription) # pylint: disable=W0122
custom_types = {custom.__name__: custom for custom in self.rougailconfig["custom_types"].values()}
exec(tiram_obj, custom_types, optiondescription) # pylint: disable=W0122
self.config = Config(
optiondescription["option_0"],
display_name=tiramisu_display_name,
@ -75,4 +78,4 @@ class Rougail:
return self.config
__ALL__ = ("Rougail", "RougailConvert", "RougailConfig", "RougailUpgrade")
__ALL__ = ("Rougail", "RougailConfig", "RougailUpgrade")

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -27,27 +27,12 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from .variable import CONVERT_OPTION
import importlib.resources
from os.path import isfile
from ..utils import load_modules
ANNOTATORS = None
#
#
# if not 'files' in dir(importlib.resources):
# # old python version
# class fake_files:
# def __init__(self, package):
# self.mod = []
# dir_package = dirname(importlib.resources._get_package(package).__file__)
# for mod in importlib.resources.contents(package):
# self.mod.append(join(dir_package, mod))
#
# def iterdir(self):
# return self.mod
# importlib.resources.files = fake_files
def get_level(module):
@ -101,4 +86,4 @@ class SpaceAnnotator: # pylint: disable=R0903
annotator(objectspace)
__all__ = ("SpaceAnnotator", "CONVERT_OPTION")
__all__ = ("SpaceAnnotator",)

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -33,58 +33,6 @@ from rougail.error import DictConsistencyError
from rougail.object_model import Calculation
def convert_boolean(value: str) -> bool:
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`"""
if isinstance(value, bool):
return value
value = value.lower()
if value == "true":
return True
elif value == "false":
return False
raise Exception(f"unknown boolean value {value}")
CONVERT_OPTION = {
"string": dict(opttype="StrOption"),
"number": dict(opttype="IntOption", func=int),
"float": dict(opttype="FloatOption", func=float),
"boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption"),
"mail": dict(opttype="EmailOption"),
"unix_filename": dict(opttype="FilenameOption"),
"date": dict(opttype="DateOption"),
"unix_user": dict(opttype="UsernameOption"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}),
"netmask": dict(opttype="NetmaskOption"),
"network": dict(opttype="NetworkOption"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}),
"broadcast": dict(opttype="BroadcastOption"),
"netbios": dict(
opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True},
),
"domainname": dict(
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False}
),
"hostname": dict(
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False}
),
"web_address": dict(
opttype="URLOption", initkwargs={"allow_ip": False, "allow_without_dot": True}
),
"port": dict(opttype="PortOption", initkwargs={"allow_private": True}),
"mac": dict(opttype="MACOption"),
"unix_permissions": dict(
opttype="PermissionsOption", initkwargs={"warnings_only": True}, func=int
),
"choice": dict(opttype="ChoiceOption"),
#
"symlink": dict(opttype="SymLinkOption"),
}
class Walk:
"""Walk to objectspace to find variable or family"""

View file

@ -10,7 +10,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -77,4 +77,5 @@ RougailConfig = {
"force_convert_dyn_option_description": False,
"suffix": "",
"tiramisu_cache": None,
"custom_types": {},
}

View file

@ -1,4 +1,4 @@
"""Takes a bunch of Rougail XML dispatched in differents folders
"""Takes a bunch of Rougail YAML dispatched in differents folders
as an input and outputs a Tiramisu's file.
Created by:
@ -10,7 +10,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -27,26 +27,22 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sample usage::
>>> from rougail import RougailConvert
>>> rougail = RougailConvert()
>>> tiramisu = rougail.save('tiramisu.py')
The Rougail
- loads the XML into an internal RougailObjSpace representation
- visits/annotates the objects
- dumps the object space as Tiramisu string
The visit/annotation stage is a complex step that corresponds to the Rougail
procedures.
"""
import logging
from pathlib import Path
from typing import Optional, Union, get_type_hints, Any, Literal, List, Dict, Iterator, Tuple
from typing import (
Optional,
Union,
get_type_hints,
Any,
Literal,
List,
Dict,
Iterator,
Tuple,
)
from itertools import chain
from re import findall
from yaml import safe_load
from pydantic import ValidationError
@ -56,13 +52,15 @@ from .annotator import SpaceAnnotator
from .tiramisureflector import TiramisuReflector
from .utils import get_realpath
from .object_model import (
CONVERT_OPTION,
Family,
Dynamic,
Variable,
_Variable,
Choice,
SymLink,
CALCULATION_TYPES,
Calculation,
VariableCalculation,
PARAM_TYPES,
AnyParam,
)
@ -100,7 +98,7 @@ class Property:
class Paths:
def __init__(self) -> None:
self._data: Dict[str, Union[Variable, Family]] = {}
self._data: Dict[str, Union[_Variable, Family]] = {}
self._dynamics: List[str] = []
self.path_prefix = None
@ -124,9 +122,28 @@ class Paths:
) -> Any:
suffix = None
dynamic_path = None
dynamic_variable_path = None
if not path in self._data:
for dynamic in self._dynamics:
if path.startswith(dynamic):
if "{{ suffix }}" in dynamic:
regexp = "^" + dynamic.replace('{{ suffix }}', '(.*)') + '.'
finded = findall(regexp, path)
if len(finded) != 1:
continue
splitted_dynamic = dynamic.split('.')
splitted_path = path.split('.')
for idx, s in enumerate(splitted_dynamic):
if '{{ suffix }}' in s:
break
suffix_path = '.'.join(splitted_path[idx + 1:])
if suffix_path:
suffix_path = "." + suffix_path
suffix = splitted_path[idx] + suffix_path
dynamic_path = dynamic
dynamic_variable_path = dynamic + suffix_path
break
elif path.startswith(dynamic):
subpaths = path[len(dynamic) :].split(".", 1)
if (
subpaths[0]
@ -136,20 +153,21 @@ class Paths:
suffix = (
dynamic.rsplit(".", 1)[-1] + subpaths[0] + "." + subpaths[1]
)
dynamic_path = dynamic + "." + subpaths[1]
dynamic_path = dynamic
dynamic_variable_path = dynamic + "." + subpaths[1]
break
if suffix:
break
if suffix is None and not path in self._data:
return None, None
if suffix and dynamic_path:
path = dynamic_path
return self._data[path], suffix
return None, None, None
dynamic = None
if suffix and dynamic_variable_path:
path = dynamic_variable_path
dynamic = self._data[dynamic_path]
return self._data[path], suffix, dynamic
def __getitem__(
self,
path: str,
) -> Union[Family, Variable]:
) -> Union[Family, _Variable]:
if not path in self._data:
raise AttributeError(f"cannot find variable or family {path}")
return self._data[path]
@ -217,7 +235,6 @@ class ParserVariable:
#
self.family = Family
self.dynamic = Dynamic
self.variable = Variable
self.choice = Choice
#
self.exclude_imports = []
@ -229,13 +246,23 @@ class ParserVariable:
self.is_init = False
super().__init__()
def get_variable(self):
convert_options = list(CONVERT_OPTION)
convert_options.extend(self.rougailconfig["custom_types"])
class Variable(_Variable):
type: Literal[*convert_options] = convert_options[0]
return Variable
def init(self):
if self.is_init:
return
self.variable = self.get_variable()
hint = get_type_hints(self.dynamic)
self.family_types = hint["type"].__args__ # pylint: disable=W0201
self.family_attrs = frozenset( # pylint: disable=W0201
set(hint) | {"redefine"} - {"name", "path", "xmlfiles"}
set(hint) - {"name", "path", "xmlfiles"} | {"redefine"}
)
self.family_calculations = self.search_calculation( # pylint: disable=W0201
hint
@ -246,7 +273,7 @@ class ParserVariable:
#
hint = get_type_hints(self.choice)
self.choice_attrs = frozenset( # pylint: disable=W0201
set(hint) | {"redefine", "exists"} - {"name", "path", "xmlfiles"}
set(hint) - {"name", "path", "xmlfiles"} | {"redefine", "exists"}
)
self.choice_calculations = self.search_calculation( # pylint: disable=W0201
hint
@ -290,7 +317,7 @@ class ParserVariable:
if isinstance(value, dict) and not self.is_calculation(
key,
value,
"variable",
self.choice_calculations,
False,
):
break
@ -356,8 +383,7 @@ class ParserVariable:
family_is_leadership: bool = False,
family_is_dynamic: bool = False,
) -> None:
""" Parse a family
"""
"""Parse a family"""
if obj is None:
return
family_obj = {}
@ -371,10 +397,11 @@ class ParserVariable:
else:
subfamily_obj[key] = value
if path in self.paths:
# it's just for modify subfamily or subvariable, do not redefine
if family_obj:
if not obj.pop("redefine", False):
raise Exception(
"The family {path} already exists and she is not redefined"
f"The family {path} already exists and she is not redefined in {filemane}"
)
self.paths.add(
path,
@ -429,8 +456,7 @@ class ParserVariable:
self,
obj: Dict[str, Any],
) -> Iterator[str]:
""" List attributes
"""
"""List attributes"""
force_to_variable = []
for key, value in obj.items():
if key in force_to_variable:
@ -446,7 +472,7 @@ class ParserVariable:
if isinstance(value, dict) and not self.is_calculation(
key,
value,
"family",
self.family_calculations,
False,
):
# it's a dict, so a new variables!
@ -462,8 +488,7 @@ class ParserVariable:
filenames: Union[str, List[str]],
family_is_dynamic: bool,
) -> None:
""" Add a new family
"""
"""Add a new family"""
family["path"] = path
if not isinstance(filenames, list):
filenames = [filenames]
@ -483,7 +508,7 @@ class ParserVariable:
if not self.is_calculation(
key,
value,
"family",
self.family_calculations,
False,
):
continue
@ -528,8 +553,7 @@ class ParserVariable:
family_is_leadership: bool = False,
family_is_dynamic: bool = False,
) -> None:
""" Parse variable
"""
"""Parse variable"""
if obj is None:
obj = {}
extra_attrs = set(obj) - self.choice_attrs
@ -545,7 +569,9 @@ class ParserVariable:
return
if not obj.pop("redefine", False):
raise Exception(f'Variable "{path}" already exists')
self.paths.add(path, self.paths[path].model_copy(update=obj), False, force=True)
self.paths.add(
path, self.paths[path].model_copy(update=obj), False, force=True
)
self.paths[path].xmlfiles.append(filename)
else:
if "exists" in obj and obj.pop("exists"):
@ -576,7 +602,7 @@ class ParserVariable:
if self.is_calculation(
key,
value,
"variable",
self.choice_calculations,
False,
):
try:
@ -597,7 +623,7 @@ class ParserVariable:
if not self.is_calculation(
key,
val,
"variable",
self.choice_calculations,
True,
):
continue
@ -617,8 +643,7 @@ class ParserVariable:
) from err
def parse_params(self, path, obj):
""" Parse variable params
"""
"""Parse variable params"""
if "params" not in obj:
return
if not isinstance(obj["params"], dict):
@ -628,7 +653,9 @@ class ParserVariable:
try:
params.append(AnyParam(key=key, value=val, type="any"))
except ValidationError as err:
raise Exception(f'"{key}" has an invalid "params" for {path}: {err}') from err
raise Exception(
f'"{key}" has an invalid "params" for {path}: {err}'
) from err
obj["params"] = params
def add_variable(
@ -681,7 +708,7 @@ class ParserVariable:
###############################################################################################
def set_name(
self,
obj: Union[Variable, Family],
obj: Union[_Variable, Family],
option_prefix: str,
):
"""Set Tiramisu object name"""
@ -697,14 +724,10 @@ class ParserVariable:
self,
attribute: str,
value: dict,
typ: Literal["variable", "family"],
calculations: list,
inside_list: bool,
):
"""Check if it's a calculation"""
if typ == "variable":
calculations = self.choice_calculations
else:
calculations = self.family_calculations
if inside_list:
calculations = calculations[0]
else:
@ -786,7 +809,9 @@ class RougailConvert(ParserVariable):
inside_list = []
outside_list = []
for key, value in hint.items():
if "Union" in value.__class__.__name__ and Calculation in value.__args__:
if "Union" in value.__class__.__name__ and (
Calculation in value.__args__ or VariableCalculation in value.__args__
):
outside_list.append(key)
if (
"Union" in value.__class__.__name__
@ -914,7 +939,9 @@ class RougailConvert(ParserVariable):
f"pffff version ... {version} not in {self.supported_version}"
)
def annotate(self):
def annotate(
self,
):
"""Apply annotation"""
if not self.paths.has_value():
self.parse_directories()
@ -940,7 +967,7 @@ class RougailConvert(ParserVariable):
def save(
self,
filename: None,
filename: str,
):
"""Return tiramisu object declaration as a string"""
self.annotate()
@ -949,5 +976,5 @@ class RougailConvert(ParserVariable):
if filename:
with open(filename, "w", encoding="utf-8") as tiramisu:
tiramisu.write(output)
# print(output)
# print(output)
return output

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -8,7 +8,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -1,7 +1,7 @@
"""Rougail object model
Silique (https://www.silique.fr)
Copyright (C) 2023
Copyright (C) 2023-2024
distribued with GPL-2 or later license
@ -21,16 +21,77 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
from typing import Optional, Union, get_type_hints, Any, Literal, List, Dict, Iterator
from pydantic import BaseModel, StrictBool, StrictInt, StrictFloat, StrictStr
from pydantic import (
BaseModel,
StrictBool,
StrictInt,
StrictFloat,
StrictStr,
ConfigDict,
)
from .utils import get_jinja_variable_to_param, get_realpath
BASETYPE = Union[StrictBool, StrictInt, StrictFloat, StrictStr, None]
def convert_boolean(value: str) -> bool:
"""Boolean coercion. The Rougail XML may contain srings like `True` or `False`"""
if isinstance(value, bool):
return value
value = value.lower()
if value == "true":
return True
elif value == "false":
return False
raise Exception(f"unknown boolean value {value}")
CONVERT_OPTION = {
"string": dict(opttype="StrOption"),
"number": dict(opttype="IntOption", func=int),
"float": dict(opttype="FloatOption", func=float),
"boolean": dict(opttype="BoolOption", func=convert_boolean),
"secret": dict(opttype="PasswordOption"),
"mail": dict(opttype="EmailOption"),
"unix_filename": dict(opttype="FilenameOption"),
"date": dict(opttype="DateOption"),
"unix_user": dict(opttype="UsernameOption"),
"ip": dict(opttype="IPOption", initkwargs={"allow_reserved": True}),
"cidr": dict(opttype="IPOption", initkwargs={"cidr": True}),
"netmask": dict(opttype="NetmaskOption"),
"network": dict(opttype="NetworkOption"),
"network_cidr": dict(opttype="NetworkOption", initkwargs={"cidr": True}),
"broadcast": dict(opttype="BroadcastOption"),
"netbios": dict(
opttype="DomainnameOption",
initkwargs={"type": "netbios", "warnings_only": True},
),
"domainname": dict(
opttype="DomainnameOption", initkwargs={"type": "domainname", "allow_ip": False}
),
"hostname": dict(
opttype="DomainnameOption", initkwargs={"type": "hostname", "allow_ip": False}
),
"web_address": dict(
opttype="URLOption", initkwargs={"allow_ip": False, "allow_without_dot": True}
),
"port": dict(opttype="PortOption", initkwargs={"allow_private": True}),
"mac": dict(opttype="MACOption"),
"unix_permissions": dict(
opttype="PermissionsOption", initkwargs={"warnings_only": True}, func=int
),
"choice": dict(opttype="ChoiceOption"),
#
"symlink": dict(opttype="SymLinkOption"),
}
class Param(BaseModel):
key: str
model_config = ConfigDict(extra="forbid")
class AnyParam(Param):
type: str
@ -70,6 +131,9 @@ PARAM_TYPES = {
class Calculation(BaseModel):
path_prefix: Optional[str]
path: str
inside_list: bool
model_config = ConfigDict(extra="forbid")
def get_realpath(
self,
@ -85,7 +149,7 @@ class Calculation(BaseModel):
param = param_obj.model_dump()
if param.get("type") == "variable":
variable_path = self.get_realpath(param["variable"])
variable, suffix = objectspace.paths.get_with_dynamic(variable_path)
variable, suffix, dynamic = objectspace.paths.get_with_dynamic(variable_path)
if not variable:
if not param.get("optional"):
raise Exception(f"cannot find {variable_path}")
@ -95,6 +159,7 @@ class Calculation(BaseModel):
param["variable"] = variable
if suffix:
param["suffix"] = suffix
param["dynamic"] = dynamic
if param.get("type") == "information":
if param["variable"]:
variable_path = self.get_realpath(param["variable"])
@ -114,7 +179,6 @@ class JinjaCalculation(Calculation):
jinja: StrictStr
params: Optional[List[Param]] = None
return_type: BASETYPE = None
inside_list: bool
def _jinja_to_function(
self,
@ -147,20 +211,21 @@ class JinjaCalculation(Calculation):
default["params"] |= self.get_params(objectspace)
if params:
default["params"] |= params
for sub_variable, suffix, true_path in get_jinja_variable_to_param(
for sub_variable, suffix, true_path, dynamic in get_jinja_variable_to_param(
self.jinja,
objectspace,
variable.xmlfiles,
objectspace.functions,
self.path_prefix,
):
if isinstance(sub_variable, objectspace.variable):
if sub_variable.path in objectspace.variables:
default["params"][true_path] = {
"type": "variable",
"variable": sub_variable,
}
if suffix:
default["params"][true_path]["suffix"] = suffix
default["params"][true_path]["dynamic"] = dynamic
return default
def to_function(
@ -223,14 +288,13 @@ class VariableCalculation(Calculation):
]
variable: StrictStr
propertyerror: bool = True
inside_list: bool
def to_function(
self,
objectspace,
) -> dict:
variable_path = self.get_realpath(self.variable)
variable, suffix = objectspace.paths.get_with_dynamic(variable_path)
variable, suffix, dynamic = objectspace.paths.get_with_dynamic(variable_path)
if not variable:
raise Exception(f"pffff {variable_path}")
if not isinstance(variable, objectspace.variable):
@ -242,6 +306,7 @@ class VariableCalculation(Calculation):
}
if suffix:
param["suffix"] = suffix
param["dynamic"] = dynamic
params = {None: [param]}
function = "calc_value"
help_function = None
@ -251,10 +316,6 @@ class VariableCalculation(Calculation):
if variable.type != "boolean":
raise Exception("only boolean!")
params[None].insert(0, self.attribute_name)
elif (
self.attribute_name != "default" and variable.path not in objectspace.multis
):
raise Exception("pffff")
if not self.inside_list and self.path in objectspace.multis:
if (
not objectspace.paths.is_dynamic(variable_path)
@ -277,7 +338,6 @@ class InformationCalculation(Calculation):
attribute_name: Literal["default"]
information: StrictStr
variable: Optional[StrictStr]
inside_list: bool
def to_function(
self,
@ -346,43 +406,15 @@ class Family(BaseModel):
xmlfiles: List[str] = []
path: str
class ConfigDict:
arbitrary_types_allowed = True
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class Dynamic(Family):
variable: str
class Variable(BaseModel):
class _Variable(BaseModel):
name: str
type: Literal[
"number",
"float",
"string",
"password",
"secret",
"mail",
"boolean",
"unix_filename",
"date",
"unix_user",
"ip",
"local_ip",
"netmask",
"network",
"broadcast",
"netbios",
"domainname",
"hostname",
"web_address",
"port",
"mac",
"cidr",
"network_cidr",
"choice",
"unix_permissions",
] = "string"
description: Optional[str] = None
default: Union[List[BASETYPE_CALC], BASETYPE_CALC] = None
params: Optional[List[Param]] = None
@ -399,17 +431,19 @@ class Variable(BaseModel):
xmlfiles: List[str] = []
path: str
class ConfigDict:
arbitrary_types_allowed = True
model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)
class Choice(Variable):
class Choice(_Variable):
type: Literal["choice"] = "choice"
choices: Union[List[BASETYPE_CALC], Calculation]
class SymLink(BaseModel):
name: str
type: str = "symlink"
opt: Variable
type: Literal["symlink"] = "symlink"
opt: _Variable
xmlfiles: List[str] = []
path: str
model_config = ConfigDict(extra="forbid")

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license

View file

@ -10,7 +10,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -33,10 +33,9 @@ from json import dumps
from os.path import isfile, basename
from .i18n import _
from .annotator import CONVERT_OPTION
from .error import DictConsistencyError
from .utils import normalize_family
from .object_model import Calculation
from .object_model import Calculation, CONVERT_OPTION
class BaseElt: # pylint: disable=R0903
@ -122,7 +121,7 @@ class TiramisuReflector:
[
"from jinja2 import StrictUndefined, DictLoader",
"from jinja2.sandbox import SandboxedEnvironment",
"from rougail.annotator.variable import CONVERT_OPTION",
"from rougail import CONVERT_OPTION",
"from tiramisu.error import ValueWarning",
"def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):",
" global ENV, CONVERT_OPTION",
@ -393,6 +392,7 @@ class Common:
param["variable"],
param.get("propertyerror", True),
param.get("suffix"),
param.get("dynamic"),
)
if param["type"] == "any":
if isinstance(param["value"], str):
@ -407,6 +407,7 @@ class Common:
param,
propertyerror,
suffix: Optional[str],
dynamic,
) -> str:
"""build variable parameters"""
if param.path == self.elt.path:
@ -417,7 +418,7 @@ class Common:
params = [f"{option_name}"]
if suffix is not None:
param_type = "ParamDynOption"
family = self.tiramisu.reflector_objects[param.path.rsplit(".", 1)[0]].get(
family = self.tiramisu.reflector_objects[dynamic.path].get(
self.calls, self.elt.path
)
params.extend([f"'{suffix}'", f"{family}"])
@ -469,7 +470,10 @@ class Variable(Common):
tiramisu,
):
super().__init__(elt, tiramisu)
self.object_type = CONVERT_OPTION[elt.type]["opttype"]
if elt.type in self.tiramisu.objectspace.rougailconfig['custom_types']:
self.object_type = self.tiramisu.objectspace.rougailconfig['custom_types'][elt.type].__name__
else:
self.object_type = CONVERT_OPTION[elt.type]["opttype"]
def _populate_attrib(
self,
@ -528,7 +532,7 @@ class Variable(Common):
else:
validators.append(val)
keys["validators"] = "[" + ", ".join(validators) + "]"
for key, value in CONVERT_OPTION[self.elt.type].get("initkwargs", {}).items():
for key, value in CONVERT_OPTION.get(self.elt.type, {}).get("initkwargs", {}).items():
if isinstance(value, str):
value = f"'{value}'"
keys[key] = value

View file

@ -4,7 +4,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -42,7 +42,7 @@ from .error import UpgradeError
from .utils import normalize_family
from .config import RougailConfig
from .annotator.variable import CONVERT_OPTION
from .object_model import CONVERT_OPTION
VERSIONS = ["0.10", "1.0"]

View file

@ -9,7 +9,7 @@ Cadoles (http://www.cadoles.com)
Copyright (C) 2019-2021
Silique (https://www.silique.fr)
Copyright (C) 2022-2023
Copyright (C) 2022-2024
distribued with GPL-2 or later license
@ -112,8 +112,8 @@ def get_jinja_variable_to_param(
variables = list(variables)
variables.sort()
for variable_path in variables:
variable, suffix = objectspace.paths.get_with_dynamic(
variable, suffix, dynamic = objectspace.paths.get_with_dynamic(
get_realpath(variable_path, path_prefix)
)
if variable and variable.path in objectspace.variables:
yield variable, suffix, variable_path
yield variable, suffix, variable_path, dynamic

7
tests/custom.py Normal file
View file

@ -0,0 +1,7 @@
from os import environ
environ['TIRAMISU_LOCALE'] = 'en'
from tiramisu import StrOption
class CustomOption(StrOption):
pass

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
["rougail.empty"]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,4 @@
---
version: '1.0'
custom:
type: custom

View file

@ -0,0 +1,6 @@
{
"rougail.custom": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1,3 @@
{
"rougail.custom": null
}

View file

@ -0,0 +1,6 @@
{
"rougail.custom": {
"owner": "default",
"value": null
}
}

View file

@ -0,0 +1,24 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
global func
func = {'calc_value': calc_value}
def _load_functions(path):
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
loader = _SourceFileLoader('func', path)
spec = _spec_from_loader(loader.name, loader)
func_ = _module_from_spec(spec)
loader.exec_module(func_)
for function in dir(func_):
if function.startswith('_'):
continue
func[function] = getattr(func_, function)
_load_functions('tests/dictionaries/../eosfunc/test.py')
option_2 = CustomOption(name="custom", doc="custom", properties=frozenset({"basic", "mandatory"}))
optiondescription_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1])

View file

@ -0,0 +1,28 @@
from tiramisu import *
from tiramisu.setting import ALLOWED_LEADER_PROPERTIES
ALLOWED_LEADER_PROPERTIES.add("basic")
ALLOWED_LEADER_PROPERTIES.add("standard")
ALLOWED_LEADER_PROPERTIES.add("advanced")
from importlib.machinery import SourceFileLoader as _SourceFileLoader
from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
global func
func = {'calc_value': calc_value}
def _load_functions(path):
global _SourceFileLoader, _spec_from_loader, _module_from_spec, func
loader = _SourceFileLoader('func', path)
spec = _spec_from_loader(loader.name, loader)
func_ = _module_from_spec(spec)
loader.exec_module(func_)
for function in dir(func_):
if function.startswith('_'):
continue
func[function] = getattr(func_, function)
_load_functions('tests/dictionaries/../eosfunc/test.py')
option_3 = CustomOption(name="custom", doc="custom", properties=frozenset({"basic", "mandatory"}))
optiondescription_2 = OptionDescription(name="rougail", doc="rougail", children=[option_3], properties=frozenset({"basic"}))
optiondescription_1 = OptionDescription(name="1", doc="1", children=[optiondescription_2], properties=frozenset({"basic"}))
option_6 = CustomOption(name="custom", doc="custom", properties=frozenset({"basic", "mandatory"}))
optiondescription_5 = OptionDescription(name="rougail", doc="rougail", children=[option_6], properties=frozenset({"basic"}))
optiondescription_4 = OptionDescription(name="2", doc="2", children=[optiondescription_5], properties=frozenset({"basic"}))
option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[optiondescription_1, optiondescription_4])

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
["rougail.general.adresse_ip_eth0", "rougail.general.adresse_netmask_eth0", "rougail.general.adresse_ip"]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
["rougail.general.adresse_ip_eth0", "rougail.general.adresse_ip"]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
["rougail.general.adresse_ip_eth0", "rougail.general.adresse_netmask_eth0"]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -21,7 +21,7 @@ def _load_functions(path):
_load_functions('tests/dictionaries/../eosfunc/test.py')
from jinja2 import StrictUndefined, DictLoader
from jinja2.sandbox import SandboxedEnvironment
from rougail.annotator.variable import CONVERT_OPTION
from rougail import CONVERT_OPTION
from tiramisu.error import ValueWarning
def jinja_to_function(__internal_jinja, __internal_type, __internal_multi, **kwargs):
global ENV, CONVERT_OPTION

View file

@ -0,0 +1 @@
[]

Some files were not shown because too many files have changed in this diff Show more