udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30382__py2.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 udata might be problematic. Click here for more details.

Files changed (425) hide show
  1. tasks/__init__.py +109 -107
  2. tasks/helpers.py +18 -18
  3. udata/__init__.py +4 -4
  4. udata/admin/views.py +5 -5
  5. udata/api/__init__.py +135 -124
  6. udata/api/commands.py +45 -37
  7. udata/api/errors.py +5 -4
  8. udata/api/fields.py +23 -21
  9. udata/api/oauth2.py +55 -74
  10. udata/api/parsers.py +15 -15
  11. udata/api/signals.py +1 -1
  12. udata/api_fields.py +137 -89
  13. udata/app.py +56 -54
  14. udata/assets.py +5 -5
  15. udata/auth/__init__.py +37 -26
  16. udata/auth/forms.py +23 -15
  17. udata/auth/helpers.py +1 -1
  18. udata/auth/mails.py +3 -3
  19. udata/auth/password_validation.py +19 -15
  20. udata/auth/views.py +94 -68
  21. udata/commands/__init__.py +71 -69
  22. udata/commands/cache.py +7 -7
  23. udata/commands/db.py +201 -140
  24. udata/commands/dcat.py +36 -30
  25. udata/commands/fixtures.py +100 -84
  26. udata/commands/images.py +21 -20
  27. udata/commands/info.py +17 -20
  28. udata/commands/init.py +10 -10
  29. udata/commands/purge.py +12 -13
  30. udata/commands/serve.py +41 -29
  31. udata/commands/static.py +16 -18
  32. udata/commands/test.py +20 -20
  33. udata/commands/tests/fixtures.py +26 -24
  34. udata/commands/worker.py +31 -33
  35. udata/core/__init__.py +12 -12
  36. udata/core/activity/__init__.py +0 -1
  37. udata/core/activity/api.py +59 -49
  38. udata/core/activity/models.py +28 -26
  39. udata/core/activity/signals.py +1 -1
  40. udata/core/activity/tasks.py +16 -10
  41. udata/core/badges/api.py +6 -6
  42. udata/core/badges/commands.py +14 -13
  43. udata/core/badges/fields.py +8 -5
  44. udata/core/badges/forms.py +7 -4
  45. udata/core/badges/models.py +16 -31
  46. udata/core/badges/permissions.py +1 -3
  47. udata/core/badges/signals.py +2 -2
  48. udata/core/badges/tasks.py +3 -2
  49. udata/core/badges/tests/test_commands.py +10 -10
  50. udata/core/badges/tests/test_model.py +24 -31
  51. udata/core/contact_point/api.py +19 -18
  52. udata/core/contact_point/api_fields.py +21 -14
  53. udata/core/contact_point/factories.py +2 -2
  54. udata/core/contact_point/forms.py +7 -6
  55. udata/core/contact_point/models.py +3 -5
  56. udata/core/dataservices/api.py +26 -21
  57. udata/core/dataservices/factories.py +13 -11
  58. udata/core/dataservices/models.py +35 -40
  59. udata/core/dataservices/permissions.py +4 -4
  60. udata/core/dataservices/rdf.py +40 -17
  61. udata/core/dataservices/tasks.py +4 -3
  62. udata/core/dataset/actions.py +10 -10
  63. udata/core/dataset/activities.py +21 -23
  64. udata/core/dataset/api.py +321 -298
  65. udata/core/dataset/api_fields.py +443 -271
  66. udata/core/dataset/apiv2.py +305 -229
  67. udata/core/dataset/commands.py +38 -36
  68. udata/core/dataset/constants.py +61 -54
  69. udata/core/dataset/csv.py +70 -74
  70. udata/core/dataset/events.py +39 -32
  71. udata/core/dataset/exceptions.py +8 -4
  72. udata/core/dataset/factories.py +57 -65
  73. udata/core/dataset/forms.py +87 -63
  74. udata/core/dataset/models.py +336 -280
  75. udata/core/dataset/permissions.py +9 -6
  76. udata/core/dataset/preview.py +15 -17
  77. udata/core/dataset/rdf.py +156 -122
  78. udata/core/dataset/search.py +92 -77
  79. udata/core/dataset/signals.py +1 -1
  80. udata/core/dataset/tasks.py +63 -54
  81. udata/core/discussions/actions.py +5 -5
  82. udata/core/discussions/api.py +124 -120
  83. udata/core/discussions/factories.py +2 -2
  84. udata/core/discussions/forms.py +9 -7
  85. udata/core/discussions/metrics.py +1 -3
  86. udata/core/discussions/models.py +25 -24
  87. udata/core/discussions/notifications.py +18 -14
  88. udata/core/discussions/permissions.py +3 -3
  89. udata/core/discussions/signals.py +4 -4
  90. udata/core/discussions/tasks.py +24 -28
  91. udata/core/followers/api.py +32 -33
  92. udata/core/followers/models.py +9 -9
  93. udata/core/followers/signals.py +3 -3
  94. udata/core/jobs/actions.py +7 -7
  95. udata/core/jobs/api.py +99 -92
  96. udata/core/jobs/commands.py +48 -49
  97. udata/core/jobs/forms.py +11 -11
  98. udata/core/jobs/models.py +6 -6
  99. udata/core/metrics/__init__.py +2 -2
  100. udata/core/metrics/commands.py +34 -30
  101. udata/core/metrics/models.py +2 -4
  102. udata/core/metrics/signals.py +1 -1
  103. udata/core/metrics/tasks.py +3 -3
  104. udata/core/organization/activities.py +12 -15
  105. udata/core/organization/api.py +167 -174
  106. udata/core/organization/api_fields.py +183 -124
  107. udata/core/organization/apiv2.py +32 -32
  108. udata/core/organization/commands.py +20 -22
  109. udata/core/organization/constants.py +11 -11
  110. udata/core/organization/csv.py +17 -15
  111. udata/core/organization/factories.py +8 -11
  112. udata/core/organization/forms.py +32 -26
  113. udata/core/organization/metrics.py +2 -1
  114. udata/core/organization/models.py +87 -67
  115. udata/core/organization/notifications.py +18 -14
  116. udata/core/organization/permissions.py +10 -11
  117. udata/core/organization/rdf.py +14 -14
  118. udata/core/organization/search.py +30 -28
  119. udata/core/organization/signals.py +7 -7
  120. udata/core/organization/tasks.py +42 -61
  121. udata/core/owned.py +38 -27
  122. udata/core/post/api.py +82 -81
  123. udata/core/post/constants.py +8 -5
  124. udata/core/post/factories.py +4 -4
  125. udata/core/post/forms.py +13 -14
  126. udata/core/post/models.py +20 -22
  127. udata/core/post/tests/test_api.py +30 -32
  128. udata/core/reports/api.py +8 -7
  129. udata/core/reports/constants.py +1 -3
  130. udata/core/reports/models.py +10 -10
  131. udata/core/reuse/activities.py +15 -19
  132. udata/core/reuse/api.py +123 -126
  133. udata/core/reuse/api_fields.py +120 -85
  134. udata/core/reuse/apiv2.py +11 -10
  135. udata/core/reuse/constants.py +23 -23
  136. udata/core/reuse/csv.py +18 -18
  137. udata/core/reuse/factories.py +5 -9
  138. udata/core/reuse/forms.py +24 -21
  139. udata/core/reuse/models.py +55 -51
  140. udata/core/reuse/permissions.py +2 -2
  141. udata/core/reuse/search.py +49 -46
  142. udata/core/reuse/signals.py +1 -1
  143. udata/core/reuse/tasks.py +4 -5
  144. udata/core/site/api.py +47 -50
  145. udata/core/site/factories.py +2 -2
  146. udata/core/site/forms.py +4 -5
  147. udata/core/site/models.py +94 -63
  148. udata/core/site/rdf.py +14 -14
  149. udata/core/spam/api.py +16 -9
  150. udata/core/spam/constants.py +4 -4
  151. udata/core/spam/fields.py +13 -7
  152. udata/core/spam/models.py +27 -20
  153. udata/core/spam/signals.py +1 -1
  154. udata/core/spam/tests/test_spam.py +6 -5
  155. udata/core/spatial/api.py +72 -80
  156. udata/core/spatial/api_fields.py +73 -58
  157. udata/core/spatial/commands.py +67 -64
  158. udata/core/spatial/constants.py +3 -3
  159. udata/core/spatial/factories.py +37 -54
  160. udata/core/spatial/forms.py +27 -26
  161. udata/core/spatial/geoids.py +17 -17
  162. udata/core/spatial/models.py +43 -47
  163. udata/core/spatial/tasks.py +2 -1
  164. udata/core/spatial/tests/test_api.py +115 -130
  165. udata/core/spatial/tests/test_fields.py +74 -77
  166. udata/core/spatial/tests/test_geoid.py +22 -22
  167. udata/core/spatial/tests/test_models.py +5 -7
  168. udata/core/spatial/translations.py +16 -16
  169. udata/core/storages/__init__.py +16 -18
  170. udata/core/storages/api.py +66 -64
  171. udata/core/storages/tasks.py +7 -7
  172. udata/core/storages/utils.py +15 -15
  173. udata/core/storages/views.py +5 -6
  174. udata/core/tags/api.py +17 -14
  175. udata/core/tags/csv.py +4 -4
  176. udata/core/tags/models.py +8 -5
  177. udata/core/tags/tasks.py +11 -13
  178. udata/core/tags/views.py +4 -4
  179. udata/core/topic/api.py +84 -73
  180. udata/core/topic/apiv2.py +157 -127
  181. udata/core/topic/factories.py +3 -4
  182. udata/core/topic/forms.py +12 -14
  183. udata/core/topic/models.py +14 -19
  184. udata/core/topic/parsers.py +26 -26
  185. udata/core/user/activities.py +30 -29
  186. udata/core/user/api.py +151 -152
  187. udata/core/user/api_fields.py +132 -100
  188. udata/core/user/apiv2.py +7 -7
  189. udata/core/user/commands.py +38 -38
  190. udata/core/user/factories.py +8 -9
  191. udata/core/user/forms.py +14 -11
  192. udata/core/user/metrics.py +2 -2
  193. udata/core/user/models.py +68 -69
  194. udata/core/user/permissions.py +4 -5
  195. udata/core/user/rdf.py +7 -8
  196. udata/core/user/tasks.py +2 -2
  197. udata/core/user/tests/test_user_model.py +24 -16
  198. udata/db/tasks.py +2 -1
  199. udata/entrypoints.py +35 -31
  200. udata/errors.py +2 -1
  201. udata/event/values.py +6 -6
  202. udata/factories.py +2 -2
  203. udata/features/identicon/api.py +5 -6
  204. udata/features/identicon/backends.py +48 -55
  205. udata/features/identicon/tests/test_backends.py +4 -5
  206. udata/features/notifications/__init__.py +0 -1
  207. udata/features/notifications/actions.py +9 -9
  208. udata/features/notifications/api.py +17 -13
  209. udata/features/territories/__init__.py +12 -10
  210. udata/features/territories/api.py +14 -15
  211. udata/features/territories/models.py +23 -28
  212. udata/features/transfer/actions.py +8 -11
  213. udata/features/transfer/api.py +84 -77
  214. udata/features/transfer/factories.py +2 -1
  215. udata/features/transfer/models.py +11 -12
  216. udata/features/transfer/notifications.py +19 -15
  217. udata/features/transfer/permissions.py +5 -5
  218. udata/forms/__init__.py +5 -2
  219. udata/forms/fields.py +164 -172
  220. udata/forms/validators.py +19 -22
  221. udata/forms/widgets.py +9 -13
  222. udata/frontend/__init__.py +31 -26
  223. udata/frontend/csv.py +68 -58
  224. udata/frontend/markdown.py +40 -44
  225. udata/harvest/actions.py +89 -77
  226. udata/harvest/api.py +294 -238
  227. udata/harvest/backends/__init__.py +4 -4
  228. udata/harvest/backends/base.py +128 -111
  229. udata/harvest/backends/dcat.py +80 -66
  230. udata/harvest/commands.py +56 -60
  231. udata/harvest/csv.py +8 -8
  232. udata/harvest/exceptions.py +6 -3
  233. udata/harvest/filters.py +24 -23
  234. udata/harvest/forms.py +27 -28
  235. udata/harvest/models.py +88 -80
  236. udata/harvest/notifications.py +15 -10
  237. udata/harvest/signals.py +13 -13
  238. udata/harvest/tasks.py +11 -10
  239. udata/harvest/tests/factories.py +23 -24
  240. udata/harvest/tests/test_actions.py +136 -166
  241. udata/harvest/tests/test_api.py +220 -214
  242. udata/harvest/tests/test_base_backend.py +117 -112
  243. udata/harvest/tests/test_dcat_backend.py +380 -308
  244. udata/harvest/tests/test_filters.py +33 -22
  245. udata/harvest/tests/test_models.py +11 -14
  246. udata/harvest/tests/test_notifications.py +6 -7
  247. udata/harvest/tests/test_tasks.py +7 -6
  248. udata/i18n.py +237 -78
  249. udata/linkchecker/backends.py +5 -11
  250. udata/linkchecker/checker.py +23 -22
  251. udata/linkchecker/commands.py +4 -6
  252. udata/linkchecker/models.py +6 -6
  253. udata/linkchecker/tasks.py +18 -20
  254. udata/mail.py +21 -21
  255. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  256. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  257. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  258. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  259. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  260. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  261. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  262. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  263. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  264. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  265. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  266. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  267. udata/migrations/2021-08-17-users-integrity.py +9 -8
  268. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  269. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  270. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  271. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  272. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  273. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  274. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  275. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  276. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  277. udata/migrations/__init__.py +123 -105
  278. udata/models/__init__.py +4 -4
  279. udata/mongo/__init__.py +13 -11
  280. udata/mongo/badges_field.py +3 -2
  281. udata/mongo/datetime_fields.py +13 -12
  282. udata/mongo/document.py +17 -16
  283. udata/mongo/engine.py +15 -16
  284. udata/mongo/errors.py +2 -1
  285. udata/mongo/extras_fields.py +30 -20
  286. udata/mongo/queryset.py +12 -12
  287. udata/mongo/slug_fields.py +38 -28
  288. udata/mongo/taglist_field.py +1 -2
  289. udata/mongo/url_field.py +5 -5
  290. udata/mongo/uuid_fields.py +4 -3
  291. udata/notifications/__init__.py +1 -1
  292. udata/notifications/mattermost.py +10 -9
  293. udata/rdf.py +167 -188
  294. udata/routing.py +40 -45
  295. udata/search/__init__.py +18 -19
  296. udata/search/adapter.py +17 -16
  297. udata/search/commands.py +44 -51
  298. udata/search/fields.py +13 -20
  299. udata/search/query.py +23 -18
  300. udata/search/result.py +9 -10
  301. udata/sentry.py +21 -19
  302. udata/settings.py +262 -198
  303. udata/sitemap.py +8 -6
  304. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
  305. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
  306. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
  307. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
  308. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
  309. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
  310. udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
  311. udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
  312. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
  313. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
  314. udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
  315. udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
  316. udata/static/common.js +1 -1
  317. udata/static/common.js.map +1 -1
  318. udata/storage/s3.py +20 -13
  319. udata/tags.py +4 -5
  320. udata/tasks.py +43 -42
  321. udata/tests/__init__.py +9 -6
  322. udata/tests/api/__init__.py +5 -6
  323. udata/tests/api/test_auth_api.py +395 -321
  324. udata/tests/api/test_base_api.py +31 -33
  325. udata/tests/api/test_contact_points.py +7 -9
  326. udata/tests/api/test_dataservices_api.py +211 -158
  327. udata/tests/api/test_datasets_api.py +823 -812
  328. udata/tests/api/test_follow_api.py +13 -15
  329. udata/tests/api/test_me_api.py +95 -112
  330. udata/tests/api/test_organizations_api.py +301 -339
  331. udata/tests/api/test_reports_api.py +35 -25
  332. udata/tests/api/test_reuses_api.py +134 -139
  333. udata/tests/api/test_swagger.py +5 -5
  334. udata/tests/api/test_tags_api.py +18 -25
  335. udata/tests/api/test_topics_api.py +94 -94
  336. udata/tests/api/test_transfer_api.py +53 -48
  337. udata/tests/api/test_user_api.py +128 -141
  338. udata/tests/apiv2/test_datasets.py +290 -198
  339. udata/tests/apiv2/test_me_api.py +10 -11
  340. udata/tests/apiv2/test_organizations.py +56 -74
  341. udata/tests/apiv2/test_swagger.py +5 -5
  342. udata/tests/apiv2/test_topics.py +69 -87
  343. udata/tests/cli/test_cli_base.py +8 -8
  344. udata/tests/cli/test_db_cli.py +21 -19
  345. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  346. udata/tests/dataset/test_csv_adapter.py +44 -35
  347. udata/tests/dataset/test_dataset_actions.py +2 -3
  348. udata/tests/dataset/test_dataset_commands.py +7 -8
  349. udata/tests/dataset/test_dataset_events.py +36 -29
  350. udata/tests/dataset/test_dataset_model.py +224 -217
  351. udata/tests/dataset/test_dataset_rdf.py +142 -131
  352. udata/tests/dataset/test_dataset_tasks.py +15 -15
  353. udata/tests/dataset/test_resource_preview.py +10 -13
  354. udata/tests/features/territories/__init__.py +9 -13
  355. udata/tests/features/territories/test_territories_api.py +71 -91
  356. udata/tests/forms/test_basic_fields.py +7 -7
  357. udata/tests/forms/test_current_user_field.py +39 -66
  358. udata/tests/forms/test_daterange_field.py +31 -39
  359. udata/tests/forms/test_dict_field.py +28 -26
  360. udata/tests/forms/test_extras_fields.py +102 -76
  361. udata/tests/forms/test_form_field.py +8 -8
  362. udata/tests/forms/test_image_field.py +33 -26
  363. udata/tests/forms/test_model_field.py +134 -123
  364. udata/tests/forms/test_model_list_field.py +7 -7
  365. udata/tests/forms/test_nested_model_list_field.py +117 -79
  366. udata/tests/forms/test_publish_as_field.py +36 -65
  367. udata/tests/forms/test_reference_field.py +34 -53
  368. udata/tests/forms/test_user_forms.py +23 -21
  369. udata/tests/forms/test_uuid_field.py +6 -10
  370. udata/tests/frontend/__init__.py +9 -6
  371. udata/tests/frontend/test_auth.py +7 -6
  372. udata/tests/frontend/test_csv.py +81 -96
  373. udata/tests/frontend/test_hooks.py +43 -43
  374. udata/tests/frontend/test_markdown.py +211 -191
  375. udata/tests/helpers.py +32 -37
  376. udata/tests/models.py +2 -2
  377. udata/tests/organization/test_csv_adapter.py +21 -16
  378. udata/tests/organization/test_notifications.py +11 -18
  379. udata/tests/organization/test_organization_model.py +13 -13
  380. udata/tests/organization/test_organization_rdf.py +29 -22
  381. udata/tests/organization/test_organization_tasks.py +16 -17
  382. udata/tests/plugin.py +76 -73
  383. udata/tests/reuse/test_reuse_model.py +21 -21
  384. udata/tests/reuse/test_reuse_task.py +11 -13
  385. udata/tests/search/__init__.py +11 -12
  386. udata/tests/search/test_adapter.py +60 -70
  387. udata/tests/search/test_query.py +16 -16
  388. udata/tests/search/test_results.py +10 -7
  389. udata/tests/site/test_site_api.py +11 -16
  390. udata/tests/site/test_site_metrics.py +20 -30
  391. udata/tests/site/test_site_model.py +4 -5
  392. udata/tests/site/test_site_rdf.py +94 -78
  393. udata/tests/test_activity.py +17 -17
  394. udata/tests/test_discussions.py +292 -299
  395. udata/tests/test_i18n.py +37 -40
  396. udata/tests/test_linkchecker.py +91 -85
  397. udata/tests/test_mail.py +13 -17
  398. udata/tests/test_migrations.py +219 -180
  399. udata/tests/test_model.py +164 -157
  400. udata/tests/test_notifications.py +17 -17
  401. udata/tests/test_owned.py +14 -14
  402. udata/tests/test_rdf.py +25 -23
  403. udata/tests/test_routing.py +89 -93
  404. udata/tests/test_storages.py +137 -128
  405. udata/tests/test_tags.py +44 -46
  406. udata/tests/test_topics.py +7 -7
  407. udata/tests/test_transfer.py +42 -49
  408. udata/tests/test_uris.py +160 -161
  409. udata/tests/test_utils.py +79 -71
  410. udata/tests/user/test_user_rdf.py +5 -9
  411. udata/tests/workers/test_jobs_commands.py +57 -58
  412. udata/tests/workers/test_tasks_routing.py +23 -29
  413. udata/tests/workers/test_workers_api.py +125 -131
  414. udata/tests/workers/test_workers_helpers.py +6 -6
  415. udata/tracking.py +4 -6
  416. udata/uris.py +45 -46
  417. udata/utils.py +68 -66
  418. udata/wsgi.py +1 -1
  419. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/METADATA +3 -2
  420. udata-9.1.2.dev30382.dist-info/RECORD +704 -0
  421. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  422. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
  423. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
  424. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
  425. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
