R: Improve backend type hints, linting and package locks
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Frontend CI / build (22.x) (push) Has been cancelled

This commit is contained in:
Ivan 2024-09-12 20:56:38 +03:00
parent 453118ea66
commit 31195cdd60
30 changed files with 228 additions and 157 deletions

View File

@ -6,16 +6,15 @@ defaults:
on: on:
push: push:
branches: [ "main" ] branches: ["main"]
paths: paths:
- rsconcept/backend/** - rsconcept/backend/**
- .github/workflows/backend.yml - .github/workflows/backend.yml
pull_request: pull_request:
branches: [ "main" ] branches: ["main"]
jobs: jobs:
build: build:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
strategy: strategy:
max-parallel: 4 max-parallel: 4
@ -31,13 +30,13 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -r requirements-dev.txt pip install -r requirements-dev-lock.txt
- name: Lint - name: Lint
run: | run: |
pylint project apps pylint project apps
mypy project apps mypy project apps
- name: Run Tests - name: Run Tests
if: '!cancelled()' if: "!cancelled()"
run: | run: |
python manage.py check python manage.py check
python manage.py test python manage.py test

View File

@ -1,4 +1,5 @@
''' Admin view: Library. ''' ''' Admin view: Library. '''
from typing import cast
from django.contrib import admin from django.contrib import admin
from . import models from . import models
@ -23,7 +24,7 @@ class LibraryTemplateAdmin(admin.ModelAdmin):
def alias(self, template: models.LibraryTemplate): def alias(self, template: models.LibraryTemplate):
if template.lib_source: if template.lib_source:
return template.lib_source.alias return cast(models.LibraryItem, template.lib_source).alias
else: else:
return 'N/A' return 'N/A'

View File

@ -0,0 +1,21 @@
# Generated by Django 5.1.1 on 2024-09-12 16:48
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0004_delete_subscription'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='libraryitem',
name='owner',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Владелец'),
),
]

View File

@ -9,17 +9,17 @@ from apps.users.models import User
class Editor(Model): class Editor(Model):
''' Editor list. ''' ''' Editor list. '''
item: ForeignKey = ForeignKey( item = ForeignKey(
verbose_name='Схема', verbose_name='Схема',
to='library.LibraryItem', to='library.LibraryItem',
on_delete=CASCADE on_delete=CASCADE
) )
editor: ForeignKey = ForeignKey( editor = ForeignKey(
verbose_name='Редактор', verbose_name='Редактор',
to=User, to=User,
on_delete=CASCADE on_delete=CASCADE
) )
time_create: DateTimeField = DateTimeField( time_create = DateTimeField(
verbose_name='Дата добавления', verbose_name='Дата добавления',
auto_now_add=True auto_now_add=True
) )

View File

@ -48,55 +48,56 @@ def validate_location(target: str) -> bool:
class LibraryItem(Model): class LibraryItem(Model):
''' Abstract library item.''' ''' Abstract library item.'''
item_type: CharField = CharField( item_type = CharField(
verbose_name='Тип', verbose_name='Тип',
max_length=50, max_length=50,
choices=LibraryItemType.choices, choices=LibraryItemType.choices,
default=LibraryItemType.RSFORM default=LibraryItemType.RSFORM
) )
owner: ForeignKey = ForeignKey( owner = ForeignKey(
verbose_name='Владелец', verbose_name='Владелец',
to=User, to=User,
on_delete=SET_NULL, on_delete=SET_NULL,
blank=True,
null=True null=True
) )
title: TextField = TextField( title = TextField(
verbose_name='Название' verbose_name='Название'
) )
alias: CharField = CharField( alias = CharField(
verbose_name='Шифр', verbose_name='Шифр',
max_length=255, max_length=255,
blank=True blank=True
) )
comment: TextField = TextField( comment = TextField(
verbose_name='Комментарий', verbose_name='Комментарий',
blank=True blank=True
) )
visible: BooleanField = BooleanField( visible = BooleanField(
verbose_name='Отображаемая', verbose_name='Отображаемая',
default=True default=True
) )
read_only: BooleanField = BooleanField( read_only = BooleanField(
verbose_name='Запретить редактирование', verbose_name='Запретить редактирование',
default=False default=False
) )
access_policy: CharField = CharField( access_policy = CharField(
verbose_name='Политика доступа', verbose_name='Политика доступа',
max_length=500, max_length=500,
choices=AccessPolicy.choices, choices=AccessPolicy.choices,
default=AccessPolicy.PUBLIC default=AccessPolicy.PUBLIC
) )
location: TextField = TextField( location = TextField(
verbose_name='Расположение', verbose_name='Расположение',
max_length=500, max_length=500,
default=LocationHead.USER default=LocationHead.USER
) )
time_create: DateTimeField = DateTimeField( time_create = DateTimeField(
verbose_name='Дата создания', verbose_name='Дата создания',
auto_now_add=True auto_now_add=True
) )
time_update: DateTimeField = DateTimeField( time_update = DateTimeField(
verbose_name='Дата изменения', verbose_name='Дата изменения',
auto_now=True auto_now=True
) )
@ -112,11 +113,11 @@ class LibraryItem(Model):
def get_absolute_url(self): def get_absolute_url(self):
return f'/api/library/{self.pk}' return f'/api/library/{self.pk}'
def editors(self) -> QuerySet[User]: def getQ_editors(self) -> QuerySet[User]:
''' Get all Editors of this item. ''' ''' Get all Editors of this item. '''
return User.objects.filter(editor__item=self.pk) return User.objects.filter(editor__item=self.pk)
def versions(self) -> QuerySet[Version]: def getQ_versions(self) -> QuerySet[Version]:
''' Get all Versions of this item. ''' ''' Get all Versions of this item. '''
return Version.objects.filter(item=self.pk).order_by('-time_create') return Version.objects.filter(item=self.pk).order_by('-time_create')

View File

@ -4,7 +4,7 @@ from django.db.models import CASCADE, ForeignKey, Model
class LibraryTemplate(Model): class LibraryTemplate(Model):
''' Template for library items and constituents. ''' ''' Template for library items and constituents. '''
lib_source: ForeignKey = ForeignKey( lib_source = ForeignKey(
verbose_name='Источник', verbose_name='Источник',
to='library.LibraryItem', to='library.LibraryItem',
on_delete=CASCADE on_delete=CASCADE

View File

@ -12,7 +12,7 @@ from django.db.models import (
class Version(Model): class Version(Model):
''' Library item version archive. ''' ''' Library item version archive. '''
item: ForeignKey = ForeignKey( item = ForeignKey(
verbose_name='Схема', verbose_name='Схема',
to='library.LibraryItem', to='library.LibraryItem',
on_delete=CASCADE on_delete=CASCADE
@ -22,14 +22,14 @@ class Version(Model):
max_length=20, max_length=20,
blank=False blank=False
) )
description: TextField = TextField( description = TextField(
verbose_name='Описание', verbose_name='Описание',
blank=True blank=True
) )
data: JSONField = JSONField( data = JSONField(
verbose_name='Содержание' verbose_name='Содержание'
) )
time_create: DateTimeField = DateTimeField( time_create = DateTimeField(
verbose_name='Дата создания', verbose_name='Дата создания',
auto_now_add=True auto_now_add=True
) )

View File

@ -84,10 +84,10 @@ class LibraryItemDetailsSerializer(serializers.ModelSerializer):
read_only_fields = ('owner', 'id', 'item_type') read_only_fields = ('owner', 'id', 'item_type')
def get_editors(self, instance: LibraryItem) -> list[int]: def get_editors(self, instance: LibraryItem) -> list[int]:
return list(instance.editors().order_by('pk').values_list('pk', flat=True)) return list(instance.getQ_editors().order_by('pk').values_list('pk', flat=True))
def get_versions(self, instance: LibraryItem) -> list: def get_versions(self, instance: LibraryItem) -> list:
return [VersionInnerSerializer(item).data for item in instance.versions().order_by('pk')] return [VersionInnerSerializer(item).data for item in instance.getQ_versions().order_by('pk')]
class UserTargetSerializer(serializers.Serializer): class UserTargetSerializer(serializers.Serializer):

View File

@ -35,64 +35,64 @@ class TestEditor(TestCase):
def test_add_editor(self): def test_add_editor(self):
self.assertTrue(Editor.add(self.item.pk, self.user1.pk)) self.assertTrue(Editor.add(self.item.pk, self.user1.pk))
self.assertEqual(self.item.editors().count(), 1) self.assertEqual(self.item.getQ_editors().count(), 1)
self.assertTrue(self.user1 in list(self.item.editors())) self.assertTrue(self.user1 in list(self.item.getQ_editors()))
self.assertFalse(Editor.add(self.item.pk, self.user1.pk)) self.assertFalse(Editor.add(self.item.pk, self.user1.pk))
self.assertEqual(self.item.editors().count(), 1) self.assertEqual(self.item.getQ_editors().count(), 1)
self.assertTrue(Editor.add(self.item.pk, self.user2.pk)) self.assertTrue(Editor.add(self.item.pk, self.user2.pk))
self.assertEqual(self.item.editors().count(), 2) self.assertEqual(self.item.getQ_editors().count(), 2)
self.assertTrue(self.user1 in self.item.editors()) self.assertTrue(self.user1 in self.item.getQ_editors())
self.assertTrue(self.user2 in self.item.editors()) self.assertTrue(self.user2 in self.item.getQ_editors())
self.user1.delete() self.user1.delete()
self.assertEqual(self.item.editors().count(), 1) self.assertEqual(self.item.getQ_editors().count(), 1)
def test_remove_editor(self): def test_remove_editor(self):
self.assertFalse(Editor.remove(self.item.pk, self.user1.pk)) self.assertFalse(Editor.remove(self.item.pk, self.user1.pk))
Editor.add(self.item.pk, self.user1.pk) Editor.add(self.item.pk, self.user1.pk)
Editor.add(self.item.pk, self.user2.pk) Editor.add(self.item.pk, self.user2.pk)
self.assertEqual(self.item.editors().count(), 2) self.assertEqual(self.item.getQ_editors().count(), 2)
self.assertTrue(Editor.remove(self.item.pk, self.user1.pk)) self.assertTrue(Editor.remove(self.item.pk, self.user1.pk))
self.assertEqual(self.item.editors().count(), 1) self.assertEqual(self.item.getQ_editors().count(), 1)
self.assertTrue(self.user2 in self.item.editors()) self.assertTrue(self.user2 in self.item.getQ_editors())
self.assertFalse(Editor.remove(self.item.pk, self.user1.pk)) self.assertFalse(Editor.remove(self.item.pk, self.user1.pk))
def test_set_editors(self): def test_set_editors(self):
Editor.set(self.item.pk, [self.user1.pk]) Editor.set(self.item.pk, [self.user1.pk])
self.assertEqual(list(self.item.editors()), [self.user1]) self.assertEqual(list(self.item.getQ_editors()), [self.user1])
Editor.set(self.item.pk, [self.user1.pk, self.user1.pk]) Editor.set(self.item.pk, [self.user1.pk, self.user1.pk])
self.assertEqual(list(self.item.editors()), [self.user1]) self.assertEqual(list(self.item.getQ_editors()), [self.user1])
Editor.set(self.item.pk, []) Editor.set(self.item.pk, [])
self.assertEqual(list(self.item.editors()), []) self.assertEqual(list(self.item.getQ_editors()), [])
Editor.set(self.item.pk, [self.user1.pk, self.user2.pk]) Editor.set(self.item.pk, [self.user1.pk, self.user2.pk])
self.assertEqual(set(self.item.editors()), set([self.user1, self.user2])) self.assertEqual(set(self.item.getQ_editors()), set([self.user1, self.user2]))
def test_set_editors_return_diff(self): def test_set_editors_return_diff(self):
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk]) added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk])
self.assertEqual(added, [self.user1.pk]) self.assertEqual(added, [self.user1.pk])
self.assertEqual(deleted, []) self.assertEqual(deleted, [])
self.assertEqual(list(self.item.editors()), [self.user1]) self.assertEqual(list(self.item.getQ_editors()), [self.user1])
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user1.pk]) added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user1.pk])
self.assertEqual(added, []) self.assertEqual(added, [])
self.assertEqual(deleted, []) self.assertEqual(deleted, [])
self.assertEqual(list(self.item.editors()), [self.user1]) self.assertEqual(list(self.item.getQ_editors()), [self.user1])
added, deleted = Editor.set_and_return_diff(self.item.pk, []) added, deleted = Editor.set_and_return_diff(self.item.pk, [])
self.assertEqual(added, []) self.assertEqual(added, [])
self.assertEqual(deleted, [self.user1.pk]) self.assertEqual(deleted, [self.user1.pk])
self.assertEqual(list(self.item.editors()), []) self.assertEqual(list(self.item.getQ_editors()), [])
added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user2.pk]) added, deleted = Editor.set_and_return_diff(self.item.pk, [self.user1.pk, self.user2.pk])
self.assertEqual(added, [self.user1.pk, self.user2.pk]) self.assertEqual(added, [self.user1.pk, self.user2.pk])
self.assertEqual(deleted, []) self.assertEqual(deleted, [])
self.assertEqual(set(self.item.editors()), set([self.user1, self.user2])) self.assertEqual(set(self.item.getQ_editors()), set([self.user1, self.user2]))

View File

@ -250,22 +250,22 @@ class TestLibraryViewset(EndpointTester):
self.executeOK(data=data, item=self.owned.pk) self.executeOK(data=data, item=self.owned.pk)
self.owned.refresh_from_db() self.owned.refresh_from_db()
self.assertEqual(self.owned.time_update, time_update) self.assertEqual(self.owned.time_update, time_update)
self.assertEqual(list(self.owned.editors()), [self.user]) self.assertEqual(list(self.owned.getQ_editors()), [self.user])
self.executeOK(data=data) self.executeOK(data=data)
self.assertEqual(list(self.owned.editors()), [self.user]) self.assertEqual(list(self.owned.getQ_editors()), [self.user])
data = {'users': [self.user2.pk]} data = {'users': [self.user2.pk]}
self.executeOK(data=data) self.executeOK(data=data)
self.assertEqual(list(self.owned.editors()), [self.user2]) self.assertEqual(list(self.owned.getQ_editors()), [self.user2])
data = {'users': []} data = {'users': []}
self.executeOK(data=data) self.executeOK(data=data)
self.assertEqual(list(self.owned.editors()), []) self.assertEqual(list(self.owned.getQ_editors()), [])
data = {'users': [self.user2.pk, self.user.pk]} data = {'users': [self.user2.pk, self.user.pk]}
self.executeOK(data=data) self.executeOK(data=data)
self.assertEqual(set(self.owned.editors()), set([self.user2, self.user])) self.assertEqual(set(self.owned.getQ_editors()), set([self.user2, self.user]))
@decl_endpoint('/api/library/{item}', method='delete') @decl_endpoint('/api/library/{item}', method='delete')

View File

@ -157,7 +157,7 @@ class LibraryViewSet(viewsets.ModelViewSet):
clone = deepcopy(item) clone = deepcopy(item)
clone.pk = None clone.pk = None
clone.owner = self.request.user clone.owner = cast(User, self.request.user)
clone.title = serializer.validated_data['title'] clone.title = serializer.validated_data['title']
clone.alias = serializer.validated_data.get('alias', '') clone.alias = serializer.validated_data.get('alias', '')
clone.comment = serializer.validated_data.get('comment', '') clone.comment = serializer.validated_data.get('comment', '')

View File

@ -44,7 +44,7 @@ class VersionViewset(
def restore(self, request: Request, pk) -> HttpResponse: def restore(self, request: Request, pk) -> HttpResponse:
''' Restore version data into current item. ''' ''' Restore version data into current item. '''
version = cast(m.Version, self.get_object()) version = cast(m.Version, self.get_object())
item = cast(m.LibraryItem, version.item) item = version.item
with transaction.atomic(): with transaction.atomic():
RSFormSerializer(item).restore_from_version(version.data) RSFormSerializer(item).restore_from_version(version.data)
return Response( return Response(

View File

@ -0,0 +1,20 @@
# Generated by Django 5.1.1 on 2024-09-12 16:48
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('library', '0005_alter_libraryitem_owner'),
('oss', '0007_argument_order'),
]
operations = [
migrations.AlterField(
model_name='operation',
name='result',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='producer', to='library.libraryitem', verbose_name='Связанная КС'),
),
]

View File

@ -4,19 +4,19 @@ from django.db.models import CASCADE, ForeignKey, Model, PositiveIntegerField
class Argument(Model): class Argument(Model):
''' Operation Argument.''' ''' Operation Argument.'''
operation: ForeignKey = ForeignKey( operation = ForeignKey(
verbose_name='Операция', verbose_name='Операция',
to='oss.Operation', to='oss.Operation',
on_delete=CASCADE, on_delete=CASCADE,
related_name='arguments' related_name='arguments'
) )
argument: ForeignKey = ForeignKey( argument = ForeignKey(
verbose_name='Аргумент', verbose_name='Аргумент',
to='oss.Operation', to='oss.Operation',
on_delete=CASCADE, on_delete=CASCADE,
related_name='descendants' related_name='descendants'
) )
order: PositiveIntegerField = PositiveIntegerField( order = PositiveIntegerField(
verbose_name='Позиция', verbose_name='Позиция',
default=0, default=0,
) )

View File

@ -4,19 +4,19 @@ from django.db.models import CASCADE, ForeignKey, Model
class Inheritance(Model): class Inheritance(Model):
''' Inheritance links parent and child constituents in synthesis operation.''' ''' Inheritance links parent and child constituents in synthesis operation.'''
operation: ForeignKey = ForeignKey( operation = ForeignKey(
verbose_name='Операция', verbose_name='Операция',
to='oss.Operation', to='oss.Operation',
on_delete=CASCADE, on_delete=CASCADE,
related_name='inheritances' related_name='inheritances'
) )
parent: ForeignKey = ForeignKey( parent = ForeignKey(
verbose_name='Исходная конституента', verbose_name='Исходная конституента',
to='rsform.Constituenta', to='rsform.Constituenta',
on_delete=CASCADE, on_delete=CASCADE,
related_name='as_parent' related_name='as_parent'
) )
child: ForeignKey = ForeignKey( child = ForeignKey(
verbose_name='Наследованная конституента', verbose_name='Наследованная конституента',
to='rsform.Constituenta', to='rsform.Constituenta',
on_delete=CASCADE, on_delete=CASCADE,

View File

@ -23,45 +23,46 @@ class OperationType(TextChoices):
class Operation(Model): class Operation(Model):
''' Operational schema Unit.''' ''' Operational schema Unit.'''
oss: ForeignKey = ForeignKey( oss = ForeignKey(
verbose_name='Схема синтеза', verbose_name='Схема синтеза',
to='library.LibraryItem', to='library.LibraryItem',
on_delete=CASCADE, on_delete=CASCADE,
related_name='operations' related_name='operations'
) )
operation_type: CharField = CharField( operation_type = CharField(
verbose_name='Тип', verbose_name='Тип',
max_length=10, max_length=10,
choices=OperationType.choices, choices=OperationType.choices,
default=OperationType.INPUT default=OperationType.INPUT
) )
result: ForeignKey = ForeignKey( result = ForeignKey(
verbose_name='Связанная КС', verbose_name='Связанная КС',
to='library.LibraryItem', to='library.LibraryItem',
blank=True,
null=True, null=True,
on_delete=SET_NULL, on_delete=SET_NULL,
related_name='producer' related_name='producer'
) )
alias: CharField = CharField( alias = CharField(
verbose_name='Шифр', verbose_name='Шифр',
max_length=255, max_length=255,
blank=True blank=True
) )
title: TextField = TextField( title = TextField(
verbose_name='Название', verbose_name='Название',
blank=True blank=True
) )
comment: TextField = TextField( comment = TextField(
verbose_name='Комментарий', verbose_name='Комментарий',
blank=True blank=True
) )
position_x: FloatField = FloatField( position_x = FloatField(
verbose_name='Положение по горизонтали', verbose_name='Положение по горизонтали',
default=0 default=0
) )
position_y: FloatField = FloatField( position_y = FloatField(
verbose_name='Положение по вертикали', verbose_name='Положение по вертикали',
default=0 default=0
) )
@ -74,10 +75,10 @@ class Operation(Model):
def __str__(self) -> str: def __str__(self) -> str:
return f'Операция {self.alias}' return f'Операция {self.alias}'
def getArguments(self) -> QuerySet[Argument]: def getQ_arguments(self) -> QuerySet[Argument]:
''' Operation arguments. ''' ''' Operation arguments. '''
return Argument.objects.filter(operation=self) return Argument.objects.filter(operation=self)
def getSubstitutions(self) -> QuerySet[Substitution]: def getQ_substitutions(self) -> QuerySet[Substitution]:
''' Operation substitutions. ''' ''' Operation substitutions. '''
return Substitution.objects.filter(operation=self) return Substitution.objects.filter(operation=self)

View File

@ -121,7 +121,6 @@ class OperationSchema:
operation.result = schema operation.result = schema
if schema is not None: if schema is not None:
operation.result = schema
operation.alias = schema.alias operation.alias = schema.alias
operation.title = schema.title operation.title = schema.title
operation.comment = schema.comment operation.comment = schema.comment
@ -139,7 +138,7 @@ class OperationSchema:
processed: list[Operation] = [] processed: list[Operation] = []
updated: list[Argument] = [] updated: list[Argument] = []
deleted: list[Argument] = [] deleted: list[Argument] = []
for current in operation.getArguments(): for current in operation.getQ_arguments():
if current.argument not in arguments: if current.argument not in arguments:
deleted.append(current) deleted.append(current)
else: else:
@ -172,7 +171,7 @@ class OperationSchema:
schema = self.cache.get_schema(operation) schema = self.cache.get_schema(operation)
processed: list[dict] = [] processed: list[dict] = []
deleted: list[Substitution] = [] deleted: list[Substitution] = []
for current in operation.getSubstitutions(): for current in operation.getQ_substitutions():
subs = [ subs = [
x for x in substitutes x for x in substitutes
if x['original'] == current.original and x['substitution'] == current.substitution if x['original'] == current.original and x['substitution'] == current.substitution
@ -215,7 +214,7 @@ class OperationSchema:
access_policy=self.model.access_policy, access_policy=self.model.access_policy,
location=self.model.location location=self.model.location
) )
Editor.set(schema.model.pk, self.model.editors().values_list('pk', flat=True)) Editor.set(schema.model.pk, self.model.getQ_editors().values_list('pk', flat=True))
operation.result = schema.model operation.result = schema.model
operation.save() operation.save()
self.save(update_fields=['time_update']) self.save(update_fields=['time_update'])
@ -223,10 +222,14 @@ class OperationSchema:
def execute_operation(self, operation: Operation) -> bool: def execute_operation(self, operation: Operation) -> bool:
''' Execute target operation. ''' ''' Execute target operation. '''
schemas: list[LibraryItem] = [arg.argument.result for arg in operation.getArguments().order_by('order')] schemas = [
if None in schemas: arg.argument.result
for arg in operation.getQ_arguments().order_by('order')
if arg.argument.result is not None
]
if len(schemas) == 0:
return False return False
substitutions = operation.getSubstitutions() substitutions = operation.getQ_substitutions()
receiver = self.create_input(self.cache.operation_by_id[operation.pk]) receiver = self.create_input(self.cache.operation_by_id[operation.pk])
parents: dict = {} parents: dict = {}
@ -284,7 +287,7 @@ class OperationSchema:
''' Trigger cascade resolutions when constituenta type is changed. ''' ''' Trigger cascade resolutions when constituenta type is changed. '''
self.cache.insert_schema(source) self.cache.insert_schema(source)
operation = self.cache.get_operation(source.model.pk) operation = self.cache.get_operation(source.model.pk)
self._cascade_change_cst_type(operation.pk, target.pk, target.cst_type) self._cascade_change_cst_type(operation.pk, target.pk, cast(CstType, target.cst_type))
def after_update_cst(self, source: RSForm, target: Constituenta, data: dict, old_data: dict) -> None: def after_update_cst(self, source: RSForm, target: Constituenta, data: dict, old_data: dict) -> None:
''' Trigger cascade resolutions when constituenta data is changed. ''' ''' Trigger cascade resolutions when constituenta data is changed. '''
@ -659,7 +662,7 @@ class OperationSchema:
substitution_id = self.cache.get_inheritor(substitution_cst.pk, operation_id) substitution_id = self.cache.get_inheritor(substitution_cst.pk, operation_id)
assert substitution_id is not None assert substitution_id is not None
substitution_inheritor = schema.cache.by_id[substitution_id] substitution_inheritor = schema.cache.by_id[substitution_id]
mapping = {cast(str, substitution_inheritor.alias): new_original} mapping = {substitution_inheritor.alias: new_original}
self._cascade_partial_mapping(mapping, dependant, operation_id, schema) self._cascade_partial_mapping(mapping, dependant, operation_id, schema)
def _process_added_substitutions(self, schema: Optional[RSForm], added: list[Substitution]) -> None: def _process_added_substitutions(self, schema: Optional[RSForm], added: list[Substitution]) -> None:

View File

@ -4,19 +4,19 @@ from django.db.models import CASCADE, ForeignKey, Model
class Substitution(Model): class Substitution(Model):
''' Substitutions as part of Synthesis operation in OSS.''' ''' Substitutions as part of Synthesis operation in OSS.'''
operation: ForeignKey = ForeignKey( operation = ForeignKey(
verbose_name='Операция', verbose_name='Операция',
to='oss.Operation', to='oss.Operation',
on_delete=CASCADE on_delete=CASCADE
) )
original: ForeignKey = ForeignKey( original = ForeignKey(
verbose_name='Удаляемая конституента', verbose_name='Удаляемая конституента',
to='rsform.Constituenta', to='rsform.Constituenta',
on_delete=CASCADE, on_delete=CASCADE,
related_name='as_original' related_name='as_original'
) )
substitution: ForeignKey = ForeignKey( substitution = ForeignKey(
verbose_name='Замещающая конституента', verbose_name='Замещающая конституента',
to='rsform.Constituenta', to='rsform.Constituenta',
on_delete=CASCADE, on_delete=CASCADE,

View File

@ -53,6 +53,7 @@ class TestChangeAttributes(EndpointTester):
alias='3', alias='3',
operation_type=OperationType.SYNTHESIS operation_type=OperationType.SYNTHESIS
) )
self.owned.set_arguments(self.operation3.pk, [self.operation1, self.operation2])
self.owned.execute_operation(self.operation3) self.owned.execute_operation(self.operation3)
self.operation3.refresh_from_db() self.operation3.refresh_from_db()
self.ks3 = RSForm(self.operation3.result) self.ks3 = RSForm(self.operation3.result)
@ -116,10 +117,10 @@ class TestChangeAttributes(EndpointTester):
self.ks1.refresh_from_db() self.ks1.refresh_from_db()
self.ks2.refresh_from_db() self.ks2.refresh_from_db()
self.ks3.refresh_from_db() self.ks3.refresh_from_db()
self.assertEqual(list(self.owned.model.editors()), [self.user3]) self.assertEqual(list(self.owned.model.getQ_editors()), [self.user3])
self.assertEqual(list(self.ks1.model.editors()), [self.user, self.user2]) self.assertEqual(list(self.ks1.model.getQ_editors()), [self.user, self.user2])
self.assertEqual(list(self.ks2.model.editors()), []) self.assertEqual(list(self.ks2.model.getQ_editors()), [])
self.assertEqual(set(self.ks3.model.editors()), set([self.user, self.user3])) self.assertEqual(set(self.ks3.model.getQ_editors()), set([self.user, self.user3]))
@decl_endpoint('/api/library/{item}', method='patch') @decl_endpoint('/api/library/{item}', method='patch')
def test_sync_from_result(self): def test_sync_from_result(self):

View File

@ -124,9 +124,9 @@ class TestChangeOperations(EndpointTester):
self.ks4D1.refresh_from_db() self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 4) self.assertEqual(self.ks4.constituents().count(), 4)
self.assertEqual(self.ks5.constituents().count(), 6) self.assertEqual(self.ks5.constituents().count(), 6)
@ -147,9 +147,9 @@ class TestChangeOperations(EndpointTester):
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
self.operation2.refresh_from_db() self.operation2.refresh_from_db()
self.assertEqual(self.operation2.result, None) self.assertEqual(self.operation2.result, None)
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 4) self.assertEqual(self.ks4.constituents().count(), 4)
self.assertEqual(self.ks5.constituents().count(), 6) self.assertEqual(self.ks5.constituents().count(), 6)
@ -181,9 +181,9 @@ class TestChangeOperations(EndpointTester):
self.operation2.refresh_from_db() self.operation2.refresh_from_db()
self.assertEqual(self.operation2.result, ks6.model) self.assertEqual(self.operation2.result, ks6.model)
self.assertEqual(self.operation2.alias, ks6.model.alias) self.assertEqual(self.operation2.alias, ks6.model.alias)
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 7) self.assertEqual(self.ks4.constituents().count(), 7)
self.assertEqual(self.ks5.constituents().count(), 9) self.assertEqual(self.ks5.constituents().count(), 9)
@ -199,9 +199,9 @@ class TestChangeOperations(EndpointTester):
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
self.operation1.refresh_from_db() self.operation1.refresh_from_db()
self.assertEqual(self.operation1.result, None) self.assertEqual(self.operation1.result, None)
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 0) self.assertEqual(subs3_4.count(), 0)
self.assertEqual(self.ks4.constituents().count(), 4) self.assertEqual(self.ks4.constituents().count(), 4)
self.assertEqual(self.ks5.constituents().count(), 7) self.assertEqual(self.ks5.constituents().count(), 7)
@ -220,9 +220,9 @@ class TestChangeOperations(EndpointTester):
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 0) self.assertEqual(subs3_4.count(), 0)
self.assertEqual(self.ks4.constituents().count(), 4) self.assertEqual(self.ks4.constituents().count(), 4)
self.assertEqual(self.ks5.constituents().count(), 7) self.assertEqual(self.ks5.constituents().count(), 7)
@ -241,9 +241,9 @@ class TestChangeOperations(EndpointTester):
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 6) self.assertEqual(self.ks4.constituents().count(), 6)
self.assertEqual(self.ks5.constituents().count(), 8) self.assertEqual(self.ks5.constituents().count(), 8)
@ -275,9 +275,9 @@ class TestChangeOperations(EndpointTester):
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 2) self.assertEqual(subs1_2.count(), 2)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 5) self.assertEqual(self.ks4.constituents().count(), 5)
self.assertEqual(self.ks5.constituents().count(), 7) self.assertEqual(self.ks5.constituents().count(), 7)
@ -300,9 +300,9 @@ class TestChangeOperations(EndpointTester):
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 4) self.assertEqual(self.ks4.constituents().count(), 4)
self.assertEqual(self.ks5.constituents().count(), 6) self.assertEqual(self.ks5.constituents().count(), 6)
@ -313,9 +313,9 @@ class TestChangeOperations(EndpointTester):
self.executeOK(data=data, item=self.owned_id) self.executeOK(data=data, item=self.owned_id)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks4.constituents().count(), 7) self.assertEqual(self.ks4.constituents().count(), 7)
self.assertEqual(self.ks5.constituents().count(), 9) self.assertEqual(self.ks5.constituents().count(), 9)

View File

@ -125,11 +125,11 @@ class TestChangeSubstitutions(EndpointTester):
self.ks4D1.refresh_from_db() self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 1) self.assertEqual(subs1_2.count(), 1)
self.assertEqual(subs1_2.first().original, self.ks1X2) self.assertEqual(subs1_2.first().original, self.ks1X2)
self.assertEqual(subs1_2.first().substitution, self.ks2S1) self.assertEqual(subs1_2.first().substitution, self.ks2S1)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(subs3_4.first().original, self.ks4S1) self.assertEqual(subs3_4.first().original, self.ks4S1)
self.assertEqual(subs3_4.first().substitution, self.ks3X1) self.assertEqual(subs3_4.first().substitution, self.ks3X1)
@ -147,11 +147,11 @@ class TestChangeSubstitutions(EndpointTester):
self.ks4D1.refresh_from_db() self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 1) self.assertEqual(subs1_2.count(), 1)
self.assertEqual(subs1_2.first().original, self.ks1X1) self.assertEqual(subs1_2.first().original, self.ks1X1)
self.assertEqual(subs1_2.first().substitution, self.ks2X1) self.assertEqual(subs1_2.first().substitution, self.ks2X1)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(subs3_4.first().original, self.ks4X1) self.assertEqual(subs3_4.first().original, self.ks4X1)
self.assertEqual(subs3_4.first().substitution, self.ks3X1) self.assertEqual(subs3_4.first().substitution, self.ks3X1)
@ -165,9 +165,9 @@ class TestChangeSubstitutions(EndpointTester):
self.executeOK(data=data, schema=self.ks1.model.pk) self.executeOK(data=data, schema=self.ks1.model.pk)
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks5.constituents().count(), 7) self.assertEqual(self.ks5.constituents().count(), 7)
self.assertEqual(self.ks4D2.definition_formal, r'X1 X2 X3 S1 DEL') self.assertEqual(self.ks4D2.definition_formal, r'X1 X2 X3 S1 DEL')
@ -180,9 +180,9 @@ class TestChangeSubstitutions(EndpointTester):
self.ks4D1.refresh_from_db() self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db() self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db() self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions() subs1_2 = self.operation4.getQ_substitutions()
self.assertEqual(subs1_2.count(), 0) self.assertEqual(subs1_2.count(), 0)
subs3_4 = self.operation5.getSubstitutions() subs3_4 = self.operation5.getQ_substitutions()
self.assertEqual(subs3_4.count(), 1) self.assertEqual(subs3_4.count(), 1)
self.assertEqual(self.ks5.constituents().count(), 7) self.assertEqual(self.ks5.constituents().count(), 7)
self.assertEqual(self.ks4D1.definition_formal, r'X4 X1') self.assertEqual(self.ks4D1.definition_formal, r'X4 X1')

View File

@ -244,7 +244,7 @@ class TestOssViewset(EndpointTester):
self.assertEqual(schema.visible, False) self.assertEqual(schema.visible, False)
self.assertEqual(schema.access_policy, self.owned.model.access_policy) self.assertEqual(schema.access_policy, self.owned.model.access_policy)
self.assertEqual(schema.location, self.owned.model.location) self.assertEqual(schema.location, self.owned.model.location)
self.assertIn(self.user2, schema.editors()) self.assertIn(self.user2, schema.getQ_editors())
@decl_endpoint('/api/oss/{item}/delete-operation', method='patch') @decl_endpoint('/api/oss/{item}/delete-operation', method='patch')
def test_delete_operation(self): def test_delete_operation(self):
@ -409,12 +409,12 @@ class TestOssViewset(EndpointTester):
self.assertEqual(self.operation3.alias, data['item_data']['alias']) self.assertEqual(self.operation3.alias, data['item_data']['alias'])
self.assertEqual(self.operation3.title, data['item_data']['title']) self.assertEqual(self.operation3.title, data['item_data']['title'])
self.assertEqual(self.operation3.comment, data['item_data']['comment']) self.assertEqual(self.operation3.comment, data['item_data']['comment'])
args = self.operation3.getArguments().order_by('order') args = self.operation3.getQ_arguments().order_by('order')
self.assertEqual(args[0].argument.pk, data['arguments'][0]) self.assertEqual(args[0].argument.pk, data['arguments'][0])
self.assertEqual(args[0].order, 0) self.assertEqual(args[0].order, 0)
self.assertEqual(args[1].argument.pk, data['arguments'][1]) self.assertEqual(args[1].argument.pk, data['arguments'][1])
self.assertEqual(args[1].order, 1) self.assertEqual(args[1].order, 1)
sub = self.operation3.getSubstitutions()[0] sub = self.operation3.getQ_substitutions()[0]
self.assertEqual(sub.original.pk, data['substitutions'][0]['original']) self.assertEqual(sub.original.pk, data['substitutions'][0]['original'])
self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution']) self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution'])

View File

@ -162,7 +162,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
oss = m.OperationSchema(self.get_object()) oss = m.OperationSchema(self.get_object())
operation = cast(m.Operation, serializer.validated_data['target']) operation = cast(m.Operation, serializer.validated_data['target'])
old_schema: Optional[LibraryItem] = operation.result old_schema = operation.result
with transaction.atomic(): with transaction.atomic():
oss.update_positions(serializer.validated_data['positions']) oss.update_positions(serializer.validated_data['positions'])
oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents']) oss.delete_operation(operation.pk, serializer.validated_data['keep_constituents'])
@ -255,7 +255,7 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
'input': msg.operationInputAlreadyConnected() 'input': msg.operationInputAlreadyConnected()
}) })
oss = m.OperationSchema(self.get_object()) oss = m.OperationSchema(self.get_object())
old_schema: Optional[LibraryItem] = target_operation.result old_schema = target_operation.result
with transaction.atomic(): with transaction.atomic():
if old_schema is not None: if old_schema is not None:
if old_schema.is_synced(oss.model): if old_schema.is_synced(oss.model):
@ -370,10 +370,13 @@ class OssViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retriev
serializer = CstTargetSerializer(data=request.data) serializer = CstTargetSerializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
cst = cast(Constituenta, serializer.validated_data['target']) cst = cast(Constituenta, serializer.validated_data['target'])
inheritance = m.Inheritance.objects.filter(child=cst) inheritance_query = m.Inheritance.objects.filter(child=cst)
while inheritance.exists(): while inheritance_query.exists():
cst = cast(m.Inheritance, inheritance.first()).parent inheritance = inheritance_query.first()
inheritance = m.Inheritance.objects.filter(child=cst) if inheritance is None:
break
cst = inheritance.parent
inheritance_query = m.Inheritance.objects.filter(child=cst)
return Response( return Response(
status=c.HTTP_200_OK, status=c.HTTP_200_OK,

View File

@ -49,56 +49,56 @@ class CstType(TextChoices):
class Constituenta(Model): class Constituenta(Model):
''' Constituenta is the base unit for every conceptual schema. ''' ''' Constituenta is the base unit for every conceptual schema. '''
schema: ForeignKey = ForeignKey( schema = ForeignKey(
verbose_name='Концептуальная схема', verbose_name='Концептуальная схема',
to='library.LibraryItem', to='library.LibraryItem',
on_delete=CASCADE on_delete=CASCADE
) )
order: PositiveIntegerField = PositiveIntegerField( order = PositiveIntegerField(
verbose_name='Позиция', verbose_name='Позиция',
default=0, default=0,
) )
alias: CharField = CharField( alias = CharField(
verbose_name='Имя', verbose_name='Имя',
max_length=8, max_length=8,
default='undefined' default='undefined'
) )
cst_type: CharField = CharField( cst_type = CharField(
verbose_name='Тип', verbose_name='Тип',
max_length=10, max_length=10,
choices=CstType.choices, choices=CstType.choices,
default=CstType.BASE default=CstType.BASE
) )
convention: TextField = TextField( convention = TextField(
verbose_name='Комментарий/Конвенция', verbose_name='Комментарий/Конвенция',
default='', default='',
blank=True blank=True
) )
term_raw: TextField = TextField( term_raw = TextField(
verbose_name='Термин (с отсылками)', verbose_name='Термин (с отсылками)',
default='', default='',
blank=True blank=True
) )
term_resolved: TextField = TextField( term_resolved = TextField(
verbose_name='Термин', verbose_name='Термин',
default='', default='',
blank=True blank=True
) )
term_forms: JSONField = JSONField( term_forms = JSONField(
verbose_name='Словоформы', verbose_name='Словоформы',
default=list default=list
) )
definition_formal: TextField = TextField( definition_formal = TextField(
verbose_name='Родоструктурное определение', verbose_name='Родоструктурное определение',
default='', default='',
blank=True blank=True
) )
definition_raw: TextField = TextField( definition_raw = TextField(
verbose_name='Текстовое определение (с отсылками)', verbose_name='Текстовое определение (с отсылками)',
default='', default='',
blank=True blank=True
) )
definition_resolved: TextField = TextField( definition_resolved = TextField(
verbose_name='Текстовое определение', verbose_name='Текстовое определение',
default='', default='',
blank=True blank=True

View File

@ -121,7 +121,7 @@ class RSForm:
update_list.append(cst) update_list.append(cst)
Constituenta.objects.bulk_update(update_list, ['definition_resolved']) Constituenta.objects.bulk_update(update_list, ['definition_resolved'])
def get_max_index(self, cst_type: CstType) -> int: def get_max_index(self, cst_type: str) -> int:
''' Get maximum alias index for specific CstType. ''' ''' Get maximum alias index for specific CstType. '''
result: int = 0 result: int = 0
cst_list: Iterable[Constituenta] = [] cst_list: Iterable[Constituenta] = []

View File

@ -26,7 +26,7 @@ class TokenType(IntEnum):
REDUCE = 299 REDUCE = 299
def get_type_prefix(cst_type: CstType) -> str: def get_type_prefix(cst_type: str) -> str:
''' Get alias prefix. ''' ''' Get alias prefix. '''
match cst_type: match cst_type:
case CstType.BASE: return 'X' case CstType.BASE: return 'X'
@ -40,7 +40,7 @@ def get_type_prefix(cst_type: CstType) -> str:
return 'X' return 'X'
def is_basic_concept(cst_type: CstType) -> bool: def is_basic_concept(cst_type: str) -> bool:
''' Evaluate if CstType is basic concept.''' ''' Evaluate if CstType is basic concept.'''
return cst_type in [ return cst_type in [
CstType.BASE, CstType.BASE,
@ -50,7 +50,7 @@ def is_basic_concept(cst_type: CstType) -> bool:
] ]
def is_base_set(cst_type: CstType) -> bool: def is_base_set(cst_type: str) -> bool:
''' Evaluate if CstType is base set or constant set.''' ''' Evaluate if CstType is base set or constant set.'''
return cst_type in [ return cst_type in [
CstType.BASE, CstType.BASE,
@ -58,7 +58,7 @@ def is_base_set(cst_type: CstType) -> bool:
] ]
def is_functional(cst_type: CstType) -> bool: def is_functional(cst_type: str) -> bool:
''' Evaluate if CstType is function.''' ''' Evaluate if CstType is function.'''
return cst_type in [ return cst_type in [
CstType.FUNCTION, CstType.FUNCTION,
@ -70,7 +70,7 @@ def guess_type(alias: str) -> CstType:
''' Get CstType for alias. ''' ''' Get CstType for alias. '''
prefix = alias[0] prefix = alias[0]
for (value, _) in CstType.choices: for (value, _) in CstType.choices:
if prefix == get_type_prefix(cast(CstType, value)): if prefix == get_type_prefix(value):
return cast(CstType, value) return cast(CstType, value)
return CstType.BASE return CstType.BASE

View File

@ -4,7 +4,8 @@
warn_return_any = True warn_return_any = True
warn_unused_configs = True warn_unused_configs = True
plugins = mypy_django_plugin.main plugins =
mypy_django_plugin.main
# Per-module options: # Per-module options:
[mypy.plugins.django-stubs] [mypy.plugins.django-stubs]

View File

@ -0,0 +1,20 @@
tzdata==2024.1
Django==5.1.1
djangorestframework==3.15.2
django-cors-headers==4.4.0
django-filter==24.3
drf-spectacular==0.27.2
drf-spectacular-sidecar==2024.7.1
coreapi==2.3.3
django-rest-passwordreset==1.4.1
cctext==0.1.4
pyconcept==0.1.6
psycopg2-binary==2.9.9
gunicorn==23.0.0
djangorestframework-stubs==3.15.1
django-extensions==3.2.3
mypy==1.11.2
pylint==3.2.7
coverage==7.6.1

View File

@ -1,5 +1,5 @@
tzdata tzdata
Django==5.1 Django
djangorestframework djangorestframework
django-cors-headers django-cors-headers
django-filter django-filter

View File

@ -1,5 +1,5 @@
tzdata==2024.1 tzdata==2024.1
Django==5.1 Django==5.1.1
djangorestframework==3.15.2 djangorestframework==3.15.2
django-cors-headers==4.4.0 django-cors-headers==4.4.0
django-filter==24.3 django-filter==24.3