Fixed the bug in the algorithm for checking symbolic links. fixed #67

master
Иванов Денис 3 years ago
parent d52239f172
commit 8140c9a84b

@ -31,7 +31,6 @@ class RegexFormat(Format):
self._dotall_flag = parameters.dotall self._dotall_flag = parameters.dotall
if parameters.comment is not False: if parameters.comment is not False:
self.comment_symbol = parameters.comment self.comment_symbol = parameters.comment
print(f'comment symbol is set to: "{self.comment_symbol}"')
self._parsed_patch = None self._parsed_patch = None
if add_header and not ignore_comments: if add_header and not ignore_comments:

@ -280,12 +280,14 @@ class ParametersProcessor:
parameter_value): parameter_value):
self._parameters_container.set_inheritable( self._parameters_container.set_inheritable(
{parameter_name: checked_value}) {parameter_name: checked_value})
return
else: else:
self._parameters_container.set_inheritable( self._parameters_container.set_inheritable(
{parameter_name: checked_value}) {parameter_name: checked_value})
else: return
self._parameters_container.set_parameter({parameter_name:
checked_value}) self._parameters_container.set_parameter({parameter_name:
checked_value})
def check_postparse_parameters(self) -> None: def check_postparse_parameters(self) -> None:
'''Метод, запускающий проверку параметров после их разбора.''' '''Метод, запускающий проверку параметров после их разбора.'''
@ -304,8 +306,6 @@ class ParametersProcessor:
'''Метод, запускающий проверку указанных параметров.''' '''Метод, запускающий проверку указанных параметров.'''
self.template_type = template_type self.template_type = template_type
self.lineno = lineno self.lineno = lineno
print('TEMPLATE PARAMETERS:')
print(parameters)
for parameter_name in parameters: for parameter_name in parameters:
if parameter_name not in self.available_parameters: if parameter_name not in self.available_parameters:
@ -441,8 +441,10 @@ class ParametersProcessor:
return parameter_value return parameter_value
def check_chmod_parameter(self, parameter_value): def check_chmod_parameter(self, parameter_value):
print('check chmod value:', parameter_value)
result = self.chmod_value_regular.search(parameter_value) result = self.chmod_value_regular.search(parameter_value)
if result: if result:
print("chmod is alphas")
parameter_value = '' parameter_value = ''
for group_number in range(3): for group_number in range(3):
current_group = result.groups()[group_number] current_group = result.groups()[group_number]
@ -457,6 +459,7 @@ class ParametersProcessor:
return int(parameter_value, 2) return int(parameter_value, 2)
elif parameter_value.isdigit(): elif parameter_value.isdigit():
parameter_value = int(parameter_value, 8) parameter_value = int(parameter_value, 8)
print("chmod is digits:", parameter_value)
return parameter_value return parameter_value
else: else:

@ -327,9 +327,8 @@ def get_target_from_link(link_path, link_source, chroot_path='/'):
относительным.''' относительным.'''
if os.path.isabs(link_source): if os.path.isabs(link_source):
if chroot_path != '/': if chroot_path != '/':
target_path = join_paths(chroot_path, return join_paths(chroot_path, link_source)
link_source) return link_source
return target_path
else: else:
link_source = link_source.split('/') link_source = link_source.split('/')
link_dir = os.path.dirname(link_path).split('/') link_dir = os.path.dirname(link_path).split('/')