@@ -1,22 +1,20 @@
1
1
  from udata import mail
2
- from udata.i18n import lazy_gettext as _
3
2
  from udata.core.dataset.models import Dataset
4
- from udata.core.reuse.models import Reuse
5
3
  from udata.core.post.models import Post
4
+ from udata.core.reuse.models import Reuse
5
+ from udata.i18n import lazy_gettext as _
6
6
  from udata.tasks import connect, get_logger
7
7
 
8
8
  from .models import Discussion, Message
9
- from .signals import (
10
- on_new_discussion, on_new_discussion_comment, on_discussion_closed
11
- )
9
+ from .signals import on_discussion_closed, on_new_discussion, on_new_discussion_comment
12
10
 
13
11
  log = get_logger(__name__)
14
12
 
15
13
 
16
14
  def owner_recipients(discussion):
17
- if getattr(discussion.subject, 'organization', None):
15
+ if getattr(discussion.subject, "organization", None):
18
16
  return [m.user for m in discussion.subject.organization.members]
19
- elif getattr(discussion.subject, 'owner', None):
17
+ elif getattr(discussion.subject, "owner", None):
20
18
  return [discussion.subject.owner]
21
19
  else:
22
20
  return []
@@ -27,13 +25,16 @@ def notify_new_discussion(discussion_id):
27
25
  discussion = Discussion.objects.get(pk=discussion_id)
