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.
Files changed (220) hide show
  1. educommon/__init__.py +0 -1
  2. educommon/about/ui/actions.py +16 -30
  3. educommon/about/ui/ui.py +3 -12
  4. educommon/about/utils.py +6 -5
  5. educommon/async_task/__init__.py +0 -1
  6. educommon/async_task/actions.py +18 -13
  7. educommon/async_task/apps.py +4 -0
  8. educommon/async_task/locker.py +2 -5
  9. educommon/async_task/migrations/0001_initial.py +55 -9
  10. educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
  11. educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
  12. educommon/async_task/models.py +9 -6
  13. educommon/async_task/tasks.py +11 -7
  14. educommon/async_task/ui.py +16 -35
  15. educommon/async_tasks/__init__.py +0 -1
  16. educommon/async_tasks/apps.py +4 -0
  17. educommon/async_tasks/locks.py +11 -21
  18. educommon/async_tasks/migrations/0001_initial.py +68 -8
  19. educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
  20. educommon/async_tasks/models.py +9 -29
  21. educommon/async_tasks/tasks.py +25 -54
  22. educommon/audit_log/__init__.py +1 -0
  23. educommon/audit_log/actions.py +27 -36
  24. educommon/audit_log/app_meta.py +7 -4
  25. educommon/audit_log/apps.py +44 -29
  26. educommon/audit_log/constants.py +7 -4
  27. educommon/audit_log/error_log/actions.py +1 -3
  28. educommon/audit_log/helpers.py +2 -4
  29. educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
  30. educommon/audit_log/migrations/0001_initial.py +91 -16
  31. educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
  32. educommon/audit_log/migrations/0003_logproxy.py +1 -3
  33. educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
  34. educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
  35. educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
  36. educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
  37. educommon/audit_log/migrations/0008_table_logged.py +0 -1
  38. educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
  39. educommon/audit_log/models.py +36 -42
  40. educommon/audit_log/permissions.py +11 -9
  41. educommon/audit_log/proxies.py +12 -23
  42. educommon/audit_log/ui.py +18 -15
  43. educommon/audit_log/utils/__init__.py +28 -60
  44. educommon/audit_log/utils/operations.py +16 -2
  45. educommon/auth/__init__.py +0 -3
  46. educommon/auth/rbac/__init__.py +2 -4
  47. educommon/auth/rbac/actions.py +148 -145
  48. educommon/auth/rbac/app_meta.py +9 -6
  49. educommon/auth/rbac/backends/base.py +2 -8
  50. educommon/auth/rbac/backends/caching.py +27 -37
  51. educommon/auth/rbac/backends/simple.py +1 -4
  52. educommon/auth/rbac/checker.py +1 -3
  53. educommon/auth/rbac/management/commands/rbac.py +6 -11
  54. educommon/auth/rbac/manager.py +18 -47
  55. educommon/auth/rbac/migrations/0001_initial.py +73 -12
  56. educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
  57. educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
  58. educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
  59. educommon/auth/rbac/models.py +63 -68
  60. educommon/auth/rbac/permissions.py +6 -7
  61. educommon/auth/rbac/ui.py +83 -84
  62. educommon/auth/rbac/utils.py +10 -11
  63. educommon/auth/rbac/validators.py +4 -5
  64. educommon/auth/simple_auth/__init__.py +1 -5
  65. educommon/auth/simple_auth/actions.py +79 -92
  66. educommon/auth/simple_auth/app_meta.py +2 -9
  67. educommon/auth/simple_auth/checkers.py +3 -3
  68. educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
  69. educommon/auth/simple_auth/validators.py +0 -1
  70. educommon/contingent/actions.py +7 -7
  71. educommon/contingent/app_meta.py +1 -4
  72. educommon/contingent/base.py +10 -15
  73. educommon/contingent/catalogs.py +424 -540
  74. educommon/contingent/contingent_plugin/actions.py +4 -15
  75. educommon/contingent/contingent_plugin/apps.py +10 -4
  76. educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
  77. educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
  78. educommon/contingent/contingent_plugin/model_views.py +2 -12
  79. educommon/contingent/contingent_plugin/models.py +2 -7
  80. educommon/contingent/contingent_plugin/observer.py +14 -13
  81. educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
  82. educommon/contingent/contingent_plugin/storage.py +8 -7
  83. educommon/contingent/contingent_plugin/utils.py +6 -6
  84. educommon/django/db/fields.py +72 -86
  85. educommon/django/db/migration/__init__.py +3 -7
  86. educommon/django/db/migration/operations.py +29 -51
  87. educommon/django/db/mixins/__init__.py +16 -10
  88. educommon/django/db/mixins/date_interval.py +47 -75
  89. educommon/django/db/mixins/validation.py +26 -26
  90. educommon/django/db/model_view/__init__.py +18 -22
  91. educommon/django/db/models.py +9 -8
  92. educommon/django/db/observer.py +9 -27
  93. educommon/django/db/partitioning/__init__.py +66 -92
  94. educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
  95. educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
  96. educommon/django/db/partitioning/management/commands/split_table.py +18 -13
  97. educommon/django/db/routers.py +6 -15
  98. educommon/django/db/signals.py +4 -2
  99. educommon/django/db/utils.py +14 -19
  100. educommon/django/db/validators/__init__.py +1 -0
  101. educommon/django/db/validators/simple.py +72 -100
  102. educommon/django/storages/atcfs/api.py +39 -53
  103. educommon/django/storages/atcfs/app_meta.py +1 -1
  104. educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
  105. educommon/django/storages/atcfs/models.py +0 -3
  106. educommon/django/storages/atcfs/monkey_patching.py +18 -12
  107. educommon/django/storages/atcfs/storage.py +14 -23
  108. educommon/extjs/fields/input_params.py +15 -45
  109. educommon/importer/XLSReader.py +143 -241
  110. educommon/importer/__init__.py +86 -4
  111. educommon/importer/api.py +53 -84
  112. educommon/importer/constants.py +4 -14
  113. educommon/importer/loggers.py +16 -26
  114. educommon/importer/proxy.py +131 -176
  115. educommon/importer/proxy_import.py +11 -12
  116. educommon/importer/report.py +4 -6
  117. educommon/importer/ui.py +32 -26
  118. educommon/importer/validators.py +4 -7
  119. educommon/integration_entities/helpers.py +14 -18
  120. educommon/ioc/__init__.py +3 -6
  121. educommon/logger/loggers.py +10 -14
  122. educommon/m3/__init__.py +20 -38
  123. educommon/m3/extensions/__init__.py +1 -0
  124. educommon/m3/extensions/listeners/__init__.py +22 -38
  125. educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
  126. educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
  127. educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
  128. educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
  129. educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
  130. educommon/m3/extensions/ui.py +15 -33
  131. educommon/m3/transaction_context.py +17 -19
  132. educommon/objectpack/actions.py +70 -88
  133. educommon/objectpack/apps.py +5 -0
  134. educommon/objectpack/filters.py +9 -15
  135. educommon/objectpack/ui.py +59 -77
  136. educommon/report/__init__.py +9 -5
  137. educommon/report/actions.py +29 -32
  138. educommon/report/constructor/__init__.py +5 -8
  139. educommon/report/constructor/app_meta.py +1 -3
  140. educommon/report/constructor/apps.py +1 -0
  141. educommon/report/constructor/base.py +33 -80
  142. educommon/report/constructor/builders/excel/_base.py +138 -286
  143. educommon/report/constructor/builders/excel/_header.py +2 -9
  144. educommon/report/constructor/builders/excel/product.py +13 -34
  145. educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
  146. educommon/report/constructor/config.py +2 -0
  147. educommon/report/constructor/editor/actions.py +101 -215
  148. educommon/report/constructor/editor/ui.py +71 -93
  149. educommon/report/constructor/exceptions.py +6 -12
  150. educommon/report/constructor/migrations/0001_initial.py +36 -44
  151. educommon/report/constructor/migrations/0002_report_filters.py +86 -72
  152. educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
  153. educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
  154. educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
  155. educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
  156. educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
  157. educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
  158. educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
  159. educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
  160. educommon/report/constructor/mixins.py +14 -15
  161. educommon/report/constructor/models.py +76 -124
  162. educommon/report/constructor/utils.py +3 -8
  163. educommon/report/constructor/validators.py +1 -3
  164. educommon/report/reporter.py +25 -43
  165. educommon/report/utils.py +14 -40
  166. educommon/rest/actions.py +7 -11
  167. educommon/rest/context.py +6 -16
  168. educommon/rest/controllers.py +10 -10
  169. educommon/rest/mixins.py +29 -27
  170. educommon/secure_media/app_meta.py +9 -9
  171. educommon/utils/__init__.py +3 -2
  172. educommon/utils/caching.py +1 -3
  173. educommon/utils/conversion.py +1 -3
  174. educommon/utils/crypto.py +1 -2
  175. educommon/utils/date.py +13 -26
  176. educommon/utils/db/__init__.py +17 -26
  177. educommon/utils/db/postgresql.py +1 -4
  178. educommon/utils/fonts/__init__.py +3 -4
  179. educommon/utils/licence/__init__.py +5 -16
  180. educommon/utils/misc.py +9 -18
  181. educommon/utils/object_grid.py +55 -62
  182. educommon/utils/phone_number/modelfields.py +1 -3
  183. educommon/utils/phone_number/phone_number.py +5 -8
  184. educommon/utils/phone_number/validators.py +8 -23
  185. educommon/utils/plugins.py +15 -28
  186. educommon/utils/registry.py +2 -1
  187. educommon/utils/seqtools.py +1 -3
  188. educommon/utils/serializer.py +9 -16
  189. educommon/utils/storage.py +3 -2
  190. educommon/utils/system.py +1 -3
  191. educommon/utils/system_app/management/commands/delete_objects.py +17 -34
  192. educommon/utils/ui.py +87 -84
  193. educommon/utils/xml/__init__.py +2 -7
  194. educommon/utils/xml/resolver.py +1 -0
  195. educommon/ws_log/actions.py +31 -76
  196. educommon/ws_log/base.py +6 -20
  197. educommon/ws_log/migrations/0001_initial.py +25 -8
  198. educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
  199. educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
  200. educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
  201. educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
  202. educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
  203. educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
  204. educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
  205. educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
  206. educommon/ws_log/models.py +21 -35
  207. educommon/ws_log/provider.py +2 -1
  208. educommon/ws_log/report.py +8 -13
  209. educommon/ws_log/smev/applications.py +12 -27
  210. educommon/ws_log/smev/exceptions.py +2 -3
  211. educommon/ws_log/ui.py +32 -32
  212. educommon/ws_log/utils.py +1 -3
  213. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/METADATA +26 -14
  214. educommon-3.13.2.dist-info/RECORD +354 -0
  215. educommon/utils/patches.py +0 -27
  216. educommon/version.conf +0 -11
  217. educommon-3.13.0.dist-info/RECORD +0 -357
  218. educommon-3.13.0.dist-info/dependency_links.txt +0 -1
  219. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +0 -0
  220. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
