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,19 +1,25 @@
1
- '''
1
+ """
2
2
  Data migrations logic
3
- '''
3
+ """
4
+
4
5
  import importlib.util
5
6
  import inspect
6
7
  import logging
7
8
  import os
8
9
  import queue
9
10
  import traceback
10
-
11
11
  from datetime import datetime
12
12
  from logging.handlers import QueueHandler
13
+
13
14
  from flask import current_app
14
15
  from mongoengine.connection import get_db
16
+ from pkg_resources import (
17
+ resource_filename,
18
+ resource_isdir,
19
+ resource_listdir,
20
+ resource_string,
21
+ )
15
22
  from pymongo import ReturnDocument
16
- from pkg_resources import resource_isdir, resource_listdir, resource_filename, resource_string
17
23
 
18
24
  from udata import entrypoints
19
25
 
@@ -21,13 +27,14 @@ log = logging.getLogger(__name__)
21
27
 
22
28
 
23
29
  class MigrationError(Exception):
24
- '''
30
+ """
25
31
  Raised on migration execution error.
26
32
 
27
33
  :param msg str: A human readable message (a reason)
28
34
  :param output str: An optionnal array of logging output
29
35
  :param exc Exception: An optionnal underlying exception
30
- '''
36
+ """
37
+
31
38
  def __init__(self, msg, output=None, exc=None, traceback=None):
32
39
  super().__init__(msg)
33
40
  self.msg = msg
@@ -37,10 +44,11 @@ class MigrationError(Exception):
37
44
 
38
45
 
39
46
  class RollbackError(MigrationError):
40
- '''
47
+ """
41
48
  Raised on rollback.
42
49
  Hold the initial migration error and rollback exception (if any)
43
- '''
50
+ """
51
+
44
52
  def __init__(self, msg, output=None, exc=None, migrate_exc=None):
45
53
  super().__init__(msg)
46
54
  self.msg = msg
@@ -54,13 +62,14 @@ class MigrationFormatter(logging.Formatter):
54
62
 
55
63
 
56
64
  class Record(dict):
57
- '''
65
+ """
58
66
  A simple wrapper to migrations document
59
- '''
67
+ """
68
+
60
69
  __getattr__ = dict.get
61
70
 
62
71
  def load(self):
63
- specs = {'plugin': self['plugin'], 'filename': self['filename']}
72
+ specs = {"plugin": self["plugin"], "filename": self["filename"]}
64
73
  self.clear()
65
74
  data = get_db().migrations.find_one(specs)
66
75
  self.update(data or specs)
@@ -77,7 +86,7 @@ class Record(dict):
77
86
 
78
87
  @property
79
88
  def status(self):
80
- '''
89
+ """
81
90
  Status is the status of the last operation.
82
91
 
83
92
  Will be `None` if the record doesn't exists.
@@ -87,69 +96,73 @@ class Record(dict):
87
96
  - rollback-error
88
97
  - error
89
98
  - recorded
90
- '''
99
+ """
91
100
  if not self.exists():
92
101
  return
93
102
  op = self.ops[-1]
94
- if op['success']:
95
- if op['type'] == 'migrate':
96
- return 'success'
97
- elif op['type'] == 'rollback':
98
- return 'rollback'
99
- elif op['type'] == 'record':
100
- return 'recorded'
103
+ if op["success"]:
104
+ if op["type"] == "migrate":
105
+ return "success"
106
+ elif op["type"] == "rollback":
107
+ return "rollback"
108
+ elif op["type"] == "record":
109
+ return "recorded"
101
110
  else:
102
- return 'unknown'
111
+ return "unknown"
103
112
  else:
104
- return 'rollback-error' if op['type'] == 'rollback' else 'error'
113
+ return "rollback-error" if op["type"] == "rollback" else "error"
105
114
 
106
115
  @property
107
116
  def last_date(self):
108
117
  if not self.exists():
109
118
  return
110
119
  op = self.ops[-1]
111
- return op['date']
120
+ return op["date"]
112
121
 
113
122
  @property
114
123
  def ok(self):
115
- '''
124
+ """
116
125
  Is true if the migration is considered as successfully applied
117
- '''
126
+ """
118
127
  if not self.exists():