28
26
  if isinstance(discussion.subject, (Dataset, Reuse, Post)):
29
27
  recipients = owner_recipients(discussion)
30
- subject = _('Your %(type)s have a new discussion',
31
- type=discussion.subject.verbose_name)
32
- mail.send(subject, recipients, 'new_discussion',
33
- discussion=discussion, message=discussion.discussion[0])
28
+ subject = _("Your %(type)s have a new discussion", type=discussion.subject.verbose_name)
29
+ mail.send(
30
+ subject,
31
+ recipients,
32
+ "new_discussion",
33
+ discussion=discussion,
34
+ message=discussion.discussion[0],
35
+ )
34
36
  else:
35
- log.warning('Unrecognized discussion subject type %s',
36
- type(discussion.subject))
37
+ log.warning("Unrecognized discussion subject type %s", type(discussion.subject))
37
38
 
38
39
 
39
40
  @connect(on_new_discussion_comment, by_id=True)
@@ -41,17 +42,15 @@ def notify_new_discussion_comment(discussion_id, message=None):
41
42
  discussion = Discussion.objects.get(pk=discussion_id)
42
43
  message = discussion.discussion[message]
43
44
  if isinstance(discussion.subject, (Dataset, Reuse, Post)):
44
- recipients = owner_recipients(discussion) + [
45
- m.posted_by for m in discussion.discussion]
45
+ recipients = owner_recipients(discussion) + [m.posted_by for m in discussion.discussion]
46
46
  recipients = list({u.id: u for u in recipients if u != message.posted_by}.values())