educommon/report/utils.py CHANGED
@@ -39,10 +39,7 @@ def get_cell_bounds(section, row_index, column_index):
39
39
  """
40
40
  merged_ranges = section.writer.wtsheet.merged_ranges
41
41
  for first_row, last_row, first_column, last_column in merged_ranges:
42
- if (
43
- first_row <= row_index <= last_row and
44
- first_column <= column_index <= last_column
45
- ):
42
+ if first_row <= row_index <= last_row and first_column <= column_index <= last_column:
46
43
  return first_row, last_row, first_column, last_column
47
44
 
48
45
  return row_index, row_index, column_index, column_index
@@ -69,13 +66,8 @@ def get_cell_width(section, row_index, column_index):
69
66
 
70
67
  :rtype: int
71
68
  """
72
- _, _, first_column, last_column = get_cell_bounds(
73
- section, row_index, column_index
74
- )
75
- return sum(
76
- section.writer.wtsheet.col(i).width
77
- for i in range(first_column, last_column + 1)
78
- )
69
+ _, _, first_column, last_column = get_cell_bounds(section, row_index, column_index)
70
+ return sum(section.writer.wtsheet.col(i).width for i in range(first_column, last_column + 1))
79
71
 
80
72
 
81
73
  def get_cell_height(section, row_index, column_index):