119
128
  return False
120
129
  op = self.ops[-1]
121
- return op['success'] and op['type'] in ('migrate', 'record')
130
+ return op["success"] and op["type"] in ("migrate", "record")
122
131
 
123
132
  def add(self, _type, migration, output, state, success):
124
133
  script = inspect.getsource(migration)
125
- return Record(self.collection.find_one_and_update(
126
- {'plugin': self.plugin, 'filename': self.filename},
127
- {
128
- '$push': {'ops': {
129
- 'date': datetime.utcnow(),
130
- 'type': _type,
131
- 'script': script,
132
- 'output': output,
133
- 'state': state,
134
- 'success': success,
135
- }}
136
- },
137
- upsert=True,
138
- return_document=ReturnDocument.AFTER,
139
- ))
134
+ return Record(
135
+ self.collection.find_one_and_update(
136
+ {"plugin": self.plugin, "filename": self.filename},
137
+ {
138
+ "$push": {
139
+ "ops": {
140
+ "date": datetime.utcnow(),
141
+ "type": _type,
142
+ "script": script,
143
+ "output": output,
144
+ "state": state,
145
+ "success": success,
146
+ }
147
+ }
148
+ },
149
+ upsert=True,
150
+ return_document=ReturnDocument.AFTER,
151
+ )
152
+ )
140
153
 
141
154
  def delete(self):
142
- return self.collection.delete_one({'_id': self._id})
155
+ return self.collection.delete_one({"_id": self._id})
143
156
 
144
157
 
145
158
  class Migration:
146
159
  def __init__(self, plugin_or_specs, filename, module_name=None):
147
- if filename is None and ':' in plugin_or_specs:
148
- plugin, filename = plugin_or_specs.split(':')
160
+ if filename is None and ":" in plugin_or_specs:
161
+ plugin, filename = plugin_or_specs.split(":")
149
162
  else:
150
163
  plugin = plugin_or_specs
151
- if not filename.endswith('.py'):
152
- filename += '.py'
164
+ if not filename.endswith(".py"):
165
+ filename += ".py"
153
166
 
154
167
  self.plugin = plugin
155
168
  self.filename = filename
@@ -163,16 +176,16 @@ class Migration:
163
176
 
164
177
  @property
165
178
  def db_query(self):
166
- return {'plugin': self.plugin, 'filename': self.filename}
179
+ return {"plugin": self.plugin, "filename": self.filename}
167
180
 
168
181
  @property
169
182
  def label(self):
170
- return ':'.join((self.plugin, self.filename))
183
+ return ":".join((self.plugin, self.filename))
171
184
 
172
185
  @property
173
186
  def record(self):
174
187
  if self._record is None:
175
- specs = {'plugin': self.plugin, 'filename': self.filename}
188
+ specs = {"plugin": self.plugin, "filename": self.filename}
176
189
  data = get_db().migrations.find_one(specs)
177
190
  self._record = Record(data or specs)
178
191
  return self._record
@@ -186,31 +199,31 @@ class Migration:
186
199
  def __eq__(self, value):
187
200
  return (
188
201
  isinstance(value, Migration)
189
- and getattr(value, 'plugin') == self.plugin
190
- and getattr(value, 'filename') == self.filename
202
+ and getattr(value, "plugin") == self.plugin
203
+ and getattr(value, "filename") == self.filename
191
204
  )
192
205
 
193
206
  def execute(self, recordonly=False, dryrun=False):