47
- subject = _('%(user)s commented your discussion',
48
- user=message.posted_by.fullname)
47
+ subject = _("%(user)s commented your discussion", user=message.posted_by.fullname)
49
48
 
50
- mail.send(subject, recipients, 'new_discussion_comment',
51
- discussion=discussion, message=message)
49
+ mail.send(
50
+ subject, recipients, "new_discussion_comment", discussion=discussion, message=message
51
+ )
52
52
  else:
53
- log.warning('Unrecognized discussion subject type %s',
54
- type(discussion.subject))
53
+ log.warning("Unrecognized discussion subject type %s", type(discussion.subject))
55
54
 
56
55
 
57
56
  @connect(on_discussion_closed, by_id=True)
@@ -59,12 +58,9 @@ def notify_discussion_closed(discussion_id, message=None):
59
58
  discussion = Discussion.objects.get(pk=discussion_id)
60
59
  message = discussion.discussion[message]
61
60
  if isinstance(discussion.subject, (Dataset, Reuse, Post)):
62
- recipients = owner_recipients(discussion) + [
63
- m.posted_by for m in discussion.discussion]
61
+ recipients = owner_recipients(discussion) + [m.posted_by for m in discussion.discussion]
64
62
  recipients = list({u.id: u for u in recipients if u != message.posted_by}.values())
