diff --git a/.vscode/settings.json b/.vscode/settings.json index 057963ff..222fdba3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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": { diff --git a/rsconcept/backend/apps/rsform/graph.py b/rsconcept/backend/apps/rsform/graph.py index 30ea144f..4177840d 100644 --- a/rsconcept/backend/apps/rsform/graph.py +++ b/rsconcept/backend/apps/rsform/graph.py @@ -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) diff --git a/rsconcept/backend/apps/rsform/messages.py b/rsconcept/backend/apps/rsform/messages.py index d65d2b9a..16e47b69 100644 --- a/rsconcept/backend/apps/rsform/messages.py +++ b/rsconcept/backend/apps/rsform/messages.py @@ -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 'Указанная конституента не обладает теоретико-множественной типизацией' diff --git a/rsconcept/backend/apps/rsform/models/Constituenta.py b/rsconcept/backend/apps/rsform/models/Constituenta.py index 840b4d70..fe09a12f 100644 --- a/rsconcept/backend/apps/rsform/models/Constituenta.py +++ b/rsconcept/backend/apps/rsform/models/Constituenta.py @@ -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(): diff --git a/rsconcept/backend/apps/rsform/models/api_RSForm.py b/rsconcept/backend/apps/rsform/models/api_RSForm.py index f2af6014..e0c03e12 100644 --- a/rsconcept/backend/apps/rsform/models/api_RSForm.py +++ b/rsconcept/backend/apps/rsform/models/api_RSForm.py @@ -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 diff --git a/rsconcept/backend/apps/rsform/models/api_RSLanguage.py b/rsconcept/backend/apps/rsform/models/api_RSLanguage.py index c92493b9..d32a8c4e 100644 --- a/rsconcept/backend/apps/rsform/models/api_RSLanguage.py +++ b/rsconcept/backend/apps/rsform/models/api_RSLanguage.py @@ -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: diff --git a/rsconcept/backend/apps/rsform/serializers/basics.py b/rsconcept/backend/apps/rsform/serializers/basics.py index c6980e19..40afd0a5 100644 --- a/rsconcept/backend/apps/rsform/serializers/basics.py +++ b/rsconcept/backend/apps/rsform/serializers/basics.py @@ -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() diff --git a/rsconcept/backend/apps/rsform/serializers/data_access.py b/rsconcept/backend/apps/rsform/serializers/data_access.py index 7b37b787..fe8c9ee4 100644 --- a/rsconcept/backend/apps/rsform/serializers/data_access.py +++ b/rsconcept/backend/apps/rsform/serializers/data_access.py @@ -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() diff --git a/rsconcept/backend/apps/rsform/serializers/io_files.py b/rsconcept/backend/apps/rsform/serializers/io_files.py index d2e906d3..8dc3783a 100644 --- a/rsconcept/backend/apps/rsform/serializers/io_files.py +++ b/rsconcept/backend/apps/rsform/serializers/io_files.py @@ -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'])) diff --git a/rsconcept/backend/apps/rsform/serializers/io_pyconcept.py b/rsconcept/backend/apps/rsform/serializers/io_pyconcept.py index cad69f3a..1aa79820 100644 --- a/rsconcept/backend/apps/rsform/serializers/io_pyconcept.py +++ b/rsconcept/backend/apps/rsform/serializers/io_pyconcept.py @@ -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): diff --git a/rsconcept/backend/apps/rsform/serializers/schema_typing.py b/rsconcept/backend/apps/rsform/serializers/schema_typing.py index 0f70c5d4..43ff4e53 100644 --- a/rsconcept/backend/apps/rsform/serializers/schema_typing.py +++ b/rsconcept/backend/apps/rsform/serializers/schema_typing.py @@ -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() diff --git a/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py b/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py index 83b722a7..fe22be46 100644 --- a/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py +++ b/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py @@ -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') diff --git a/rsconcept/backend/apps/rsform/tests/s_models/t_LibraryItem.py b/rsconcept/backend/apps/rsform/tests/s_models/t_LibraryItem.py index bfcdbf30..8b35e29d 100644 --- a/rsconcept/backend/apps/rsform/tests/s_models/t_LibraryItem.py +++ b/rsconcept/backend/apps/rsform/tests/s_models/t_LibraryItem.py @@ -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') diff --git a/rsconcept/backend/apps/rsform/tests/s_models/t_RSForm.py b/rsconcept/backend/apps/rsform/tests/s_models/t_RSForm.py index a6f4a369..c7cc2fff 100644 --- a/rsconcept/backend/apps/rsform/tests/s_models/t_RSForm.py +++ b/rsconcept/backend/apps/rsform/tests/s_models/t_RSForm.py @@ -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]) diff --git a/rsconcept/backend/apps/rsform/tests/t_graph.py b/rsconcept/backend/apps/rsform/tests/t_graph.py index 314e6dac..63713f95 100644 --- a/rsconcept/backend/apps/rsform/tests/t_graph.py +++ b/rsconcept/backend/apps/rsform/tests/t_graph.py @@ -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)) diff --git a/rsconcept/backend/apps/rsform/tests/t_utils.py b/rsconcept/backend/apps/rsform/tests/t_utils.py index d59d3d71..27f0d1de 100644 --- a/rsconcept/backend/apps/rsform/tests/t_utils.py +++ b/rsconcept/backend/apps/rsform/tests/t_utils.py @@ -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]+)') diff --git a/rsconcept/backend/apps/rsform/utils.py b/rsconcept/backend/apps/rsform/utils.py index 2b37d33a..b5e73e1f 100644 --- a/rsconcept/backend/apps/rsform/utils.py +++ b/rsconcept/backend/apps/rsform/utils.py @@ -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 diff --git a/rsconcept/backend/apps/rsform/views/rsforms.py b/rsconcept/backend/apps/rsform/views/rsforms.py index f8a7b56d..c206828a 100644 --- a/rsconcept/backend/apps/rsform/views/rsforms.py +++ b/rsconcept/backend/apps/rsform/views/rsforms.py @@ -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, diff --git a/rsconcept/backend/apps/rsform/views/versions.py b/rsconcept/backend/apps/rsform/views/versions.py index 3159444e..bf7e21d6 100644 --- a/rsconcept/backend/apps/rsform/views/versions.py +++ b/rsconcept/backend/apps/rsform/views/versions.py @@ -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. ''' diff --git a/rsconcept/backend/apps/users/messages.py b/rsconcept/backend/apps/users/messages.py index b4d6fc2d..a99495fb 100644 --- a/rsconcept/backend/apps/users/messages.py +++ b/rsconcept/backend/apps/users/messages.py @@ -1,8 +1,10 @@ ''' Utility: Text messages. ''' # pylint: skip-file + def passwordAuthFailed(): return 'Неизвестное сочетание имени пользователя и пароля' + def passwordsNotMatch(): return 'Введенные пароли не совпадают' diff --git a/rsconcept/backend/apps/users/models.py b/rsconcept/backend/apps/users/models.py index 8bf01a73..510b504b 100644 --- a/rsconcept/backend/apps/users/models.py +++ b/rsconcept/backend/apps/users/models.py @@ -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 diff --git a/rsconcept/backend/project/settings.py b/rsconcept/backend/project/settings.py index 86f5fa1f..7abd0854 100644 --- a/rsconcept/backend/project/settings.py +++ b/rsconcept/backend/project/settings.py @@ -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'.