educommon 3.13.0__py3-none-any.whl → 3.13.2__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.
- educommon/__init__.py +0 -1
- educommon/about/ui/actions.py +16 -30
- educommon/about/ui/ui.py +3 -12
- educommon/about/utils.py +6 -5
- educommon/async_task/__init__.py +0 -1
- educommon/async_task/actions.py +18 -13
- educommon/async_task/apps.py +4 -0
- educommon/async_task/locker.py +2 -5
- educommon/async_task/migrations/0001_initial.py +55 -9
- educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
- educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
- educommon/async_task/models.py +9 -6
- educommon/async_task/tasks.py +11 -7
- educommon/async_task/ui.py +16 -35
- educommon/async_tasks/__init__.py +0 -1
- educommon/async_tasks/apps.py +4 -0
- educommon/async_tasks/locks.py +11 -21
- educommon/async_tasks/migrations/0001_initial.py +68 -8
- educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
- educommon/async_tasks/models.py +9 -29
- educommon/async_tasks/tasks.py +25 -54
- educommon/audit_log/__init__.py +1 -0
- educommon/audit_log/actions.py +27 -36
- educommon/audit_log/app_meta.py +7 -4
- educommon/audit_log/apps.py +44 -29
- educommon/audit_log/constants.py +7 -4
- educommon/audit_log/error_log/actions.py +1 -3
- educommon/audit_log/helpers.py +2 -4
- educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
- educommon/audit_log/migrations/0001_initial.py +91 -16
- educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
- educommon/audit_log/migrations/0003_logproxy.py +1 -3
- educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
- educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
- educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
- educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
- educommon/audit_log/migrations/0008_table_logged.py +0 -1
- educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
- educommon/audit_log/models.py +36 -42
- educommon/audit_log/permissions.py +11 -9
- educommon/audit_log/proxies.py +12 -23
- educommon/audit_log/ui.py +18 -15
- educommon/audit_log/utils/__init__.py +28 -60
- educommon/audit_log/utils/operations.py +16 -2
- educommon/auth/__init__.py +0 -3
- educommon/auth/rbac/__init__.py +2 -4
- educommon/auth/rbac/actions.py +148 -145
- educommon/auth/rbac/app_meta.py +9 -6
- educommon/auth/rbac/backends/base.py +2 -8
- educommon/auth/rbac/backends/caching.py +27 -37
- educommon/auth/rbac/backends/simple.py +1 -4
- educommon/auth/rbac/checker.py +1 -3
- educommon/auth/rbac/management/commands/rbac.py +6 -11
- educommon/auth/rbac/manager.py +18 -47
- educommon/auth/rbac/migrations/0001_initial.py +73 -12
- educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
- educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
- educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
- educommon/auth/rbac/models.py +63 -68
- educommon/auth/rbac/permissions.py +6 -7
- educommon/auth/rbac/ui.py +83 -84
- educommon/auth/rbac/utils.py +10 -11
- educommon/auth/rbac/validators.py +4 -5
- educommon/auth/simple_auth/__init__.py +1 -5
- educommon/auth/simple_auth/actions.py +79 -92
- educommon/auth/simple_auth/app_meta.py +2 -9
- educommon/auth/simple_auth/checkers.py +3 -3
- educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
- educommon/auth/simple_auth/validators.py +0 -1
- educommon/contingent/actions.py +7 -7
- educommon/contingent/app_meta.py +1 -4
- educommon/contingent/base.py +10 -15
- educommon/contingent/catalogs.py +424 -540
- educommon/contingent/contingent_plugin/actions.py +4 -15
- educommon/contingent/contingent_plugin/apps.py +10 -4
- educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
- educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
- educommon/contingent/contingent_plugin/model_views.py +2 -12
- educommon/contingent/contingent_plugin/models.py +2 -7
- educommon/contingent/contingent_plugin/observer.py +14 -13
- educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
- educommon/contingent/contingent_plugin/storage.py +8 -7
- educommon/contingent/contingent_plugin/utils.py +6 -6
- educommon/django/db/fields.py +72 -86
- educommon/django/db/migration/__init__.py +3 -7
- educommon/django/db/migration/operations.py +29 -51
- educommon/django/db/mixins/__init__.py +16 -10
- educommon/django/db/mixins/date_interval.py +47 -75
- educommon/django/db/mixins/validation.py +26 -26
- educommon/django/db/model_view/__init__.py +18 -22
- educommon/django/db/models.py +9 -8
- educommon/django/db/observer.py +9 -27
- educommon/django/db/partitioning/__init__.py +66 -92
- educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
- educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
- educommon/django/db/partitioning/management/commands/split_table.py +18 -13
- educommon/django/db/routers.py +6 -15
- educommon/django/db/signals.py +4 -2
- educommon/django/db/utils.py +14 -19
- educommon/django/db/validators/__init__.py +1 -0
- educommon/django/db/validators/simple.py +72 -100
- educommon/django/storages/atcfs/api.py +39 -53
- educommon/django/storages/atcfs/app_meta.py +1 -1
- educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
- educommon/django/storages/atcfs/models.py +0 -3
- educommon/django/storages/atcfs/monkey_patching.py +18 -12
- educommon/django/storages/atcfs/storage.py +14 -23
- educommon/extjs/fields/input_params.py +15 -45
- educommon/importer/XLSReader.py +143 -241
- educommon/importer/__init__.py +86 -4
- educommon/importer/api.py +53 -84
- educommon/importer/constants.py +4 -14
- educommon/importer/loggers.py +16 -26
- educommon/importer/proxy.py +131 -176
- educommon/importer/proxy_import.py +11 -12
- educommon/importer/report.py +4 -6
- educommon/importer/ui.py +32 -26
- educommon/importer/validators.py +4 -7
- educommon/integration_entities/helpers.py +14 -18
- educommon/ioc/__init__.py +3 -6
- educommon/logger/loggers.py +10 -14
- educommon/m3/__init__.py +20 -38
- educommon/m3/extensions/__init__.py +1 -0
- educommon/m3/extensions/listeners/__init__.py +22 -38
- educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
- educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
- educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
- educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
- educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
- educommon/m3/extensions/ui.py +15 -33
- educommon/m3/transaction_context.py +17 -19
- educommon/objectpack/actions.py +70 -88
- educommon/objectpack/apps.py +5 -0
- educommon/objectpack/filters.py +9 -15
- educommon/objectpack/ui.py +59 -77
- educommon/report/__init__.py +9 -5
- educommon/report/actions.py +29 -32
- educommon/report/constructor/__init__.py +5 -8
- educommon/report/constructor/app_meta.py +1 -3
- educommon/report/constructor/apps.py +1 -0
- educommon/report/constructor/base.py +33 -80
- educommon/report/constructor/builders/excel/_base.py +138 -286
- educommon/report/constructor/builders/excel/_header.py +2 -9
- educommon/report/constructor/builders/excel/product.py +13 -34
- educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
- educommon/report/constructor/config.py +2 -0
- educommon/report/constructor/editor/actions.py +101 -215
- educommon/report/constructor/editor/ui.py +71 -93
- educommon/report/constructor/exceptions.py +6 -12
- educommon/report/constructor/migrations/0001_initial.py +36 -44
- educommon/report/constructor/migrations/0002_report_filters.py +86 -72
- educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
- educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
- educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
- educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
- educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
- educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
- educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
- educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
- educommon/report/constructor/mixins.py +14 -15
- educommon/report/constructor/models.py +76 -124
- educommon/report/constructor/utils.py +3 -8
- educommon/report/constructor/validators.py +1 -3
- educommon/report/reporter.py +25 -43
- educommon/report/utils.py +14 -40
- educommon/rest/actions.py +7 -11
- educommon/rest/context.py +6 -16
- educommon/rest/controllers.py +10 -10
- educommon/rest/mixins.py +29 -27
- educommon/secure_media/app_meta.py +9 -9
- educommon/utils/__init__.py +3 -2
- educommon/utils/caching.py +1 -3
- educommon/utils/conversion.py +1 -3
- educommon/utils/crypto.py +1 -2
- educommon/utils/date.py +13 -26
- educommon/utils/db/__init__.py +17 -26
- educommon/utils/db/postgresql.py +1 -4
- educommon/utils/fonts/__init__.py +3 -4
- educommon/utils/licence/__init__.py +5 -16
- educommon/utils/misc.py +9 -18
- educommon/utils/object_grid.py +55 -62
- educommon/utils/phone_number/modelfields.py +1 -3
- educommon/utils/phone_number/phone_number.py +5 -8
- educommon/utils/phone_number/validators.py +8 -23
- educommon/utils/plugins.py +15 -28
- educommon/utils/registry.py +2 -1
- educommon/utils/seqtools.py +1 -3
- educommon/utils/serializer.py +9 -16
- educommon/utils/storage.py +3 -2
- educommon/utils/system.py +1 -3
- educommon/utils/system_app/management/commands/delete_objects.py +17 -34
- educommon/utils/ui.py +87 -84
- educommon/utils/xml/__init__.py +2 -7
- educommon/utils/xml/resolver.py +1 -0
- educommon/ws_log/actions.py +31 -76
- educommon/ws_log/base.py +6 -20
- educommon/ws_log/migrations/0001_initial.py +25 -8
- educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
- educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
- educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
- educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
- educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
- educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
- educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
- educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
- educommon/ws_log/models.py +21 -35
- educommon/ws_log/provider.py +2 -1
- educommon/ws_log/report.py +8 -13
- educommon/ws_log/smev/applications.py +12 -27
- educommon/ws_log/smev/exceptions.py +2 -3
- educommon/ws_log/ui.py +32 -32
- educommon/ws_log/utils.py +1 -3
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/METADATA +26 -14
- educommon-3.13.2.dist-info/RECORD +354 -0
- educommon/utils/patches.py +0 -27
- educommon/version.conf +0 -11
- educommon-3.13.0.dist-info/RECORD +0 -357
- educommon-3.13.0.dist-info/dependency_links.txt +0 -1
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +0 -0
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
@@ -21,9 +21,9 @@ class ProxyLoader:
|
|
21
21
|
message = None
|
22
22
|
"""Сообщение о результате."""
|
23
23
|
|
24
|
-
def __init__(
|
25
|
-
|
26
|
-
|
24
|
+
def __init__(
|
25
|
+
self, loaders, _file, file_name, context=None, separate_logs=False, ignore_bad_rows=False, result_logger=None
|
26
|
+
):
|
27
27
|
"""Загрузка файла по словарю прокси-загрузчиков.
|
28
28
|
|
29
29
|
:param dict loaders: словарь постраничных загрузчиков файла
|
@@ -55,8 +55,7 @@ class ProxyLoader:
|
|
55
55
|
:param dict log: лог
|
56
56
|
:rtype str
|
57
57
|
"""
|
58
|
-
return '\n'.join(
|
59
|
-
self.xls_loader.log + self.xls_loader.prepare_row_errors(log))
|
58
|
+
return '\n'.join(self.xls_loader.log + self.xls_loader.prepare_row_errors(log))
|
60
59
|
|
61
60
|
def load(self):
|
62
61
|
"""Импорт данных из файла."""
|
@@ -96,7 +95,7 @@ class ProxyLoader:
|
|
96
95
|
loader_cls = self.loaders.get(sheet.upper())
|
97
96
|
if not loader_cls:
|
98
97
|
# Если не найден загрузчик для листа
|
99
|
-
error_msg = 'Некорректное имя листа "
|
98
|
+
error_msg = f'Некорректное имя листа "{sheet}"'
|
100
99
|
import_log[data[0][self.xls_loader.XLS_POS]] = error_msg
|
101
100
|
# Заносим запись об ошибке при обработке листа в общий лог
|
102
101
|
self.result_logger.on_sheet_errors(sheet, [error_msg])
|
@@ -110,7 +109,7 @@ class ProxyLoader:
|
|
110
109
|
log=import_log,
|
111
110
|
context=self.context,
|
112
111
|
warning_log=warning_log,
|
113
|
-
result_logger=self.result_logger
|
112
|
+
result_logger=self.result_logger,
|
114
113
|
)
|
115
114
|
|
116
115
|
log = self.make_log(import_log)
|
@@ -120,14 +119,14 @@ class ProxyLoader:
|
|
120
119
|
# если задан режим разделения логов
|
121
120
|
if log:
|
122
121
|
# всё же были какие-то ошибки
|
123
|
-
final_log = [
|
122
|
+
final_log = [' ОШИБКИ:\n ', log]
|
124
123
|
else:
|
125
|
-
final_log = [
|
124
|
+
final_log = [
|
125
|
+
SUCCESFUL_IMPORTED,
|
126
|
+
]
|
126
127
|
|
127
128
|
if warning_log:
|
128
|
-
final_log.extend([
|
129
|
-
" ПРЕДУПРЕЖДЕНИЯ:\n ", self.make_log(warning_log)
|
130
|
-
])
|
129
|
+
final_log.extend([' ПРЕДУПРЕЖДЕНИЯ:\n ', self.make_log(warning_log)])
|
131
130
|
|
132
131
|
self.message = '\n'.join(final_log)
|
133
132
|
else:
|
educommon/importer/report.py
CHANGED
@@ -13,14 +13,14 @@ from educommon.report.reporter import (
|
|
13
13
|
|
14
14
|
|
15
15
|
class BaseFailureImportReport:
|
16
|
-
"""Базовый класс отчета об
|
16
|
+
"""Базовый класс отчета об импорте."""
|
17
17
|
|
18
18
|
template_name = None
|
19
19
|
reports_dir = 'reports'
|
20
20
|
default_extension = 'xlsx'
|
21
21
|
|
22
22
|
def __init__(self, data):
|
23
|
-
""":param data - данные для
|
23
|
+
""":param data - данные для отчета."""
|
24
24
|
|
25
25
|
self.data = data
|
26
26
|
# Текущая директория
|
@@ -33,9 +33,7 @@ class BaseFailureImportReport:
|
|
33
33
|
self.out_file_path = get_path(self.base_name)
|
34
34
|
# url адрес, по которому будет доступен отчет
|
35
35
|
self.out_file_url = get_url(self.base_name)
|
36
|
-
self.report = SpreadsheetReport(os.path.join(
|
37
|
-
reports_dir, '%s.%s' % (self.template_name, self.default_extension)
|
38
|
-
))
|
36
|
+
self.report = SpreadsheetReport(os.path.join(reports_dir, f'{self.template_name}.{self.default_extension}'))
|
39
37
|
|
40
38
|
# Создадим директории, если их нет
|
41
39
|
folder_path = get_path('')
|
@@ -43,5 +41,5 @@ class BaseFailureImportReport:
|
|
43
41
|
os.makedirs(folder_path)
|
44
42
|
|
45
43
|
def make(self):
|
46
|
-
"""Сбор
|
44
|
+
"""Сбор отчета."""
|
47
45
|
raise NotImplementedError
|
educommon/importer/ui.py
CHANGED
@@ -12,58 +12,61 @@ class BaseImportWindow(BaseEditWindow):
|
|
12
12
|
"""Базовое окно загрузки шаблона импорта."""
|
13
13
|
|
14
14
|
def _init_components(self):
|
15
|
-
super(
|
15
|
+
super()._init_components()
|
16
|
+
|
16
17
|
self.file_field = ext.ExtFileUploadField(
|
17
18
|
anchor='100%',
|
18
19
|
allow_blank=False,
|
19
20
|
name='uploaded',
|
20
|
-
label=
|
21
|
+
label='Файл для загрузки',
|
21
22
|
)
|
22
23
|
|
23
24
|
def _do_layout(self):
|
24
|
-
super(
|
25
|
+
super()._do_layout()
|
26
|
+
|
25
27
|
self.form.items.append(self.file_field)
|
26
28
|
|
27
29
|
def set_params(self, params):
|
28
|
-
super(
|
30
|
+
super().set_params(params)
|
31
|
+
|
29
32
|
self.height = 110
|
30
33
|
# FIXME: При переопределении придется копипастить
|
31
34
|
# Проброс ID окна для окна результата
|
32
|
-
self.handler_beforesubmit =
|
35
|
+
self.handler_beforesubmit = """
|
33
36
|
function (submit) {submit.params["import_window_id"] = win.id}
|
34
|
-
|
37
|
+
"""
|
35
38
|
|
36
39
|
self.form.file_upload = True
|
37
40
|
self.save_btn.text = 'Загрузить'
|
38
|
-
self.file_field.possible_file_extensions = params.get(
|
39
|
-
'extensions', None
|
40
|
-
)
|
41
|
+
self.file_field.possible_file_extensions = params.get('extensions', None)
|
41
42
|
|
42
43
|
|
43
44
|
class ImportResultWindow(BaseWindow):
|
44
45
|
"""Окно для вывода результата импорта."""
|
45
46
|
|
46
47
|
def _init_components(self):
|
47
|
-
super(
|
48
|
+
super()._init_components()
|
49
|
+
|
48
50
|
self.result_field = ext.ExtTextArea(read_only=True)
|
49
51
|
|
50
|
-
self.close_btn = ext.ExtButton(
|
51
|
-
text='Закрыть',
|
52
|
-
handler='function() {win.close()}'
|
53
|
-
)
|
52
|
+
self.close_btn = ext.ExtButton(text='Закрыть', handler='function() {win.close()}')
|
54
53
|
|
55
54
|
# Кнопка "Отмена" не блокируется в режиме "только для чтения"
|
56
55
|
self._mro_exclude_list.append(self.close_btn)
|
57
56
|
|
58
57
|
def _do_layout(self):
|
59
|
-
super(
|
58
|
+
super()._do_layout()
|
59
|
+
|
60
60
|
self.items.append(self.result_field)
|
61
|
-
self.buttons.extend(
|
62
|
-
|
63
|
-
|
61
|
+
self.buttons.extend(
|
62
|
+
[
|
63
|
+
self.close_btn,
|
64
|
+
]
|
65
|
+
)
|
64
66
|
|
65
67
|
def set_params(self, params):
|
66
|
-
super(
|
68
|
+
super().set_params(params)
|
69
|
+
|
67
70
|
self.body_style = 'padding: 0;'
|
68
71
|
self.layout = 'fit'
|
69
72
|
self.modal = False
|
@@ -75,37 +78,40 @@ class ConfirmImportResultWindow(ImportResultWindow):
|
|
75
78
|
"""Окно для подтверждения импорта при наличии ошибок."""
|
76
79
|
|
77
80
|
def _init_components(self):
|
78
|
-
super(
|
81
|
+
super()._init_components()
|
82
|
+
|
79
83
|
self.confirm_import_btn = ext.ExtButton(
|
80
84
|
text='Загрузить данные, в которых нет ошибок',
|
81
85
|
)
|
82
86
|
|
83
87
|
def _do_layout(self):
|
84
|
-
super(
|
88
|
+
super()._do_layout()
|
89
|
+
|
85
90
|
self.buttons.insert(0, self.confirm_import_btn)
|
86
91
|
|
87
92
|
def set_params(self, params):
|
88
|
-
super(
|
93
|
+
super().set_params(params)
|
94
|
+
|
89
95
|
self.parent_window_id = params['import_window_id']
|
90
96
|
|
91
97
|
if params.get('exit_from_import_on_close', False):
|
92
98
|
# Закрытие окна импорта и окна результата
|
93
|
-
self.close_btn.handler =
|
99
|
+
self.close_btn.handler = """
|
94
100
|
function() {
|
95
101
|
if (win.parentWindow) win.parentWindow.close();
|
96
102
|
win.close();
|
97
103
|
}
|
98
|
-
|
104
|
+
"""
|
99
105
|
|
100
106
|
if params.get('hide_confirm_button', False):
|
101
107
|
self.confirm_import_btn.hidden = True
|
102
108
|
else:
|
103
109
|
# Хэндлер пробрасывает параметр для пропуска ошибок и снова
|
104
110
|
# сабмитит форму импорта.
|
105
|
-
self.confirm_import_btn.handler =
|
111
|
+
self.confirm_import_btn.handler = """
|
106
112
|
function() {
|
107
113
|
win.close();
|
108
114
|
win.parentWindow.actionContextJson.ignore_bad_rows = true;
|
109
115
|
win.parentWindow.submitForm();
|
110
116
|
}
|
111
|
-
|
117
|
+
"""
|
educommon/importer/validators.py
CHANGED
@@ -1,23 +1,20 @@
|
|
1
|
-
"""
|
2
|
-
Базовые валидаторы для импортируемых данных.
|
1
|
+
"""Базовые валидаторы для импортируемых данных.
|
3
2
|
|
4
3
|
Использовать только для расширения/исправления логики, реализованной с помощью
|
5
4
|
`educommon.importer`. При написании новых классов для импорта/экспорта данных
|
6
5
|
рекомендуется использовать пакет `data-transfer`.
|
7
6
|
"""
|
7
|
+
|
8
8
|
from abc import (
|
9
9
|
ABCMeta,
|
10
10
|
)
|
11
11
|
|
12
12
|
|
13
13
|
class IImportDataValidator(metaclass=ABCMeta):
|
14
|
-
"""
|
15
|
-
Базовый класс валидатора импортируемых данных.
|
16
|
-
"""
|
14
|
+
"""Базовый класс валидатора импортируемых данных."""
|
17
15
|
|
18
16
|
def __call__(self, data_row, errors, warnings):
|
19
|
-
"""
|
20
|
-
Валидирует строку входных данных.
|
17
|
+
"""Валидирует строку входных данных.
|
21
18
|
|
22
19
|
:param data_row: словарь, представляющий одну строку импортируемых
|
23
20
|
данных
|
@@ -29,8 +29,7 @@ from educommon.integration_entities.enums import (
|
|
29
29
|
|
30
30
|
|
31
31
|
class AbstractEntitySaver(ABC):
|
32
|
-
"""
|
33
|
-
Абстрактный класс сохранения записей в моделях.
|
32
|
+
"""Абстрактный класс сохранения записей в моделях.
|
34
33
|
|
35
34
|
Используется в рамках выгрузок РВД, Сферум и ГИСРУО.
|
36
35
|
"""
|
@@ -72,8 +71,7 @@ class AbstractEntitySaver(ABC):
|
|
72
71
|
|
73
72
|
@property
|
74
73
|
def _to_delete_entities(self) -> Union[list, Iterable[Model]]:
|
75
|
-
"""
|
76
|
-
Возвращает записи для удаления.
|
74
|
+
"""Возвращает записи для удаления.
|
77
75
|
|
78
76
|
Частный случай, поэтому по умолчанию возвращает пустой список.
|
79
77
|
"""
|
@@ -119,16 +117,14 @@ class AbstractEntitySaver(ABC):
|
|
119
117
|
)
|
120
118
|
|
121
119
|
def _delete_entities(self) -> None:
|
122
|
-
"""
|
123
|
-
Удаляет записи или обрабатывает записи для удаления.
|
120
|
+
"""Удаляет записи или обрабатывает записи для удаления.
|
124
121
|
|
125
122
|
Частный случай, поэтому метод мало где может пригодиться.
|
126
123
|
"""
|
127
124
|
|
128
125
|
|
129
126
|
class EntitySaver(AbstractEntitySaver):
|
130
|
-
"""
|
131
|
-
Стандартный класс для сохранения моделей.
|
127
|
+
"""Стандартный класс для сохранения моделей.
|
132
128
|
|
133
129
|
Стандартный, потому что используется в большинстве случаев.
|
134
130
|
"""
|
@@ -171,25 +167,25 @@ class EntitySaverWithRealDeleting(EntitySaver):
|
|
171
167
|
|
172
168
|
|
173
169
|
class ChainEntitySaver(AbstractEntitySaver):
|
174
|
-
"""
|
175
|
-
Класс для сохранения моделей.
|
170
|
+
"""Класс для сохранения моделей.
|
176
171
|
|
177
172
|
Chain, потому что формирование объектов для сохранения происходит с помощью itertools.chain
|
178
173
|
"""
|
179
174
|
|
180
175
|
def _get_entities_base(self, operation_type: EntityLogOperation) -> Iterable[Model]:
|
181
176
|
"""Базовый метод, возвращающий объекты для сохранения в зависимости от типа операции."""
|
182
|
-
return chain.from_iterable(
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
177
|
+
return chain.from_iterable(
|
178
|
+
[
|
179
|
+
entities.values()
|
180
|
+
for operation_entities in self._to_save_entities.values()
|
181
|
+
for operation, entities in operation_entities.items()
|
182
|
+
if operation == operation_type
|
183
|
+
]
|
184
|
+
)
|
188
185
|
|
189
186
|
|
190
187
|
class IterableEntitySaver(AbstractEntitySaver):
|
191
|
-
"""
|
192
|
-
Класс для сохранения моделей.
|
188
|
+
"""Класс для сохранения моделей.
|
193
189
|
|
194
190
|
Iterable, потому что формирование объектов для сохранения происходит в цикле.
|
195
191
|
Используется в gis_ruo.
|
educommon/ioc/__init__.py
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
При необходимости использования в общей кодовой базе объектов проекта,
|
5
5
|
нужно добавить переменные со значением ``educommon.Undefined`` в данный модуль.
|
6
6
|
"""
|
7
|
+
|
7
8
|
from educommon import (
|
8
9
|
Undefined,
|
9
10
|
)
|
@@ -85,9 +86,7 @@ def register(name, value):
|
|
85
86
|
if globals()[name] is value:
|
86
87
|
return value
|
87
88
|
|
88
|
-
assert globals()[name] is Undefined, (
|
89
|
-
'"{}" already registered'.format(name)
|
90
|
-
)
|
89
|
+
assert globals()[name] is Undefined, '"{}" already registered'.format(name)
|
91
90
|
|
92
91
|
globals()[name] = value
|
93
92
|
|
@@ -100,8 +99,6 @@ def get(name):
|
|
100
99
|
*name* должен быть предварительно зарегистрирован через **register**.
|
101
100
|
"""
|
102
101
|
assert name in globals(), 'Object {} is not registered'.format(name)
|
103
|
-
assert globals()[name] is not Undefined, (
|
104
|
-
'"{}" not registered'.format(name)
|
105
|
-
)
|
102
|
+
assert globals()[name] is not Undefined, '"{}" not registered'.format(name)
|
106
103
|
|
107
104
|
return globals()[name]
|
educommon/logger/loggers.py
CHANGED
@@ -29,9 +29,7 @@ _srcfile = os.path.normcase(addLevelName.__code__.co_filename)
|
|
29
29
|
|
30
30
|
|
31
31
|
class WebEduLogger(getLoggerClass()):
|
32
|
-
"""
|
33
|
-
Расширенный логер для работы с различными версиями Python.
|
34
|
-
"""
|
32
|
+
"""Расширенный логер для работы с различными версиями Python."""
|
35
33
|
|
36
34
|
def makeRecord(
|
37
35
|
self,
|
@@ -46,9 +44,7 @@ class WebEduLogger(getLoggerClass()):
|
|
46
44
|
extra: Optional[Mapping[str, object]] = ...,
|
47
45
|
sinfo: Optional[str] = ...,
|
48
46
|
) -> WebEduLogRecord:
|
49
|
-
"""
|
50
|
-
Метод формирования записи лога.
|
51
|
-
"""
|
47
|
+
"""Метод формирования записи лога."""
|
52
48
|
rv = WebEduLogRecord(name, level, fn, lno, msg, args, exc_info, func)
|
53
49
|
|
54
50
|
if extra:
|
@@ -71,16 +67,16 @@ class WebEduLogger(getLoggerClass()):
|
|
71
67
|
stacklevel=1,
|
72
68
|
request=None,
|
73
69
|
):
|
74
|
-
"""
|
75
|
-
|
76
|
-
|
70
|
+
"""Низкоуровневая процедура логирования.
|
71
|
+
|
72
|
+
Создает LogRecord и передает его всем обработчикам данного логгера.
|
77
73
|
"""
|
78
74
|
sinfo = None
|
79
75
|
|
80
76
|
if _srcfile:
|
81
|
-
#IronPython doesn't track Python frames, so findCaller raises an
|
82
|
-
#exception on some versions of IronPython. We trap it here so that
|
83
|
-
#IronPython can use logging.
|
77
|
+
# IronPython doesn't track Python frames, so findCaller raises an
|
78
|
+
# exception on some versions of IronPython. We trap it here so that
|
79
|
+
# IronPython can use logging.
|
84
80
|
try:
|
85
81
|
python_version = platform.python_version()
|
86
82
|
|
@@ -90,9 +86,9 @@ class WebEduLogger(getLoggerClass()):
|
|
90
86
|
fn, lno, func, sinfo = self.findCaller(stack_info, stacklevel)
|
91
87
|
|
92
88
|
except ValueError: # pragma: no cover
|
93
|
-
fn, lno, func =
|
89
|
+
fn, lno, func = '(unknown file)', 0, '(unknown function)'
|
94
90
|
else: # pragma: no cover
|
95
|
-
fn, lno, func =
|
91
|
+
fn, lno, func = '(unknown file)', 0, '(unknown function)'
|
96
92
|
|
97
93
|
if exc_info:
|
98
94
|
if isinstance(exc_info, BaseException):
|
educommon/m3/__init__.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Вспомогательные средства для работы с компонентами M3."""
|
2
|
+
|
2
3
|
import inspect
|
3
4
|
import sys
|
4
5
|
from functools import (
|
@@ -72,6 +73,7 @@ def convert_validation_error_to(exc, new_line='<br/>', model=None):
|
|
72
73
|
Если аргумент указан, то данные будут извлекаться именно из этой
|
73
74
|
модели.
|
74
75
|
"""
|
76
|
+
|
75
77
|
def get_model_meta(error):
|
76
78
|
if model is not None:
|
77
79
|
return model._meta
|
@@ -85,31 +87,24 @@ def convert_validation_error_to(exc, new_line='<br/>', model=None):
|
|
85
87
|
if 'self' not in error_frame.f_locals:
|
86
88
|
raise
|
87
89
|
model_instance = error_frame.f_locals['self']
|
90
|
+
|
88
91
|
return model_instance._meta
|
89
92
|
|
90
93
|
def get_messages_from_dict(model_meta, data):
|
91
94
|
result = []
|
92
95
|
for field_name, field_errors in data.items():
|
93
96
|
if field_name == NON_FIELD_ERRORS:
|
94
|
-
result.append(
|
95
|
-
new_line.join(
|
96
|
-
'- {0}'.format(err) for err in field_errors
|
97
|
-
)
|
98
|
-
)
|
97
|
+
result.append(new_line.join('- {0}'.format(err) for err in field_errors))
|
99
98
|
else:
|
100
99
|
model_field = model_meta.get_field(field_name)
|
101
|
-
verbose_name =
|
102
|
-
result.append(new_line.join(
|
103
|
-
|
104
|
-
for err in field_errors
|
105
|
-
))
|
100
|
+
verbose_name = model_field.verbose_name or ''
|
101
|
+
result.append(new_line.join('- {0}: {1}'.format(verbose_name, err) for err in field_errors))
|
102
|
+
|
106
103
|
return result
|
107
104
|
|
108
105
|
def get_messages_from_list(messages):
|
109
|
-
result = [
|
110
|
-
|
111
|
-
for message in messages
|
112
|
-
]
|
106
|
+
result = ['- ' + message for message in messages]
|
107
|
+
|
113
108
|
return result
|
114
109
|
|
115
110
|
assert issubclass(exc, Exception), type(exc)
|
@@ -127,8 +122,7 @@ def convert_validation_error_to(exc, new_line='<br/>', model=None):
|
|
127
122
|
|
128
123
|
if hasattr(e, 'message_dict'):
|
129
124
|
title = 'На форме имеются некорректно заполненные поля:'
|
130
|
-
messages = [title] + get_messages_from_dict(model_meta,
|
131
|
-
e.message_dict)
|
125
|
+
messages = [title] + get_messages_from_dict(model_meta, e.message_dict)
|
132
126
|
else:
|
133
127
|
title = 'При проверке данных найдены ошибки:'
|
134
128
|
messages = [title] + get_messages_from_list(e.messages)
|
@@ -155,12 +149,10 @@ class ModelProxyValidationMixin:
|
|
155
149
|
model_errors = error.update_error_dict({})
|
156
150
|
|
157
151
|
for field_name, messages in model_errors.items():
|
158
|
-
|
159
152
|
# В зависимости от версии Django в messages могут быть
|
160
153
|
# как сообщения в виде строк, так и экземпляры ValidationError,
|
161
154
|
# поэтому приводим его к списку, содержащему только строки
|
162
|
-
messages = sum([m.messages if isinstance(
|
163
|
-
m, DjangoValidationError) else [m] for m in messages], [])
|
155
|
+
messages = sum([m.messages if isinstance(m, DjangoValidationError) else [m] for m in messages], [])
|
164
156
|
|
165
157
|
if field_name != NON_FIELD_ERRORS:
|
166
158
|
full_field_name = '.'.join((model_name, field_name))
|
@@ -216,9 +208,7 @@ class ModelProxyValidationMixin:
|
|
216
208
|
errors = {}
|
217
209
|
|
218
210
|
models = ( # элементы составной модели
|
219
|
-
name
|
220
|
-
for name in (list(self.relations) + [primary_model_name])
|
221
|
-
if not exclude or name not in exclude
|
211
|
+
name for name in (list(self.relations) + [primary_model_name]) if not exclude or name not in exclude
|
222
212
|
)
|
223
213
|
|
224
214
|
for model_name in models:
|
@@ -250,8 +240,7 @@ class ModelProxyValidationMixin:
|
|
250
240
|
try:
|
251
241
|
model.full_clean(model_exclude)
|
252
242
|
except DjangoValidationError as error:
|
253
|
-
errors = self.__update_error_dict(error, errors,
|
254
|
-
model_name)
|
243
|
+
errors = self.__update_error_dict(error, errors, model_name)
|
255
244
|
if not errors:
|
256
245
|
valid_key = '_ModelValidationMixin__object_is_valid'
|
257
246
|
model.__dict__[valid_key] = True
|
@@ -296,10 +285,9 @@ class PackValidationMixin:
|
|
296
285
|
from objectpack.slave_object_pack.actions import (
|
297
286
|
SlavePack,
|
298
287
|
)
|
288
|
+
|
299
289
|
if isinstance(self, SlavePack):
|
300
|
-
obj.__dict__.update(
|
301
|
-
self._get_parents_dict(context, key_fmt='%s_id')
|
302
|
-
)
|
290
|
+
obj.__dict__.update(self._get_parents_dict(context, key_fmt='%s_id'))
|
303
291
|
save_row = super(SlavePack, self).save_row
|
304
292
|
else:
|
305
293
|
save_row = super(PackValidationMixin, self).save_row
|
@@ -336,14 +324,8 @@ def get_pack(pack_or_model):
|
|
336
324
|
"""
|
337
325
|
observer = ioc.get('observer')
|
338
326
|
|
339
|
-
if (
|
340
|
-
(
|
341
|
-
isinstance(pack_or_model, str) and
|
342
|
-
'.' in pack_or_model
|
343
|
-
) or (
|
344
|
-
inspect.isclass(pack_or_model) and
|
345
|
-
issubclass(pack_or_model, ActionPack)
|
346
|
-
)
|
327
|
+
if (isinstance(pack_or_model, str) and '.' in pack_or_model) or (
|
328
|
+
inspect.isclass(pack_or_model) and issubclass(pack_or_model, ActionPack)
|
347
329
|
):
|
348
330
|
# Пак задан именем класса в пакете или классом
|
349
331
|
result = ControllerCache.find_pack(pack_or_model)
|
@@ -376,6 +358,7 @@ def get_pack_id(pack_or_model):
|
|
376
358
|
"""
|
377
359
|
pack = get_pack(pack_or_model)
|
378
360
|
result = pack.id_param_name
|
361
|
+
|
379
362
|
return result
|
380
363
|
|
381
364
|
|
@@ -396,13 +379,12 @@ def get_id_value(context, pack_or_model):
|
|
396
379
|
:param pack_or_model: Аргумент, определяющий пак, из которого будет
|
397
380
|
получено имя параметра, идентифицирующего объект (*id_param_name*).
|
398
381
|
"""
|
399
|
-
assert isinstance(
|
400
|
-
context, ObservableController.VerboseDeclarativeContext
|
401
|
-
), type(context)
|
382
|
+
assert isinstance(context, ObservableController.VerboseDeclarativeContext), type(context)
|
402
383
|
|
403
384
|
if isinstance(pack_or_model, (Action, ActionPack)):
|
404
385
|
pack_or_model = pack_or_model.__class__
|
405
386
|
|
406
387
|
pack = get_pack(pack_or_model)
|
407
388
|
result = getattr(context, pack.id_param_name)
|
389
|
+
|
408
390
|
return result
|