65
- subject = _('A discussion has been closed')
66
- mail.send(subject, recipients, 'discussion_closed',
67
- discussion=discussion, message=message)
63
+ subject = _("A discussion has been closed")
64
+ mail.send(subject, recipients, "discussion_closed", discussion=discussion, message=message)
68
65
  else:
69
- log.warning('Unrecognized discussion subject type %s',
70
- type(discussion.subject))
66
+ log.warning("Unrecognized discussion subject type %s", type(discussion.subject))
@@ -4,72 +4,71 @@ from flask import current_app, request
4
4
  from flask_security import current_user
5
5
 
6
6
  from udata import tracking
7
- from udata.api import api, API, fields
8
- from udata.models import Follow
7
+ from udata.api import API, api, fields
9
8
  from udata.core.user.api_fields import user_ref_fields
9
+ from udata.models import Follow
10
10
  from udata.utils import id_or_404
11
11
 
12
12
  from .signals import on_new_follow
13
13
 
14
+ follow_fields = api.model(
15
+ "Follow",
16
+ {
17
+ "id": fields.String(description="The follow object technical ID", readonly=True),
18
+ "follower": fields.Nested(user_ref_fields, description="The follower", readonly=True),
19
+ "since": fields.ISODateTime(
20
+ description="The date from which the user started following", readonly=True
21
+ ),
22
+ },
23
+ )
14
24
 
15
- follow_fields = api.model('Follow', {
16
- 'id': fields.String(
17
- description='The follow object technical ID', readonly=True),
18
- 'follower': fields.Nested(
19
- user_ref_fields, description='The follower', readonly=True),
20
- 'since': fields.ISODateTime(
21
- description='The date from which the user started following',
22
- readonly=True)
23
- })
24
-
25
- follow_page_fields = api.model('FollowPage', fields.pager(follow_fields))
25
+ follow_page_fields = api.model("FollowPage", fields.pager(follow_fields))
26
26
 
27
27
  parser = api.parser()
28
+ parser.add_argument("page", type=int, default=1, location="args", help="The page to fetch")
28
29
  parser.add_argument(
29
- 'page', type=int, default=1, location='args', help='The page to fetch')
30
- parser.add_argument(
31
- 'page_size', type=int, default=20, location='args',
32
- help='The page size to fetch')
30
+ "page_size", type=int, default=20, location="args", help="The page size to fetch"
31
+ )
33
32
 
