rougail/src/rougail/path.py

184 lines
7.5 KiB
Python

from .i18n import _
from .utils import normalize_family
from .error import CreoleOperationError, CreoleDictConsistencyError
from .annotator import VARIABLE_NAMESPACE
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 = {}
# Family
def add_family(self,
namespace: str,
name: str,
variableobj: str,
) -> str: # pylint: disable=C0111
self.families[name] = dict(name=name,
namespace=namespace,
variableobj=variableobj,
)
def get_family_path(self,
name: str,
current_namespace: str,
) -> str: # pylint: disable=C0111
if current_namespace is None: # pragma: no cover
raise CreoleOperationError('current_namespace must not be None')
dico = self.families[normalize_family(name,
check_name=False,
allow_dot=True,
)]
if dico['namespace'] != VARIABLE_NAMESPACE and current_namespace != dico['namespace']:
raise CreoleDictConsistencyError(_('A family located in the {} namespace '
'shall not be used in the {} namespace').format(
dico['namespace'], current_namespace))
path = dico['name']
if dico['namespace'] is not None and '.' not in dico['name']:
path = '.'.join([dico['namespace'], path])
return path
def get_family_obj(self,
name: str,
) -> 'Family': # pylint: disable=C0111
if name not in self.families:
raise CreoleDictConsistencyError(_('unknown family {}').format(name))
dico = self.families[name]
return dico['variableobj']
# Leadership
def set_leader(self,
namespace: str,
leader_family_name: str,
name: str,
leader_name: str,
) -> None: # pylint: disable=C0111
if namespace != VARIABLE_NAMESPACE:
# need rebuild path and move object in new path
old_path = namespace + '.' + leader_family_name + '.' + name
dico = self._get_variable(old_path)
del self.variables[old_path]
new_path = namespace + '.' + leader_family_name + '.' + leader_name + '.' + name
self.add_variable(namespace,
new_path,
dico['family'],
False,
dico['variableobj'],
)
name = new_path
dico = self._get_variable(name)
if dico['leader'] != None:
raise CreoleDictConsistencyError(_('Already defined leader {} for variable'
' {}'.format(dico['leader'], name)))
dico['leader'] = leader_name
def get_leader(self, name): # pylint: disable=C0111
return self._get_variable(name)['leader']
# Variable
def add_variable(self,
namespace: str,
name: str,
family: str,
is_dynamic: bool,
variableobj,
) -> str: # pylint: disable=C0111
if namespace == VARIABLE_NAMESPACE or '.' in name:
varname = name
else:
varname = '.'.join([namespace, family, name])
self.variables[varname] = dict(name=name,
family=family,
namespace=namespace,
leader=None,
is_dynamic=is_dynamic,
variableobj=variableobj)
def get_variable_name(self,
name,
): # pylint: disable=C0111
return self._get_variable(name)['name']
def get_variable_obj(self,
name:str,
) -> 'Variable': # pylint: disable=C0111
return self._get_variable(name)['variableobj']
def get_variable_family_name(self,
name: str,
) -> str: # pylint: disable=C0111
return self._get_variable(name)['family']
def get_variable_family_path(self,
name: str,
) -> str: # pylint: disable=C0111
dico = self._get_variable(name)
list_path = [dico['namespace'], dico['family']]
if dico['leader'] is not None:
list_path.append(dico['leader'])
return '.'.join(list_path)
def get_variable_namespace(self,
name: str,
) -> str: # pylint: disable=C0111
return self._get_variable(name)['namespace']
def get_variable_path(self,
name: str,
current_namespace: str,
allow_source: str=False,
with_suffix: bool=False,
) -> str: # pylint: disable=C0111
if current_namespace is None: # pragma: no cover
raise CreoleOperationError('current_namespace must not be None')
if with_suffix:
dico, suffix = self._get_variable(name,
with_suffix=True,
)
else:
dico = self._get_variable(name)
if not allow_source:
if dico['namespace'] not in [VARIABLE_NAMESPACE, 'services'] and current_namespace != dico['namespace']:
raise CreoleDictConsistencyError(_('A variable located in the {} namespace '
'shall not be used in the {} namespace').format(
dico['namespace'], current_namespace))
if '.' in dico['name']:
value = dico['name']
else:
list_path = [dico['namespace'], dico['family']]
if dico['leader'] is not None:
list_path.append(dico['leader'])
list_path.append(dico['name'])
value = '.'.join(list_path)
if with_suffix:
return value, suffix
return value
def path_is_defined(self,
name: str,
) -> str: # pylint: disable=C0111
return name in self.variables
def _get_variable(self,
name: str,
with_suffix: bool=False,
) -> str:
if name not in self.variables:
if name.startswith(f'{VARIABLE_NAMESPACE}.'):
name = name.split('.')[-1]
if name not in self.variables:
for var_name, variable in self.variables.items():
if variable['is_dynamic'] and name.startswith(var_name):
return variable, name[len(var_name):]
raise CreoleDictConsistencyError(_('unknown option {}').format(name))
if with_suffix:
return self.variables[name], None
return self.variables[name]