mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring: enable formatting with autopep8
This commit is contained in:
parent
9e4f7ca2f2
commit
18c09ecd93
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
|
@ -4,6 +4,7 @@
|
||||||
".pytest_cache/": true
|
".pytest_cache/": true
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "rsconcept/frontend/node_modules/typescript/lib",
|
"typescript.tsdk": "rsconcept/frontend/node_modules/typescript/lib",
|
||||||
|
"eslint.workingDirectories": ["rsconcept/frontend"],
|
||||||
"isort.args": [
|
"isort.args": [
|
||||||
"--line-length",
|
"--line-length",
|
||||||
"100",
|
"100",
|
||||||
|
@ -12,10 +13,16 @@
|
||||||
"--project",
|
"--project",
|
||||||
"apps"
|
"apps"
|
||||||
],
|
],
|
||||||
"eslint.workingDirectories": ["rsconcept/frontend"],
|
"autopep8.args": [
|
||||||
|
"--max-line-length",
|
||||||
|
"120",
|
||||||
|
"--aggressive",
|
||||||
|
"--ignore",
|
||||||
|
"E303"
|
||||||
|
],
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.formatOnSave": false,
|
|
||||||
"editor.defaultFormatter": "ms-python.autopep8",
|
"editor.defaultFormatter": "ms-python.autopep8",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.insertSpaces": true,
|
"editor.insertSpaces": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
|
|
|
@ -7,13 +7,14 @@ ItemType = TypeVar("ItemType")
|
||||||
|
|
||||||
class Graph(Generic[ItemType]):
|
class Graph(Generic[ItemType]):
|
||||||
''' Directed graph. '''
|
''' Directed graph. '''
|
||||||
def __init__(self, graph: Optional[dict[ItemType, list[ItemType]]]=None):
|
|
||||||
|
def __init__(self, graph: Optional[dict[ItemType, list[ItemType]]] = None):
|
||||||
if graph is None:
|
if graph is None:
|
||||||
self.outputs: dict[ItemType, list[ItemType]] = {}
|
self.outputs: dict[ItemType, list[ItemType]] = {}
|
||||||
self.inputs: dict[ItemType, list[ItemType]] = {}
|
self.inputs: dict[ItemType, list[ItemType]] = {}
|
||||||
else:
|
else:
|
||||||
self.outputs = graph
|
self.outputs = graph
|
||||||
self.inputs: dict[ItemType, list[ItemType]] = {id : [] for id in graph.keys()} #type: ignore[no-redef]
|
self.inputs: dict[ItemType, list[ItemType]] = {id: [] for id in graph.keys()} # type: ignore[no-redef]
|
||||||
for parent in graph.keys():
|
for parent in graph.keys():
|
||||||
for child in graph[parent]:
|
for child in graph[parent]:
|
||||||
self.inputs[child].append(parent)
|
self.inputs[child].append(parent)
|
||||||
|
|
|
@ -1,41 +1,54 @@
|
||||||
''' Utility: Text messages. '''
|
''' Utility: Text messages. '''
|
||||||
# pylint: skip-file
|
# pylint: skip-file
|
||||||
|
|
||||||
|
|
||||||
def constituentaNotOwned(title: str):
|
def constituentaNotOwned(title: str):
|
||||||
return f'Конституента не принадлежит схеме: {title}'
|
return f'Конституента не принадлежит схеме: {title}'
|
||||||
|
|
||||||
|
|
||||||
def substitutionNotInList():
|
def substitutionNotInList():
|
||||||
return 'Отождествляемая конституента отсутствует в списке'
|
return 'Отождествляемая конституента отсутствует в списке'
|
||||||
|
|
||||||
|
|
||||||
def schemaNotOwned():
|
def schemaNotOwned():
|
||||||
return 'Нет доступа к схеме'
|
return 'Нет доступа к схеме'
|
||||||
|
|
||||||
|
|
||||||
def renameTrivial(name: str):
|
def renameTrivial(name: str):
|
||||||
return f'Имя должно отличаться от текущего: {name}'
|
return f'Имя должно отличаться от текущего: {name}'
|
||||||
|
|
||||||
|
|
||||||
def substituteTrivial(name: str):
|
def substituteTrivial(name: str):
|
||||||
return f'Отождествление конституенты с собой не корректно: {name}'
|
return f'Отождествление конституенты с собой не корректно: {name}'
|
||||||
|
|
||||||
|
|
||||||
def substituteDouble(name: str):
|
def substituteDouble(name: str):
|
||||||
return f'Повторное отождествление: {name}'
|
return f'Повторное отождествление: {name}'
|
||||||
|
|
||||||
|
|
||||||
def aliasTaken(name: str):
|
def aliasTaken(name: str):
|
||||||
return f'Имя уже используется: {name}'
|
return f'Имя уже используется: {name}'
|
||||||
|
|
||||||
|
|
||||||
def pyconceptFailure():
|
def pyconceptFailure():
|
||||||
return 'Invalid data response from pyconcept'
|
return 'Invalid data response from pyconcept'
|
||||||
|
|
||||||
|
|
||||||
def typificationInvalidStr():
|
def typificationInvalidStr():
|
||||||
return 'Invalid typification string'
|
return 'Invalid typification string'
|
||||||
|
|
||||||
|
|
||||||
def libraryTypeUnexpected():
|
def libraryTypeUnexpected():
|
||||||
return 'Attempting to use invalid adaptor for non-RSForm item'
|
return 'Attempting to use invalid adaptor for non-RSForm item'
|
||||||
|
|
||||||
|
|
||||||
def exteorFileVersionNotSupported():
|
def exteorFileVersionNotSupported():
|
||||||
return 'Некорректный формат файла Экстеор. Сохраните файл в новой версии'
|
return 'Некорректный формат файла Экстеор. Сохраните файл в новой версии'
|
||||||
|
|
||||||
|
|
||||||
def invalidPosition():
|
def invalidPosition():
|
||||||
return 'Invalid position: should be positive integer'
|
return 'Invalid position: should be positive integer'
|
||||||
|
|
||||||
|
|
||||||
def constituentaNoStructure():
|
def constituentaNoStructure():
|
||||||
return 'Указанная конституента не обладает теоретико-множественной типизацией'
|
return 'Указанная конституента не обладает теоретико-множественной типизацией'
|
||||||
|
|
|
@ -17,7 +17,7 @@ from django.urls import reverse
|
||||||
from ..utils import apply_pattern
|
from ..utils import apply_pattern
|
||||||
|
|
||||||
_REF_ENTITY_PATTERN = re.compile(r'@{([^0-9\-].*?)\|.*?}')
|
_REF_ENTITY_PATTERN = re.compile(r'@{([^0-9\-].*?)\|.*?}')
|
||||||
_GLOBAL_ID_PATTERN = re.compile(r'([XCSADFPT][0-9]+)') # cspell:disable-line
|
_GLOBAL_ID_PATTERN = re.compile(r'([XCSADFPT][0-9]+)') # cspell:disable-line
|
||||||
|
|
||||||
|
|
||||||
def _empty_forms():
|
def _empty_forms():
|
||||||
|
|
|
@ -29,6 +29,7 @@ _INSERT_LAST: int = -1
|
||||||
|
|
||||||
class RSForm:
|
class RSForm:
|
||||||
''' RSForm is math form of conceptual schema. '''
|
''' RSForm is math form of conceptual schema. '''
|
||||||
|
|
||||||
def __init__(self, item: LibraryItem):
|
def __init__(self, item: LibraryItem):
|
||||||
if item.item_type != LibraryItemType.RSFORM:
|
if item.item_type != LibraryItemType.RSFORM:
|
||||||
raise ValueError(msg.libraryTypeUnexpected())
|
raise ValueError(msg.libraryTypeUnexpected())
|
||||||
|
@ -144,7 +145,7 @@ class RSForm:
|
||||||
for (value, _) in CstType.choices:
|
for (value, _) in CstType.choices:
|
||||||
indices[value] = self.get_max_index(cast(CstType, value))
|
indices[value] = self.get_max_index(cast(CstType, value))
|
||||||
|
|
||||||
mapping: dict[str, str] = {}
|
mapping: dict[str, str] = {}
|
||||||
for cst in items:
|
for cst in items:
|
||||||
indices[cst.cst_type] = indices[cst.cst_type] + 1
|
indices[cst.cst_type] = indices[cst.cst_type] + 1
|
||||||
newAlias = f'{get_type_prefix(cst.cst_type)}{indices[cst.cst_type]}'
|
newAlias = f'{get_type_prefix(cst.cst_type)}{indices[cst.cst_type]}'
|
||||||
|
@ -195,7 +196,7 @@ class RSForm:
|
||||||
self.item.save()
|
self.item.save()
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def create_cst(self, data: dict, insert_after: Optional[str]=None) -> Constituenta:
|
def create_cst(self, data: dict, insert_after: Optional[str] = None) -> Constituenta:
|
||||||
''' Create new cst from data. '''
|
''' Create new cst from data. '''
|
||||||
resolver = self.resolver()
|
resolver = self.resolver()
|
||||||
cst = self._insert_new(data, insert_after)
|
cst = self._insert_new(data, insert_after)
|
||||||
|
@ -224,7 +225,7 @@ class RSForm:
|
||||||
):
|
):
|
||||||
''' Execute constituenta substitution. '''
|
''' Execute constituenta substitution. '''
|
||||||
assert original.pk != substitution.pk
|
assert original.pk != substitution.pk
|
||||||
mapping = { original.alias: substitution.alias }
|
mapping = {original.alias: substitution.alias}
|
||||||
self.apply_mapping(mapping)
|
self.apply_mapping(mapping)
|
||||||
if transfer_term:
|
if transfer_term:
|
||||||
substitution.term_raw = original.term_raw
|
substitution.term_raw = original.term_raw
|
||||||
|
@ -331,8 +332,8 @@ class RSForm:
|
||||||
return
|
return
|
||||||
update_list = \
|
update_list = \
|
||||||
Constituenta.objects \
|
Constituenta.objects \
|
||||||
.only('id', 'order', 'schema') \
|
.only('id', 'order', 'schema') \
|
||||||
.filter(schema=self.item, order__gte=start)
|
.filter(schema=self.item, order__gte=start)
|
||||||
for cst in update_list:
|
for cst in update_list:
|
||||||
cst.order += shift
|
cst.order += shift
|
||||||
Constituenta.objects.bulk_update(update_list, ['order'])
|
Constituenta.objects.bulk_update(update_list, ['order'])
|
||||||
|
@ -350,7 +351,7 @@ class RSForm:
|
||||||
if position == _INSERT_LAST:
|
if position == _INSERT_LAST:
|
||||||
position = lastPosition + 1
|
position = lastPosition + 1
|
||||||
else:
|
else:
|
||||||
position = max(1, min(position, lastPosition + 1))
|
position = max(1, min(position, lastPosition + 1))
|
||||||
return position
|
return position
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
@ -362,7 +363,7 @@ class RSForm:
|
||||||
cst.save()
|
cst.save()
|
||||||
order += 1
|
order += 1
|
||||||
|
|
||||||
def _insert_new(self, data: dict, insert_after: Optional[str]=None) -> Constituenta:
|
def _insert_new(self, data: dict, insert_after: Optional[str] = None) -> Constituenta:
|
||||||
if insert_after is not None:
|
if insert_after is not None:
|
||||||
cst_after = Constituenta.objects.get(pk=insert_after)
|
cst_after = Constituenta.objects.get(pk=insert_after)
|
||||||
return self.insert_new(data['alias'], data['cst_type'], cst_after.order + 1)
|
return self.insert_new(data['alias'], data['cst_type'], cst_after.order + 1)
|
||||||
|
@ -426,21 +427,22 @@ class RSForm:
|
||||||
|
|
||||||
class SemanticInfo:
|
class SemanticInfo:
|
||||||
''' Semantic information derived from constituents. '''
|
''' Semantic information derived from constituents. '''
|
||||||
|
|
||||||
def __init__(self, schema: RSForm):
|
def __init__(self, schema: RSForm):
|
||||||
self._graph = schema._graph_formal()
|
self._graph = schema._graph_formal()
|
||||||
self._items = list(
|
self._items = list(
|
||||||
schema.constituents() \
|
schema.constituents()
|
||||||
.only('id', 'alias', 'cst_type', 'definition_formal') \
|
.only('id', 'alias', 'cst_type', 'definition_formal')
|
||||||
.order_by('order')
|
.order_by('order')
|
||||||
)
|
)
|
||||||
self._cst_by_alias = { cst.alias : cst for cst in self._items }
|
self._cst_by_alias = {cst.alias: cst for cst in self._items}
|
||||||
self._cst_by_ID = { cst.id : cst for cst in self._items }
|
self._cst_by_ID = {cst.id: cst for cst in self._items}
|
||||||
self.info = {
|
self.info = {
|
||||||
cst.id: {
|
cst.id: {
|
||||||
'is_simple' : False, \
|
'is_simple': False,
|
||||||
'is_template' : False, \
|
'is_template': False,
|
||||||
'parent' : cst.id, \
|
'parent': cst.id,
|
||||||
'children' : []
|
'children': []
|
||||||
}
|
}
|
||||||
for cst in self._items
|
for cst in self._items
|
||||||
}
|
}
|
||||||
|
@ -483,8 +485,8 @@ class SemanticInfo:
|
||||||
|
|
||||||
dependencies = self._graph.inputs[target.id]
|
dependencies = self._graph.inputs[target.id]
|
||||||
has_complex_dependency = any(
|
has_complex_dependency = any(
|
||||||
self.is_template(cst_id) and \
|
self.is_template(cst_id) and
|
||||||
not self.is_simple_expression(cst_id) for cst_id in dependencies
|
not self.is_simple_expression(cst_id) for cst_id in dependencies
|
||||||
)
|
)
|
||||||
if has_complex_dependency:
|
if has_complex_dependency:
|
||||||
return False
|
return False
|
||||||
|
@ -534,11 +536,11 @@ class SemanticInfo:
|
||||||
|
|
||||||
parent_info = self[parent.id]
|
parent_info = self[parent.id]
|
||||||
if not is_base_set(parent.cst_type) and \
|
if not is_base_set(parent.cst_type) and \
|
||||||
(not parent_info['is_template'] or not parent_info['is_simple']):
|
(not parent_info['is_template'] or not parent_info['is_simple']):
|
||||||
sources.add(parent_info['parent'])
|
sources.add(parent_info['parent'])
|
||||||
return sources
|
return sources
|
||||||
|
|
||||||
def _need_check_head(self, sources: set[int], head: str)-> bool:
|
def _need_check_head(self, sources: set[int], head: str) -> bool:
|
||||||
if len(sources) == 0:
|
if len(sources) == 0:
|
||||||
return True
|
return True
|
||||||
elif len(sources) != 1:
|
elif len(sources) != 1:
|
||||||
|
@ -551,15 +553,16 @@ class SemanticInfo:
|
||||||
|
|
||||||
class _OrderManager:
|
class _OrderManager:
|
||||||
''' Ordering helper class '''
|
''' Ordering helper class '''
|
||||||
|
|
||||||
def __init__(self, schema: RSForm):
|
def __init__(self, schema: RSForm):
|
||||||
self._semantic = schema.semantic()
|
self._semantic = schema.semantic()
|
||||||
self._graph = schema._graph_formal()
|
self._graph = schema._graph_formal()
|
||||||
self._items = list(
|
self._items = list(
|
||||||
schema.constituents() \
|
schema.constituents()
|
||||||
.only('id', 'order', 'alias', 'cst_type', 'definition_formal') \
|
.only('id', 'order', 'alias', 'cst_type', 'definition_formal')
|
||||||
.order_by('order')
|
.order_by('order')
|
||||||
)
|
)
|
||||||
self._cst_by_ID = { cst.id : cst for cst in self._items }
|
self._cst_by_ID = {cst.id: cst for cst in self._items}
|
||||||
|
|
||||||
def restore_order(self) -> None:
|
def restore_order(self) -> None:
|
||||||
''' Implement order restoration process. '''
|
''' Implement order restoration process. '''
|
||||||
|
@ -579,9 +582,9 @@ class _OrderManager:
|
||||||
result = [cst for cst in self._items if cst.cst_type == CstType.BASE]
|
result = [cst for cst in self._items if cst.cst_type == CstType.BASE]
|
||||||
result = result + [cst for cst in self._items if cst.cst_type == CstType.CONSTANT]
|
result = result + [cst for cst in self._items if cst.cst_type == CstType.CONSTANT]
|
||||||
kernel = [
|
kernel = [
|
||||||
cst.id for cst in self._items if \
|
cst.id for cst in self._items if
|
||||||
cst.cst_type in [CstType.STRUCTURED, CstType.AXIOM] or \
|
cst.cst_type in [CstType.STRUCTURED, CstType.AXIOM] or
|
||||||
self._cst_by_ID[self._semantic.parent(cst.id)].cst_type == CstType.STRUCTURED
|
self._cst_by_ID[self._semantic.parent(cst.id)].cst_type == CstType.STRUCTURED
|
||||||
]
|
]
|
||||||
kernel = kernel + self._graph.expand_inputs(kernel)
|
kernel = kernel + self._graph.expand_inputs(kernel)
|
||||||
result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.id in kernel]
|
result = result + [cst for cst in self._items if result.count(cst) == 0 and cst.id in kernel]
|
||||||
|
@ -604,7 +607,6 @@ class _OrderManager:
|
||||||
result.append(child)
|
result.append(child)
|
||||||
self._items = result
|
self._items = result
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def _save_order(self) -> None:
|
def _save_order(self) -> None:
|
||||||
order = 1
|
order = 1
|
||||||
|
|
|
@ -9,7 +9,7 @@ import pyconcept
|
||||||
from .. import messages as msg
|
from .. import messages as msg
|
||||||
from .Constituenta import CstType
|
from .Constituenta import CstType
|
||||||
|
|
||||||
_RE_GLOBALS = r'[XCSADFPT]\d+' # cspell:disable-line
|
_RE_GLOBALS = r'[XCSADFPT]\d+' # cspell:disable-line
|
||||||
_RE_TEMPLATE = r'R\d+'
|
_RE_TEMPLATE = r'R\d+'
|
||||||
_RE_COMPLEX_SYMBOLS = r'[∀∃×ℬ;|:]'
|
_RE_COMPLEX_SYMBOLS = r'[∀∃×ℬ;|:]'
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ def get_type_prefix(cst_type: CstType) -> str:
|
||||||
case CstType.STRUCTURED: return 'S'
|
case CstType.STRUCTURED: return 'S'
|
||||||
case CstType.AXIOM: return 'A'
|
case CstType.AXIOM: return 'A'
|
||||||
case CstType.TERM: return 'D'
|
case CstType.TERM: return 'D'
|
||||||
case CstType.FUNCTION: return 'F'
|
case CstType.FUNCTION: return 'F'
|
||||||
case CstType.PREDICATE: return 'P'
|
case CstType.PREDICATE: return 'P'
|
||||||
case CstType.THEOREM: return 'T'
|
case CstType.THEOREM: return 'T'
|
||||||
return 'X'
|
return 'X'
|
||||||
|
@ -140,9 +140,9 @@ def generate_structure(alias: str, expression: str, parse: dict) -> list:
|
||||||
for (n, item) in enumerate(ast):
|
for (n, item) in enumerate(ast):
|
||||||
if n == 0:
|
if n == 0:
|
||||||
generated.append({
|
generated.append({
|
||||||
'text': link, # generated text
|
'text': link, # generated text
|
||||||
'operation': None, # applied operation. None if text should be skipped
|
'operation': None, # applied operation. None if text should be skipped
|
||||||
'is_boolean': False # is the result of operation has an additional boolean
|
'is_boolean': False # is the result of operation has an additional boolean
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ def generate_structure(alias: str, expression: str, parse: dict) -> list:
|
||||||
parent_type = ast[parent_index]['typeID']
|
parent_type = ast[parent_index]['typeID']
|
||||||
parent_text = generated[parent_index]['text']
|
parent_text = generated[parent_index]['text']
|
||||||
parent_is_boolean = generated[parent_index]['is_boolean']
|
parent_is_boolean = generated[parent_index]['is_boolean']
|
||||||
assert(parent_type in [TokenType.BOOLEAN, TokenType.DECART])
|
assert parent_type in [TokenType.BOOLEAN, TokenType.DECART]
|
||||||
|
|
||||||
if parent_is_boolean:
|
if parent_is_boolean:
|
||||||
if parent_type == TokenType.BOOLEAN:
|
if parent_type == TokenType.BOOLEAN:
|
||||||
|
|
|
@ -65,6 +65,7 @@ class ErrorDescriptionSerializer(serializers.Serializer):
|
||||||
child=serializers.CharField()
|
child=serializers.CharField()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class NodeDataSerializer(serializers.Serializer):
|
class NodeDataSerializer(serializers.Serializer):
|
||||||
''' Serializer: Node data. '''
|
''' Serializer: Node data. '''
|
||||||
dataType = serializers.CharField()
|
dataType = serializers.CharField()
|
||||||
|
@ -74,11 +75,11 @@ class NodeDataSerializer(serializers.Serializer):
|
||||||
class ASTNodeSerializer(serializers.Serializer):
|
class ASTNodeSerializer(serializers.Serializer):
|
||||||
''' Serializer: Syntax tree node. '''
|
''' Serializer: Syntax tree node. '''
|
||||||
uid = serializers.IntegerField()
|
uid = serializers.IntegerField()
|
||||||
parent = serializers.IntegerField() # type: ignore
|
parent = serializers.IntegerField() # type: ignore
|
||||||
typeID = serializers.IntegerField()
|
typeID = serializers.IntegerField()
|
||||||
start = serializers.IntegerField()
|
start = serializers.IntegerField()
|
||||||
finish = serializers.IntegerField()
|
finish = serializers.IntegerField()
|
||||||
data = NodeDataSerializer() # type: ignore
|
data = NodeDataSerializer() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class ExpressionParseSerializer(serializers.Serializer):
|
class ExpressionParseSerializer(serializers.Serializer):
|
||||||
|
@ -91,7 +92,7 @@ class ExpressionParseSerializer(serializers.Serializer):
|
||||||
ast = serializers.ListField(
|
ast = serializers.ListField(
|
||||||
child=ASTNodeSerializer()
|
child=ASTNodeSerializer()
|
||||||
)
|
)
|
||||||
errors = serializers.ListField( # type: ignore
|
errors = serializers.ListField( # type: ignore
|
||||||
child=ErrorDescriptionSerializer()
|
child=ErrorDescriptionSerializer()
|
||||||
)
|
)
|
||||||
args = serializers.ListField(
|
args = serializers.ListField(
|
||||||
|
@ -116,7 +117,7 @@ class ReferenceDataSerializer(serializers.Serializer):
|
||||||
class ReferenceSerializer(serializers.Serializer):
|
class ReferenceSerializer(serializers.Serializer):
|
||||||
''' Serializer: Language reference. '''
|
''' Serializer: Language reference. '''
|
||||||
type = serializers.CharField()
|
type = serializers.CharField()
|
||||||
data = ReferenceDataSerializer() # type: ignore
|
data = ReferenceDataSerializer() # type: ignore
|
||||||
pos_input = TextPositionSerializer()
|
pos_input = TextPositionSerializer()
|
||||||
pos_output = TextPositionSerializer()
|
pos_output = TextPositionSerializer()
|
||||||
|
|
||||||
|
|
|
@ -88,12 +88,12 @@ class CstSerializer(serializers.ModelSerializer):
|
||||||
read_only_fields = ('id', 'order', 'alias', 'cst_type', 'definition_resolved', 'term_resolved')
|
read_only_fields = ('id', 'order', 'alias', 'cst_type', 'definition_resolved', 'term_resolved')
|
||||||
|
|
||||||
def update(self, instance: Constituenta, validated_data) -> Constituenta:
|
def update(self, instance: Constituenta, validated_data) -> Constituenta:
|
||||||
data = validated_data # Note: use alias for better code readability
|
data = validated_data # Note: use alias for better code readability
|
||||||
schema = RSForm(instance.schema)
|
schema = RSForm(instance.schema)
|
||||||
definition: Optional[str] = data['definition_raw'] if 'definition_raw' in data else None
|
definition: Optional[str] = data['definition_raw'] if 'definition_raw' in data else None
|
||||||
term: Optional[str] = data['term_raw'] if 'term_raw' in data else None
|
term: Optional[str] = data['term_raw'] if 'term_raw' in data else None
|
||||||
term_changed = 'term_forms' in data
|
term_changed = 'term_forms' in data
|
||||||
if definition is not None and definition != instance.definition_raw :
|
if definition is not None and definition != instance.definition_raw:
|
||||||
data['definition_resolved'] = schema.resolver().resolve(definition)
|
data['definition_resolved'] = schema.resolver().resolve(definition)
|
||||||
if term is not None and term != instance.term_raw:
|
if term is not None and term != instance.term_raw:
|
||||||
data['term_resolved'] = schema.resolver().resolve(term)
|
data['term_resolved'] = schema.resolver().resolve(term)
|
||||||
|
@ -368,7 +368,7 @@ class CstSubstituteSerializer(serializers.Serializer):
|
||||||
class InlineSynthesisSerializer(serializers.Serializer):
|
class InlineSynthesisSerializer(serializers.Serializer):
|
||||||
''' Serializer: Inline synthesis operation input. '''
|
''' Serializer: Inline synthesis operation input. '''
|
||||||
receiver = PKField(many=False, queryset=LibraryItem.objects.all())
|
receiver = PKField(many=False, queryset=LibraryItem.objects.all())
|
||||||
source = PKField(many=False, queryset=LibraryItem.objects.all()) # type: ignore
|
source = PKField(many=False, queryset=LibraryItem.objects.all()) # type: ignore
|
||||||
items = PKField(many=True, queryset=Constituenta.objects.all())
|
items = PKField(many=True, queryset=Constituenta.objects.all())
|
||||||
substitutions = serializers.ListField(
|
substitutions = serializers.ListField(
|
||||||
child=CstSubstituteSerializerBase()
|
child=CstSubstituteSerializerBase()
|
||||||
|
|
|
@ -12,6 +12,7 @@ _TRS_VERSION_MIN = 16
|
||||||
_TRS_VERSION = 16
|
_TRS_VERSION = 16
|
||||||
_TRS_HEADER = 'Exteor 4.8.13.1000 - 30/05/2022'
|
_TRS_HEADER = 'Exteor 4.8.13.1000 - 30/05/2022'
|
||||||
|
|
||||||
|
|
||||||
class FileSerializer(serializers.Serializer):
|
class FileSerializer(serializers.Serializer):
|
||||||
''' Serializer: File input. '''
|
''' Serializer: File input. '''
|
||||||
file = serializers.FileField(allow_empty_file=False)
|
file = serializers.FileField(allow_empty_file=False)
|
||||||
|
@ -25,6 +26,7 @@ class RSFormUploadSerializer(serializers.Serializer):
|
||||||
|
|
||||||
class RSFormTRSSerializer(serializers.Serializer):
|
class RSFormTRSSerializer(serializers.Serializer):
|
||||||
''' Serializer: TRS file production and loading for RSForm. '''
|
''' Serializer: TRS file production and loading for RSForm. '''
|
||||||
|
|
||||||
def to_representation(self, instance: RSForm) -> dict:
|
def to_representation(self, instance: RSForm) -> dict:
|
||||||
result = self._prepare_json_rsform(instance)
|
result = self._prepare_json_rsform(instance)
|
||||||
items = instance.constituents().order_by('order')
|
items = instance.constituents().order_by('order')
|
||||||
|
@ -115,7 +117,7 @@ class RSFormTRSSerializer(serializers.Serializer):
|
||||||
if self.context['load_meta']:
|
if self.context['load_meta']:
|
||||||
result['title'] = data.get('title', 'Без названия')
|
result['title'] = data.get('title', 'Без названия')
|
||||||
result['alias'] = data.get('alias', '')
|
result['alias'] = data.get('alias', '')
|
||||||
result['comment']= data.get('comment', '')
|
result['comment'] = data.get('comment', '')
|
||||||
if 'id' in data:
|
if 'id' in data:
|
||||||
result['id'] = data['id']
|
result['id'] = data['id']
|
||||||
self.instance = RSForm(LibraryItem.objects.get(pk=result['id']))
|
self.instance = RSForm(LibraryItem.objects.get(pk=result['id']))
|
||||||
|
|
|
@ -10,6 +10,7 @@ from ..models import RSForm
|
||||||
|
|
||||||
class PyConceptAdapter:
|
class PyConceptAdapter:
|
||||||
''' RSForm adapter for interacting with pyconcept module. '''
|
''' RSForm adapter for interacting with pyconcept module. '''
|
||||||
|
|
||||||
def __init__(self, data: Union[RSForm, dict]):
|
def __init__(self, data: Union[RSForm, dict]):
|
||||||
try:
|
try:
|
||||||
if 'items' in cast(dict, data):
|
if 'items' in cast(dict, data):
|
||||||
|
|
|
@ -14,6 +14,7 @@ class NewCstResponse(serializers.Serializer):
|
||||||
new_cst = serializers.IntegerField()
|
new_cst = serializers.IntegerField()
|
||||||
schema = RSFormParseSerializer()
|
schema = RSFormParseSerializer()
|
||||||
|
|
||||||
|
|
||||||
class NewMultiCstResponse(serializers.Serializer):
|
class NewMultiCstResponse(serializers.Serializer):
|
||||||
''' Serializer: Create multiple cst response. '''
|
''' Serializer: Create multiple cst response. '''
|
||||||
cst_list = serializers.ListField(
|
cst_list = serializers.ListField(
|
||||||
|
@ -21,6 +22,7 @@ class NewMultiCstResponse(serializers.Serializer):
|
||||||
)
|
)
|
||||||
schema = RSFormParseSerializer()
|
schema = RSFormParseSerializer()
|
||||||
|
|
||||||
|
|
||||||
class NewVersionResponse(serializers.Serializer):
|
class NewVersionResponse(serializers.Serializer):
|
||||||
''' Serializer: Create cst response. '''
|
''' Serializer: Create cst response. '''
|
||||||
version = serializers.IntegerField()
|
version = serializers.IntegerField()
|
||||||
|
|
|
@ -8,6 +8,7 @@ from apps.rsform.models import Constituenta, CstType, LibraryItem, LibraryItemTy
|
||||||
|
|
||||||
class TestConstituenta(TestCase):
|
class TestConstituenta(TestCase):
|
||||||
''' Testing Constituenta model. '''
|
''' Testing Constituenta model. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.schema1 = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, title='Test1')
|
self.schema1 = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, title='Test1')
|
||||||
self.schema2 = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, title='Test2')
|
self.schema2 = LibraryItem.objects.create(item_type=LibraryItemType.RSFORM, title='Test2')
|
||||||
|
|
|
@ -6,6 +6,7 @@ from apps.rsform.models import LibraryItem, LibraryItemType, Subscription, User
|
||||||
|
|
||||||
class TestLibraryItem(TestCase):
|
class TestLibraryItem(TestCase):
|
||||||
''' Testing LibraryItem model. '''
|
''' Testing LibraryItem model. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user1 = User.objects.create(username='User1')
|
self.user1 = User.objects.create(username='User1')
|
||||||
self.user2 = User.objects.create(username='User2')
|
self.user2 = User.objects.create(username='User2')
|
||||||
|
|
|
@ -7,6 +7,7 @@ from apps.rsform.models import Constituenta, CstType, RSForm, User
|
||||||
|
|
||||||
class TestRSForm(TestCase):
|
class TestRSForm(TestCase):
|
||||||
''' Testing RSForm wrapper. '''
|
''' Testing RSForm wrapper. '''
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.user1 = User.objects.create(username='User1')
|
self.user1 = User.objects.create(username='User1')
|
||||||
self.user2 = User.objects.create(username='User2')
|
self.user2 = User.objects.create(username='User2')
|
||||||
|
@ -81,7 +82,7 @@ class TestRSForm(TestCase):
|
||||||
def test_insert_at_reorder(self):
|
def test_insert_at_reorder(self):
|
||||||
self.schema.insert_new('X1')
|
self.schema.insert_new('X1')
|
||||||
d1 = self.schema.insert_new('D1')
|
d1 = self.schema.insert_new('D1')
|
||||||
d2 = self.schema.insert_new('D2',position=1)
|
d2 = self.schema.insert_new('D2', position=1)
|
||||||
d1.refresh_from_db()
|
d1.refresh_from_db()
|
||||||
self.assertEqual(d1.order, 3)
|
self.assertEqual(d1.order, 3)
|
||||||
self.assertEqual(d2.order, 1)
|
self.assertEqual(d2.order, 1)
|
||||||
|
@ -345,8 +346,8 @@ class TestRSForm(TestCase):
|
||||||
definition_resolved='очень сильный человек'
|
definition_resolved='очень сильный человек'
|
||||||
)
|
)
|
||||||
|
|
||||||
x1.term_raw='слон'
|
x1.term_raw = 'слон'
|
||||||
x1.term_resolved='слон'
|
x1.term_resolved = 'слон'
|
||||||
x1.save()
|
x1.save()
|
||||||
|
|
||||||
self.schema.on_term_change([x1.id])
|
self.schema.on_term_change([x1.id])
|
||||||
|
|
|
@ -8,7 +8,6 @@ from apps.rsform.utils import apply_pattern, fix_old_references
|
||||||
class TestUtils(unittest.TestCase):
|
class TestUtils(unittest.TestCase):
|
||||||
''' Test various utility functions. '''
|
''' Test various utility functions. '''
|
||||||
|
|
||||||
|
|
||||||
def test_apply_mapping_patter(self):
|
def test_apply_mapping_patter(self):
|
||||||
mapping = {'X101': 'X20'}
|
mapping = {'X101': 'X20'}
|
||||||
pattern = re.compile(r'(X[0-9]+)')
|
pattern = re.compile(r'(X[0-9]+)')
|
||||||
|
|
|
@ -15,16 +15,18 @@ _REF_OLD_PATTERN = re.compile(r'@{([^0-9\-][^\}\|\{]*?)\|([^\}\|\{]*?)\|([^\}\|\
|
||||||
|
|
||||||
class ObjectOwnerOrAdmin(BasePermission):
|
class ObjectOwnerOrAdmin(BasePermission):
|
||||||
''' Permission for object ownership restriction '''
|
''' Permission for object ownership restriction '''
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if request.user == obj.owner:
|
if request.user == obj.owner:
|
||||||
return True
|
return True
|
||||||
if not hasattr(request.user, 'is_staff'):
|
if not hasattr(request.user, 'is_staff'):
|
||||||
return False
|
return False
|
||||||
return request.user.is_staff # type: ignore
|
return request.user.is_staff # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class IsClaimable(IsAuthenticated):
|
class IsClaimable(IsAuthenticated):
|
||||||
''' Permission for object ownership restriction '''
|
''' Permission for object ownership restriction '''
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if not super().has_permission(request, view):
|
if not super().has_permission(request, view):
|
||||||
return False
|
return False
|
||||||
|
@ -33,22 +35,24 @@ class IsClaimable(IsAuthenticated):
|
||||||
|
|
||||||
class SchemaOwnerOrAdmin(BasePermission):
|
class SchemaOwnerOrAdmin(BasePermission):
|
||||||
''' Permission for object ownership restriction '''
|
''' Permission for object ownership restriction '''
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if request.user == obj.schema.owner:
|
if request.user == obj.schema.owner:
|
||||||
return True
|
return True
|
||||||
if not hasattr(request.user, 'is_staff'):
|
if not hasattr(request.user, 'is_staff'):
|
||||||
return False
|
return False
|
||||||
return request.user.is_staff # type: ignore
|
return request.user.is_staff # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class ItemOwnerOrAdmin(BasePermission):
|
class ItemOwnerOrAdmin(BasePermission):
|
||||||
''' Permission for object ownership restriction '''
|
''' Permission for object ownership restriction '''
|
||||||
|
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if request.user == obj.item.owner:
|
if request.user == obj.item.owner:
|
||||||
return True
|
return True
|
||||||
if not hasattr(request.user, 'is_staff'):
|
if not hasattr(request.user, 'is_staff'):
|
||||||
return False
|
return False
|
||||||
return request.user.is_staff # type: ignore
|
return request.user.is_staff # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def read_zipped_json(data, json_filename: str) -> dict:
|
def read_zipped_json(data, json_filename: str) -> dict:
|
||||||
|
@ -77,11 +81,11 @@ def apply_pattern(text: str, mapping: dict[str, str], pattern: re.Pattern[str])
|
||||||
for segment in re.finditer(pattern, text):
|
for segment in re.finditer(pattern, text):
|
||||||
entity = segment.group(1)
|
entity = segment.group(1)
|
||||||
if entity in mapping:
|
if entity in mapping:
|
||||||
output += text[pos_input : segment.start(1)]
|
output += text[pos_input: segment.start(1)]
|
||||||
output += mapping[entity]
|
output += mapping[entity]
|
||||||
output += text[segment.end(1) : segment.end(0)]
|
output += text[segment.end(1): segment.end(0)]
|
||||||
pos_input = segment.end(0)
|
pos_input = segment.end(0)
|
||||||
output += text[pos_input : len(text)]
|
output += text[pos_input: len(text)]
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,10 +96,10 @@ def fix_old_references(text: str) -> str:
|
||||||
pos_input: int = 0
|
pos_input: int = 0
|
||||||
output: str = ''
|
output: str = ''
|
||||||
for segment in re.finditer(_REF_OLD_PATTERN, text):
|
for segment in re.finditer(_REF_OLD_PATTERN, text):
|
||||||
output += text[pos_input : segment.start(0)]
|
output += text[pos_input: segment.start(0)]
|
||||||
output += f'@{{{segment.group(1)}|{segment.group(2)},{segment.group(3)}}}'
|
output += f'@{{{segment.group(1)}|{segment.group(2)},{segment.group(3)}}}'
|
||||||
pos_input = segment.end(0)
|
pos_input = segment.end(0)
|
||||||
output += text[pos_input : len(text)]
|
output += text[pos_input: len(text)]
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -90,12 +90,12 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
cst = cast(m.Constituenta, serializer.validated_data['target'])
|
cst = cast(m.Constituenta, serializer.validated_data['target'])
|
||||||
|
|
||||||
schema_details = s.RSFormParseSerializer(schema.item).data['items']
|
schema_details = s.RSFormParseSerializer(schema.item).data['items']
|
||||||
cst_parse = next(item for item in schema_details if item['id']==cst.id)['parse']
|
cst_parse = next(item for item in schema_details if item['id'] == cst.id)['parse']
|
||||||
if not cst_parse['typification']:
|
if not cst_parse['typification']:
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_400_BAD_REQUEST,
|
status=c.HTTP_400_BAD_REQUEST,
|
||||||
data={f'{cst.id}': msg.constituentaNoStructure()}
|
data={f'{cst.id}': msg.constituentaNoStructure()}
|
||||||
)
|
)
|
||||||
|
|
||||||
result = schema.produce_structure(cst, cst_parse)
|
result = schema.produce_structure(cst, cst_parse)
|
||||||
return Response(
|
return Response(
|
||||||
|
@ -131,7 +131,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
cst.cst_type = serializer.validated_data['cst_type']
|
cst.cst_type = serializer.validated_data['cst_type']
|
||||||
cst.save()
|
cst.save()
|
||||||
|
|
||||||
mapping = { old_alias: cst.alias }
|
mapping = {old_alias: cst.alias}
|
||||||
schema.apply_mapping(mapping, change_aliases=False)
|
schema.apply_mapping(mapping, change_aliases=False)
|
||||||
schema.item.refresh_from_db()
|
schema.item.refresh_from_db()
|
||||||
cst.refresh_from_db()
|
cst.refresh_from_db()
|
||||||
|
@ -350,7 +350,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
serializer = s.ExpressionSerializer(data=request.data)
|
serializer = s.ExpressionSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
expression = serializer.validated_data['expression']
|
expression = serializer.validated_data['expression']
|
||||||
schema = s.PyConceptAdapter(self._get_schema())
|
schema = s.PyConceptAdapter(self._get_schema())
|
||||||
result = pyconcept.check_expression(json.dumps(schema.data), expression)
|
result = pyconcept.check_expression(json.dumps(schema.data), expression)
|
||||||
return Response(
|
return Response(
|
||||||
status=c.HTTP_200_OK,
|
status=c.HTTP_200_OK,
|
||||||
|
|
|
@ -121,14 +121,14 @@ def retrieve_version(request: Request, pk_item: int, pk_version: int):
|
||||||
|
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
summary='export versioned data as file',
|
summary='export versioned data as file',
|
||||||
tags=['Version'],
|
tags=['Version'],
|
||||||
request=None,
|
request=None,
|
||||||
responses={
|
responses={
|
||||||
(c.HTTP_200_OK, 'application/zip'): bytes,
|
(c.HTTP_200_OK, 'application/zip'): bytes,
|
||||||
c.HTTP_404_NOT_FOUND: None
|
c.HTTP_404_NOT_FOUND: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def export_file(request: Request, pk: int):
|
def export_file(request: Request, pk: int):
|
||||||
''' Endpoint: Download Exteor compatible file for versioned data. '''
|
''' Endpoint: Download Exteor compatible file for versioned data. '''
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
''' Utility: Text messages. '''
|
''' Utility: Text messages. '''
|
||||||
# pylint: skip-file
|
# pylint: skip-file
|
||||||
|
|
||||||
|
|
||||||
def passwordAuthFailed():
|
def passwordAuthFailed():
|
||||||
return 'Неизвестное сочетание имени пользователя и пароля'
|
return 'Неизвестное сочетание имени пользователя и пароля'
|
||||||
|
|
||||||
|
|
||||||
def passwordsNotMatch():
|
def passwordsNotMatch():
|
||||||
return 'Введенные пароли не совпадают'
|
return 'Введенные пароли не совпадают'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
''' Models: User profile and Authentification. '''
|
''' Models: User profile and Authorization. '''
|
||||||
|
|
||||||
# Note: using User import to isolate original
|
# Note: using User import to isolate original
|
||||||
# pylint: disable=unused-import,ungrouped-imports
|
# pylint: disable=unused-import,ungrouped-imports
|
||||||
|
|
|
@ -23,6 +23,7 @@ def _get_secret(key: str, default):
|
||||||
return f.read()
|
return f.read()
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
_TRUE_VARIANTS = [True, 'True', '1']
|
_TRUE_VARIANTS = [True, 'True', '1']
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user