|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
import ast
|
|
|
|
|
import dis
|
|
|
|
|
from typing import List, Union
|
|
|
|
|
from typing import List, Union, Any
|
|
|
|
|
from contextlib import contextmanager
|
|
|
|
|
from inspect import signature, getsource
|
|
|
|
|
from types import FunctionType, LambdaType
|
|
|
|
@ -160,12 +160,10 @@ class HashValue:
|
|
|
|
|
def subscribers(self):
|
|
|
|
|
return self.master_variable.subscribers
|
|
|
|
|
|
|
|
|
|
def get_value(self):
|
|
|
|
|
if self.master_variable.variable_type is HashType:
|
|
|
|
|
self = self.master_variable.get_value()[self.key]
|
|
|
|
|
elif self.master_variable.variable_type is TableType:
|
|
|
|
|
self = self.master_variable.get_value()[
|
|
|
|
|
self.parent.row_index][self.key]
|
|
|
|
|
def get_value(self) -> str:
|
|
|
|
|
'''Метод для получения значения хэша. Перед возвращением значения
|
|
|
|
|
обновляет себя на наиболее актуальную версию значения хэша.'''
|
|
|
|
|
self = self.master_variable.get_value()[self.key]
|
|
|
|
|
return self.value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -180,6 +178,12 @@ class Hash:
|
|
|
|
|
self.master_variable = master_variable
|
|
|
|
|
self.row_index = None
|
|
|
|
|
|
|
|
|
|
def get_hash(self) -> dict:
|
|
|
|
|
dict_value = {}
|
|
|
|
|
for key in self._values.keys():
|
|
|
|
|
dict_value.update({key: self._values[key].get_value()})
|
|
|
|
|
return dict_value
|
|
|
|
|
|
|
|
|
|
def __getattr__(self, key: str):
|
|
|
|
|
'''Метод возвращает ноду пространства имен или значение переменной.'''
|
|
|
|
|
if key in self._values:
|
|
|
|
@ -222,8 +226,7 @@ class HashType(VariableType):
|
|
|
|
|
|
|
|
|
|
class Table:
|
|
|
|
|
'''Класс, соответствующий типу переменных таблиц.'''
|
|
|
|
|
def __init__(self, values: Union[List[Hash], List[dict]],
|
|
|
|
|
master_variable, fields=None):
|
|
|
|
|
def __init__(self, values: List[dict], master_variable, fields=None):
|
|
|
|
|
self._rows = list()
|
|
|
|
|
self.master_variable = master_variable
|
|
|
|
|
|
|
|
|
@ -231,21 +234,20 @@ class Table:
|
|
|
|
|
if fields is not None:
|
|
|
|
|
self.columns.update(self.fields)
|
|
|
|
|
else:
|
|
|
|
|
self.columns = set(values[0])
|
|
|
|
|
self.columns = set(values[0].keys())
|
|
|
|
|
|
|
|
|
|
for row in values:
|
|
|
|
|
if isinstance(row, Hash):
|
|
|
|
|
if isinstance(row, dict):
|
|
|
|
|
self._check_columns(row)
|
|
|
|
|
self._rows.append(row)
|
|
|
|
|
elif isinstance(row, dict):
|
|
|
|
|
self._check_columns(row)
|
|
|
|
|
row_hash = Hash(row, master_variable)
|
|
|
|
|
self._rows.append(row_hash)
|
|
|
|
|
else:
|
|
|
|
|
raise VariableTypeError("can not create table using value '{}'"
|
|
|
|
|
" with type '{}'".format(row,
|
|
|
|
|
type(row)))
|
|
|
|
|
|
|
|
|
|
def get_table(self):
|
|
|
|
|
return self._rows
|
|
|
|
|
|
|
|
|
|
def _check_columns(self, value: Union[List[Hash], List[dict]]) -> None:
|
|
|
|
|
'''Метод для проверки наличия в хэше только тех полей, которые
|
|
|
|
|
соответствуют заданным для таблицы колонкам.'''
|
|
|
|
@ -280,8 +282,7 @@ class TableType(VariableType):
|
|
|
|
|
name = 'table'
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def process_value(self, value: Union[Table, List[dict], List[Hash]],
|
|
|
|
|
variable) -> Table:
|
|
|
|
|
def process_value(self, value: List[dict], variable) -> Table:
|
|
|
|
|
print('PROCESS TABLE')
|
|
|
|
|
if not isinstance(value, list) and not isinstance(value, Table):
|
|
|
|
|
raise VariableTypeError("can not set value with type '{_type}' to"
|
|
|
|
@ -294,14 +295,22 @@ class TableType(VariableType):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VariableWrapper:
|
|
|
|
|
'''Класс обертки для переменных, с помощью которого отслеживается
|
|
|
|
|
применение переменной в образовании значения переменной от нее зависящей.
|
|
|
|
|
'''
|
|
|
|
|
def __init__(self, variable, subscriptions):
|
|
|
|
|
self._variable = variable
|
|
|
|
|
self._subscriptions = subscriptions
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def value(self):
|
|
|
|
|
'''Метод возвращающий значение переменной и при этом добавляющий его в
|
|
|
|
|
подписки.'''
|
|
|
|
|
self._subscriptions.add(self._variable)
|
|
|
|
|
return self._variable.get_value()
|
|
|
|
|
value = self._variable.get_value()
|
|
|
|
|
if isinstance(value, Hash):
|
|
|
|
|
value = value.get_hash()
|
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def subscriptions(self):
|
|
|
|
@ -313,9 +322,7 @@ class VariableWrapper:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DependenceSource:
|
|
|
|
|
current_namespace = None
|
|
|
|
|
datavars_root = None
|
|
|
|
|
|
|
|
|
|
'''Класс зависимости как источника значения переменной.'''
|
|
|
|
|
def __init__(self, variables, depend=None):
|
|
|
|
|
self.error = None
|
|
|
|
|
self._args = variables
|
|
|
|
@ -335,7 +342,7 @@ class DependenceSource:
|
|
|
|
|
else:
|
|
|
|
|
self._check_function(self.depend_function)
|
|
|
|
|
|
|
|
|
|
def calculate_value(self):
|
|
|
|
|
def calculate_value(self) -> Any:
|
|
|
|
|
'''Метод для расчета значения переменной с использованием зависимостей
|
|
|
|
|
и заданной для них функции.'''
|
|
|
|
|
self._subscriptions = set()
|
|
|
|
@ -435,6 +442,8 @@ class VariableNode:
|
|
|
|
|
self.namespace.add_variable(self)
|
|
|
|
|
|
|
|
|
|
self.subscribers = set()
|
|
|
|
|
# Список текущих подписок, для проверки их актуальности при
|
|
|
|
|
# динамическом связывании.
|
|
|
|
|
self._subscriptions = set()
|
|
|
|
|
|
|
|
|
|
# Если значение переменной None -- значит она обнулена.
|
|
|
|
@ -446,6 +455,10 @@ class VariableNode:
|
|
|
|
|
if source is not None:
|
|
|
|
|
self.update_value()
|
|
|
|
|
|
|
|
|
|
# Флаг, указывающий, что значение было изменено в процессе работы
|
|
|
|
|
# утилит или с помощью тега set из шаблона.
|
|
|
|
|
self.set_by_user = False
|
|
|
|
|
|
|
|
|
|
self._readonly = False
|
|
|
|
|
|
|
|
|
|
def update_value(self) -> None:
|
|
|
|
@ -463,10 +476,12 @@ class VariableNode:
|
|
|
|
|
with self._start_calculate():
|
|
|
|
|
try:
|
|
|
|
|
value = self._source.calculate_value()
|
|
|
|
|
# Обновляем подписки
|
|
|
|
|
# Обновляем подписки. Сначала убираем лишние.
|
|
|
|
|
for subscription in self._subscriptions:
|
|
|
|
|
if subscription not in self._source.subscriptions:
|
|
|
|
|
subscription.subscribers.remove(self)
|
|
|
|
|
|
|
|
|
|
# Теперь добавляем новые.
|
|
|
|
|
for subscription in self._source.subscriptions:
|
|
|
|
|
subscription.subscribers.add(self)
|
|
|
|
|
self._subscriptions = self._source.subscriptions
|
|
|
|
@ -521,7 +536,7 @@ class VariableNode:
|
|
|
|
|
finally:
|
|
|
|
|
self.calculating = False
|
|
|
|
|
|
|
|
|
|
def get_value(self):
|
|
|
|
|
def get_value(self) -> Any:
|
|
|
|
|
'''Метод для получения значения переменной.'''
|
|
|
|
|
if self.value is None:
|
|
|
|
|
self.update_value()
|
|
|
|
@ -559,12 +574,12 @@ class NamespaceNode:
|
|
|
|
|
self.namespaces = dict()
|
|
|
|
|
self.parent = parent
|
|
|
|
|
|
|
|
|
|
def add_variable(self, variable: VariableNode):
|
|
|
|
|
def add_variable(self, variable: VariableNode) -> None:
|
|
|
|
|
'''Метод для добавления переменной в пространство имен.'''
|
|
|
|
|
self.variables.update({variable.name: variable})
|
|
|
|
|
variable.namespace = self
|
|
|
|
|
|
|
|
|
|
def add_namespace(self, namespace):
|
|
|
|
|
def add_namespace(self, namespace) -> None:
|
|
|
|
|
'''Метод для добавления пространства имен в пространство имен.'''
|
|
|
|
|
self.namespaces.update({namespace.name: namespace})
|
|
|
|
|
namespace.parent = self
|
|
|
|
@ -576,7 +591,7 @@ class NamespaceNode:
|
|
|
|
|
else:
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
def __getattr__(self, name: str):
|
|
|
|
|
def __getattr__(self, name: str) -> None:
|
|
|
|
|
'''Метод возвращает ноду пространства имен или значение переменной.'''
|
|
|
|
|
if name in self.namespaces:
|
|
|
|
|
return self.namespaces[name]
|
|
|
|
@ -588,7 +603,7 @@ class NamespaceNode:
|
|
|
|
|
variable_name=name,
|
|
|
|
|
namespace_name=self.name))
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, name: str):
|
|
|
|
|
def __getitem__(self, name: str) -> None:
|
|
|
|
|
'''Метод возвращает ноду пространства имен или ноду переменной.'''
|
|
|
|
|
if name in self.namespaces:
|
|
|
|
|
return self.namespaces[name]
|
|
|
|
|