194
- '''
207
+ """
195
208
  Execute a migration
196
209
 
197
210
  If recordonly is True, the migration is only recorded
198
211
  If dryrun is True, the migration is neither executed nor recorded
199
- '''
212
+ """
200
213
  q = queue.Queue(-1) # no limit on size
201
214
  handler = QueueHandler(q)
202
215
  handler.setFormatter(MigrationFormatter())
203
- logger = getattr(self.module, 'log', logging.getLogger(self.module.__name__))
216
+ logger = getattr(self.module, "log", logging.getLogger(self.module.__name__))
204
217
  logger.propagate = False
205
218
  for h in logger.handlers:
206
219
  logger.removeHandler(h)
207
220
  logger.addHandler(handler)
208
221
 
209
- if not hasattr(self.module, 'migrate'):
210
- error = SyntaxError('A migration should at least have a migrate(db) function')
211
- raise MigrationError('Error while executing migration', exc=error)
222
+ if not hasattr(self.module, "migrate"):
223
+ error = SyntaxError("A migration should at least have a migrate(db) function")
224
+ raise MigrationError("Error while executing migration", exc=error)
212
225
 
213
- out = [['info', 'Recorded only']] if recordonly else []
226
+ out = [["info", "Recorded only"]] if recordonly else []
214
227
  state = {}
215
228
 
216
229
  if not recordonly and not dryrun:
@@ -222,115 +235,120 @@ class Migration:
222
235
  except Exception as e:
223
236
  out = _extract_output(q)
224
237
  tb = traceback.format_exc()
225
- self.add_record('migrate', out, db._state, False, traceback=tb)
226
- fe = MigrationError('Error while executing migration',
227
- output=out, exc=e, traceback=tb)
228
- if hasattr(self.module, 'rollback'):
238
+ self.add_record("migrate", out, db._state, False, traceback=tb)
239
+ fe = MigrationError(
240
+ "Error while executing migration", output=out, exc=e, traceback=tb
241
+ )
242
+ if hasattr(self.module, "rollback"):
229
243
  try:
230
244
  self.module.rollback(db)
231
245
  out = _extract_output(q)
232
- self.add_record('rollback', out, db._state, True)
233
- msg = 'Error while executing migration, rollback has been applied'
246
+ self.add_record("rollback", out, db._state, True)
247
+ msg = "Error while executing migration, rollback has been applied"
234
248
  fe = RollbackError(msg, output=out, migrate_exc=fe)
235
249
  except Exception as re:
236
250
  out = _extract_output(q)
237
- self.add_record('rollback', out, db._state, False)
238
- msg = 'Error while executing migration rollback'
251
+ self.add_record("rollback", out, db._state, False)
252
+ msg = "Error while executing migration rollback"
239
253
  fe = RollbackError(msg, output=out, exc=re, migrate_exc=fe)
240
254
  raise fe
241
255
 
242
256
  if not dryrun:
243
- self.add_record('migrate', out, state, True)
257
+ self.add_record("migrate", out, state, True)
244
258
 
245
259
  return out
246
260
 
247
261
  def unrecord(self):
248
- '''Delete a migration record'''
262
+ """Delete a migration record"""
249
263
  if not self.record.exists():
250
264
  return False
251
265
  return bool(self.collection.delete_one(self.db_query).deleted_count)
252
266
 
253
267
  def add_record(self, type, output, state, success, traceback=None):
254
268
  script = inspect.getsource(self.module)
255
- return Record(self.collection.find_one_and_update(
256
- self.db_query,
257
- {
258
- '$push': {'ops': {
259
- 'date': datetime.utcnow(),
260
- 'type': type,
261
- 'script': script,
262
- 'output': output,
263
- 'state': state,
264
- 'success': success,
265
- 'traceback': traceback,
266
- }}
267
- },
268
- upsert=True,
269
- return_document=ReturnDocument.AFTER,
270
- ))
269
+ return Record(
270
+ self.collection.find_one_and_update(
271
+ self.db_query,
272
+ {
273
+ "$push": {
274
+ "ops": {
275
+ "date": datetime.utcnow(),
276
+ "type": type,
277
+ "script": script,
278
+ "output": output,
279
+ "state": state,
280
+ "success": success,
281
+ "traceback": traceback,
282
+ }
283
+ }
284
+ },
285
+ upsert=True,
286
+ return_document=ReturnDocument.AFTER,
287
+ )
288
+ )
271
289
 
272
290
 
273
291
  def get(plugin, filename):
274
- '''Get a migration'''
292
+ """Get a migration"""
275
293
  return Migration(plugin, filename)
276
294
 
277
295
 
278
296
  def list_available():
279
- '''
297
+ """
280
298
  List available migrations for udata and enabled plugins
281
299
 
