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]