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