282
300
  Each row is a tuple with following signature:
283
301
 
284
302
  (plugin, package, filename)
285
- '''
303
+ """
286
304
  migrations = []
287
305
 
288
- migrations.extend(_iter('udata', 'udata'))
306
+ migrations.extend(_iter("udata", "udata"))
289
307
 
290
- plugins = entrypoints.get_enabled('udata.models', current_app)
308
+ plugins = entrypoints.get_enabled("udata.models", current_app)
291
309
  for plugin, module in plugins.items():
292
310
  migrations.extend(_iter(plugin, module))
293
311
  return sorted(migrations, key=lambda m: m.filename)
294
312
 
295
313
 
296
314
  def _iter(plugin, module):
297
- '''
315
+ """
298
316
  Iterate over migrations for a given plugin module
299
317
 
300
318
  Yield tuples in the form (plugin_name, module_name, filename)
301
- '''
319
+ """
302
320
  module_name = module if isinstance(module, str) else module.__name__
303
- if not resource_isdir(module_name, 'migrations'):
321
+ if not resource_isdir(module_name, "migrations"):
304
322
  return
305
- for filename in resource_listdir(module_name, 'migrations'):
306
- if filename.endswith('.py') and not filename.startswith('__'):
323
+ for filename in resource_listdir(module_name, "migrations"):
324
+ if filename.endswith(".py") and not filename.startswith("__"):
307
325
  yield Migration(plugin, filename, module_name)
308
326
 
309
327
 
310
328
  def _module_name(plugin):
311
- '''Get the module name for a given plugin'''
312
- if plugin == 'udata':
313
- return 'udata'
314
- module = entrypoints.get_plugin_module('udata.models', current_app, plugin)
329
+ """Get the module name for a given plugin"""
330
+ if plugin == "udata":
331
+ return "udata"
332
+ module = entrypoints.get_plugin_module("udata.models", current_app, plugin)
315
333
  if module is None:
316
- raise MigrationError('Plugin {} not found'.format(plugin))
334
+ raise MigrationError("Plugin {} not found".format(plugin))
317
335
  return module.__name__
318
336
 
319
337
 
320
338
  def load_migration(plugin, filename, module_name=None):