@@ -95,17 +87,11 @@ def get_cell_height(section, row_index, column_index):
95
87
  :returns: Высоту ячейки в `твипах <https://goo.gl/hfUW7x>`_.
96
88
  :rtype: int
97
89
  """
98
- first_row, last_row, _, _ = get_cell_bounds(
99
- section, row_index, column_index
100
- )
101
- return sum(
102
- section.writer.wtsheet.row(i).height
103
- for i in range(first_row, last_row + 1)
104
- )
90
+ first_row, last_row, _, _ = get_cell_bounds(section, row_index, column_index)
91
+ return sum(section.writer.wtsheet.row(i).height for i in range(first_row, last_row + 1))
105
92
 
106
93
 
107
- def adjust_row_height(section, row_idx, col_idx, text, font,
108
- adjusted_row_index=None):
94
+ def adjust_row_height(section, row_idx, col_idx, text, font, adjusted_row_index=None):
109
95
  """Увеличивает высоту строки, если необходимо.
110
96
 
111
97
  Высота строки устанавливается такая, чтобы текст `text`
@@ -135,6 +121,7 @@ def adjust_row_height(section, row_idx, col_idx, text, font,
135
121
  ячейки будет увеличена равномерно. Номер указывается относительно
136
122
  ячейки, нумерация начинается с нуля.
137
123
  """
124
+
138
125
  def get_text_height(column_width):
139
126
  """Вычисляет высоту строки отчета в зависимости от текста."""
140
127
  # Т.к. высота и ширина ячейки измеряется в единицах относительно
@@ -145,9 +132,7 @@ def adjust_row_height(section, row_idx, col_idx, text, font,
145
132
  # DEFAULT_CHAR_SIZE * 0.8 определяет ширину отступов слева и справа (в
146
133
  # сумме, а не каждого отступа по отдельности). Источник точной
147
134
  # информации об отступах в ячейке найти не удалось.
148
- width_in_chars = (
149
- int(column_width - DEFAULT_CHAR_SIZE * 0.8) // DEFAULT_CHAR_SIZE
150
- )
135
+ width_in_chars = int(column_width - DEFAULT_CHAR_SIZE * 0.8) // DEFAULT_CHAR_SIZE
151
136
 
152
137
  str_width_px, str_height_px = normal_font.getsize('0' * width_in_chars)
153
138
 
@@ -155,17 +140,13 @@ def adjust_row_height(section, row_idx, col_idx, text, font,
155
140
  _, choosen_font_height_px = font.getsize('0')
156
141
  height_scale = (choosen_font_height_px * 1.0) / str_height_px
157
142
 
158
- rows_count = len(
159
- split_text(text, font, str_width_px)
160
- )
143
+ rows_count = len(split_text(text, font, str_width_px))
161
144
 
162
145
  height = int(rows_count * height_scale * DEFAULT_CHAR_SIZE)
163
146
 
164
147
  return height
165
148
 
166
- first_row, last_row, first_column, last_column = get_cell_bounds(
167
- section, row_idx, col_idx
168
- )
149
+ first_row, last_row, first_column, last_column = get_cell_bounds(section, row_idx, col_idx)
169
150
 
170
151
  merged = first_row != last_row or first_column != last_column
171
152
 
@@ -192,20 +173,15 @@ def adjust_row_height(section, row_idx, col_idx, text, font,
192
173
  row = section.writer.wtsheet.row(r)
193
174
  add_row_height(row, height_delta // row_count)
194
175
  else:
195
- assert adjusted_row_index > row_count, (
196
- adjusted_row_index, row_count
197
- )
198
- row = section.writer.wtsheet.row(
199
- first_row + adjusted_row_index
200
- )
176
+ assert adjusted_row_index > row_count, (adjusted_row_index, row_count)
177
+ row = section.writer.wtsheet.row(first_row + adjusted_row_index)
201
178
  add_row_height(row, height_delta)
202
179
  else:
203
180
  row = section.writer.wtsheet.row(row_idx)
204
181
  add_row_height(row, height_delta)
205
182
 
206
183
 
207
- def adjust_row_height_arial(section, row_idx, col_idx, text, font_size=10,
208
- adjusted_row_index=None):
184
+ def adjust_row_height_arial(section, row_idx, col_idx, text, font_size=10, adjusted_row_index=None):
209
185
  """Устанавливает высоту строки автоматически.
210
186
 
211
187
  Высота строки устанавливается такая, чтобы текст text
@@ -226,6 +202,4 @@ def adjust_row_height_arial(section, row_idx, col_idx, text, font_size=10,
226
202
  ячейки, нумерация начинается с нуля.
227
203
  """
228
204
  font = get_font(ARIAL, font_size)
229
- adjust_row_height(
230
- section, row_idx, col_idx, text, font, adjusted_row_index
231
- )
205
+ adjust_row_height(section, row_idx, col_idx, text, font, adjusted_row_index)
educommon/rest/actions.py CHANGED
@@ -8,7 +8,7 @@ from educommon.rest import (
8
8
 
9
9
 
10
10
  class BaseRestPack(BasePack):
11
- """Базовый пак для всех REST пакокв."""
11
+ """Базовый пак для всех REST паков."""
12
12
 
13
13
 
14
14
  class RestPack(
@@ -17,10 +17,10 @@ class RestPack(
17
17
  mixins.CreateModelMixin,
18
18
  mixins.UpdateModelMixin,
19
19
  mixins.DestroyModelMixin,
20
- BaseRestPack
20
+ BaseRestPack,
21
21
  ):
22
- """
23
- Пак для обработки запросов методами: GET, POST, PUT, PATCH, DELETE.
22
+ """Пак для обработки запросов методами: GET, POST, PUT, PATCH, DELETE.
23
+
24
24
  Для обработки запросов методом GET исользуются методы пака list и retrieve.
25
25
  Для обработки запросов методом POST используется метод пака create.
26
26
  Для обработки запросов методом PUT и PATCH используется метод пака update.
@@ -28,12 +28,8 @@ class RestPack(
28
28
  """
29
29
 
30
30
 
31
- class RestReadOnlyPack(
32
- mixins.ListModelMixin,
33
- mixins.RetrieveModelMixin,
34
- BaseRestPack
35
- ):
36
- """
37
- Пак который обрабатывает запросы только методом GET.
31
+ class RestReadOnlyPack(mixins.ListModelMixin, mixins.RetrieveModelMixin, BaseRestPack):
32
+ """Пак который обрабатывает запросы только методом GET.
33
+
38
34
  Доступные методы пака: list и retrieve.
39
35
  """
educommon/rest/context.py CHANGED
@@ -12,14 +12,9 @@ from educommon.rest.misc import (
12
12
  )
13
13
 
14
14
 
15
- class RestDeclarativeActionContext(
16
- ObservableController.VerboseDeclarativeContext
17
- ):
18
-
15
+ class RestDeclarativeActionContext(ObservableController.VerboseDeclarativeContext):
19
16
  def build(self, request, rules):
20
- """
21
- Выполняет заполнение собственных атрибутов
22
- согласно переданному запросу, исходя из списка правил
17
+ """Выполняет заполнение собственных атрибутов согласно переданному запросу, исходя из списка правил.
23
18
 
24
19
  :param request:запрос, на основе которого производится
25
20
  заполнение контекста
@@ -30,7 +25,7 @@ class RestDeclarativeActionContext(
30
25
 
31
26
  :raise: TypeError, ContextBuildingError, CriticalContextBuildingError
32
27
  """
33
- assert self.matches(rules), "rules must be a dict or pair!"
28
+ assert self.matches(rules), 'rules must be a dict or pair!'
34
29
  # определяем режим, если правилла описаны парой
35
30
  if isinstance(rules, tuple):
36
31
  # режим
@@ -54,10 +49,7 @@ class RestDeclarativeActionContext(
54
49
  try:
55
50
  parser = self._parsers[parser]
56
51
  except KeyError:
57
- raise TypeError(
58
- 'Неизвестный парсер контекста: "%s"' %
59
- parser
60
- )
52
+ raise TypeError(f'Неизвестный парсер контекста: "{parser}"')
61
53
 
62
54
  add_error_to = None
63
55
  try:
@@ -84,12 +76,10 @@ class RestDeclarativeActionContext(
84
76
  add_error_to = errors
85
77
 
86
78
  if add_error_to is not None:
87
- add_error_to.append(
88
- parser_data.get('verbose_name', key))
79
+ add_error_to.append(parser_data.get('verbose_name', key))
89
80
  # ошибка критична, если хотя бы один из параметров
90
81
  # не имеет verbose_name
91
- only_noncritical = only_noncritical and (
92
- 'verbose_name' in parser_data)
82
+ only_noncritical = only_noncritical and ('verbose_name' in parser_data)
93
83
  continue
94
84
 
95
85
  setattr(self, key, val)
@@ -24,9 +24,7 @@ class RestObservableController(ObservableController):
24
24
  api = None
25
25
  object_id_regex = re.compile(r'/(?P<id>\d+)$')
26
26
 
27
- class VerboseDeclarativeContext(
28
- RestDeclarativeActionContext
29
- ):
27
+ class VerboseDeclarativeContext(RestDeclarativeActionContext):
30
28
  def build(self, request, rules):
31
29
  self.__declared = list(rules.keys()) + self.__internal_attrs
32
30
 
@@ -36,7 +34,7 @@ class RestObservableController(ObservableController):
36
34
  if self.__debug:
37
35
  raise
38
36
  else:
39
- _warn('%r, url="%s"' % (e, request.path_info))
37
+ _warn(f'{e!r}, url="{request.path_info}"')
40
38
 
41
39
  for k, v in list(get_request_params(request).items()):
42
40
  if not hasattr(self, k):
@@ -53,17 +51,18 @@ class RestObservableController(ObservableController):
53
51
  pass
54
52
 
55
53
  def __init__(self, observer, *args, **kwargs):
56
- super(RestObservableController, self).__init__(
57
- observer, *args, **kwargs)
54
+ super().__init__(observer, *args, **kwargs)
55
+
58
56
  self.api = {}
59
57
 
60
58
  def append_pack(self, pack):
61
- super(RestObservableController, self).append_pack(pack)
59
+ super().append_pack(pack)
60
+
62
61
  self.api[pack.__class__.__name__] = pack.get_absolute_url()
63
62
 
64
63
  def process_request(self, request):
65
- """
66
- Обработка входящего запроса *request* от клиента.
64
+ """Обработка входящего запроса *request* от клиента.
65
+
67
66
  Экшен определяется исходя из метода запроса.
68
67
  """
69
68
 
@@ -73,4 +72,5 @@ class RestObservableController(ObservableController):
73
72
 
74
73
  path = self.object_id_regex.sub('', request.path)
75
74
  request.path = '{}/{}'.format(path.rstrip('/'), request.method.lower())
76
- return super(RestObservableController, self).process_request(request)
75
+
76
+ return super().process_request(request)
educommon/rest/mixins.py CHANGED
@@ -12,48 +12,50 @@ class BaseRestAction(BaseAction):
12
12
 
13
13
 
14
14
  class ListModelMixin:
15
- """
16
- Примесь для REST паков, обработка запросов метода GET.
15
+ """Примесь для REST паков, обработка запросов метода GET.
16
+
17
17
  Получения списка объектов.
18
18
  """
19
19
 
20
20
  def __init__(self):
21
- super(ListModelMixin, self).__init__()
21
+ super().__init__()
22
+
22
23
  if not hasattr(self, 'get_action'):
23
24
  self.get_action = GetAction()
24
25
  self.actions.append(self.get_action)
25
26
 
26
27
  def list(self, request, context):
27
- """
28
- Метод отвечает за обработку запроса методом GET.
28
+ """Метод отвечает за обработку запроса методом GET.
29
+
29
30
  Получение списка объектов.
30
31
  """
31
32
  raise NotImplementedError
32
33
 
33
34
 
34
35
  class RetrieveModelMixin:
35
- """
36
- Примесь для REST паков, обработка запросов метода GET.
36
+ """Примесь для REST паков, обработка запросов метода GET.
37
+
37
38
  Получение конкретно объекта по context.id.
38
39
  """
39
40
 
40
41
  def __init__(self):
41
- super(RetrieveModelMixin, self).__init__()
42
+ super().__init__()
43
+
42
44
  if not hasattr(self, 'get_action'):
43
45
  self.get_action = GetAction()
44
46
  self.actions.append(self.get_action)
45
47
 
46
48
  def retrieve(self, request, context):
47
- """
48
- Метод отвечает за обработку запроса методом GET.
49
+ """Метод отвечает за обработку запроса методом GET.
50
+
49
51
  Получение конкретного объекта по context.id.
50
52
  """
51
53
  raise NotImplementedError
52
54
 
53
55
 
54
56
  class GetAction(BaseRestAction):
55
- """
56
- Экшен обработки запроса методом GET.
57
+ """Экшен обработки запроса методом GET.
58
+
57
59
  Делегирует обработку методам пака.
58
60
  """
59
61
 
@@ -71,7 +73,8 @@ class CreateModelMixin:
71
73
  """Примесь для REST паков, обработка запросов методом POST."""
72
74
 
73
75
  def __init__(self):
74
- super(CreateModelMixin, self).__init__()
76
+ super().__init__()
77
+
75
78
  self.post_action = PostAction()
76
79
  self.actions.append(self.post_action)
77
80
 
@@ -81,8 +84,8 @@ class CreateModelMixin:
81
84
 
82
85
 
83
86
  class PostAction(BaseRestAction):
84
- """
85
- Экшен обработки запроса методом POST.
87
+ """Экшен обработки запроса методом POST.
88
+
86
89
  Делегирует обработку методам пака.
87
90
  """
88
91
 
@@ -97,13 +100,11 @@ class UpdateModelMixin:
97
100
  """Примесь для REST паков, обработка запросов методом PUT и PATCH."""
98
101
 
99
102
  def __init__(self):
100
- super(UpdateModelMixin, self).__init__()
103
+ super().__init__()
104
+
101
105
  self.put_action = PutAction()
102
106
  self.patch_action = PatchAction()
103
- self.actions.extend([
104
- self.put_action,
105
- self.patch_action
106
- ])
107
+ self.actions.extend([self.put_action, self.patch_action])
107
108
 
108
109
  def update(self, request, context):
109
110
  """Метод отвечает за изменение объекта."""
@@ -111,8 +112,8 @@ class UpdateModelMixin:
111
112
 
112
113
 
113
114
  class PutAction(BaseRestAction):
114
- """
115
- Экшен обработки запроса методом PUT.
115
+ """Экшен обработки запроса методом PUT.
116
+
116
117
  Делегирует обработку методам пака.
117
118
  """
118
119
 
@@ -124,8 +125,8 @@ class PutAction(BaseRestAction):
124
125
 
125
126
 
126
127
  class PatchAction(BaseRestAction):
127
- """
128
- Экшен обработки запроса методом PATCH.
128
+ """Экшен обработки запроса методом PATCH.
129
+
129
130
  Делегирует обработку методам пака.
130
131
  """
131
132
 
@@ -140,7 +141,8 @@ class DestroyModelMixin:
140
141
  """Примесь для REST паков, обработка запросов методом DELETE."""
141
142
 
142
143
  def __init__(self):
143
- super(DestroyModelMixin, self).__init__()
144
+ super().__init__()
145
+
144
146
  self.delete_action = DeleteAction()
145
147
  self.actions.append(self.delete_action)
146
148
 
@@ -150,8 +152,8 @@ class DestroyModelMixin:
150
152
 
151
153
 
152
154
  class DeleteAction(BaseRestAction):
153
- """
154
- Экшен обработки запроса методом PATCH.
155
+ """Экшен обработки запроса методом PATCH.
156
+
155
157
  Делегирует обработку методам пака.
156
158
  """
157
159
 
@@ -22,24 +22,24 @@ from m3_django_compat import (
22
22
 
23
23
 
24
24
  def check_autorization(request, path):
25
-
26
25
  # Если файл в media/public, то отдаем сразу без проверки
27
26
  # Вообще это делается соответствующим конфигурированием NGINX
28
27
  path_list = path.split(os.path.sep)
29
- if path_list and path_list[0] == "public":
28
+ if path_list and path_list[0] == 'public':
30
29
  return sendfile(request, os.path.join(settings.MEDIA_ROOT, path))
31
30
 
32
31
  if not is_authenticated(request.user):
33
32
  result = M3JSONEncoder().encode(
34
- {'success': False,
35
- 'message': 'Вы не авторизованы. Возможно, закончилось время '
36
- 'пользовательской сессии. Для повторной '
37
- 'аутентификации обновите страницу.'})
33
+ {
34
+ 'success': False,
35
+ 'message': 'Вы не авторизованы. Возможно, закончилось время '
36
+ 'пользовательской сессии. Для повторной '
37
+ 'аутентификации обновите страницу.',
38
+ }
39
+ )
38
40
  return http.HttpResponse(result, content_type='application/json')
39
41
 
40
42
  return sendfile(request, os.path.join(settings.MEDIA_ROOT, path))
41
43
 
42
44
 
43
- urlpatterns = [
44
- re_path(r'^media/(?P<path>.*)$', check_autorization)
45
- ]
45
+ urlpatterns = [re_path(r'^media/(?P<path>.*)$', check_autorization)]
@@ -57,11 +57,12 @@ class SingletonMeta(type):
57
57
  """
58
58
 
59
59
  def __init__(cls, name, bases, attrs):
60
- super(SingletonMeta, cls).__init__(name, bases, attrs)
60
+ super().__init__(name, bases, attrs)
61
+
61
62
  cls.instance = None
62
63
 
63
64
  def __call__(cls, *args, **kwargs):
64
65
  if cls.instance is None:
65
- cls.instance = super(SingletonMeta, cls).__call__(*args, **kwargs)
66
+ cls.instance = super().__call__(*args, **kwargs)
66
67
 
67
68
  return cls.instance
@@ -87,9 +87,7 @@ class CacheWrapper:
87
87
  """
88
88
  kwarg_vals = tuple(callargs[k] for k in self.names_kwargs)
89
89
  hash_kwargs = hash(kwarg_vals)
90
- cache_key = '_'.join((
91
- self.cache_prefix, self.fn.__name__, str(hash_kwargs)
92
- ))
90
+ cache_key = '_'.join((self.cache_prefix, self.fn.__name__, str(hash_kwargs)))
93
91
  return cache_key
94
92
 
95
93
  def update_cache(self, value, **kw):
@@ -72,7 +72,5 @@ def float_or_none(value: Union[int, str, None]) -> Optional[float]:
72
72
  return result
73
73
 
74
74
 
75
- control_chars = ''.join(map(
76
- chr, itertools.chain(range(0x00, 0x20), range(0x7f, 0xa0))
77
- ))
75
+ control_chars = ''.join(map(chr, itertools.chain(range(0x00, 0x20), range(0x7F, 0xA0))))
78
76
  control_char_re = re.compile(f'[{re.escape(control_chars)}]')
educommon/utils/crypto.py CHANGED
@@ -36,8 +36,7 @@ class HashData:
36
36
 
37
37
  if openssl_stderr:
38
38
  raise IOError(
39
- 'Ошибка вычисления значения HASH по алгоритму '
40
- f'{self.hash_algorithm}',
39
+ f'Ошибка вычисления значения HASH по алгоритму {self.hash_algorithm}',
41
40
  )
42
41
 
43
42
  matches = re.compile(self.HASH_PATTERN).search(openssl_stdout.decode())
educommon/utils/date.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Вспомогательные средства для работы с датами."""
2
+
2
3
  import datetime
3
4
  from collections import (
4
5
  namedtuple,
@@ -38,7 +39,7 @@ WEEKDAYS = (
38
39
  (THU_IDX, 'Четверг'),
39
40
  (FRI_IDX, 'Пятница'),
40
41
  (SAT_IDX, 'Суббота'),
41
- (SUN_IDX, 'Воскресенье')
42
+ (SUN_IDX, 'Воскресенье'),
42
43
  )
43
44
  WEEKDAYS_DICT = dict(WEEKDAYS)
44
45
 
@@ -59,6 +60,7 @@ def date_range_to_str(date_from, date_to, can_be_one_day_long=False):
59
60
  (<2001.01.01>, None, , True) -> "01.01.2001"
60
61
  (None, <2002.02.02>, True) -> "02.02.2002"
61
62
  """
63
+
62
64
  def fmt(date):
63
65
  return date.strftime('%d.%m.%Y') if date else ''
64
66
 
@@ -73,14 +75,14 @@ def date_range_to_str(date_from, date_to, can_be_one_day_long=False):
73
75
  if date_from == date_to:
74
76
  result = fmt(date_from)
75
77
  else:
76
- result = 'с %s по %s' % (fmt(date_from), fmt(date_to))
78
+ result = f{fmt(date_from)} по {fmt(date_to)}'
77
79
  else:
78
80
  if can_be_one_day_long:
79
81
  result = fmt(date_from or date_to or None)
80
82
  elif date_from:
81
- result = 'с %s' % fmt(date_from)
83
+ result = f{fmt(date_from)}'
82
84
  elif date_to:
83
- result = 'по %s' % fmt(date_to)
85
+ result = f'по {fmt(date_to)}'
84
86
  return result
85
87
 
86
88
 
@@ -97,9 +99,7 @@ def iter_days_between(date_from, date_to, odd_weeks_only=False):
97
99
  if date_from > date_to:
98
100
  raise ValueError('date_from must be lower or equal date_to!')
99
101
 
100
- for dt in rrule.rrule(
101
- rrule.DAILY, dtstart=date_from, until=date_to
102
- ):
102
+ for dt in rrule.rrule(rrule.DAILY, dtstart=date_from, until=date_to):
103
103
  if odd_weeks_only and dt.isocalendar()[1] % 2 != 0:
104
104
  # если требуются четные недели относительно начала года
105
105
  continue
@@ -154,11 +154,7 @@ def get_week_dates(date=None):
154
154
 
155
155
  monday = get_week_start(date)
156
156
 
157
- return (
158
- day.date()
159
- for day in rrule.rrule(rrule.DAILY, dtstart=monday,
160
- count=len(WEEKDAYS))
161
- )
157
+ return (day.date() for day in rrule.rrule(rrule.DAILY, dtstart=monday, count=len(WEEKDAYS)))
162
158
 
163
159
 
164
160
  def get_weekdays_for_date(date=None, weekday_names=None):
@@ -176,10 +172,7 @@ def get_weekdays_for_date(date=None, weekday_names=None):
176
172
  """
177
173
  weekday_names = weekday_names or WEEKDAYS_DICT
178
174
 
179
- return tuple(
180
- (weekday_names[day.weekday()], day)
181
- for day in get_week_dates(date)
182
- )
175
+ return tuple((weekday_names[day.weekday()], day) for day in get_week_dates(date))
183
176
 
184
177
 
185
178
  def get_today_min_datetime() -> datetime:
@@ -193,7 +186,7 @@ def get_today_max_datetime() -> datetime:
193
186
 
194
187
 
195
188
  def get_date_range_intersection(
196
- *date_ranges: Tuple[datetime.date, datetime.date]
189
+ *date_ranges: Tuple[datetime.date, datetime.date],
197
190
  ) -> Union[Tuple[datetime.date, datetime.date], tuple]:
198
191
  """Возвращает минимальный внутренний диапазон дат из переданных диапазонов дат.
199
192
 
@@ -210,19 +203,14 @@ def get_date_range_intersection(
210
203
  return date_range
211
204
 
212
205
 
213
- def is_date_range_intersection(
214
- *date_ranges: Tuple[datetime.date, datetime.date]
215
- ) -> bool:
206
+ def is_date_range_intersection(*date_ranges: Tuple[datetime.date, datetime.date]) -> bool:
216
207
  """Возвращает признак того, что диапазоны дат пересекаются."""
217
208
  intersection = get_date_range_intersection(*date_ranges)
218
209
 
219
210
  return True if intersection else False
220
211
 
221
212
 
222
- def date_to_str(
223
- date_: Optional[Union[datetime.date, datetime.datetime]],
224
- fmt: str = settings.DATE_FORMAT
225
- ) -> str:
213
+ def date_to_str(date_: Optional[Union[datetime.date, datetime.datetime]], fmt: str = settings.DATE_FORMAT) -> str:
226
214
  """Конвертирует дату в строку или возвращает '' если даты нет."""
227
215
  return date_.strftime(fmt) if date_ else ''
228
216
 
@@ -244,8 +232,7 @@ class Week(namedtuple('Week', ('year', 'week'))):
244
232
  неделя года.
245
233
  """
246
234
  d = datetime.date(self.year, 1, 4)
247
- return d + datetime.timedelta(
248
- weeks=self.week - 1, days=-d.weekday() + number)
235
+ return d + datetime.timedelta(weeks=self.week - 1, days=-d.weekday() + number)
249
236
 
250
237
  def monday(self) -> datetime.date:
251
238
  """Дата понедельника."""