34
- NOTE = 'Returns the number of followers left after the operation'
33
+ NOTE = "Returns the number of followers left after the operation"
35
34
 
36
35
 
37
36
  class FollowAPI(API):
38
- '''
37
+ """
39
38
  Base Follow Model API.
40
- '''
39
+ """
40
+
41
41
  model = None
42
42
 
43
43
  @api.expect(parser)
44
44
  @api.marshal_with(follow_page_fields)
45
45
  def get(self, id):
46
- '''List all followers for a given object'''
46
+ """List all followers for a given object"""
47
47
  args = parser.parse_args()
48
- model = self.model.objects.only('id').get_or_404(id=id_or_404(id))
48
+ model = self.model.objects.only("id").get_or_404(id=id_or_404(id))
49
49
  qs = Follow.objects(following=model, until=None)
50
- return qs.paginate(args['page'], args['page_size'])
50
+ return qs.paginate(args["page"], args["page_size"])
51
51
 
52
52
  @api.secure
53
53
  @api.doc(description=NOTE)
54
54
  def post(self, id):
55
- '''Follow an object given its ID'''
55
+ """Follow an object given its ID"""
56
56
  model = self.model.objects.get_or_404(id=id_or_404(id))
57
57
  follow, created = Follow.objects.get_or_create(
58
- follower=current_user.id, following=model, until=None)
58
+ follower=current_user.id, following=model, until=None
59
+ )
59
60
  count = Follow.objects.followers(model).count()
60
- if not current_app.config['TESTING']:
61
+ if not current_app.config["TESTING"]:
61
62
  tracking.send_signal(on_new_follow, request, current_user)
62
- return {'followers': count}, 201 if created else 200
63
+ return {"followers": count}, 201 if created else 200
63
64
 
64
65
  @api.secure
65
66
  @api.doc(description=NOTE)
66
67
  def delete(self, id):
67
- '''Unfollow an object given its ID'''
68
- model = self.model.objects.only('id').get_or_404(id=id_or_404(id))
69
- follow = Follow.objects.get_or_404(follower=current_user.id,
70
- following=model,
71
- until=None)
68
+ """Unfollow an object given its ID"""
69
+ model = self.model.objects.only("id").get_or_404(id=id_or_404(id))
70
+ follow = Follow.objects.get_or_404(follower=current_user.id, following=model, until=None)
72
71
  follow.until = datetime.utcnow()
73
72
  follow.save()
74
73
  count = Follow.objects.followers(model).count()
75
- return {'followers': count}, 200
74
+ return {"followers": count}, 200
@@ -1,10 +1,10 @@
1
1
  from datetime import datetime
2
2
 
3
3
  from udata.mongo import db
4
- from .signals import on_follow, on_unfollow
5
4
 
5
+ from .signals import on_follow, on_unfollow
6
6
 
7
- __all__ = ('Follow', )
7
+ __all__ = ("Follow",)
8
8
 
9
9
 
10
10
  class FollowQuerySet(db.BaseQuerySet):
@@ -19,19 +19,19 @@ class FollowQuerySet(db.BaseQuerySet):
19
19
 
20
20
 
21
21
  class Follow(db.Document):
22
- follower = db.ReferenceField('User', required=True)
22
+ follower = db.ReferenceField("User", required=True)
23
23
  following = db.GenericReferenceField()
24
24
  since = db.DateTimeField(required=True, default=datetime.utcnow)
25
25
  until = db.DateTimeField()
26
26
 
27
27
  meta = {
28
- 'indexes': [
29
- 'follower',
30
- 'following',
31
- ('follower', 'until'),
32
- ('following', 'until'),
28
+ "indexes": [
29
+ "follower",
30
+ "following",
31
+ ("follower", "until"),
32
+ ("following", "until"),
33
33
  ],
34
- 'queryset_class': FollowQuerySet,
34
+ "queryset_class": FollowQuerySet,
35
35
  }
36
36
 
37
37
 
@@ -3,13 +3,13 @@ from blinker import Namespace
3
3
  namespace = Namespace()
4
4
 
5
5
  #: Trigerred when an user follow someone or something
6
- on_follow = namespace.signal('on-follow')
6
+ on_follow = namespace.signal("on-follow")
7
7
 
8
8
  #: Trigerred when an user follow someone or something (again)
9
9
  # We cannot reuse the `on_follow` one because we need to trigger it
10
10
  # from the view to pass user information for tracking
11
11
  # (vs `db.post_save.connect` signal).
12
- on_new_follow = namespace.signal('on-new-follow')
12
+ on_new_follow = namespace.signal("on-new-follow")
13
13
 
14
14
  #: Trigerred when an user unfollow someone or something
15
- on_unfollow = namespace.signal('on-unfollow')
15
+ on_unfollow = namespace.signal("on-unfollow")
@@ -9,20 +9,20 @@ def run(name, args, kwargs):
9
9
  args = args or []
10
10
  kwargs = dict(k.split() for k in kwargs) if kwargs else {}
11
11
  if name not in celery.tasks:
12
- log.error('Job %s not found', name)
12
+ log.error("Job %s not found", name)
13
13
  job = celery.tasks[name]
14
- log.info('Running job %s', name)
14
+ log.info("Running job %s", name)
15
15
  job.run(*args, **kwargs)
16
- log.info('Job %s done', name)
16
+ log.info("Job %s done", name)
17
17
 
18
18
 
19
19
  def delay(name, args, kwargs):
20
- '''Run a job asynchronously'''
20
+ """Run a job asynchronously"""
21
21
  args = args or []
22
22
  kwargs = dict(k.split() for k in kwargs) if kwargs else {}
23
23
  if name not in celery.tasks:
24
- log.error('Job %s not found', name)
24
+ log.error("Job %s not found", name)
25
25
  job = celery.tasks[name]
26
- log.info('Sending job %s', name)
26
+ log.info("Sending job %s", name)
27
27
  async_result = job.delay(*args, **kwargs)
28
- log.info('Job %s sended to workers', async_result.id)
28
+ log.info("Job %s sended to workers", async_result.id)
udata/core/jobs/api.py CHANGED
@@ -1,103 +1,108 @@
1
1
  from celery import states
2
2
  from celery.result import AsyncResult
3
3
  from celery.utils import get_full_cls_name
4
- from kombu.utils.encoding import safe_repr
5
4
  from flask import request
5
+ from kombu.utils.encoding import safe_repr
6
6
 
7
- from udata.api import api, API, fields
7
+ from udata.api import API, api, fields
8
8
  from udata.auth import admin_permission
9
- from udata.tasks import schedulables, celery
9
+ from udata.tasks import celery, schedulables
10
10
  from udata.utils import id_or_404
11
11
 
12
12
  from .forms import CrontabTaskForm, IntervalTaskForm
13
- from .models import PeriodicTask, PERIODS
14
-
15
- ns = api.namespace(
16
- 'workers', 'Asynchronous workers related operations', path='')
17
-
18
- crontab_fields = api.model('Crontab', {
19
- 'minute': fields.String(
20
- description='Cron expression for minute', required=True, default='*'),
21
- 'hour': fields.String(
22
- description='Cron expression for hour', required=True, default='*'),
23
- 'day_of_week': fields.String(
24
- description='Cron expression for day of week', required=True,
25
- default='*'),
26
- 'day_of_month': fields.String(
27
- description='Cron expression for day of month', required=True,
28
- default='*'),
29
- 'month_of_year': fields.String(
30
- description='Cron expression for month of year', required=True,
31
- default='*'),
32
- })
33
-
34
- interval_fields = api.model('Interval', {
35
- 'every': fields.Integer(
36
- description='The interval without unit', required=True),
37
- 'period': fields.String(
38
- description='The period/interval type', required=True, enum=PERIODS),
39
- })
40
-
41
- job_fields = api.model('Job', {
42
- 'id': fields.String(
43
- description='The job unique identifier', readonly=True),
44
- 'name': fields.String(description='The job unique name', required=True),
45
- 'description': fields.String(description='The job description'),
46
- 'task': fields.String(
47
- description='The task name', required=True,
48
- enum=[job.name for job in schedulables()]),
49
- 'crontab': fields.Nested(crontab_fields, allow_null=True),
50
- 'interval': fields.Nested(interval_fields, allow_null=True),
51
- 'args': fields.List(
52
- fields.Raw, description='The job execution arguments', default=[]),
53
- 'kwargs': fields.Raw(
54
- description='The job execution keyword arguments', default={}),
55
- 'schedule': fields.String(
56
- attribute='schedule_display',
57
- description='The schedule display', readonly=True),
58
- 'last_run_at': fields.ISODateTime(
59
- description='The last job execution date', readonly=True),
60
- 'last_run_id': fields.String(
61
- description='The last execution task id', readonly=True),
62
- 'enabled': fields.Boolean(
63
- description='Is this job enabled', default=False),
64
- })
65
-
66
- task_fields = api.model('Task', {
67
- 'id': fields.String(description='Tha task execution ID', readonly=True),
68
- 'status': fields.String(
69
- description='Cron expression for hour', readonly=True,
70
- enum=list(states.ALL_STATES)),
71
- 'result': fields.String(description='The task results if exists'),
72
- 'exc': fields.String(description='The exception thrown during execution'),
73
- 'traceback': fields.String(description='The execution traceback'),
74
- })
75
-
76
-
77
- @ns.route('/jobs/', endpoint='jobs')
13
+ from .models import PERIODS, PeriodicTask
14
+
15
+ ns = api.namespace("workers", "Asynchronous workers related operations", path="")
16
+
17
+ crontab_fields = api.model(
18
+ "Crontab",
19
+ {
20
+ "minute": fields.String(
21
+ description="Cron expression for minute", required=True, default="*"
22
+ ),
23
+ "hour": fields.String(description="Cron expression for hour", required=True, default="*"),
24
+ "day_of_week": fields.String(
25
+ description="Cron expression for day of week", required=True, default="*"
26
+ ),
27
+ "day_of_month": fields.String(
28
+ description="Cron expression for day of month", required=True, default="*"
29
+ ),
30
+ "month_of_year": fields.String(
31
+ description="Cron expression for month of year", required=True, default="*"
32
+ ),
33
+ },
34
+ )
35
+
36
+ interval_fields = api.model(
37
+ "Interval",
38
+ {
39
+ "every": fields.Integer(description="The interval without unit", required=True),
40
+ "period": fields.String(
41
+ description="The period/interval type", required=True, enum=PERIODS
42
+ ),
43
+ },
44
+ )
45
+
46
+ job_fields = api.model(
47
+ "Job",
48
+ {
49
+ "id": fields.String(description="The job unique identifier", readonly=True),
50
+ "name": fields.String(description="The job unique name", required=True),
51
+ "description": fields.String(description="The job description"),
52
+ "task": fields.String(
53
+ description="The task name", required=True, enum=[job.name for job in schedulables()]
54
+ ),
55
+ "crontab": fields.Nested(crontab_fields, allow_null=True),
56
+ "interval": fields.Nested(interval_fields, allow_null=True),
57
+ "args": fields.List(fields.Raw, description="The job execution arguments", default=[]),
58
+ "kwargs": fields.Raw(description="The job execution keyword arguments", default={}),
59
+ "schedule": fields.String(
60
+ attribute="schedule_display", description="The schedule display", readonly=True
61
+ ),
62
+ "last_run_at": fields.ISODateTime(description="The last job execution date", readonly=True),
63
+ "last_run_id": fields.String(description="The last execution task id", readonly=True),
64
+ "enabled": fields.Boolean(description="Is this job enabled", default=False),
65
+ },
66
+ )
67
+
68
+ task_fields = api.model(
69
+ "Task",
70
+ {
71
+ "id": fields.String(description="Tha task execution ID", readonly=True),
72
+ "status": fields.String(
73
+ description="Cron expression for hour", readonly=True, enum=list(states.ALL_STATES)
74
+ ),
75
+ "result": fields.String(description="The task results if exists"),
76
+ "exc": fields.String(description="The exception thrown during execution"),
77
+ "traceback": fields.String(description="The execution traceback"),
78
+ },
79
+ )
80
+
81
+
82
+ @ns.route("/jobs/", endpoint="jobs")
78
83
  class JobsAPI(API):
79
- @api.doc(id='list_jobs')
84
+ @api.doc(id="list_jobs")
80
85
  @api.marshal_list_with(job_fields)
81
86
  def get(self):
82
- '''List all scheduled jobs'''
87
+ """List all scheduled jobs"""
83
88
  return list(PeriodicTask.objects)
84
89
 
85
90
  @api.secure(admin_permission)
86
91
  @api.expect(job_fields)
87
92
  @api.marshal_with(job_fields)
88
93
  def post(self):
89
- '''Create a new scheduled job'''
90
- if 'crontab' in request.json and 'interval' in request.json:
91
- api.abort(400, 'Cannot define both interval and crontab schedule')
92
- if 'crontab' in request.json:
94
+ """Create a new scheduled job"""
95
+ if "crontab" in request.json and "interval" in request.json:
96
+ api.abort(400, "Cannot define both interval and crontab schedule")
97
+ if "crontab" in request.json:
93
98
  form = api.validate(CrontabTaskForm)
94
99
  else:
95
100
  form = api.validate(IntervalTaskForm)
96
101
  return form.save(), 201
97
102
 
98
103
 
99
- @ns.route('/jobs/<string:id>', endpoint='job')
100
- @api.param('id', 'A job ID')
104
+ @ns.route("/jobs/<string:id>", endpoint="job")
105
+ @api.param("id", "A job ID")
101
106
  class JobAPI(API):
102
107
  def get_or_404(self, id):
103
108
  task = PeriodicTask.objects(id=id).first()
@@ -107,15 +112,15 @@ class JobAPI(API):
107
112
 
108
113
  @api.marshal_with(job_fields)
109
114
  def get(self, id):
110
- '''Fetch a single scheduled job'''
115
+ """Fetch a single scheduled job"""
111
116
  return self.get_or_404(id_or_404(id))
112
117
 
113
118
  @api.secure(admin_permission)
114
119
  @api.marshal_with(job_fields)
115
120
  def put(self, id):
116
- '''Update a single scheduled job'''
121
+ """Update a single scheduled job"""
117
122
  task = self.get_or_404(id_or_404(id))
118
- if 'crontab' in request.json:
123
+ if "crontab" in request.json:
119
124
  task.interval = None
120
125
  task.crontab = PeriodicTask.Crontab()
121
126
  form = api.validate(CrontabTaskForm, task)
@@ -126,35 +131,37 @@ class JobAPI(API):
126
131
  return form.save()
127
132
 
128
133
  @api.secure(admin_permission)
129
- @api.response(204, 'Successfuly deleted')
134
+ @api.response(204, "Successfuly deleted")
130
135
  def delete(self, id):
131
- '''Delete a single scheduled job'''
136
+ """Delete a single scheduled job"""
132
137
  task = self.get_or_404(id_or_404(id))
133
138
  task.delete()
134
- return '', 204
139
+ return "", 204
135
140
 
136
141
 
137
- @ns.route('/tasks/<string:id>', endpoint='task')
142
+ @ns.route("/tasks/<string:id>", endpoint="task")
138
143
  class TaskAPI(API):
139
144
  @api.marshal_with(task_fields)
140
145
  def get(self, id):
141
- '''Get a tasks status given its ID'''
146
+ """Get a tasks status given its ID"""
142
147
  result = AsyncResult(id, app=celery)
143
148
  status, retval = result.status, result.result
144
- data = {'id': id, 'status': status, 'result': retval}
149
+ data = {"id": id, "status": status, "result": retval}
145
150
  if status in states.EXCEPTION_STATES:
146
151
  traceback = result.traceback
147
- data.update({
148
- 'result': safe_repr(retval),
149
- 'exc': get_full_cls_name(retval.__class__),
150
- 'traceback': traceback,
151
- })
152
+ data.update(
153
+ {
154
+ "result": safe_repr(retval),
155
+ "exc": get_full_cls_name(retval.__class__),
156
+ "traceback": traceback,
157
+ }
158
+ )
152
159
  return data
153
160
 
154
161
 
155
- @ns.route('/jobs/schedulables', endpoint='schedulable_jobs')
162
+ @ns.route("/jobs/schedulables", endpoint="schedulable_jobs")
156
163
  class JobsReferenceAPI(API):
157
164
  @api.doc(model=[str])
158
165
  def get(self):
159
- '''List all schedulable jobs'''
166
+ """List all schedulable jobs"""
160
167
  return [job.name for job in schedulables()]