321
- '''
339
+ """
322
340
  Load a migration from its python file
323
341
 
324
342
  :returns: the loaded module
325
- '''
343
+ """
326
344
  module_name = module_name or _module_name(plugin)
327
345
  basename = os.path.splitext(os.path.basename(filename))[0]
328
- name = '.'.join((module_name, 'migrations', basename))
329
- filename = os.path.join('migrations', filename)
346
+ name = ".".join((module_name, "migrations", basename))
347
+ filename = os.path.join("migrations", filename)
330
348
  try:
331
349
  script = resource_string(module_name, filename)
332
350
  except Exception:
333
- msg = 'Unable to load file {} from module {}'.format(filename, module_name)
351
+ msg = "Unable to load file {} from module {}".format(filename, module_name)
334
352
  raise MigrationError(msg)
335
353
  spec = importlib.util.spec_from_loader(name, loader=None)
336
354
  module = importlib.util.module_from_spec(spec)
@@ -340,7 +358,7 @@ def load_migration(plugin, filename, module_name=None):
340
358
 
341
359
 
342
360
  def _extract_output(q):
343
- '''Extract log output from a QueueHandler queue'''
361
+ """Extract log output from a QueueHandler queue"""
344
362
  out = []
345
363
  while not q.empty():
346
364
  record = q.get()
udata/models/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
- from mongoengine.errors import ValidationError
1
+ from mongoengine.errors import ValidationError # noqa
2
2
 
3
- from udata import entrypoints
4
- from udata.mongo import *
3
+ from udata import entrypoints # noqa
4
+ from udata.mongo import * # noqa
5
5
 
6
6
  # Load all core models and mixins
7
7
  from udata.core.spatial.models import * # noqa
@@ -33,4 +33,4 @@ import udata.linkchecker.models # noqa
33
33
 
34
34
 
35
35
  def init_app(app):
36
- entrypoints.get_enabled('udata.models', app)
36
+ entrypoints.get_enabled("udata.models", app)
udata/mongo/__init__.py CHANGED
@@ -8,8 +8,9 @@ from .engine import db
8
8
 
9
9
  log = logging.getLogger(__name__)
10
10
 
11
- MONGODB_DEPRECATED_SETTINGS = 'MONGODB_PORT', 'MONGODB_DB'
12
- MONGODB_DEPRECATED_MSG = '{0} is deprecated, use the MONGODB_HOST url syntax'
11
+ MONGODB_DEPRECATED_SETTINGS = "MONGODB_PORT", "MONGODB_DB"
12
+ MONGODB_DEPRECATED_MSG = "{0} is deprecated, use the MONGODB_HOST url syntax"
13
+
13
14
 
14
15
  def validate_config(config):
15
16
  for setting in MONGODB_DEPRECATED_SETTINGS:
@@ -17,26 +18,27 @@ def validate_config(config):
17
18
  msg = MONGODB_DEPRECATED_MSG.format(setting)
18
19
  log.warning(msg)
19
20
  warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
20
- url = config['MONGODB_HOST']
21
+ url = config["MONGODB_HOST"]
21
22
  parsed_url = urlparse(url)
22
23
  if not all((parsed_url.scheme, parsed_url.netloc)):
23
- raise ConfigError('{0} is not a valid MongoDB URL'.format(url))
24
+ raise ConfigError("{0} is not a valid MongoDB URL".format(url))
24
25
  if len(parsed_url.path) <= 1:
25
- raise ConfigError('{0} is missing the database path'.format(url))
26
+ raise ConfigError("{0} is missing the database path".format(url))
26
27
 
27
28
 
28
29
  def build_test_config(config):
29
- if 'MONGODB_HOST_TEST' in config:
30
- config['MONGODB_HOST'] = config['MONGODB_HOST_TEST']
30
+ if "MONGODB_HOST_TEST" in config:
31
+ config["MONGODB_HOST"] = config["MONGODB_HOST_TEST"]
31
32
  else:
32
33
  # use `{database_name}-test` database for testing
33
- parsed_url = urlparse(config['MONGODB_HOST'])
34
- parsed_url = parsed_url._replace(path='%s-test' % parsed_url.path)
35
- config['MONGODB_HOST'] = parsed_url.geturl()
34
+ parsed_url = urlparse(config["MONGODB_HOST"])
35
+ parsed_url = parsed_url._replace(path="%s-test" % parsed_url.path)
36
+ config["MONGODB_HOST"] = parsed_url.geturl()
36
37
  validate_config(config)
37
38
 
39
+
38
40
  def init_app(app):
39
41
  validate_config(app.config)
40
- if app.config['TESTING']:
42
+ if app.config["TESTING"]:
41
43
  build_test_config(app.config)
42
44
  db.init_app(app)
@@ -20,15 +20,16 @@ class BadgesField(ListField):
20
20
 
21
21
  for key in value:
22
22
  if key not in self.registered:
23
- errors[key] = 'Badge {0} is not registered'.format(key)
23
+ errors[key] = "Badge {0} is not registered".format(key)
24
24
 
25
25
  if errors:
26
- self.error('Unknown badges types', errors=errors)
26
+ self.error("Unknown badges types", errors=errors)
27
27
 
28
28
  def __call__(self, key):
29
29
  def inner(cls):
30
30
  self.register(key, cls)
31
31
  return cls
32
+
32
33
  return inner
33
34
 
34
35
 
@@ -1,22 +1,21 @@
1
1
  import logging
2
-
3
2
  from datetime import date, datetime
4
- from dateutil.parser import parse
5
3
 
4
+ from dateutil.parser import parse
6
5
  from mongoengine import EmbeddedDocument
7
6
  from mongoengine.fields import BaseField, DateTimeField
8
7
  from mongoengine.signals import pre_save
9
8
 
10
9
  from udata.i18n import lazy_gettext as _
11
10
 
12
-
13
11
  log = logging.getLogger(__name__)
14
12
 
15
13
 
16
14
  class DateField(BaseField):
17
- '''
15
+ """
18
16
  Store date in iso format