@ -3,11 +3,11 @@
import re import re
import ast import ast
import dis import dis
from typing import List, Any, Union
from contextlib import contextmanager from contextlib import contextmanager
from inspect import signature, getsource from inspect import signature, getsource
from types import FunctionType, LambdaType from types import FunctionType, LambdaType
from calculate.utils.tools import Singleton from calculate.utils.tools import Singleton
from typing import List, Any, Union, Generator, Callable
class DependenceError(Exception): class DependenceError(Exception):
@ -27,25 +27,25 @@ class VariableNotFoundError(VariableError):
class CyclicVariableError(VariableError): class CyclicVariableError(VariableError):
def __init__(self, *queue): def __init__(self, *queue: List[str]):
self.queue = queue self.queue: List[str] = queue
def __str__(self): def __str__(self) -> str:
return "Cyclic dependence in variables: {}".format(", ".join( return "Cyclic dependence in variables: {}".format(", ".join(
self.queue[:-1])) self.queue[:-1]))
class VariableType: class VariableType:
'''Базовый класс для типов.''' '''Базовый класс для типов.'''
name = 'undefined' name: str = 'undefined'
python_type = None python_type: type = None
@classmethod @classmethod
def process_value(cls, value, variable): def process_value(cls, value: Any, variable: "VariableNode") -> Any:
return value return value
@classmethod @classmethod
def readonly(cls, variable_object) -> None: def readonly(cls, variable_object: "VariableNode") -> None:
variable_object.variable_type = cls variable_object.variable_type = cls
variable_object.readonly = True variable_object.readonly = True
@ -53,21 +53,21 @@ class VariableType:
class IniType(VariableType): class IniType(VariableType):
'''Класс, соответствующий типу переменных созданных в calculate.ini файлах. '''Класс, соответствующий типу переменных созданных в calculate.ini файлах.
''' '''
name = 'ini' name: str = 'ini'
python_type: type = str python_type: type = str
@classmethod @classmethod
def process_value(cls, value, variable): def process_value(cls, value: Any, variable: "VariableNode") -> Any:
return value return value
class StringType(VariableType): class StringType(VariableType):
'''Класс, соответствующий типу переменных с строковым значением.''' '''Класс, соответствующий типу переменных с строковым значением.'''
name = 'string' name: str = 'string'
python_type: type = str python_type: type = str
@classmethod @classmethod
def process_value(cls, value, variable) -> str: def process_value(cls, value: Any, variable: "VariableNode") -> str:
if isinstance(value, str): if isinstance(value, str):
return value return value
else: else:
@ -82,11 +82,11 @@ class StringType(VariableType):
class IntegerType(VariableType): class IntegerType(VariableType):
'''Класс, соответствующий типу переменных с целочисленным значением.''' '''Класс, соответствующий типу переменных с целочисленным значением.'''
name = 'integer' name: str = 'integer'
python_type: type = int python_type: type = int
@classmethod @classmethod
def process_value(cls, value, variable) -> int: def process_value(cls, value: Any, variable: "VariableNode") -> int:
if isinstance(value, int): if isinstance(value, int):
return value return value
else: else:
@ -101,11 +101,11 @@ class IntegerType(VariableType):
class FloatType(VariableType): class FloatType(VariableType):
'''Класс, соответствующий типу переменных с вещественным значением.''' '''Класс, соответствующий типу переменных с вещественным значением.'''
name = 'float' name: str = 'float'
python_type: type = float python_type: type = float
@classmethod @classmethod
def process_value(cls, value, variable) -> float: def process_value(cls, value: Any, variable: "VariableNode") -> float:
if isinstance(value, float): if isinstance(value, float):
return value return value
else: else:
@ -120,13 +120,13 @@ class FloatType(VariableType):
class BooleanType(VariableType): class BooleanType(VariableType):
'''Класс, соответствующий типу переменных с булевым значением.''' '''Класс, соответствующий типу переменных с булевым значением.'''
name = 'bool' name: str = 'bool'
python_type: type = bool python_type: type = bool
true_values = {'True', 'true'} true_values: set = {'True', 'true'}
false_values = {'False', 'false'} false_values: set = {'False', 'false'}
@classmethod @classmethod
def process_value(cls, value, variable) -> bool: def process_value(cls, value: Any, variable: "VariableNode") -> bool:
if isinstance(value, bool): if isinstance(value, bool):
return value return value
elif isinstance(value, str): elif isinstance(value, str):
@ -148,7 +148,7 @@ class ListType(VariableType):
python_type: type = list python_type: type = list
@classmethod @classmethod
def process_value(cls, value, variable) -> list: def process_value(cls, value: Any, variable: "VariableNode") -> list:
if isinstance(value, list): if isinstance(value, list):
return value return value
elif isinstance(value, str): elif isinstance(value, str):
@ -171,18 +171,20 @@ class HashValue:
хозяина, что позволяет инвалидировать подписки переменной хозяина при любом хозяина, что позволяет инвалидировать подписки переменной хозяина при любом
изменении хэша или инвалидировать весь хэш при изменении одной из изменении хэша или инвалидировать весь хэш при изменении одной из
зависимостей.''' зависимостей.'''
def __init__(self, key: str, value, master_variable, parent): def __init__(self, key: Any, value: Any,
self.key = key master_variable: "VariableNode",
self.value = value parent: "Hash"):
self.master_variable = master_variable self.key: Any = key
self.parent = parent self.value: Any = value
self.master_variable: "VariableNode" = master_variable
self.parent: "Hash" = parent
@property @property
def subscriptions(self): def subscriptions(self) -> set:
return self.master_variable.subscriptions return self.master_variable.subscriptions
@property @property
def subscribers(self): def subscribers(self) -> set:
return self.master_variable.subscribers return self.master_variable.subscribers
def get_value(self) -> str: def get_value(self) -> str:
@ -191,7 +193,7 @@ class HashValue:
self = self.master_variable.get_value()[self.key] self = self.master_variable.get_value()[self.key]
return self.value return self.value
def set(self, value) -> None: def set(self, value: Any) -> None:
'''Метод для задания одного значения хэша без изменения источника '''Метод для задания одного значения хэша без изменения источника
значения.''' значения.'''
current_hash = self.master_variable.get_value().get_hash() current_hash = self.master_variable.get_value().get_hash()
@ -206,17 +208,18 @@ class HashValue:
class Hash: class Hash:
'''Класс реализующий контейнер для хранения хэша в переменной '''Класс реализующий контейнер для хранения хэша в переменной
соответствующего типа.''' соответствующего типа.'''
def __init__(self, values: dict, master_variable, parent=None): def __init__(self, values: dict,
self.fixed = master_variable.fixed master_variable: "VariableNode"):
self._values = dict() self.fixed: bool = master_variable.fixed
self._fields = set() self._values: dict = dict()
self._fields: set = set()
for key, value in values.items(): for key, value in values.items():
self._values.update({key: HashValue(key, value, master_variable, self._values.update({key: HashValue(key, value, master_variable,
self)}) self)})
if self.fixed: if self.fixed:
self._fields.add(key) self._fields.add(key)
self.master_variable = master_variable self.master_variable: "VariableNode" = master_variable
self.row_index = None self.row_index: Union[int, None] = None
def get_hash(self) -> dict: def get_hash(self) -> dict:
'''Метод для получения словаря из значений хэша.''' '''Метод для получения словаря из значений хэша.'''
@ -258,7 +261,7 @@ class Hash:
key=key, key=key,
hash_name=self.master_variable.get_fullname())) hash_name=self.master_variable.get_fullname()))
def __iter__(self): def __iter__(self) -> Generator[Any, None, None]:
for key in self._values.keys(): for key in self._values.keys():
yield key yield key
@ -271,11 +274,11 @@ class Hash:
class HashType(VariableType): class HashType(VariableType):
'''Класс, соответствующий типу переменных хэшей.''' '''Класс, соответствующий типу переменных хэшей.'''
name = 'hash' name: str = 'hash'
python_type: type = dict python_type: type = dict
@classmethod @classmethod
def process_value(cls, values, variable) -> Hash: def process_value(cls, values: Any, variable: "VariableNode") -> Hash:
if not isinstance(values, dict): if not isinstance(values, dict):
raise VariableTypeError("can not set value with type '{_type}' to" raise VariableTypeError("can not set value with type '{_type}' to"
" hash variable: value must be 'dict' type" " hash variable: value must be 'dict' type"
@ -287,7 +290,7 @@ class HashType(VariableType):
return updated_hash return updated_hash
@classmethod @classmethod
def fixed(cls, variable_object) -> None: def fixed(cls, variable_object: "VariableNode") -> None:
'''Метод, который передается переменной вместо типа, если нужно задать '''Метод, который передается переменной вместо типа, если нужно задать
тип фиксированного хэша.''' тип фиксированного хэша.'''
variable_object.variable_type = cls variable_object.variable_type = cls
@ -296,11 +299,12 @@ class HashType(VariableType):
class Table: class Table:
'''Класс, соответствующий типу переменных таблиц.''' '''Класс, соответствующий типу переменных таблиц.'''
def __init__(self, values: List[dict], master_variable, fields=None): def __init__(self, values: List[dict], master_variable: "VariableNode",
self._rows = list() fields: Union[List[str], None] = None):
self.master_variable = master_variable self._rows: List[dict] = list()
self.master_variable: "VariableNode" = master_variable
self.columns = set() self.columns: set = set()
if fields is not None: if fields is not None:
self.columns.update(fields) self.columns.update(fields)
else: else:
@ -319,7 +323,7 @@ class Table:
'''Метод для получения всего списка строк таблицы.''' '''Метод для получения всего списка строк таблицы.'''
return self._rows return self._rows
def add_row(self, row: dict): def add_row(self, row: dict) -> None:
'''Метод для добавления строк в таблицу.''' '''Метод для добавления строк в таблицу.'''
self._check_columns(row) self._check_columns(row)
self._rows.append(row) self._rows.append(row)
@ -353,7 +357,7 @@ class Table:
else: else:
raise VariableError("Table value is not subscriptable") raise VariableError("Table value is not subscriptable")
def __iter__(self): def __iter__(self) -> Generator[dict, None, None]:
for row in self._rows: for row in self._rows:
yield row yield row
@ -362,17 +366,18 @@ class Table:
return key in self._values return key in self._values
return False return False
def __len__(self): def __len__(self) -> int:
return len(self._rows) return len(self._rows)
class TableType(VariableType): class TableType(VariableType):
name = 'table' name: str = 'table'
# TODO Сомнительно. # TODO Сомнительно.
python_type: type = list python_type: type = list
@classmethod @classmethod
def process_value(self, value: List[dict], variable) -> Table: def process_value(self, value: List[dict],
variable: "VariableNode") -> Table:
if not isinstance(value, list) and not isinstance(value, Table): if not isinstance(value, list) and not isinstance(value, Table):
raise VariableTypeError("can not set value with type '{_type}' to" raise VariableTypeError("can not set value with type '{_type}' to"
" hash variable: value must be 'dict' type" " hash variable: value must be 'dict' type"
@ -390,10 +395,10 @@ class TableType(VariableType):
class Static: class Static:
'''Класс для указания в качестве аргументов зависимостей статичных '''Класс для указания в качестве аргументов зависимостей статичных
значений, а не только переменных.''' значений, а не только переменных.'''
def __init__(self, value): def __init__(self, value: Any):
self.value = value self.value: Any = value
def get_value(self): def get_value(self) -> Any:
return self.value return self.value
@ -401,9 +406,10 @@ class VariableWrapper:
'''Класс обертки для переменных, с помощью которого отслеживается '''Класс обертки для переменных, с помощью которого отслеживается
применение переменной в образовании значения переменной от нее зависящей. применение переменной в образовании значения переменной от нее зависящей.
''' '''
def __init__(self, variable, subscriptions): def __init__(self, variable: "VariableNode",
self._variable = variable subscriptions: set):
self._subscriptions = subscriptions self._variable: "VariableNode" = variable
self._subscriptions: set = subscriptions
@property @property
def value(self): def value(self):
@ -429,12 +435,12 @@ class VariableWrapper:
class DependenceSource: class DependenceSource:
'''Класс зависимости как источника значения переменной.''' '''Класс зависимости как источника значения переменной.'''
def __init__(self, variables: tuple, depend=None): def __init__(self, variables: tuple,
self.error = None depend: Union[Callable, None] = None):
self._args = variables self._args: Union[tuple, list] = variables
self.depend_function = depend self.depend_function: Union[Callable, None] = depend
self._subscriptions = set() self._subscriptions: set = set()
self._args_founded = False self._args_founded: bool = False
def check(self) -> None: def check(self) -> None:
'''Метод для запуска проверки корректности функции зависимости, а также '''Метод для запуска проверки корректности функции зависимости, а также
@ -469,7 +475,7 @@ class DependenceSource:
in self._args]), in self._args]),
str(error))) str(error)))
def _get_args(self, namespace): def _get_args(self, namespace: "NamespaceNode") -> None:
'''Метод для преобразования списка аргументов функции зависимости, '''Метод для преобразования списка аргументов функции зависимости,
содержащего переменные и строки, в список аргументов состоящий только содержащего переменные и строки, в список аргументов состоящий только
из нод переменных и значений хэшей.''' из нод переменных и значений хэшей.'''
@ -477,7 +483,8 @@ class DependenceSource:
self._args = self.find_variables(self._args, namespace) self._args = self.find_variables(self._args, namespace)
self._args_founded = True self._args_founded = True
def find_variables(self, variables, namespace): def find_variables(self, variables: Union[tuple, list],
namespace: "NamespaceNode") -> List["VariableNode"]:
'''Метод для поиска переменных по заданным путям к ним.''' '''Метод для поиска переменных по заданным путям к ним.'''
output = [] output = []
for variable in variables: for variable in variables:
@ -514,7 +521,8 @@ class DependenceSource:
self.check_signature(function_to_check, self._args) self.check_signature(function_to_check, self._args)
@staticmethod @staticmethod
def check_signature(function_to_check, arguments): def check_signature(function_to_check: Callable,
arguments: Union[tuple, list]) -> None:
'''Метод для проверки соответствия сигнатуры функции и заданного для '''Метод для проверки соответствия сигнатуры функции и заданного для
нее набора аргументов.''' нее набора аргументов.'''
function_signature = signature(function_to_check) function_signature = signature(function_to_check)
@ -524,12 +532,12 @@ class DependenceSource:
len(function_signature.parameters), len(function_signature.parameters),
len(arguments))) len(arguments)))
def __ne__(self, other) -> bool: def __ne__(self, other: Any) -> bool:
if not isinstance(other, DependenceSource): if not isinstance(other, DependenceSource):
return True return True
return not self == other return not self == other
def __eq__(self, other) -> bool: def __eq__(self, other: Any) -> bool:
if not isinstance(other, DependenceSource): if not isinstance(other, DependenceSource):
return False return False
@ -568,44 +576,44 @@ class DependenceSource:
class VariableNode: class VariableNode:
'''Класс ноды соответствующей переменной в дереве переменных.''' '''Класс ноды соответствующей переменной в дереве переменных.'''
def __init__(self, name: str, namespace: "NamespaceNode", def __init__(self, name: str, namespace: "NamespaceNode",
variable_type=VariableType, variable_type: type = VariableType,
source=None, fields: list = []): source: Any = None, fields: list = []):
self.name = name self.name: str = name
if issubclass(variable_type, VariableType): if issubclass(variable_type, VariableType):
self.variable_type = variable_type self.variable_type: type = variable_type
else: else:
raise VariableTypeError('variable_type must be VariableType' raise VariableTypeError('variable_type must be VariableType'
', but not {}'.format(type(variable_type))) ', but not {}'.format(type(variable_type)))
self.calculating = False self.calculating: bool = False
self.fields = fields self.fields: list = fields
self.namespace = namespace self.namespace: "NamespaceNode" = namespace
self.namespace.add_variable(self) self.namespace.add_variable(self)
self.subscribers = set() self.subscribers: set = set()
# Список текущих подписок, для проверки их актуальности при # Список текущих подписок, для проверки их актуальности при
# динамическом связывании. # динамическом связывании.
self._subscriptions = set() self._subscriptions: set = set()
self.value = None self.value: Any = None
self._invalidated = True self._invalidated: bool = True
# Флаг имеющий значение только для переменных типа HashType. # Флаг имеющий значение только для переменных типа HashType.
# Предназначен для включения проверки соответствия полей хэша при # Предназначен для включения проверки соответствия полей хэша при
# установке значения. # установке значения.
self._fixed = False self._fixed: bool = False
# Источник значения переменной, может быть значением, а может быть # Источник значения переменной, может быть значением, а может быть
# зависимостью. # зависимостью.
self._source = source self._source: Any = source
if source is not None: if source is not None:
self.update_value() self.update_value()
# Флаг, указывающий, что значение было изменено в процессе работы # Флаг, указывающий, что значение было изменено в процессе работы
# утилит или с помощью тега set из шаблона. # утилит или с помощью тега set из шаблона.
self.set_by_user = False self.set_by_user: bool = False
self._readonly = False self._readonly: bool = False
def update_value(self) -> None: def update_value(self) -> None:
'''Метод для обновления значения переменной с помощью указанного '''Метод для обновления значения переменной с помощью указанного
@ -646,7 +654,8 @@ class VariableNode:
self._invalidated = False self._invalidated = False
def set_variable_type(self, variable_type: VariableType, def set_variable_type(self, variable_type: VariableType,
readonly: str = None, fixed: str = None) -> None: readonly: Union[bool, None] = None,
fixed: Union[bool, None] = None) -> None:
'''Метод для установки типа переменной.''' '''Метод для установки типа переменной.'''
if readonly is not None and isinstance(readonly, bool): if readonly is not None and isinstance(readonly, bool):
self._readonly = readonly self._readonly = readonly
@ -664,7 +673,7 @@ class VariableNode:
elif callable(variable_type): elif callable(variable_type):
variable_type(self) variable_type(self)
def set(self, value): def set(self, value: Any) -> None:
'''Метод для установки временного пользовательского значения '''Метод для установки временного пользовательского значения
переменной.''' переменной.'''
# Сбрасываем флаги, чтобы провести инвалидацию. # Сбрасываем флаги, чтобы провести инвалидацию.
@ -674,7 +683,7 @@ class VariableNode:
self.value = self.variable_type.process_value(value, self) self.value = self.variable_type.process_value(value, self)
self._invalidate(set_by_user=True) self._invalidate(set_by_user=True)
def reset(self): def reset(self) -> None:
'''Метод для сброса пользовательского значения.''' '''Метод для сброса пользовательского значения.'''
if self.set_by_user: if self.set_by_user:
self._invalidated = False self._invalidated = False
@ -682,11 +691,11 @@ class VariableNode:
self._invalidate() self._invalidate()
@property @property
def source(self): def source(self) -> None:
return self._source return self._source
@source.setter @source.setter
def source(self, source) -> None: def source(self, source: Any) -> None:
# Если источники не совпадают или текущее значение переменной было # Если источники не совпадают или текущее значение переменной было
# установлено пользователем, то инвалидируем переменную и меняем # установлено пользователем, то инвалидируем переменную и меняем
# источник. # источник.
@ -712,10 +721,10 @@ class VariableNode:
return self._fixed return self._fixed
@fixed.setter @fixed.setter
def fixed(self, value) -> bool: def fixed(self, value: bool) -> bool:
self._fixed = value self._fixed = value
def _invalidate(self, set_by_user=False) -> None: def _invalidate(self, set_by_user: bool = False) -> None:
'''Метод для инвалидации данной переменной и всех зависящих от нее '''Метод для инвалидации данной переменной и всех зависящих от нее
переменных.''' переменных.'''
if not self._invalidated and not self.set_by_user: if not self._invalidated and not self.set_by_user:
@ -763,7 +772,7 @@ class VariableNode:
raise VariableError("'{}' variable type is not subscriptable.". raise VariableError("'{}' variable type is not subscriptable.".
format(self.variable_type.name)) format(self.variable_type.name))
def __repr__(self): def __repr__(self) -> str:
return '<Variable: {} with value: {}>'.format(self.get_fullname(), return '<Variable: {} with value: {}>'.format(self.get_fullname(),
self.value or self.value or
'INVALIDATED') 'INVALIDATED')
@ -771,7 +780,8 @@ class VariableNode:
class NamespaceNode: class NamespaceNode:
'''Класс ноды соответствующей пространству имен в дереве переменных.''' '''Класс ноды соответствующей пространству имен в дереве переменных.'''
def __init__(self, name='', parent=None): def __init__(self, name: str = '',
parent: Union["NamespaceNode", None] = None):
self._name = name self._name = name
self._variables = dict() self._variables = dict()
self._namespaces = dict() self._namespaces = dict()
@ -787,7 +797,7 @@ class NamespaceNode:
self._variables.update({variable.name: variable}) self._variables.update({variable.name: variable})
variable.namespace = self variable.namespace = self
def add_namespace(self, namespace) -> None: def add_namespace(self, namespace: "NamespaceNode") -> None:
'''Метод для добавления пространства имен в пространство имен.''' '''Метод для добавления пространства имен в пространство имен.'''
if namespace._name in self._variables: if namespace._name in self._variables:
raise VariableError("variable with the name '{}' is already in" raise VariableError("variable with the name '{}' is already in"
@ -797,7 +807,7 @@ class NamespaceNode:
self._namespaces.update({namespace._name: namespace}) self._namespaces.update({namespace._name: namespace})
namespace._parent = self namespace._parent = self
def clear(self): def clear(self) -> None:
'''Метод для очистки пространства имен. Очищает и пространства имен '''Метод для очистки пространства имен. Очищает и пространства имен
и переменные. Предназначен только для использования в calculate.ini.''' и переменные. Предназначен только для использования в calculate.ini.'''
for namespace_name in self._namespaces.keys(): for namespace_name in self._namespaces.keys():
@ -818,7 +828,7 @@ class NamespaceNode:
else: else:
return self._parent.get_package_name() return self._parent.get_package_name()
def __getattr__(self, name: str): def __getattr__(self, name: str) -> Any:
'''Метод возвращает ноду пространства имен или значение переменной.''' '''Метод возвращает ноду пространства имен или значение переменной.'''
if name in self._namespaces: if name in self._namespaces:
return self._namespaces[name] return self._namespaces[name]
@ -849,13 +859,13 @@ class NamespaceNode:
variable_name=name, variable_name=name,
namespace_name=self._name)) namespace_name=self._name))
def __contains__(self, name): def __contains__(self, name: str) -> bool:
return name in self._namespaces or name in self._variables return name in self._namespaces or name in self._variables
def __repr__(self): def __repr__(self) -> str:
return '<Namespace: {}>'.format(self.get_fullname()) return '<Namespace: {}>'.format(self.get_fullname())
def __deepcopy__(self, memo): def __deepcopy__(self, memo: dict) -> "NamespaceNode":
'''Пространство имен не копируется даже при глубоком копировании.''' '''Пространство имен не копируется даже при глубоком копировании.'''
return self return self
@ -863,10 +873,11 @@ class NamespaceNode:
class DependenceAPI(metaclass=Singleton): class DependenceAPI(metaclass=Singleton):
'''Класс образующий интерфейс для создания зависимостей.''' '''Класс образующий интерфейс для создания зависимостей.'''
def __init__(self): def __init__(self):
self.current_namespace = None self.current_namespace: NamespaceNode = None
self.datavars_root = None self.datavars_root = None
def __call__(self, *variables, depend=None): def __call__(self, *variables: list,
depend: Union[Callable, None] = None) -> DependenceSource:
subscriptions = list() subscriptions = list()
for variable in variables: for variable in variables:
if not (isinstance(variable, str) or if not (isinstance(variable, str) or
@ -876,7 +887,9 @@ class DependenceAPI(metaclass=Singleton):
subscriptions.append(variable) subscriptions.append(variable)
return DependenceSource(subscriptions, depend=depend) return DependenceSource(subscriptions, depend=depend)
def _get_variable(self, variable_name, current_namespace=None): def _get_variable(self, variable_name: str,
current_namespace: Union[NamespaceNode, None] = None
) -> VariableNode:
'''Метод для поиска переменной в пространствах имен.''' '''Метод для поиска переменной в пространствах имен.'''
if current_namespace is None: if current_namespace is None:
current_namespace = self.current_namespace current_namespace = self.current_namespace
@ -884,7 +897,10 @@ class DependenceAPI(metaclass=Singleton):
current_namespace=current_namespace) current_namespace=current_namespace)
@staticmethod @staticmethod
def find_variable(variable_name, datavars_root, current_namespace=None): def find_variable(variable_name: str,
datavars_root,
current_namespace: Union[NamespaceNode, None] = None
) -> VariableNode:
'''Метод для поиска переменных по строковому пути от корня переменных '''Метод для поиска переменных по строковому пути от корня переменных
или от текущего пространства имен.''' или от текущего пространства имен.'''
name_parts = variable_name.split('.') name_parts = variable_name.split('.')
@ -912,7 +928,7 @@ class DependenceAPI(metaclass=Singleton):
class CopyAPI(metaclass=Singleton): class CopyAPI(metaclass=Singleton):
'''Класс для создания зависимостей представляющих собой простое копирование '''Класс для создания зависимостей представляющих собой простое копирование
значения переменной в зависимую переменную.''' значения переменной в зависимую переменную.'''
def __call__(self, variable: Union[str, VariableNode]): def __call__(self, variable: Union[str, VariableNode]) -> "Dependence":
return Dependence(variable) return Dependence(variable)
@ -923,7 +939,7 @@ class FormatAPI(metaclass=Singleton):
pattern = re.compile( pattern = re.compile(
r'{\s*([a-zA-Z][a-zA-Z_0-9]+)?(.[a-zA-Z][a-zA-Z_0-9]+)+\s*}') r'{\s*([a-zA-Z][a-zA-Z_0-9]+)?(.[a-zA-Z][a-zA-Z_0-9]+)+\s*}')
def __call__(self, string: str): def __call__(self, string: str) -> "Dependence":
vars_list = [] vars_list = []
def subfunc(matchobj): def subfunc(matchobj):
@ -942,7 +958,7 @@ class CalculateAPI(metaclass=Singleton):
'''Метод для создания зависимостей, представляющих собой функцию для '''Метод для создания зависимостей, представляющих собой функцию для
вычисления значения зависимой переменной на основе значений указанных вычисления значения зависимой переменной на основе значений указанных
переменных.''' переменных.'''
def __call__(self, *args): def __call__(self, *args) -> "Dependence":
depend_function = args[0] depend_function = args[0]
return Dependence(*args[1:], depend=depend_function) return Dependence(*args[1:], depend=depend_function)
@ -951,12 +967,17 @@ class VariableAPI(metaclass=Singleton):
'''Класс для создания переменных при задании их через '''Класс для создания переменных при задании их через
python-скрипты.''' python-скрипты.'''
def __init__(self): def __init__(self):
self.current_namespace = None self.current_namespace: Union[NamespaceNode, None] = None
# TODO Продумать другой способ обработки ошибок. # TODO Продумать другой способ обработки ошибок.
self.errors = [] self.errors: list = []
def __call__(self, name: str, source=None, type=VariableType, def __call__(self, name: str,
readonly=False, fixed=False, force=False, fields=None): source: Any = None,
type=VariableType,
readonly: bool = False,
fixed: bool = False,
force: bool = False,
fields: Union[list, None] = None) -> "Dependence":
'''Метод для создания переменных внутри with Namespace('name').''' '''Метод для создания переменных внутри with Namespace('name').'''
if name not in self.current_namespace._variables: if name not in self.current_namespace._variables:
variable = VariableNode(name, self.current_namespace) variable = VariableNode(name, self.current_namespace)
@ -1011,13 +1032,13 @@ class NamespaceAPI(metaclass=Singleton):
можно получить доступ к переменным.''' можно получить доступ к переменным.'''
return self._datavars return self._datavars
def set_datavars(self, datavars): def set_datavars(self, datavars) -> None:
'''Метод для установки корневого пространства имен, которое пока что '''Метод для установки корневого пространства имен, которое пока что
будет использоваться для предоставления доступа к переменным.''' будет использоваться для предоставления доступа к переменным.'''
self._datavars = datavars self._datavars = datavars
self._variables_fabric.current_namespace = self._datavars self._variables_fabric.current_namespace = self._datavars
def reset(self): def reset(self) -> None:
'''Метод для сброса корневого пространства имен.''' '''Метод для сброса корневого пространства имен.'''
if isinstance(self._datavars, NamespaceNode): if isinstance(self._datavars, NamespaceNode):
self._datavars = NamespaceNode('<root>') self._datavars = NamespaceNode('<root>')
@ -1028,7 +1049,7 @@ class NamespaceAPI(metaclass=Singleton):
self._variables_fabric.current_namespace = self._datavars self._variables_fabric.current_namespace = self._datavars
self._dependence_fabric.current_namespace = self._datavars self._dependence_fabric.current_namespace = self._datavars
def set_current_namespace(self, namespace: NamespaceNode): def set_current_namespace(self, namespace: NamespaceNode) -> None:
'''Метод для установки текущего пространства имен, в которое будут '''Метод для установки текущего пространства имен, в которое будут
добавляться далее переменные и пространства имен.''' добавляться далее переменные и пространства имен.'''
self.current_namespace = namespace self.current_namespace = namespace
@ -1036,7 +1057,7 @@ class NamespaceAPI(metaclass=Singleton):
self._dependence_fabric.current_namespace = namespace self._dependence_fabric.current_namespace = namespace
@contextmanager @contextmanager
def __call__(self, namespace_name): def __call__(self, namespace_name: str):
'''Метод для создания пространств имен с помощью with.''' '''Метод для создания пространств имен с помощью with.'''
if namespace_name not in self.current_namespace._namespaces: if namespace_name not in self.current_namespace._namespaces:
namespace = NamespaceNode(namespace_name, namespace = NamespaceNode(namespace_name,

@ -1580,6 +1580,20 @@ class TestDirectoryProcessor:
assert os.path.lexists(join_paths(CHROOT_PATH, '/etc/link_0')) assert os.path.lexists(join_paths(CHROOT_PATH, '/etc/link_0'))
assert os.path.lexists(join_paths(CHROOT_PATH, '/etc/link_1')) assert os.path.lexists(join_paths(CHROOT_PATH, '/etc/link_1'))
def test_using_directory_template_to_an_link_to_directory(self):
datavars.main['cl_template_path'] = os.path.join(CHROOT_PATH,
'templates_55')
directory_processor = DirectoryProcessor('install',
datavars_module=datavars
)
directory_processor.process_template_directories()
assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_75/file_0'))
assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_75/file_1'))
assert os.path.exists(join_paths(CHROOT_PATH, '/etc/link_3/file_0'))
assert os.path.exists(join_paths(CHROOT_PATH, '/etc/link_3/file_1'))
def test_view_tree(self): def test_view_tree(self):
list_path = join_paths(CHROOT_PATH, '/etc') list_path = join_paths(CHROOT_PATH, '/etc')
show_tree(list_path) show_tree(list_path)

@ -35,10 +35,10 @@ class TestTemplateParameters:
DIR, 1) DIR, 1)
parameters_processor.check_postparse_parameters() parameters_processor.check_postparse_parameters()
assert (parameters_object.append == 'join' and assert parameters_object.append == 'join'
parameters_object.chmod == 0o600 and assert parameters_object.chmod == 0o600
parameters_object.force and assert parameters_object.force
not parameters_object.autoupdate) assert not parameters_object.autoupdate
def test_if_TemplateParameters_object_is_intialized_using_dictionary_with_append_parameter__a_value_of_the_parameter_will_be_checked(self): def test_if_TemplateParameters_object_is_intialized_using_dictionary_with_append_parameter__a_value_of_the_parameter_will_be_checked(self):
parameters = {'append': 'join'} parameters = {'append': 'join'}

@ -0,0 +1 @@
bring me horizon -- the sadness will never end

@ -0,0 +1 @@
{% calculate package = "test-category/test-package", name = 'link_3' %}
Loading…
Cancel
Save