2021-01-17 18:39:15 +01:00
|
|
|
"""Manage path to find objects
|
2021-01-30 08:15:26 +01:00
|
|
|
|
|
|
|
Created by:
|
|
|
|
EOLE (http://eole.orion.education.fr)
|
|
|
|
Copyright (C) 2005-2018
|
|
|
|
|
|
|
|
Forked by:
|
|
|
|
Cadoles (http://www.cadoles.com)
|
|
|
|
Copyright (C) 2019-2021
|
|
|
|
|
|
|
|
distribued with GPL-2 or later license
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
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
|
2021-01-17 18:39:15 +01:00
|
|
|
"""
|
2020-07-06 19:47:45 +02:00
|
|
|
from .i18n import _
|
2021-01-12 13:36:27 +01:00
|
|
|
from .error import DictConsistencyError
|
2020-08-12 08:23:38 +02:00
|
|
|
from .config import Config
|
2021-01-17 17:15:58 +01:00
|
|
|
from .utils import normalize_family
|
2020-07-06 19:47:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Path:
|
|
|
|
"""Helper class to handle the `path` attribute of a CreoleObjSpace
|
|
|
|
instance.
|
|
|
|
|
|
|
|
sample: path="creole.general.condition"
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
self.variables = {}
|
|
|
|
self.families = {}
|
2020-11-11 16:59:44 +01:00
|
|
|
self.full_paths_families = {}
|
|
|
|
self.full_paths_variables = {}
|
2020-07-06 19:47:45 +02:00
|
|
|
|
|
|
|
# Family
|
|
|
|
def add_family(self,
|
|
|
|
namespace: str,
|
|
|
|
name: str,
|
2020-07-06 20:58:11 +02:00
|
|
|
variableobj: str,
|
2020-07-06 19:47:45 +02:00
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Add a new family
|
|
|
|
"""
|
2021-01-11 22:34:16 +01:00
|
|
|
if namespace == Config['variable_namespace']:
|
2020-07-24 14:59:09 +02:00
|
|
|
full_name = '.'.join([namespace, name])
|
2020-11-11 16:59:44 +01:00
|
|
|
self.full_paths_families[name] = full_name
|
2020-07-24 14:59:09 +02:00
|
|
|
else:
|
2021-01-17 18:39:15 +01:00
|
|
|
if '.' not in name: # pragma: no cover
|
|
|
|
msg = _(f'Variable "{name}" in namespace "{namespace}" must have dot')
|
|
|
|
raise DictConsistencyError(msg, 39)
|
2020-07-24 14:59:09 +02:00
|
|
|
full_name = name
|
2021-01-11 22:34:16 +01:00
|
|
|
if full_name in self.families and \
|
|
|
|
self.families[full_name]['variableobj'] != variableobj: # pragma: no cover
|
2020-12-26 15:15:51 +01:00
|
|
|
raise DictConsistencyError(_(f'Duplicate family name "{name}"'), 37)
|
2020-07-24 14:59:09 +02:00
|
|
|
self.families[full_name] = dict(name=name,
|
|
|
|
namespace=namespace,
|
|
|
|
variableobj=variableobj,
|
|
|
|
)
|
2021-01-11 22:34:16 +01:00
|
|
|
variableobj.path = full_name
|
|
|
|
|
|
|
|
def add_leadership(self,
|
|
|
|
namespace: str,
|
|
|
|
path: str,
|
|
|
|
variableobj: str,
|
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""add a new leadership
|
|
|
|
"""
|
2021-01-11 22:34:16 +01:00
|
|
|
self.families[path] = dict(name=path,
|
|
|
|
namespace=namespace,
|
|
|
|
variableobj=variableobj,
|
|
|
|
)
|
|
|
|
variableobj.path = path
|
2020-07-06 19:47:45 +02:00
|
|
|
|
2021-01-11 22:34:16 +01:00
|
|
|
def get_family(self,
|
|
|
|
name: str,
|
2021-01-17 17:15:58 +01:00
|
|
|
current_namespace: str,
|
2021-01-11 22:34:16 +01:00
|
|
|
) -> 'Family': # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Get a family
|
|
|
|
"""
|
2021-01-17 17:15:58 +01:00
|
|
|
name = '.'.join([normalize_family(subname) for subname in name.split('.')])
|
|
|
|
if name not in self.families and name in self.full_paths_families:
|
|
|
|
name = self.full_paths_families[name]
|
|
|
|
if name not in self.families:
|
|
|
|
raise DictConsistencyError(_('unknown option {}').format(name), 42)
|
|
|
|
dico = self.families[name]
|
2021-01-17 18:39:15 +01:00
|
|
|
if current_namespace not in [Config['variable_namespace'], 'services'] and \
|
|
|
|
current_namespace != dico['namespace']:
|
|
|
|
msg = _(f'A family located in the "{dico["namespace"]}" namespace '
|
|
|
|
f'shall not be used in the "{current_namespace}" namespace')
|
|
|
|
raise DictConsistencyError(msg, 38)
|
2021-01-17 17:15:58 +01:00
|
|
|
return dico['variableobj']
|
2020-07-31 09:41:30 +02:00
|
|
|
|
2020-07-06 19:47:45 +02:00
|
|
|
# Leadership
|
|
|
|
def set_leader(self,
|
|
|
|
namespace: str,
|
|
|
|
leader_family_name: str,
|
2021-01-16 08:50:11 +01:00
|
|
|
leadership_name: str,
|
2020-07-06 19:47:45 +02:00
|
|
|
name: str,
|
|
|
|
) -> None: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""set a variable a leadership member
|
|
|
|
"""
|
2020-07-24 14:59:09 +02:00
|
|
|
# need rebuild path and move object in new path
|
2021-01-16 08:50:11 +01:00
|
|
|
old_path = leader_family_name + '.' + name
|
|
|
|
leadership_path = leader_family_name + '.' + leadership_name
|
|
|
|
new_path = leadership_path + '.' + name
|
2020-12-26 15:15:51 +01:00
|
|
|
self.variables[new_path] = self.variables.pop(old_path)
|
2021-01-16 08:50:11 +01:00
|
|
|
self.variables[new_path]['leader'] = leadership_path
|
2021-01-10 09:07:22 +01:00
|
|
|
self.variables[new_path]['variableobj'].path = new_path
|
2021-01-16 08:50:11 +01:00
|
|
|
self.variables[new_path]['family'] = leadership_path
|
2020-08-12 08:23:38 +02:00
|
|
|
if namespace == Config['variable_namespace']:
|
2020-11-11 16:59:44 +01:00
|
|
|
self.full_paths_variables[name] = new_path
|
2020-07-06 19:47:45 +02:00
|
|
|
|
2021-01-16 08:50:11 +01:00
|
|
|
def is_in_leadership(self, name):
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Is the variable is in a leadership
|
|
|
|
"""
|
2021-01-16 08:50:11 +01:00
|
|
|
return self._get_variable(name)['leader'] is not None
|
|
|
|
|
|
|
|
def is_leader(self, path): # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Is the variable is a leader
|
|
|
|
"""
|
2021-01-16 08:50:11 +01:00
|
|
|
variable = self._get_variable(path)
|
|
|
|
if not variable['leader']:
|
|
|
|
return False
|
|
|
|
leadership = self.get_family(variable['leader'], variable['variableobj'].namespace)
|
|
|
|
return leadership.variable[0].path == path
|
2020-07-06 19:47:45 +02:00
|
|
|
|
|
|
|
# Variable
|
2021-01-19 19:28:29 +01:00
|
|
|
def add_variable(self, # pylint: disable=R0913
|
2020-07-06 19:47:45 +02:00
|
|
|
namespace: str,
|
|
|
|
name: str,
|
|
|
|
family: str,
|
|
|
|
is_dynamic: bool,
|
2020-07-06 20:58:11 +02:00
|
|
|
variableobj,
|
2020-07-06 19:47:45 +02:00
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Add a new variable (with path)
|
|
|
|
"""
|
2020-07-24 14:59:09 +02:00
|
|
|
if '.' not in name:
|
2021-01-16 08:50:11 +01:00
|
|
|
full_path = '.'.join([family, name])
|
2021-01-10 09:07:22 +01:00
|
|
|
if namespace == Config['variable_namespace']:
|
|
|
|
self.full_paths_variables[name] = full_path
|
2020-07-06 19:47:45 +02:00
|
|
|
else:
|
2021-01-10 09:07:22 +01:00
|
|
|
full_path = name
|
|
|
|
variableobj.path = full_path
|
|
|
|
self.variables[full_path] = dict(name=name,
|
2020-07-24 14:59:09 +02:00
|
|
|
family=family,
|
|
|
|
leader=None,
|
|
|
|
is_dynamic=is_dynamic,
|
2020-12-26 15:15:51 +01:00
|
|
|
variableobj=variableobj,
|
|
|
|
)
|
2020-07-06 19:47:45 +02:00
|
|
|
|
2021-01-17 18:04:49 +01:00
|
|
|
def get_variable(self,
|
|
|
|
name: str,
|
|
|
|
) -> 'Variable': # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Get variable object from a path
|
|
|
|
"""
|
2021-01-12 13:36:27 +01:00
|
|
|
variable, suffix = self._get_variable(name, with_suffix=True)
|
|
|
|
if suffix:
|
2021-01-16 08:50:11 +01:00
|
|
|
raise DictConsistencyError(_(f"{name} is a dynamic variable"), 36)
|
2021-01-12 13:36:27 +01:00
|
|
|
return variable['variableobj']
|
2020-07-06 19:47:45 +02:00
|
|
|
|
2021-01-16 08:50:11 +01:00
|
|
|
def get_variable_family_path(self,
|
2020-07-06 19:47:45 +02:00
|
|
|
name: str,
|
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""Get the full path of a family
|
|
|
|
"""
|
2020-07-06 19:47:45 +02:00
|
|
|
return self._get_variable(name)['family']
|
|
|
|
|
|
|
|
def get_variable_path(self,
|
|
|
|
name: str,
|
|
|
|
current_namespace: str,
|
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""get full path of a variable
|
|
|
|
"""
|
2021-01-12 13:36:27 +01:00
|
|
|
dico, suffix = self._get_variable(name,
|
|
|
|
with_suffix=True,
|
|
|
|
)
|
|
|
|
namespace = dico['variableobj'].namespace
|
2021-01-17 18:39:15 +01:00
|
|
|
if namespace not in [Config['variable_namespace'], 'services'] and \
|
|
|
|
current_namespace != namespace:
|
|
|
|
msg = _(f'A variable located in the "{namespace}" namespace shall not be used '
|
|
|
|
f'in the "{current_namespace}" namespace')
|
|
|
|
raise DictConsistencyError(msg, 41)
|
2021-01-12 13:36:27 +01:00
|
|
|
return dico['variableobj'].path, suffix
|
2020-07-06 19:47:45 +02:00
|
|
|
|
|
|
|
def path_is_defined(self,
|
2021-01-17 18:39:15 +01:00
|
|
|
path: str,
|
2020-07-06 19:47:45 +02:00
|
|
|
) -> str: # pylint: disable=C0111
|
2021-01-17 18:39:15 +01:00
|
|
|
"""The path is a valid path
|
|
|
|
"""
|
|
|
|
if '.' not in path and path not in self.variables and path in self.full_paths_variables:
|
2020-07-24 14:59:09 +02:00
|
|
|
return True
|
2021-01-17 18:39:15 +01:00
|
|
|
return path in self.variables
|
2020-07-06 19:47:45 +02:00
|
|
|
|
2020-12-24 18:26:15 +01:00
|
|
|
def variable_is_dynamic(self,
|
|
|
|
name: str,
|
|
|
|
) -> bool:
|
2021-01-17 18:39:15 +01:00
|
|
|
"""This variable is in dynamic family
|
|
|
|
"""
|
2020-12-24 18:26:15 +01:00
|
|
|
return self._get_variable(name)['is_dynamic']
|
|
|
|
|
2020-07-06 19:47:45 +02:00
|
|
|
def _get_variable(self,
|
|
|
|
name: str,
|
|
|
|
with_suffix: bool=False,
|
|
|
|
) -> str:
|
2021-01-17 17:15:58 +01:00
|
|
|
name = '.'.join([normalize_family(subname) for subname in name.split('.')])
|
2020-07-06 19:47:45 +02:00
|
|
|
if name not in self.variables:
|
2020-12-26 15:15:51 +01:00
|
|
|
if '.' not in name and name in self.full_paths_variables:
|
|
|
|
name = self.full_paths_variables[name]
|
|
|
|
elif with_suffix:
|
|
|
|
for var_name, full_path in self.full_paths_variables.items():
|
|
|
|
if name.startswith(var_name):
|
|
|
|
variable = self._get_variable(full_path)
|
|
|
|
if variable['is_dynamic']:
|
|
|
|
return variable, name[len(var_name):]
|
|
|
|
if name not in self.variables:
|
|
|
|
raise DictConsistencyError(_('unknown option {}').format(name), 42)
|
2020-07-06 19:47:45 +02:00
|
|
|
if with_suffix:
|
|
|
|
return self.variables[name], None
|
|
|
|
return self.variables[name]
|