19
- '''
17
+ """
18
+
20
19
  def to_python(self, value):
21
20
  if isinstance(value, date):
22
21
  return value
@@ -40,7 +39,7 @@ class DateField(BaseField):
40
39
 
41
40
  def validate(self, value):
42
41
  if not isinstance(value, date):
43
- self.error('DateField only accepts date values')
42
+ self.error("DateField only accepts date values")
44
43
 
45
44
 
46
45
  class DateRange(EmbeddedDocument):
@@ -48,7 +47,7 @@ class DateRange(EmbeddedDocument):
48
47
  end = DateField()
49
48
 
50
49
  def to_dict(self):
51
- return {'start': self.start, 'end': self.end}
50
+ return {"start": self.start, "end": self.end}
52
51
 
53
52
  def clean(self):
54
53
  if self.start and self.end and self.start > self.end:
@@ -56,14 +55,16 @@ class DateRange(EmbeddedDocument):
56
55
 
57
56
 
58
57
  class Datetimed(object):
59
- created_at = DateTimeField(verbose_name=_('Creation date'),
60
- default=datetime.utcnow, required=True)
61
- last_modified = DateTimeField(verbose_name=_('Last modification date'),
62
- default=datetime.utcnow, required=True)
58
+ created_at = DateTimeField(
59
+ verbose_name=_("Creation date"), default=datetime.utcnow, required=True
60
+ )
61
+ last_modified = DateTimeField(
62
+ verbose_name=_("Last modification date"), default=datetime.utcnow, required=True
63
+ )
63
64
 
64
65
 
65
66
  @pre_save.connect
66
67
  def set_modified_datetime(sender, document, **kwargs):
67
68
  changed = document._get_changed_fields()
68
- if isinstance(document, Datetimed) and 'last_modified' not in changed:
69
+ if isinstance(document, Datetimed) and "last_modified" not in changed:
69
70
  document.last_modified = datetime.utcnow()
udata/mongo/document.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import logging
2
-
3
2
  from collections.abc import Iterable
4
3
 
5
4
  from flask_mongoengine import Document
@@ -10,7 +9,7 @@ log = logging.getLogger(__name__)
10
9
 
11
10
 
12
11
  def serialize(value):
13
- if hasattr(value, 'to_dict'):
12
+ if hasattr(value, "to_dict"):
14
13
  return value.to_dict()
15
14
  elif isinstance(value, Iterable) and not isinstance(value, str):
16
15
  return [serialize(val) for val in value]
@@ -20,30 +19,32 @@ def serialize(value):
20
19
 
21
20
  class UDataDocument(Document):
22
21
  meta = {
23
- 'abstract': True,
24
- 'queryset_class': UDataQuerySet,
22
+ "abstract": True,
23
+ "queryset_class": UDataQuerySet,
25
24
  }
26
25
 
27
26
  def to_dict(self, exclude=None):
28
- id_field = self._meta['id_field']
27
+ id_field = self._meta["id_field"]
29
28
  excluded_keys = set(exclude or [])
30
- excluded_keys.add('_id')
31
- excluded_keys.add('_cls')
32
- data = dict((
33
- (key, serialize(value))
34
- for key, value in self.to_mongo().items()
35
- if key not in excluded_keys
36
- ))
29
+ excluded_keys.add("_id")
30
+ excluded_keys.add("_cls")
31
+ data = dict(
32
+ (
33
+ (key, serialize(value))
34
+ for key, value in self.to_mongo().items()
35
+ if key not in excluded_keys
36
+ )
37
+ )
37
38
  data[id_field] = getattr(self, id_field)
38
39
  return data
39
40
 
40
41
  def __str__(self):
41
- return '{classname}({id})'.format(
42
- classname=self.__class__.__name__,
43
- id=getattr(self, self._meta['id_field'])
42
+ return "{classname}({id})".format(
43
+ classname=self.__class__.__name__, id=getattr(self, self._meta["id_field"])
44
44
  )
45
45
 
46
46
 
47
47
  class DomainModel(UDataDocument):
48
- '''Placeholder for inheritance'''
48
+ """Placeholder for inheritance"""
49
+
49
50
  pass