You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import re
class VariableType:
'''Базовый класс для типов.'''
@classmethod
def check(self, value: str) -> bool:
return True
class VariableError(Exception):
pass
class VariableTypeError(Exception):
pass
class StringType(VariableType):
pass
class IntegerType(VariableType):
integer_pattern = re.compile(r"^-?\d+$")
@classmethod
def check(self, value: str) -> bool:
return self.integer_pattern.match(value)
class FloatType(VariableType):
float_pattern = re.compile(r"^-?\d+(\.\d+)?$")
@classmethod
def check(self, value: str) -> bool:
return self.integer_pattern.match(value)
class BooleanType(VariableType):
pass
class ListType(VariableType):
pass
class ReadonlyType(VariableType):
pass
class VariableNode:
def __init__(self, name, namespace, variable_type=StringType):
self.name = name
if issubclass(variable_type, VariableType):
self.variable_type = variable_type
else:
raise VariableTypeError('variable_type must be VariableType'
', but not {}'.format(type(variable_type)))
self.namespace = namespace
self.set_function = None
self.value = None
self.subscribers = set()
self.subscriptions = tuple()
def update_value(self, value=None):
if self.set_function is not None:
if self.subscriptions:
self.value = self.set_function(*(subscription.value for
subscription in
self.subscriptions))
elif value is not None:
self.value = self.set_function(value)
else:
# Пока что полагаем ее обнуленной в этой ситуации.
# TODO Обдумать поведение.
self.value = None
elif self.subscriptions:
# Пока что будем полагать, что в такой ситуации берем значение из
# последней подписки.
self.value = self.subscriptions[-1]
else:
self.value = value
@property
def fullname(self) -> str:
if self.namespace:
return "{}.{}".format(self.namespace.fullname, self.name)
else:
return self.name
def __repr__(self):
return '<Variable: {} with value: {}>'.format(self.fullname,
self.value or
'INVALIDATED')
class NamespaceNode:
def __init__(self, name='', parent=None):
self.name = name
self.variables = dict()
self.namespaces = dict()
self.parent = parent
def add_variable(self, variable: VariableNode):
self.variables.update({variable.name: variable})
variable.namespace = self
def add_namespace(self, namespace):
self.namespaces.update({namespace.name: namespace})
namespace.parent = self
@property
def fullname(self) -> str:
if self.parent is not None:
return '{}.{}'.format(self.parent.fullname, self.name)
else:
return self.name
def get_variable_node(self, name):
if name in self.variables:
return self.variables[name]
else:
raise VariableError("Variable '{variable_name}' is not found in"
" the namespace '{namespace_name}'".format(
variable_name=name,
namespace_name=self.name))
def __getattr__(self, name: str):
if name in self.namespaces:
return self.namespaces[name]
elif name in self.variables:
return self.variables[name].value
else:
raise VariableError("'{variable_name}' is not found in the"
" namespace '{namespace_name}'".format(
variable_name=name,
namespace_name=self.name))
def __repr__(self):
return '<Namespace: {}>'.format(self.fullname)