edu-rdm-integration 3.17.0__py3-none-any.whl → 3.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of edu-rdm-integration might be problematic. Click here for more details.

Files changed (37) hide show
  1. edu_rdm_integration/models.py +1 -1
  2. edu_rdm_integration/pipelines/cleanup_outdated_data/__init__.py +0 -0
  3. edu_rdm_integration/pipelines/cleanup_outdated_data/apps.py +11 -0
  4. edu_rdm_integration/pipelines/cleanup_outdated_data/management/__init__.py +0 -0
  5. edu_rdm_integration/pipelines/cleanup_outdated_data/management/commands/__init__.py +0 -0
  6. edu_rdm_integration/pipelines/cleanup_outdated_data/management/commands/rdm_cleanup_outdated_data.py +20 -0
  7. edu_rdm_integration/rdm_entities/models.py +52 -0
  8. edu_rdm_integration/rdm_models/models.py +252 -15
  9. edu_rdm_integration/stages/collect_data/functions/base/functions.py +3 -3
  10. edu_rdm_integration/stages/collect_data/functions/base/helpers.py +1 -0
  11. edu_rdm_integration/stages/collect_data/functions/base/managers.py +6 -6
  12. edu_rdm_integration/stages/collect_data/functions/base/mixins.py +1 -0
  13. edu_rdm_integration/stages/collect_data/functions/base/runners.py +3 -4
  14. edu_rdm_integration/stages/collect_data/functions/calculated/base/caches.py +4 -4
  15. edu_rdm_integration/stages/collect_data/functions/calculated/strategies.py +1 -0
  16. edu_rdm_integration/stages/collect_data/functions/non_calculated/base/caches.py +4 -4
  17. edu_rdm_integration/stages/collect_data/functions/non_calculated/strategies.py +1 -0
  18. edu_rdm_integration/stages/collect_data/models.py +2 -5
  19. edu_rdm_integration/stages/collect_data/operations.py +6 -5
  20. edu_rdm_integration/stages/collect_data/tests.py +4 -4
  21. edu_rdm_integration/stages/export_data/functions/base/caches.py +9 -3
  22. edu_rdm_integration/stages/export_data/functions/base/functions.py +3 -4
  23. edu_rdm_integration/stages/export_data/functions/base/helpers.py +4 -4
  24. edu_rdm_integration/stages/export_data/functions/base/managers.py +3 -3
  25. edu_rdm_integration/stages/export_data/functions/base/runners.py +1 -0
  26. edu_rdm_integration/stages/export_data/functions/base/tests.py +3 -6
  27. edu_rdm_integration/stages/export_data/models.py +8 -3
  28. edu_rdm_integration/stages/export_data/strategies.py +1 -0
  29. edu_rdm_integration/stages/service/model_outdated_data/__init__.py +0 -0
  30. edu_rdm_integration/stages/service/model_outdated_data/cleaners.py +26 -0
  31. edu_rdm_integration/stages/service/model_outdated_data/managers.py +45 -0
  32. edu_rdm_integration/stages/service/outdated_service_data/__init__.py +0 -0
  33. {edu_rdm_integration-3.17.0.dist-info → edu_rdm_integration-3.18.1.dist-info}/METADATA +5 -4
  34. {edu_rdm_integration-3.17.0.dist-info → edu_rdm_integration-3.18.1.dist-info}/RECORD +37 -28
  35. {edu_rdm_integration-3.17.0.dist-info → edu_rdm_integration-3.18.1.dist-info}/WHEEL +0 -0
  36. {edu_rdm_integration-3.17.0.dist-info → edu_rdm_integration-3.18.1.dist-info}/licenses/LICENSE +0 -0
  37. {edu_rdm_integration-3.17.0.dist-info → edu_rdm_integration-3.18.1.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
1
- # Модели
1
+ # Модели
@@ -0,0 +1,11 @@
1
+ from django.apps import (
2
+ AppConfig,
3
+ )
4
+
5
+
6
+ class RDMCleanupOutdatedDataAppConfig(AppConfig):
7
+ """Приложение для организации процесса очистки устаревших данных РВД."""
8
+
9
+ name = 'edu_rdm_integration.pipelines.cleanup_outdated_data'
10
+ label = 'edu_rdm_integration_cleanup_outdated_data_pipeline'
11
+ verbose_name = 'Приложение для организации процесса очистки устаревших данных РВД.'
@@ -0,0 +1,20 @@
1
+ from django.core.management import (
2
+ BaseCommand,
3
+ )
4
+
5
+ from edu_rdm_integration.stages.service.model_outdated_data.managers import (
6
+ ModelOutdatedDataCleanerManager,
7
+ )
8
+
9
+
10
+ class Command(BaseCommand):
11
+ """Ночная команда для очистки устаревших данных РВД."""
12
+
13
+ nightly_script = True
14
+
15
+ help = 'Ночная команда для очистки устаревших данных РВД.'
16
+
17
+ def handle(self, *args, **options):
18
+ """Запуск очистки устаревших данных РВД."""
19
+ model_data_cleaner_manager = ModelOutdatedDataCleanerManager()
20
+ model_data_cleaner_manager.run()
@@ -1,3 +1,11 @@
1
+ from typing import (
2
+ Optional,
3
+ Type,
4
+ )
5
+
6
+ from educommon.integration_entities.entities import (
7
+ BaseEntity,
8
+ )
1
9
  from m3_db_utils.models import (
2
10
  ModelEnumValue,
3
11
  TitledModelEnum,
@@ -61,3 +69,47 @@ class RDMEntityEnum(TitledModelEnum):
61
69
  model_enums = sorted(model_enums, key=lambda value: value.order_number)
62
70
 
63
71
  return model_enums
72
+
73
+ @classmethod
74
+ def extend(
75
+ cls,
76
+ key,
77
+ title: str = '',
78
+ entity: Type[BaseEntity] = None,
79
+ main_model_enum: tuple = (),
80
+ additional_model_enums: tuple = (),
81
+ order_number: Optional[int] = None,
82
+ *args,
83
+ **kwargs,
84
+ ):
85
+ """Метод расширения модели-перечисления, например из плагина.
86
+
87
+ Необходимо, чтобы сама модель-перечисление была расширяемой. Для этого необходимо, чтобы был установлен
88
+ extensible = True в Meta.
89
+
90
+ Args:
91
+ key: ключ элемента перечисления, указывается заглавными буквами с разделителем нижнее подчеркивание
92
+ title: название элемента перечисления
93
+ entity: сущность, регистрируемая в модели-перечислении
94
+ main_model_enum: основная модель РВД из модели-перечисления
95
+ additional_model_enums: дополнительные модели РВД из модели-перечисления
96
+ order_number: порядковый номер значения модели перечисления используемый при сортировке
97
+ args: порядковые аргументы для создания значения модели перечисления
98
+ kwargs: именованные аргументы для создания значения модели перечисления
99
+ """
100
+ try:
101
+ order_number = cls._calculate_order_number(order_number=order_number)
102
+ except ValueError as e:
103
+ raise ValueError(f'Trying register entity "{entity.__name__}". {e.args[0]}')
104
+
105
+ model_enum_value = ModelEnumValue(
106
+ key=key,
107
+ title=title,
108
+ entity=entity,
109
+ main_model_enum=main_model_enum,
110
+ additional_model_enums=additional_model_enums,
111
+ order_number=order_number,
112
+ **kwargs,
113
+ )
114
+
115
+ setattr(cls, key, model_enum_value)
@@ -1,3 +1,11 @@
1
+ from collections import (
2
+ defaultdict,
3
+ )
4
+ from typing import (
5
+ Optional,
6
+ Type,
7
+ )
8
+
1
9
  from django.db.models import (
2
10
  CASCADE,
3
11
  DateTimeField,
@@ -14,7 +22,12 @@ from educommon.django.db.mixins import (
14
22
  from educommon.integration_entities.enums import (
15
23
  EntityLogOperation,
16
24
  )
25
+ from educommon.utils.seqtools import (
26
+ topological_sort,
27
+ )
17
28
  from m3_db_utils.models import (
29
+ FictiveForeignKeyField,
30
+ ModelEnumValue,
18
31
  TitledModelEnum,
19
32
  )
20
33
 
@@ -22,6 +35,36 @@ from m3_db_utils.models import (
22
35
  class BaseRDMModel(ReprStrPreModelMixin, BaseObjectModel):
23
36
  """Базовая модель РВД."""
24
37
 
38
+ created = DateTimeField(
39
+ verbose_name='Дата создания',
40
+ auto_now_add=True,
41
+ null=True,
42
+ blank=True,
43
+ db_index=True,
44
+ )
45
+ modified = DateTimeField(
46
+ verbose_name='Дата изменения',
47
+ auto_now=True,
48
+ null=True,
49
+ blank=True,
50
+ db_index=True,
51
+ )
52
+
53
+ @property
54
+ def attrs_for_repr_str(self):
55
+ """Список атрибутов для отображения экземпляра модели."""
56
+ return ['created', 'modified']
57
+
58
+ class Meta:
59
+ abstract = True
60
+
61
+
62
+ class BaseMainRDMModel(BaseRDMModel):
63
+ """Абстрактная основная модель РВД.
64
+
65
+ Является базовым классом для моделей РВД, которые являются основными для сущностей РВД.
66
+ """
67
+
25
68
  collecting_sub_stage = ForeignKey(
26
69
  verbose_name='Подэтап сбора данных',
27
70
  to='edu_rdm_integration_collect_data_stage.RDMCollectingDataSubStage',
@@ -39,21 +82,6 @@ class BaseRDMModel(ReprStrPreModelMixin, BaseObjectModel):
39
82
  choices=EntityLogOperation.get_choices(),
40
83
  )
41
84
 
42
- created = DateTimeField(
43
- verbose_name='Дата создания',
44
- auto_now_add=True,
45
- null=True,
46
- blank=True,
47
- db_index=True,
48
- )
49
- modified = DateTimeField(
50
- verbose_name='Дата изменения',
51
- auto_now=True,
52
- null=True,
53
- blank=True,
54
- db_index=True,
55
- )
56
-
57
85
  @property
58
86
  def attrs_for_repr_str(self):
59
87
  """Список атрибутов для отображения экземпляра модели."""
@@ -66,8 +94,217 @@ class BaseRDMModel(ReprStrPreModelMixin, BaseObjectModel):
66
94
  class RDMModelEnum(TitledModelEnum):
67
95
  """Модель-перечисление моделей "Региональная витрина данных"."""
68
96
 
97
+ is_strict_order_number = True
98
+ """Флаг, указывающий на уникальность порядкового номера элементов модели-перечисления."""
99
+
69
100
  class Meta:
70
101
  db_table = 'rdm_model'
71
102
  extensible = True
72
103
  verbose_name = 'Модель-перечисление моделей "Региональной витрины данных"'
73
104
  verbose_name_plural = 'Модели-перечисления моделей "Региональной витрины данных"'
105
+
106
+ @classmethod
107
+ def _get_model_relations(cls, model: Type['BaseRDMModel']) -> dict[str, str]:
108
+ """Получение списка связей модели РВД."""
109
+ model_label_enum_data = cls.get_model_label_enum_data()
110
+ model_relations = {}
111
+
112
+ for field in model._meta.concrete_fields:
113
+ if isinstance(field, FictiveForeignKeyField):
114
+ model_label = field.to
115
+ elif isinstance(field, ForeignKey):
116
+ model_label = field.related_model._meta.label
117
+ else:
118
+ continue
119
+
120
+ if model_label in model_label_enum_data:
121
+ model_key = model_label_enum_data[model_label].key
122
+ model_relations[field.attname] = model_key
123
+
124
+ return model_relations
125
+
126
+ @classmethod
127
+ def _get_models_relations(cls) -> dict[str, dict[str, str]]:
128
+ """Получение списка связей всех зарегистрированных моделей РВД."""
129
+ model_label_enum_data = cls.get_model_label_enum_data()
130
+ all_models = [model_enum_value.model for model_enum_value in model_label_enum_data.values()]
131
+
132
+ models_relations = {}
133
+ for model in all_models:
134
+ model_key = model_label_enum_data[model._meta.label].key
135
+ model_relations = cls._get_model_relations(model=model)
136
+
137
+ if model_relations:
138
+ models_relations[model_key] = model_relations
139
+
140
+ return models_relations
141
+
142
+ @classmethod
143
+ def _sort_models_dependencies(cls, models_dependencies: list[tuple[str, str]]) -> list[str]:
144
+ """Сортировка моделей РВД по зависимости друг от друга."""
145
+ sorted_dependencies_models = topological_sort(models_dependencies)
146
+
147
+ ordered_models = [*sorted_dependencies_models.cyclic, *reversed(sorted_dependencies_models.sorted)]
148
+
149
+ return ordered_models
150
+
151
+ @classmethod
152
+ def _get_ordered_models(cls) -> list[str]:
153
+ """Получение списка моделей РВД в порядке их зависимости.
154
+
155
+ Есть возможность указать дополнительные модели, для которых совместно с зарегистрированными моделями РВД будет
156
+ рассчитываться порядок.
157
+
158
+ Returns:
159
+ list[str]: список моделей РВД в порядке их зависимости
160
+ """
161
+ enum_keys = cls.get_model_enum_keys()
162
+ models_relations = cls._get_models_relations()
163
+
164
+ models_dependencies = []
165
+ for model_key, model_relations in models_relations.items():
166
+ for _, related_model_key in model_relations.items():
167
+ models_dependencies.append((model_key, related_model_key))
168
+
169
+ ordered_models = cls._sort_models_dependencies(models_dependencies=models_dependencies)
170
+
171
+ without_dependencies = set(enum_keys).difference(set(ordered_models))
172
+
173
+ ordered_models = [*without_dependencies, *ordered_models]
174
+
175
+ return ordered_models
176
+
177
+ @classmethod
178
+ def _recalculate_order_numbers(cls, *args, **kwargs):
179
+ """Перерасчет порядковых номеров элементов модели-перечисления.
180
+
181
+ При добавлении новой модели РВД в модель-перечисление производится перерасчет порядковых номеров уже
182
+ добавленных элементов. Порядок моделей РВД выстраивается по зависимости друг от друга. Зависимость определяется
183
+ внешними ключами (ForeignKey) и фиктивными внешними ключами (FictiveForeignKey). Сначала идут модели не имеющие
184
+ зависимостей, затем модели, которые зависят от других моделей. Сортировка моделей РВД происходит по алгоритму
185
+ топологической сортировки.
186
+ """
187
+ ordered_model_keys = cls._get_ordered_models()
188
+
189
+ for model_enum_value in cls._get_enum_data().values():
190
+ if model_enum_value.is_manual_order_number:
191
+ try:
192
+ manual_index_model_key = ordered_model_keys[model_enum_value.order_number - 1]
193
+ except IndexError:
194
+ continue
195
+
196
+ if manual_index_model_key != model_enum_value.key and cls.is_strict_order_number:
197
+ raise ValueError(
198
+ f'Order number "{model_enum_value.order_number}" is already in use in the "{cls.__name__}". '
199
+ f'Please choose a different one.'
200
+ )
201
+ else:
202
+ model_enum_value.order_number = ordered_model_keys.index(model_enum_value.key) + 1
203
+
204
+ @classmethod
205
+ def _calculate_tmp_order_number(cls) -> int:
206
+ """Вычисление временного порядкового номера элемента модели-перечисления."""
207
+ order_number_enum_data = cls._get_order_number_enum_data()
208
+
209
+ order_numbers = order_number_enum_data.keys()
210
+ tmp_order_number = max(order_numbers) + 1 if order_number_enum_data else 1
211
+
212
+ return tmp_order_number
213
+
214
+ @classmethod
215
+ def _validate_manual_order_number(cls, order_number: int, model: Type['BaseRDMModel']):
216
+ """Валидация пользовательского порядкового номера."""
217
+ ordered_models = cls._get_ordered_models()
218
+
219
+ try:
220
+ manual_index_model = ordered_models[order_number - 1]
221
+ except IndexError:
222
+ return
223
+
224
+ if manual_index_model != model._meta.label and cls.is_strict_order_number:
225
+ raise ValueError(
226
+ f'Order number "{order_number}" is already in use in the "{cls.__name__}". '
227
+ f'Please choose a different one.'
228
+ )
229
+
230
+ @classmethod
231
+ def _update_reverse_relations(cls):
232
+ """Обновление обратных связей моделей РВД.
233
+
234
+ У значения модели-перечисления
235
+ """
236
+ enum_data = cls._get_enum_data()
237
+ # Обнуление обратных связей всех моделей
238
+ for model_enum_value in enum_data.values():
239
+ model_enum_value.reverse_relations = defaultdict(list)
240
+
241
+ models_relations = cls._get_models_relations()
242
+
243
+ for model_key, model_relations in models_relations.items():
244
+ for field_name, related_model_key in model_relations.items():
245
+ enum_data[related_model_key].reverse_relations[model_key].append(field_name)
246
+
247
+ @classmethod
248
+ def get_model_label_enum_data(cls) -> dict[str, Type['ModelEnumValue']]:
249
+ """Получение словаря значений модели-перечисления с лейблом модели в качестве значения."""
250
+ enum_data = cls._get_enum_data()
251
+
252
+ model_label_enum_data = {model_value.model._meta.label: model_value for model_value in enum_data.values()}
253
+
254
+ return model_label_enum_data
255
+
256
+ @classmethod
257
+ def extend(
258
+ cls,
259
+ key,
260
+ model: Type['BaseRDMModel'] = None,
261
+ title: str = '',
262
+ creating_trigger_models: tuple = (),
263
+ loggable_models: tuple = (),
264
+ order_number: Optional[int] = None,
265
+ *args,
266
+ **kwargs,
267
+ ):
268
+ """Метод расширения модели-перечисления, например из плагина.
269
+
270
+ Необходимо, чтобы сама модель-перечисление была расширяемой. Для этого необходимо, чтобы был установлен
271
+ extensible = True в Meta.
272
+
273
+ Args:
274
+ key: ключ элемента перечисления, указывается заглавными буквами с разделителем нижнее подчеркивание
275
+ title: название элемента перечисления
276
+ model: модель, регистрируемая в модели-перечислении
277
+ creating_trigger_models: модели продукта, которые инициируют создание записей модели РВД
278
+ loggable_models: модели продукта, отслеживаемые в логах
279
+ order_number: порядковый номер значения модели перечисления используемый при сортировке
280
+ args: порядковые аргументы для модели-перечисления
281
+ kwargs: именованные аргументы для модели-перечисления
282
+ """
283
+ if key.upper() in cls.get_model_enum_keys():
284
+ raise ValueError('Model enum value with key "{key}" already exists.')
285
+
286
+ if model is None:
287
+ raise ValueError(f'Trying extend model "{cls.__name__}". Argument "model" is required.')
288
+
289
+ is_manual_order_number = order_number is not None
290
+
291
+ if order_number is None:
292
+ order_number = cls._calculate_tmp_order_number()
293
+ else:
294
+ cls._validate_manual_order_number(order_number=order_number, model=model)
295
+
296
+ model_enum_value = ModelEnumValue(
297
+ key=key,
298
+ model=model,
299
+ title=title,
300
+ creating_trigger_models=creating_trigger_models,
301
+ loggable_models=loggable_models,
302
+ order_number=order_number,
303
+ is_manual_order_number=is_manual_order_number,
304
+ reverse_relations=defaultdict(list),
305
+ **kwargs,
306
+ )
307
+ setattr(cls, key, model_enum_value)
308
+
309
+ cls._recalculate_order_numbers()
310
+ cls._update_reverse_relations()
@@ -2,6 +2,9 @@ from abc import (
2
2
  ABCMeta,
3
3
  )
4
4
 
5
+ from edu_function_tools.functions import (
6
+ EduLazySavingPredefinedQueueFunction,
7
+ )
5
8
  from educommon import (
6
9
  logger,
7
10
  )
@@ -9,9 +12,6 @@ from educommon.integration_entities.mixins import (
9
12
  EntitiesMixin,
10
13
  )
11
14
 
12
- from edu_function_tools.functions import (
13
- EduLazySavingPredefinedQueueFunction,
14
- )
15
15
  from edu_rdm_integration.core.consts import (
16
16
  LOGS_DELIMITER,
17
17
  )
@@ -2,6 +2,7 @@ from edu_function_tools.helpers import (
2
2
  EduFunctionHelper,
3
3
  EduRunnerHelper,
4
4
  )
5
+
5
6
  from edu_rdm_integration.core.operations import (
6
7
  ALL_OPERATIONS,
7
8
  UPDATED_OPERATIONS,
@@ -12,6 +12,12 @@ from django.apps import (
12
12
  apps,
13
13
  )
14
14
 
15
+ from edu_function_tools.managers import (
16
+ EduRunnerManager,
17
+ )
18
+ from edu_function_tools.runners import (
19
+ EduRunner,
20
+ )
15
21
  from educommon import (
16
22
  logger,
17
23
  )
@@ -21,13 +27,7 @@ from educommon.audit_log.helpers import (
21
27
  from educommon.audit_log.models import (
22
28
  AuditLog,
23
29
  )
24
- from edu_function_tools.runners import (
25
- EduRunner,
26
- )
27
30
 
28
- from edu_function_tools.managers import (
29
- EduRunnerManager,
30
- )
31
31
  from edu_rdm_integration.core.consts import (
32
32
  DATETIME_FORMAT,
33
33
  LOGS_DELIMITER,
@@ -58,6 +58,7 @@ if TYPE_CHECKING:
58
58
  from edu_function_tools.caches import (
59
59
  EduEntityCache,
60
60
  )
61
+
61
62
  from edu_rdm_integration.rdm_models.models import (
62
63
  BaseRDMModel,
63
64
  )
@@ -2,13 +2,12 @@ from django.conf import (
2
2
  settings,
3
3
  )
4
4
 
5
- from educommon.utils.seqtools import (
6
- make_chunks,
7
- )
8
-
9
5
  from edu_function_tools.runners import (
10
6
  EduRunner,
11
7
  )
8
+ from educommon.utils.seqtools import (
9
+ make_chunks,
10
+ )
12
11
 
13
12
 
14
13
  class BaseCollectingDataRunner(EduRunner):
@@ -8,14 +8,14 @@ from typing import (
8
8
  Union,
9
9
  )
10
10
 
11
- from educommon.utils.conversion import (
12
- int_or_none,
13
- )
14
-
15
11
  from edu_function_tools.caches import (
16
12
  EduFunctionCacheStorage,
17
13
  EduRunnerCacheStorage,
18
14
  )
15
+ from educommon.utils.conversion import (
16
+ int_or_none,
17
+ )
18
+
19
19
  from edu_rdm_integration.stages.collect_data.functions.base.mixins import (
20
20
  ReformatLogsMixin,
21
21
  )
@@ -5,6 +5,7 @@ from typing import (
5
5
  from edu_function_tools.strategies import (
6
6
  EduSyncBaseRunnerLazySavingPredefinedQueueFunctionImplementationStrategy,
7
7
  )
8
+
8
9
  from edu_rdm_integration.core.consts import (
9
10
  REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA,
10
11
  )
@@ -8,6 +8,10 @@ from typing import (
8
8
  Union,
9
9
  )
10
10
 
11
+ from edu_function_tools.caches import (
12
+ EduFunctionCacheStorage,
13
+ EduRunnerCacheStorage,
14
+ )
11
15
  from educommon.audit_log.utils import (
12
16
  get_model_by_table,
13
17
  )
@@ -21,10 +25,6 @@ from educommon.utils.conversion import (
21
25
  int_or_none,
22
26
  )
23
27
 
24
- from edu_function_tools.caches import (
25
- EduFunctionCacheStorage,
26
- EduRunnerCacheStorage,
27
- )
28
28
  from edu_rdm_integration.core.mapping import (
29
29
  MODEL_FIELDS_LOG_FILTER,
30
30
  )
@@ -5,6 +5,7 @@ from typing import (
5
5
  from edu_function_tools.strategies import (
6
6
  EduSyncBaseRunnerLazySavingPredefinedQueueFunctionImplementationStrategy,
7
7
  )
8
+
8
9
  from edu_rdm_integration.core.consts import (
9
10
  REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA,
10
11
  )
@@ -17,9 +17,6 @@ from django.db.models import (
17
17
  from django.utils import (
18
18
  timezone,
19
19
  )
20
- from edu_function_tools.models import (
21
- EduEntity,
22
- )
23
20
  from m3.db import (
24
21
  BaseObjectModel,
25
22
  )
@@ -175,13 +172,13 @@ class RDMCollectingDataSubStage(ReprStrPreModelMixin, BaseObjectModel):
175
172
  """Подэтап сбора данных для сущностей в рамках функции."""
176
173
 
177
174
  stage = ForeignKey(
178
- to=RDMCollectingDataStage,
175
+ to='edu_rdm_integration_collect_data_stage.RDMCollectingDataStage',
179
176
  verbose_name='Этап сбора данных',
180
177
  on_delete=PROTECT,
181
178
  )
182
179
 
183
180
  function = ForeignKey(
184
- to=EduEntity,
181
+ to='function_tools.Entity',
185
182
  verbose_name='Функция',
186
183
  on_delete=PROTECT,
187
184
  )
@@ -17,15 +17,15 @@ from django.utils import (
17
17
  timezone,
18
18
  )
19
19
 
20
+ from edu_function_tools.managers import (
21
+ EduRunnerManager,
22
+ )
20
23
  from educommon import (
21
24
  logger,
22
25
  )
23
26
  from educommon.utils.date import (
24
27
  get_today_min_datetime,
25
28
  )
26
- from edu_function_tools.managers import (
27
- EduRunnerManager,
28
- )
29
29
  from m3_db_utils.consts import (
30
30
  DEFAULT_ORDER_NUMBER,
31
31
  )
@@ -80,8 +80,9 @@ class BaseCollectModelsData(BaseOperationData):
80
80
  super().__init__(**kwargs)
81
81
 
82
82
  # Если модели не указаны, берется значение по умолчанию - все модели:
83
- models = models if models else RDMModelEnum.get_enum_data().keys()
84
- self.models: list[ModelEnumValue] = [RDMModelEnum.get_model_enum_value(model) for model in models]
83
+ model_enum_data = RDMModelEnum.get_enum_data()
84
+ models = models if models else model_enum_data.keys()
85
+ self.models: list[ModelEnumValue] = [v for k, v in model_enum_data.items() if k in models]
85
86
 
86
87
  self.logs_period_started_at = logs_period_started_at
87
88
  self.logs_period_ended_at = logs_period_ended_at
@@ -23,6 +23,10 @@ from django.utils import (
23
23
  timezone,
24
24
  )
25
25
 
26
+ from edu_function_tools.models import (
27
+ EduEntity,
28
+ EduEntityType,
29
+ )
26
30
  from educommon.audit_log.models import (
27
31
  AuditLog,
28
32
  Table,
@@ -33,10 +37,6 @@ from educommon.integration_entities.enums import (
33
37
  from educommon.utils.phone_number.phone_number import (
34
38
  PhoneNumber,
35
39
  )
36
- from edu_function_tools.models import (
37
- EduEntity,
38
- EduEntityType,
39
- )
40
40
 
41
41
  from edu_rdm_integration.core.consts import (
42
42
  REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA,
@@ -1,5 +1,5 @@
1
- from educommon.integration_entities.entities import (
2
- BaseEntity,
1
+ from typing_extensions import (
2
+ TYPE_CHECKING,
3
3
  )
4
4
 
5
5
  from edu_function_tools.caches import (
@@ -8,6 +8,12 @@ from edu_function_tools.caches import (
8
8
  )
9
9
 
10
10
 
11
+ if TYPE_CHECKING:
12
+ from educommon.integration_entities.entities import (
13
+ BaseEntity,
14
+ )
15
+
16
+
11
17
  class BaseExportDataRunnerCacheStorage(EduRunnerCacheStorage):
12
18
  """Базовый кеш помощников ранеров функций выгрузки данных для интеграции с "Региональная витрина данных"."""
13
19
 
@@ -15,7 +21,7 @@ class BaseExportDataRunnerCacheStorage(EduRunnerCacheStorage):
15
21
  class BaseExportDataFunctionCacheStorage(EduFunctionCacheStorage):
16
22
  """Базовый кеш помощников функций выгрузки данных для интеграции с "Региональная витрина данных"."""
17
23
 
18
- def _prepare_entity_instances(self, model_ids, *args, **kwargs) -> list[BaseEntity]:
24
+ def _prepare_entity_instances(self, model_ids, *args, **kwargs) -> list['BaseEntity']:
19
25
  """Формирование списка объектов сущностей для дальнейшей выгрузки.
20
26
 
21
27
  Необходимо переопределить логику формирования объектов у потомков.
@@ -15,6 +15,9 @@ from transliterate import (
15
15
  slugify,
16
16
  )
17
17
 
18
+ from edu_function_tools.functions import (
19
+ EduLazySavingPredefinedQueueGlobalHelperFunction,
20
+ )
18
21
  from educommon import (
19
22
  logger,
20
23
  )
@@ -25,9 +28,6 @@ from educommon.integration_entities.mixins import (
25
28
  EntitiesMixin,
26
29
  )
27
30
 
28
- from edu_function_tools.functions import (
29
- EduLazySavingPredefinedQueueGlobalHelperFunction,
30
- )
31
31
  from edu_rdm_integration.core.consts import (
32
32
  LOGS_DELIMITER,
33
33
  )
@@ -236,4 +236,3 @@ class BaseExportDataFunction(
236
236
  def get_function_data(self):
237
237
  """Возвращает словарь с данными сущностей подготовленных к выгрузке."""
238
238
  return self._data
239
-
@@ -10,6 +10,10 @@ from django.conf import (
10
10
  settings,
11
11
  )
12
12
 
13
+ from edu_function_tools.helpers import (
14
+ EduFunctionHelper,
15
+ EduRunnerHelper,
16
+ )
13
17
  from educommon.utils.conversion import (
14
18
  str_without_control_chars,
15
19
  )
@@ -17,10 +21,6 @@ from educommon.utils.crypto import (
17
21
  HashData,
18
22
  )
19
23
 
20
- from edu_function_tools.helpers import (
21
- EduFunctionHelper,
22
- EduRunnerHelper,
23
- )
24
24
  from edu_rdm_integration.core.consts import (
25
25
  DATE_FORMAT,
26
26
  EXPORT_DATETIME_FORMAT,
@@ -10,6 +10,9 @@ from typing import (
10
10
  Iterator,
11
11
  )
12
12
 
13
+ from edu_function_tools.managers import (
14
+ EduRunnerManager,
15
+ )
13
16
  from educommon import (
14
17
  logger,
15
18
  )
@@ -17,9 +20,6 @@ from m3_db_utils.models import (
17
20
  ModelEnumValue,
18
21
  )
19
22
 
20
- from edu_function_tools.managers import (
21
- EduRunnerManager,
22
- )
23
23
  from edu_rdm_integration.core.consts import (
24
24
  LOGS_DELIMITER,
25
25
  )
@@ -1,6 +1,7 @@
1
1
  from edu_function_tools.runners import (
2
2
  EduRunner,
3
3
  )
4
+
4
5
  from edu_rdm_integration.stages.export_data.functions.base.helpers import (
5
6
  BaseExportDataRunnerHelper,
6
7
  )
@@ -80,6 +80,7 @@ class BaseExportTestCase(TestCase):
80
80
 
81
81
  @classmethod
82
82
  def tearDownClass(cls) -> None:
83
+ """Удаляет временные директории."""
83
84
  try:
84
85
  shutil.rmtree(TEST_DIR)
85
86
  except OSError:
@@ -120,8 +121,7 @@ class BaseExportManagerTestCase(BaseExportTestCase):
120
121
  period_ended_at=self.export_period_ended_at,
121
122
  ).first()
122
123
  exported_data_substage = ExportingDataSubStage.objects.filter(
123
- function_id=function_tools_entities[EduEntityType.FUNCTION.key],
124
- stage=exported_data_stage
124
+ function_id=function_tools_entities[EduEntityType.FUNCTION.key], stage=exported_data_stage
125
125
  ).first()
126
126
 
127
127
  return exported_data_stage, exported_data_substage
@@ -153,10 +153,7 @@ class BaseExportFunctionTestCase(BaseExportTestCase):
153
153
  @override_settings(MEDIA_ROOT=(TEST_DIR + '/media'))
154
154
  def run_exporting_function(self, exporting_stage: ExportingDataStage, model_ids: list[int]) -> dict:
155
155
  """Запускает функцию экспорта."""
156
- exporting_function = self.export_function(
157
- stage=exporting_stage,
158
- model_ids=model_ids
159
- )
156
+ exporting_function = self.export_function(stage=exporting_stage, model_ids=model_ids)
160
157
  exporting_function.run()
161
158
 
162
159
  return exporting_function.get_function_data()
@@ -18,13 +18,13 @@ from django.db.models import (
18
18
  from django.utils import (
19
19
  timezone,
20
20
  )
21
- from edu_function_tools.models import (
22
- EduEntity,
23
- )
24
21
  from m3.db import (
25
22
  BaseObjectModel,
26
23
  )
27
24
 
25
+ from edu_function_tools.models import (
26
+ EduEntity,
27
+ )
28
28
  from educommon.django.db.mixins import (
29
29
  ReprStrPreModelMixin,
30
30
  )
@@ -168,6 +168,11 @@ class RDMExportingDataSubStageStatus(TitledModelEnum):
168
168
  verbose_name = 'Модель-перечисление статусов подэтапа выгрузки данных'
169
169
  verbose_name_plural = 'Модели-перечисления статусов подэтапов выгрузки данных'
170
170
 
171
+ @classmethod
172
+ def get_not_finished_statuses(cls):
173
+ """Получить список статусов, которые не завершены."""
174
+ return cls.CREATED, cls.IN_PROGRESS, cls.FAILED, cls.READY_FOR_EXPORT, cls.PROCESS_ERROR
175
+
171
176
 
172
177
  class RDMExportingDataSubStage(ReprStrPreModelMixin, BaseObjectModel):
173
178
  """Подэтап выгрузки данных."""
@@ -5,6 +5,7 @@ from typing import (
5
5
  from edu_function_tools.strategies import (
6
6
  EduSyncBaseRunnerLazySavingPredefinedQueueFunctionImplementationStrategy,
7
7
  )
8
+
8
9
  from edu_rdm_integration.core.consts import (
9
10
  REGIONAL_DATA_MART_INTEGRATION_EXPORTING_DATA,
10
11
  )
@@ -0,0 +1,26 @@
1
+ from abc import (
2
+ ABCMeta,
3
+ abstractmethod,
4
+ )
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ )
8
+
9
+
10
+ if TYPE_CHECKING:
11
+ from m3_db_utils.models import (
12
+ ModelEnumValue,
13
+ )
14
+
15
+
16
+ class BaseModelOutdatedDataCleaner(metaclass=ABCMeta):
17
+ """Базовый класс уборщика устаревших данных моделей РВД."""
18
+
19
+ def __init__(self, model_enum_value: 'ModelEnumValue', *args, **kwargs):
20
+ self._model_enum_value = model_enum_value
21
+
22
+ super().__init__(*args, **kwargs)
23
+
24
+ @abstractmethod
25
+ def run(self):
26
+ """Запуск очистки устаревших данных."""
@@ -0,0 +1,45 @@
1
+ import importlib
2
+ from typing import (
3
+ TYPE_CHECKING,
4
+ )
5
+
6
+ from edu_rdm_integration.rdm_models.models import (
7
+ RDMModelEnum,
8
+ )
9
+
10
+
11
+ if TYPE_CHECKING:
12
+ from m3_db_utils.models import (
13
+ ModelEnumValue,
14
+ )
15
+
16
+
17
+ class ModelOutdatedDataCleanerManager:
18
+ """Управляет очисткой устаревших данных моделей РВД.
19
+
20
+ Получает все модели РВД зарегистрированные в модели-перечислении edu_rdm_integration.rdm_models.models.RDMModelEnum.
21
+ У каждой модели проверяет наличие поля outdated_data_cleaners. Если такое поле есть, то инстанцирует его и вызывает
22
+ метод run.
23
+ """
24
+
25
+ def _process_model(self, model_enum_value: 'ModelEnumValue'):
26
+ """Обрабатывает модель РВД."""
27
+ if not hasattr(model_enum_value, 'outdated_data_cleaners'):
28
+ return
29
+
30
+ for outdated_data_cleaner in model_enum_value.outdated_data_cleaners:
31
+ if isinstance(outdated_data_cleaner, str):
32
+ outdated_data_cleaner_module_path, cleaner_name = outdated_data_cleaner.rsplit('.', 1)
33
+ outdated_data_cleaner_module = importlib.import_module(outdated_data_cleaner_module_path)
34
+ outdated_data_cleaner = getattr(outdated_data_cleaner_module, cleaner_name)
35
+
36
+ outdated_data_cleaner(model_enum_value=model_enum_value).run()
37
+
38
+ def _process_models(self):
39
+ """Обрабатывает все модели РВД."""
40
+ for model_enum_value in RDMModelEnum.get_model_enum_values():
41
+ self._process_model(model_enum_value=model_enum_value)
42
+
43
+ def run(self):
44
+ """Запускает очистку устаревших данных моделей РВД."""
45
+ self._process_models()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: edu-rdm-integration
3
- Version: 3.17.0
3
+ Version: 3.18.1
4
4
  Summary: Интеграция с Региональной витриной данных
5
5
  Author-email: BARS Group <education_dev@bars.group>
6
6
  Project-URL: Homepage, https://stash.bars-open.ru/projects/EDUBASE/repos/edu-rdm-integration/browse
@@ -27,15 +27,15 @@ Requires-Dist: transliterate<2
27
27
  Requires-Dist: Django<5.0,>=3.1
28
28
  Requires-Dist: celery<5.3,>=4.4.7
29
29
  Requires-Dist: asyncpg==0.23.0
30
- Requires-Dist: educommon<4,>=3.24.0
30
+ Requires-Dist: educommon<4,>=3.25.0
31
31
  Requires-Dist: edu-function-tools<1,>=0.2.0
32
- Requires-Dist: m3-db-utils<1,>=0.3.10
32
+ Requires-Dist: m3-db-utils<1,>=0.7.0
33
33
  Requires-Dist: m3-django-compat<2,>=1.10.2
34
34
  Requires-Dist: m3-ui<2.3,>=2.2.122
35
35
  Requires-Dist: uploader-client<1,>=0.3.0
36
36
  Provides-Extra: dev
37
37
  Requires-Dist: isort==5.12.0; extra == "dev"
38
- Requires-Dist: ruff==0.12.0; extra == "dev"
38
+ Requires-Dist: ruff==0.12.1; extra == "dev"
39
39
  Requires-Dist: flake8<7,>=4.0.1; extra == "dev"
40
40
  Requires-Dist: pytest<8,>=3.2.5; extra == "dev"
41
41
  Requires-Dist: pytest-cov<5; extra == "dev"
@@ -125,6 +125,7 @@ INSTALLED_APPS = (
125
125
  'edu_rdm_integration.core.registry',
126
126
  'edu_rdm_integration.rdm_entities',
127
127
  'edu_rdm_integration.rdm_models',
128
+ 'edu_rdm_integration.pipelines.cleanup_outdated_data',
128
129
  'edu_rdm_integration.pipelines.transfer',
129
130
  'edu_rdm_integration.stages.collect_data',
130
131
  'edu_rdm_integration.stages.export_data',
@@ -1,6 +1,6 @@
1
1
  edu_rdm_integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  edu_rdm_integration/apps.py,sha256=Rrwr04Q-fFmr-2nivyKmfdKj5tB3o_8T82CvVFMnswY,3094
3
- edu_rdm_integration/models.py,sha256=p0QBlNTn3y106bDtbbKhK1xkMnMUCBuMVJ50Qk63Bak,14
3
+ edu_rdm_integration/models.py,sha256=Yzbq2HmGZ8YzBUZpX2V49m_Bc3Q_MSZTaMQPz6kjns8,15
4
4
  edu_rdm_integration/collect_and_export_data/__init__.py,sha256=LXkkpOw-CudTwly71opsc50LvknVTbylr4RRgEoRJ80,79
5
5
  edu_rdm_integration/collect_and_export_data/apps.py,sha256=xzvyL8jwloAFff_SurVWbjJ3TAk5Z2ala51eqwz6Y0k,336
6
6
  edu_rdm_integration/collect_and_export_data/models.py,sha256=yOhOu4Ma74WtPFEoTfqKsU1SWsv6m80YcltFPbvsRT4,55
@@ -44,6 +44,11 @@ edu_rdm_integration/migrations/0017_delete_uploaddatacommand.py,sha256=9hte6Ds-y
44
44
  edu_rdm_integration/migrations/0018_auto_20250704_0725.py,sha256=Ui70ymzkSLCuiU4ydCTK8bBn2JaJJPW7w1gQ2RvmVVc,5661
45
45
  edu_rdm_integration/migrations/__init__.py,sha256=X664cwuc-WxtjYBAbwJJaK7JEIDqY1Y0eSj0f8V76SU,79
46
46
  edu_rdm_integration/pipelines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ edu_rdm_integration/pipelines/cleanup_outdated_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ edu_rdm_integration/pipelines/cleanup_outdated_data/apps.py,sha256=tyTlr1Wt574eby2vIV68FMm7SPFSZKYw6zNkD8x6COE,507
49
+ edu_rdm_integration/pipelines/cleanup_outdated_data/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ edu_rdm_integration/pipelines/cleanup_outdated_data/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ edu_rdm_integration/pipelines/cleanup_outdated_data/management/commands/rdm_cleanup_outdated_data.py,sha256=Mhas_dqs3NPpCKyRxdGFkQCrsic8_48fRDFhVAmq2MU,676
47
52
  edu_rdm_integration/pipelines/transfer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
53
  edu_rdm_integration/pipelines/transfer/actions.py,sha256=e94NVtTcFIqBBTZ9vbSfh_0oXUWK9ZOx2pDYnIePJVc,5920
49
54
  edu_rdm_integration/pipelines/transfer/app_meta.py,sha256=jshfepDDJrbCACtJBJBPuidAVJ6rcziQiet27wqOIjk,373
@@ -60,7 +65,7 @@ edu_rdm_integration/rdm_entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
60
65
  edu_rdm_integration/rdm_entities/apps.py,sha256=2rg5IqBjzpvNsjK-1lnrknxH002XYTDCcrEcARCV-ms,302
61
66
  edu_rdm_integration/rdm_entities/entities.py,sha256=zfIVpXwiNWEeotiS17xZtijSXe3rx6utCFhZ18fGPhM,14850
62
67
  edu_rdm_integration/rdm_entities/mixins.py,sha256=TFxRpajEGHwpFMOJ1G5sJK7hOTEdiv2dWqZzvbUOow4,3081
63
- edu_rdm_integration/rdm_entities/models.py,sha256=uYrUvjM91RfU7Eo_brYo_pOAARwW3esn-m7hXr-btt4,3349
68
+ edu_rdm_integration/rdm_entities/models.py,sha256=vGDQTS-iLnt-THRd89s24uzSXR4nBHLeEdWdPDxf2r4,5759
64
69
  edu_rdm_integration/rdm_entities/utils.py,sha256=zpVmqcJVYjQSHot9ZrVufDeSECP9kosgTmB8ydFDG8w,1095
65
70
  edu_rdm_integration/rdm_entities/migrations/0001_initial.py,sha256=TL8zkmtbFdwdKkFy8wn5SC7dpLBFlS6s8PBp1YBPAog,1664
66
71
  edu_rdm_integration/rdm_entities/migrations/0002_rename_regionaldatamartentityenum_rdmentityenum.py,sha256=CJmQp5TPAL66DBzho01tnWDrCa1fOmEI4AdaS0UbAB0,510
@@ -68,7 +73,7 @@ edu_rdm_integration/rdm_entities/migrations/__init__.py,sha256=47DEQpj8HBSa-_TIm
68
73
  edu_rdm_integration/rdm_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
74
  edu_rdm_integration/rdm_models/apps.py,sha256=JJwHzCXYVe5cEhvDg61KkrLoRT_ZbJCIAWEM2lOQyHU,288
70
75
  edu_rdm_integration/rdm_models/mixins.py,sha256=NuPklb0SppvIfgHK_FCfX7VnD3Wsh48fR85hULoQUNY,2301
71
- edu_rdm_integration/rdm_models/models.py,sha256=YAUENyIF7kutFmYbWWezRqbPbeRDolk1SXAECY7TkoI,2213
76
+ edu_rdm_integration/rdm_models/models.py,sha256=d8DkdDGV3zUYvtlp8ldmMM4k-j3GamUm7AaE5Js-GP4,13235
72
77
  edu_rdm_integration/rdm_models/utils.py,sha256=Xk0HEpFEGAndoAD2TdubK4SI_dW2BvchQ7UeMEfvpfQ,631
73
78
  edu_rdm_integration/rdm_models/migrations/0001_initial.py,sha256=qXgObuG2nfOLEnGJBoBqmq30TXetOv21UZU4trMV7mQ,1529
74
79
  edu_rdm_integration/rdm_models/migrations/0002_rename_regionaldatamartmodelenum_rdmmodelenum.py,sha256=hNTLriOc9r9WEVKahJURA3yXhZ3ivbwJJ_HaMC46PpI,451
@@ -80,9 +85,9 @@ edu_rdm_integration/stages/collect_data/consts.py,sha256=tzaK9oxzdMRq3oTEocPz4um
80
85
  edu_rdm_integration/stages/collect_data/generators.py,sha256=azl0s_xJp6Mg2ARNLKd4o4ikVcarUN3ysb4xm8pYlyY,12434
81
86
  edu_rdm_integration/stages/collect_data/helpers.py,sha256=xy8z9yJKEMjNUPNhrsRRtnYy6RVbwDoD5zSDAX7y_6U,5260
82
87
  edu_rdm_integration/stages/collect_data/mixins.py,sha256=izioaiPC26BDODgi_Lhy33IaH207945tGjFnbFLMQyI,2072
83
- edu_rdm_integration/stages/collect_data/models.py,sha256=wBN1hT6c4pRotsv8EhW-dnvjJvbfk_3w49NMCF5uUyM,9426
84
- edu_rdm_integration/stages/collect_data/operations.py,sha256=eqE_npV6Z72UYatwncaxYhSCwoHv4H09uLtEg19dQ08,11849
85
- edu_rdm_integration/stages/collect_data/tests.py,sha256=qVSeJYWMCQkOVXP1sMe8XzCgdvRFXs9KdcOA_USLteQ,5550
88
+ edu_rdm_integration/stages/collect_data/models.py,sha256=WHGDg-qFyR88fryaD9joxT3bb0tj1yOYaH0XnbGRvAE,9424
89
+ edu_rdm_integration/stages/collect_data/operations.py,sha256=K-St1Avwq093VU1fKzYB19vHRthK_DX6nGPO6PYAipk,11883
90
+ edu_rdm_integration/stages/collect_data/tests.py,sha256=OqxCSdSAOQm92WcBQRF2s0o3VYf-N4e60xpJ1TGdKO8,5550
86
91
  edu_rdm_integration/stages/collect_data/function_templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
92
  edu_rdm_integration/stages/collect_data/function_templates/function_collect_data_template/__init__.py-tpl,sha256=pmUE0_cdK0_PUi0fhu25pcza04deRSfVpU63qPOFKQE,155
88
93
  edu_rdm_integration/stages/collect_data/function_templates/function_collect_data_template/apps.py-tpl,sha256=PU5vgYdhtqu440mRAtIzZ78eIc-no3CsPS3rr1kPpOU,319
@@ -103,15 +108,15 @@ edu_rdm_integration/stages/collect_data/functions/__init__.py,sha256=47DEQpj8HBS
103
108
  edu_rdm_integration/stages/collect_data/functions/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
109
  edu_rdm_integration/stages/collect_data/functions/base/caches.py,sha256=uFArwPl71zdZxwQPfBNNj3D8D6zOdMHQUJYSV8mZiGg,2138
105
110
  edu_rdm_integration/stages/collect_data/functions/base/consts.py,sha256=nzP7973d-YG29l-JxJcq7dF81QDLP7FRtTq0dSq46GM,304
106
- edu_rdm_integration/stages/collect_data/functions/base/functions.py,sha256=GipTVAmoXJlAf1UDCBHagq9ZRUCO4cNNBMf7Os8b0bk,3002
107
- edu_rdm_integration/stages/collect_data/functions/base/helpers.py,sha256=3k5ZWjloFzFPnySbckmjGBmOrKfdhtdyX0pWXRBuvwg,931
108
- edu_rdm_integration/stages/collect_data/functions/base/managers.py,sha256=q9U0MpcI8lyEcAuK4-zlRzs8FSsYODfW3mlsB75u_gQ,6120
109
- edu_rdm_integration/stages/collect_data/functions/base/mixins.py,sha256=LAGrtYpor2lKTPRop1LBllwPg_t4zra3e6VD1BjDqwk,18233
110
- edu_rdm_integration/stages/collect_data/functions/base/runners.py,sha256=OnQbbjsCx8O_EVz_Ga2JvpOCDzBJe5ASXdDgaCEwluo,1526
111
+ edu_rdm_integration/stages/collect_data/functions/base/functions.py,sha256=s-JdkHAuv6FjUjwmHKz7X2PXZU8the6JOA9KDSiy_lQ,3002
112
+ edu_rdm_integration/stages/collect_data/functions/base/helpers.py,sha256=738rlcRnKONoYo-DzzAAWOB0QToKKkFrLhzhypObboI,932
113
+ edu_rdm_integration/stages/collect_data/functions/base/managers.py,sha256=srlaOnALgQoC6Y_5Vk9fD1DxkbufCZaFRqCMrg8JmHM,6120
114
+ edu_rdm_integration/stages/collect_data/functions/base/mixins.py,sha256=j06of4GO61kzKoJAiaT_fBtC1ok7hfaTkRVKqiqtdYI,18234
115
+ edu_rdm_integration/stages/collect_data/functions/base/runners.py,sha256=rR0bkxwk7iU2ENUamVKfs3MwmPO8oV1wkXLchh4sGEg,1525
111
116
  edu_rdm_integration/stages/collect_data/functions/calculated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
- edu_rdm_integration/stages/collect_data/functions/calculated/strategies.py,sha256=X3vVPpNGK30GHqvq6rq0dkYbLPwFcDAzCLWbM91M2Dc,7423
117
+ edu_rdm_integration/stages/collect_data/functions/calculated/strategies.py,sha256=K1xKY-nNjPW3GAYkNUfwSS3BhCaYJlBXk_3FpVALKYI,7424
113
118
  edu_rdm_integration/stages/collect_data/functions/calculated/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
- edu_rdm_integration/stages/collect_data/functions/calculated/base/caches.py,sha256=ovWtVQVShPMO1KgWRVD-t_L1AG1F3_paM9ae4QZrqnQ,2813
119
+ edu_rdm_integration/stages/collect_data/functions/calculated/base/caches.py,sha256=ecC_n-Jlswjl_x-btO2qwZv9Dz6xBrPYI7jnY5UQACc,2813
115
120
  edu_rdm_integration/stages/collect_data/functions/calculated/base/consts.py,sha256=DsgPOF_2iCzZTPity27oDDkpS6Axdhd5C94uSkIwA1g,84
116
121
  edu_rdm_integration/stages/collect_data/functions/calculated/base/enums.py,sha256=BSmwrkzYwEQhz9NbZCJsldY532PqgZJzxzsVk6ue0bM,93
117
122
  edu_rdm_integration/stages/collect_data/functions/calculated/base/errors.py,sha256=Yjcp4gPO0F4j43_NSmbaIapK9RBCiUMgphviF4QO100,300
@@ -125,9 +130,9 @@ edu_rdm_integration/stages/collect_data/functions/calculated/base/strings.py,sha
125
130
  edu_rdm_integration/stages/collect_data/functions/calculated/base/tests.py,sha256=MoRY-a75Ow-7EjeQYxkXWunwqTGuBMaUyEkEV2oy05I,59
126
131
  edu_rdm_integration/stages/collect_data/functions/calculated/base/validators.py,sha256=RJUDhzGsxOoyiHeAcUyUVuo25D7cnE9PVaJQObMFH0U,883
127
132
  edu_rdm_integration/stages/collect_data/functions/non_calculated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
- edu_rdm_integration/stages/collect_data/functions/non_calculated/strategies.py,sha256=7jqATwupQ_X-xR4C7D1dfHZGXVsorb4JfyqJNpV5L5g,7225
133
+ edu_rdm_integration/stages/collect_data/functions/non_calculated/strategies.py,sha256=8F-Mr0uyOydwojhE0_X4lUzFENw08tgMReM8h9zh5BI,7226
129
134
  edu_rdm_integration/stages/collect_data/functions/non_calculated/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- edu_rdm_integration/stages/collect_data/functions/non_calculated/base/caches.py,sha256=QvFXGIPRdtJMqPBcnx1J_SejzmhgVXBSfUxpXNUmciA,6523
135
+ edu_rdm_integration/stages/collect_data/functions/non_calculated/base/caches.py,sha256=AE3KBaPDSouLjNIz58cQqtgGgam2aj4LEN_S4RXYPYw,6523
131
136
  edu_rdm_integration/stages/collect_data/functions/non_calculated/base/consts.py,sha256=pds1t4eHzovm7Yz2o5je3UHqRE8gqfT2sL-IwpoBN_o,66
132
137
  edu_rdm_integration/stages/collect_data/functions/non_calculated/base/enums.py,sha256=BSmwrkzYwEQhz9NbZCJsldY532PqgZJzxzsVk6ue0bM,93
133
138
  edu_rdm_integration/stages/collect_data/functions/non_calculated/base/errors.py,sha256=F1CbAT-IbAhb8MlVl-Q9foBya5RbDglzAT_Mr06gV3w,271
@@ -162,9 +167,9 @@ edu_rdm_integration/stages/export_data/consts.py,sha256=ZEi1kXMs-54KFKxkyGIQVwZ4
162
167
  edu_rdm_integration/stages/export_data/generators.py,sha256=XsTGcKm0oDgE3fUVDxRMkNFriOeuPDBAWi32nx5ASuc,3974
163
168
  edu_rdm_integration/stages/export_data/helpers.py,sha256=uBl85AWS-V0usHeLf7VeAsy0ywvqXL_zT1Kgho-MRTM,6537
164
169
  edu_rdm_integration/stages/export_data/mixins.py,sha256=YCr5aNcZmDx07JIr-vMietQQ3sZ82caWc7SWOMfdSjY,1772
165
- edu_rdm_integration/stages/export_data/models.py,sha256=2qaVF86WEtAuQHBPF9wmDVg0F64SYEDyV8gV7dI4dkE,11767
170
+ edu_rdm_integration/stages/export_data/models.py,sha256=amPrzRzhnX0L7TTnQJH78tmJXCN6_HnK2mt9I9kqhVI,12024
166
171
  edu_rdm_integration/stages/export_data/operations.py,sha256=g8rj4TaFnkRkaBD4omckBTGwsTlYpuBydOwwxY9hEiI,13188
167
- edu_rdm_integration/stages/export_data/strategies.py,sha256=l_KXWbYanhhdJ1ldf_pSGO7IkUoXpOOPKhaOzTcqiJY,6519
172
+ edu_rdm_integration/stages/export_data/strategies.py,sha256=93pRhUOLL_q4VbWTY3CtC5J8rgPPO2EYn0fJk_oLuLk,6520
168
173
  edu_rdm_integration/stages/export_data/function_templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
169
174
  edu_rdm_integration/stages/export_data/function_templates/function_export_data_template/__init__.py-tpl,sha256=pmUE0_cdK0_PUi0fhu25pcza04deRSfVpU63qPOFKQE,155
170
175
  edu_rdm_integration/stages/export_data/function_templates/function_export_data_template/apps.py-tpl,sha256=PU5vgYdhtqu440mRAtIzZ78eIc-no3CsPS3rr1kPpOU,319
@@ -183,19 +188,19 @@ edu_rdm_integration/stages/export_data/function_templates/function_export_data_t
183
188
  edu_rdm_integration/stages/export_data/function_templates/function_export_data_template/validators.py-tpl,sha256=TIPYLk-rPGE9A1hViZ1Mym8XVJjk1qRlG67YTGZHcIE,587
184
189
  edu_rdm_integration/stages/export_data/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
185
190
  edu_rdm_integration/stages/export_data/functions/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
186
- edu_rdm_integration/stages/export_data/functions/base/caches.py,sha256=ovJnyagYnyV7BjqZJ7YbdAgXz-3qwNUZT-gbVBZDkt0,1456
191
+ edu_rdm_integration/stages/export_data/functions/base/caches.py,sha256=Qea50rW_k_dD6unh93faDkHIv5VrC6I3cRt6InANh4g,1543
187
192
  edu_rdm_integration/stages/export_data/functions/base/consts.py,sha256=wRwgxRhQ21uFm9vF0Ub_R7cmep2nYWqGFQDxsIiM2ys,544
188
193
  edu_rdm_integration/stages/export_data/functions/base/enums.py,sha256=BSmwrkzYwEQhz9NbZCJsldY532PqgZJzxzsVk6ue0bM,93
189
194
  edu_rdm_integration/stages/export_data/functions/base/errors.py,sha256=hd1iXftfJa9oXV2ahBaxu-mfFHsRLSyq_nqAVCLseeA,265
190
- edu_rdm_integration/stages/export_data/functions/base/functions.py,sha256=018Tq8jccGGXuZbbzmYIrlr5CCkSi_OZ2YCE1Q4swBM,9468
191
- edu_rdm_integration/stages/export_data/functions/base/helpers.py,sha256=e5oc1YH1fqUQMsIQmseAZTe_UNhb63aPHdk3dw7Q_rI,4495
192
- edu_rdm_integration/stages/export_data/functions/base/managers.py,sha256=Td5iQ8xq62kar1l8p49DPw1NlFt_Wft4XqmoVenFodM,6082
195
+ edu_rdm_integration/stages/export_data/functions/base/functions.py,sha256=lxMDmNWAV93eln17VoVoCz9TdbFfjQ77FVMe3J9r0SI,9467
196
+ edu_rdm_integration/stages/export_data/functions/base/helpers.py,sha256=hD5U2NdDSnVLlFL7RO5lMhHbrG6yeuiUgYUSaqNMA8A,4495
197
+ edu_rdm_integration/stages/export_data/functions/base/managers.py,sha256=4d-68lvLiIT2h93pDfQfw1TNEypmZ7vd63BEDgKa5Js,6082
193
198
  edu_rdm_integration/stages/export_data/functions/base/presenters.py,sha256=DiraTz-aYLzdbz2JKDPBVPPNJpWW376DCBuJwvQQ9bQ,377
194
199
  edu_rdm_integration/stages/export_data/functions/base/requests.py,sha256=kZkjuNBvAUraNFN0nxMBD4yHMpN3I0qKnLgJJthq1Ug,2342
195
200
  edu_rdm_integration/stages/export_data/functions/base/results.py,sha256=GGVrgemlyyRmyjxovC6jRTRkJSoed-gfBu9LVknRxgs,505
196
- edu_rdm_integration/stages/export_data/functions/base/runners.py,sha256=0OvibNyzTfvnud_WUn5Bo99iHYjqiFA4xrgf9ED2oyw,2422
201
+ edu_rdm_integration/stages/export_data/functions/base/runners.py,sha256=Mc_kQrzaM6jaoSjWev0Dyc0adsSMtcZ1aHsqeXoEARs,2423
197
202
  edu_rdm_integration/stages/export_data/functions/base/strings.py,sha256=-k9dex8A7hCpkzUkudVkKRAbNRuuqog2hYl2xmibl8I,181
198
- edu_rdm_integration/stages/export_data/functions/base/tests.py,sha256=ANnqlap_ZvKh0BU-QQcQUjFRQUioVJLAUSU6AyKEm5c,5818
203
+ edu_rdm_integration/stages/export_data/functions/base/tests.py,sha256=QYgprO30EakW0rAhV1NhTIUHB1fvzoQQaQRe9B-ncmc,5842
199
204
  edu_rdm_integration/stages/export_data/functions/base/validators.py,sha256=THOLA-9fG5-187O9UkoUgTlJ_7gLLmM9adhEKao1mg8,883
200
205
  edu_rdm_integration/stages/export_data/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
201
206
  edu_rdm_integration/stages/export_data/management/base.py,sha256=u_4Oc6F5OoMiYH7BHYD42Vv7c56vnHxFVqNyPaPv6MI,4068
@@ -214,6 +219,10 @@ edu_rdm_integration/stages/export_data/registry/templates/ui-js/stage_for_export
214
219
  edu_rdm_integration/stages/service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
215
220
  edu_rdm_integration/stages/service/apps.py,sha256=lgCG4_kpwgfDWh6y-GNuUwz5SOjkP7oS8kkUyVUcNRg,648
216
221
  edu_rdm_integration/stages/service/tasks.py,sha256=PPCtT6EpLkAKRczY0KIT6GeE9eBkv60fl2W6KFvCRqc,2302
222
+ edu_rdm_integration/stages/service/model_outdated_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
+ edu_rdm_integration/stages/service/model_outdated_data/cleaners.py,sha256=gk5_wUNVJwr3D6k5fJDzbSGEhWUXqk9yT6xPK7OP1hw,637
224
+ edu_rdm_integration/stages/service/model_outdated_data/managers.py,sha256=U2rBg-t-X9YfapP4xRRfKiou7sX0V10WxrPHyeCQ-oI,1880
225
+ edu_rdm_integration/stages/service/outdated_service_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
217
226
  edu_rdm_integration/stages/upload_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
218
227
  edu_rdm_integration/stages/upload_data/apps.py,sha256=aFhVPK-65b35CGKoAeAgQ0mm3STaWtZg7rqk3eL-b7s,620
219
228
  edu_rdm_integration/stages/upload_data/consts.py,sha256=yTygXxS5dBRCvrE7Q3D0jEGSC5apIKvVAAViDM8QcKA,223
@@ -245,8 +254,8 @@ edu_rdm_integration/stages/upload_data/uploader_log/ui.py,sha256=mU3XA9zVKHGqzNk
245
254
  edu_rdm_integration/stages/upload_data/uploader_log/migrations/0001_initial.py,sha256=r5oOB7DBK9-mfuqPAgjXUJY5-hEcmMdILCwDTpaLnBc,753
246
255
  edu_rdm_integration/stages/upload_data/uploader_log/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
247
256
  edu_rdm_integration/stages/upload_data/uploader_log/templates/ui-js/object-grid-buttons.js,sha256=2xyGe0wdVokM0RhpzRzcRvJPBkBmPe3SlZry4oP4Nzs,6201
248
- edu_rdm_integration-3.17.0.dist-info/licenses/LICENSE,sha256=uw43Gjjj-1vXWCItfSrNDpbejnOwZMrNerUh8oWbq8Q,3458
249
- edu_rdm_integration-3.17.0.dist-info/METADATA,sha256=9OfQ0SfmcdceqyoyeH6Dqmo5EBlTm1Hb-lH3z5rIx7k,39815
250
- edu_rdm_integration-3.17.0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
251
- edu_rdm_integration-3.17.0.dist-info/top_level.txt,sha256=nRJV0O14UtNE-jGIYG03sohgFnZClvf57H5m6VBXe9Y,20
252
- edu_rdm_integration-3.17.0.dist-info/RECORD,,
257
+ edu_rdm_integration-3.18.1.dist-info/licenses/LICENSE,sha256=uw43Gjjj-1vXWCItfSrNDpbejnOwZMrNerUh8oWbq8Q,3458
258
+ edu_rdm_integration-3.18.1.dist-info/METADATA,sha256=z62LjHvYsuM80OsfmDUHhG4k7L_j67LgX8sWV4-ABKc,39873
259
+ edu_rdm_integration-3.18.1.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
260
+ edu_rdm_integration-3.18.1.dist-info/top_level.txt,sha256=nRJV0O14UtNE-jGIYG03sohgFnZClvf57H5m6VBXe9Y,20
261
+ edu_rdm_integration-3.18.1.dist-info/RECORD,,