udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30454__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 (413) 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 +111 -134
  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 +58 -55
  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/cors.py +99 -0
  199. udata/db/tasks.py +2 -1
  200. udata/entrypoints.py +35 -31
  201. udata/errors.py +2 -1
  202. udata/event/values.py +6 -6
  203. udata/factories.py +2 -2
  204. udata/features/identicon/api.py +5 -6
  205. udata/features/identicon/backends.py +48 -55
  206. udata/features/identicon/tests/test_backends.py +4 -5
  207. udata/features/notifications/__init__.py +0 -1
  208. udata/features/notifications/actions.py +9 -9
  209. udata/features/notifications/api.py +17 -13
  210. udata/features/territories/__init__.py +12 -10
  211. udata/features/territories/api.py +14 -15
  212. udata/features/territories/models.py +23 -28
  213. udata/features/transfer/actions.py +8 -11
  214. udata/features/transfer/api.py +84 -77
  215. udata/features/transfer/factories.py +2 -1
  216. udata/features/transfer/models.py +11 -12
  217. udata/features/transfer/notifications.py +19 -15
  218. udata/features/transfer/permissions.py +5 -5
  219. udata/forms/__init__.py +5 -2
  220. udata/forms/fields.py +164 -172
  221. udata/forms/validators.py +19 -22
  222. udata/forms/widgets.py +9 -13
  223. udata/frontend/__init__.py +31 -26
  224. udata/frontend/csv.py +68 -58
  225. udata/frontend/markdown.py +40 -44
  226. udata/harvest/actions.py +89 -77
  227. udata/harvest/api.py +294 -238
  228. udata/harvest/backends/__init__.py +4 -4
  229. udata/harvest/backends/base.py +128 -111
  230. udata/harvest/backends/dcat.py +80 -66
  231. udata/harvest/commands.py +56 -60
  232. udata/harvest/csv.py +8 -8
  233. udata/harvest/exceptions.py +6 -3
  234. udata/harvest/filters.py +24 -23
  235. udata/harvest/forms.py +27 -28
  236. udata/harvest/models.py +88 -80
  237. udata/harvest/notifications.py +15 -10
  238. udata/harvest/signals.py +13 -13
  239. udata/harvest/tasks.py +11 -10
  240. udata/harvest/tests/factories.py +23 -24
  241. udata/harvest/tests/test_actions.py +136 -166
  242. udata/harvest/tests/test_api.py +220 -214
  243. udata/harvest/tests/test_base_backend.py +117 -112
  244. udata/harvest/tests/test_dcat_backend.py +380 -308
  245. udata/harvest/tests/test_filters.py +33 -22
  246. udata/harvest/tests/test_models.py +11 -14
  247. udata/harvest/tests/test_notifications.py +6 -7
  248. udata/harvest/tests/test_tasks.py +7 -6
  249. udata/i18n.py +237 -78
  250. udata/linkchecker/backends.py +5 -11
  251. udata/linkchecker/checker.py +23 -22
  252. udata/linkchecker/commands.py +4 -6
  253. udata/linkchecker/models.py +6 -6
  254. udata/linkchecker/tasks.py +18 -20
  255. udata/mail.py +21 -21
  256. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  257. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  258. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  259. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  260. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  261. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  262. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  263. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  264. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  265. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  266. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  267. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  268. udata/migrations/2021-08-17-users-integrity.py +9 -8
  269. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  270. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  271. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  272. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  273. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  274. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  275. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  276. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  277. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  278. udata/migrations/__init__.py +123 -105
  279. udata/models/__init__.py +4 -4
  280. udata/mongo/__init__.py +13 -11
  281. udata/mongo/badges_field.py +3 -2
  282. udata/mongo/datetime_fields.py +13 -12
  283. udata/mongo/document.py +17 -16
  284. udata/mongo/engine.py +15 -16
  285. udata/mongo/errors.py +2 -1
  286. udata/mongo/extras_fields.py +30 -20
  287. udata/mongo/queryset.py +12 -12
  288. udata/mongo/slug_fields.py +38 -28
  289. udata/mongo/taglist_field.py +1 -2
  290. udata/mongo/url_field.py +5 -5
  291. udata/mongo/uuid_fields.py +4 -3
  292. udata/notifications/__init__.py +1 -1
  293. udata/notifications/mattermost.py +10 -9
  294. udata/rdf.py +167 -188
  295. udata/routing.py +40 -45
  296. udata/search/__init__.py +18 -19
  297. udata/search/adapter.py +17 -16
  298. udata/search/commands.py +44 -51
  299. udata/search/fields.py +13 -20
  300. udata/search/query.py +23 -18
  301. udata/search/result.py +9 -10
  302. udata/sentry.py +21 -19
  303. udata/settings.py +262 -198
  304. udata/sitemap.py +8 -6
  305. udata/storage/s3.py +20 -13
  306. udata/tags.py +4 -5
  307. udata/tasks.py +43 -42
  308. udata/tests/__init__.py +9 -6
  309. udata/tests/api/__init__.py +8 -6
  310. udata/tests/api/test_auth_api.py +395 -321
  311. udata/tests/api/test_base_api.py +33 -35
  312. udata/tests/api/test_contact_points.py +7 -9
  313. udata/tests/api/test_dataservices_api.py +211 -158
  314. udata/tests/api/test_datasets_api.py +823 -812
  315. udata/tests/api/test_follow_api.py +13 -15
  316. udata/tests/api/test_me_api.py +95 -112
  317. udata/tests/api/test_organizations_api.py +301 -339
  318. udata/tests/api/test_reports_api.py +35 -25
  319. udata/tests/api/test_reuses_api.py +134 -139
  320. udata/tests/api/test_swagger.py +5 -5
  321. udata/tests/api/test_tags_api.py +18 -25
  322. udata/tests/api/test_topics_api.py +94 -94
  323. udata/tests/api/test_transfer_api.py +53 -48
  324. udata/tests/api/test_user_api.py +128 -141
  325. udata/tests/apiv2/test_datasets.py +290 -198
  326. udata/tests/apiv2/test_me_api.py +10 -11
  327. udata/tests/apiv2/test_organizations.py +56 -74
  328. udata/tests/apiv2/test_swagger.py +5 -5
  329. udata/tests/apiv2/test_topics.py +69 -87
  330. udata/tests/cli/test_cli_base.py +8 -8
  331. udata/tests/cli/test_db_cli.py +21 -19
  332. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  333. udata/tests/dataset/test_csv_adapter.py +44 -35
  334. udata/tests/dataset/test_dataset_actions.py +2 -3
  335. udata/tests/dataset/test_dataset_commands.py +7 -8
  336. udata/tests/dataset/test_dataset_events.py +36 -29
  337. udata/tests/dataset/test_dataset_model.py +224 -217
  338. udata/tests/dataset/test_dataset_rdf.py +142 -131
  339. udata/tests/dataset/test_dataset_tasks.py +15 -15
  340. udata/tests/dataset/test_resource_preview.py +10 -13
  341. udata/tests/features/territories/__init__.py +9 -13
  342. udata/tests/features/territories/test_territories_api.py +71 -91
  343. udata/tests/forms/test_basic_fields.py +7 -7
  344. udata/tests/forms/test_current_user_field.py +39 -66
  345. udata/tests/forms/test_daterange_field.py +31 -39
  346. udata/tests/forms/test_dict_field.py +28 -26
  347. udata/tests/forms/test_extras_fields.py +102 -76
  348. udata/tests/forms/test_form_field.py +8 -8
  349. udata/tests/forms/test_image_field.py +33 -26
  350. udata/tests/forms/test_model_field.py +134 -123
  351. udata/tests/forms/test_model_list_field.py +7 -7
  352. udata/tests/forms/test_nested_model_list_field.py +117 -79
  353. udata/tests/forms/test_publish_as_field.py +36 -65
  354. udata/tests/forms/test_reference_field.py +34 -53
  355. udata/tests/forms/test_user_forms.py +23 -21
  356. udata/tests/forms/test_uuid_field.py +6 -10
  357. udata/tests/frontend/__init__.py +9 -6
  358. udata/tests/frontend/test_auth.py +7 -6
  359. udata/tests/frontend/test_csv.py +81 -96
  360. udata/tests/frontend/test_hooks.py +43 -43
  361. udata/tests/frontend/test_markdown.py +211 -191
  362. udata/tests/helpers.py +32 -37
  363. udata/tests/models.py +2 -2
  364. udata/tests/organization/test_csv_adapter.py +21 -16
  365. udata/tests/organization/test_notifications.py +11 -18
  366. udata/tests/organization/test_organization_model.py +13 -13
  367. udata/tests/organization/test_organization_rdf.py +29 -22
  368. udata/tests/organization/test_organization_tasks.py +16 -17
  369. udata/tests/plugin.py +79 -73
  370. udata/tests/reuse/test_reuse_model.py +21 -21
  371. udata/tests/reuse/test_reuse_task.py +11 -13
  372. udata/tests/search/__init__.py +11 -12
  373. udata/tests/search/test_adapter.py +60 -70
  374. udata/tests/search/test_query.py +16 -16
  375. udata/tests/search/test_results.py +10 -7
  376. udata/tests/site/test_site_api.py +11 -16
  377. udata/tests/site/test_site_metrics.py +20 -30
  378. udata/tests/site/test_site_model.py +4 -5
  379. udata/tests/site/test_site_rdf.py +94 -78
  380. udata/tests/test_activity.py +17 -17
  381. udata/tests/test_cors.py +62 -0
  382. udata/tests/test_discussions.py +292 -299
  383. udata/tests/test_i18n.py +37 -40
  384. udata/tests/test_linkchecker.py +91 -85
  385. udata/tests/test_mail.py +13 -17
  386. udata/tests/test_migrations.py +219 -180
  387. udata/tests/test_model.py +164 -157
  388. udata/tests/test_notifications.py +17 -17
  389. udata/tests/test_owned.py +14 -14
  390. udata/tests/test_rdf.py +25 -23
  391. udata/tests/test_routing.py +89 -93
  392. udata/tests/test_storages.py +137 -128
  393. udata/tests/test_tags.py +44 -46
  394. udata/tests/test_topics.py +7 -7
  395. udata/tests/test_transfer.py +42 -49
  396. udata/tests/test_uris.py +160 -161
  397. udata/tests/test_utils.py +79 -71
  398. udata/tests/user/test_user_rdf.py +5 -9
  399. udata/tests/workers/test_jobs_commands.py +57 -58
  400. udata/tests/workers/test_tasks_routing.py +23 -29
  401. udata/tests/workers/test_workers_api.py +125 -131
  402. udata/tests/workers/test_workers_helpers.py +6 -6
  403. udata/tracking.py +4 -6
  404. udata/uris.py +45 -46
  405. udata/utils.py +68 -66
  406. udata/wsgi.py +1 -1
  407. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/METADATA +7 -3
  408. udata-9.1.2.dev30454.dist-info/RECORD +706 -0
  409. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  410. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
  411. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
  412. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
  413. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,9 @@
1
1
  import importlib.util
2
- import pytest
3
-
4
2
  from datetime import datetime
5
3
  from textwrap import dedent
6
4
 
5
+ import pytest
6
+
7
7
  from udata import migrations
8
8
  from udata.tests.helpers import assert_equal_dates
9
9
 
@@ -13,23 +13,23 @@ class MigrationsMock:
13
13
  self.root = root
14
14
  self.plugins = set()
15
15
  self.enabled = set()
16
- self.build_module('udata')
16
+ self.build_module("udata")
17
17
 
18
- def add_migration(self, plugin, filename, content='', enable=True):
18
+ def add_migration(self, plugin, filename, content="", enable=True):
19
19
  module = self.ensure_plugin(plugin, enabled=enable)
20
- module.ensure_dir('migrations')
21
- migration = module / 'migrations' / filename
20
+ module.ensure_dir("migrations")
21
+ migration = module / "migrations" / filename
22
22
  migration.write(dedent(content))
23
23
 
24
24
  def build_module(self, name):
25
25
  root = self.root.ensure_dir(name)
26
- root.ensure('__init__.py')
26
+ root.ensure("__init__.py")
27
27
 
28
28
  def ensure_plugin(self, plugin, enabled=True):
29
- if plugin not in self.plugins and plugin != 'udata':
29
+ if plugin not in self.plugins and plugin != "udata":
30
30
  self.build_module(plugin)
31
31
  self.plugins.add(plugin)
32
- if enabled and plugin != 'udata':
32
+ if enabled and plugin != "udata":
33
33
  self.enabled.add(plugin)
34
34
  else:
35
35
  self.enabled.discard(plugin)
@@ -37,7 +37,7 @@ class MigrationsMock:
37
37
 
38
38
  def _load_module(self, name, path):
39
39
  # See: https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
40
- spec = importlib.util.spec_from_file_location(name, str(path / '__init__.py'))
40
+ spec = importlib.util.spec_from_file_location(name, str(path / "__init__.py"))
41
41
  module = importlib.util.module_from_spec(spec)
42
42
  return module
43
43
 
@@ -59,10 +59,7 @@ class MigrationsMock:
59
59
  return self._resource_path(name, dirname).check(dir=1, exists=1)
60
60
 
61
61
  def mock_get_enabled_entrypoints(self, entrypoint, app):
62
- return {
63
- plugin: self._load_module(plugin, self.root / plugin)
64
- for plugin in self.enabled
65
- }
62
+ return {plugin: self._load_module(plugin, self.root / plugin) for plugin in self.enabled}
66
63
 
67
64
  def mock_get_plugin_module(self, entrypoint, app, plugin):
68
65
  return self._load_module(plugin, self.root / plugin)
@@ -70,83 +67,94 @@ class MigrationsMock:
70
67
 
71
68
  @pytest.fixture
72
69
  def mock(app, tmpdir, mocker):
73
- '''
70
+ """
74
71
  Mock migrations files
75
- '''
72
+ """
76
73
  m = MigrationsMock(tmpdir)
77
- mocker.patch('udata.migrations.resource_listdir', side_effect=m.mock_resource_listdir)
78
- mocker.patch('udata.migrations.resource_isdir', side_effect=m.mock_resource_isdir)
79
- mocker.patch('udata.migrations.resource_string', side_effect=m.mock_resource_string)
80
- mocker.patch('udata.migrations.resource_filename', side_effect=m.mock_resource_filename)
81
- mocker.patch('udata.entrypoints.get_enabled', side_effect=m.mock_get_enabled_entrypoints)
82
- mocker.patch('udata.entrypoints.get_plugin_module', side_effect=m.mock_get_plugin_module)
74
+ mocker.patch("udata.migrations.resource_listdir", side_effect=m.mock_resource_listdir)
75
+ mocker.patch("udata.migrations.resource_isdir", side_effect=m.mock_resource_isdir)
76
+ mocker.patch("udata.migrations.resource_string", side_effect=m.mock_resource_string)
77
+ mocker.patch("udata.migrations.resource_filename", side_effect=m.mock_resource_filename)
78
+ mocker.patch("udata.entrypoints.get_enabled", side_effect=m.mock_get_enabled_entrypoints)
79
+ mocker.patch("udata.entrypoints.get_plugin_module", side_effect=m.mock_get_plugin_module)
83
80
  yield m
84
81
 
85
82
 
86
- @pytest.mark.parametrize('args', [
87
- ('udata', 'test.py'),
88
- ('udata', 'test'),
89
- ('udata:test.py', None),
90
- ('udata:test.py', None),
91
- ])
83
+ @pytest.mark.parametrize(
84
+ "args",
85
+ [
86
+ ("udata", "test.py"),
87
+ ("udata", "test"),
88
+ ("udata:test.py", None),
89
+ ("udata:test.py", None),
90
+ ],
91
+ )
92
92
  def test_get_migration(args):
93
93
  migration = migrations.get(*args)
94
94
 
95
95
  assert isinstance(migration, migrations.Migration)
96
- assert migration.plugin == 'udata'
97
- assert migration.filename == 'test.py'
96
+ assert migration.plugin == "udata"
97
+ assert migration.filename == "test.py"
98
98
 
99
99
 
100
100
  def test_list_available_migrations(mock):
101
- mock.add_migration('udata', '01_core_migration.py')
102
- mock.add_migration('test', '02_test_migration.py')
103
- mock.add_migration('other', '03_other_migration.py')
101
+ mock.add_migration("udata", "01_core_migration.py")
102
+ mock.add_migration("test", "02_test_migration.py")
103
+ mock.add_migration("other", "03_other_migration.py")
104
104
  # Should not list `__*.py` files
105
- mock.add_migration('test', '__private.py')
105
+ mock.add_migration("test", "__private.py")
106
106
  # Should not list migrations for disabled plugin
107
- mock.add_migration('disabled', 'should_not_be_there.py', enable=False)
107
+ mock.add_migration("disabled", "should_not_be_there.py", enable=False)
108
108
  # Should not fail on plugins without migrations dir
109
- mock.ensure_plugin('nomigrations')
109
+ mock.ensure_plugin("nomigrations")
110
110
 
111
111
  availables = migrations.list_available()
112
112
 
113
113
  assert len(availables) == 3
114
- assert availables == [migrations.Migration(p, f) for p, f in (
115
- ('udata', '01_core_migration.py'),
116
- ('test', '02_test_migration.py'),
117
- ('other', '03_other_migration.py'),
118
- )]
114
+ assert availables == [
115
+ migrations.Migration(p, f)
116
+ for p, f in (
117
+ ("udata", "01_core_migration.py"),
118
+ ("test", "02_test_migration.py"),
119
+ ("other", "03_other_migration.py"),
120
+ )
121
+ ]
119
122
 
120
123
 
121
124
  def test_get_record(db):
122
125
  inserted = {
123
- 'plugin': 'test',
124
- 'filename': 'filename.py',
125
- 'ops': [{
126
- 'date': datetime.utcnow(),
127
- 'type': 'migrate',
128
- 'script': 'script',
129
- 'output': 'output',
130
- 'success': True,
131
- }]
126
+ "plugin": "test",
127
+ "filename": "filename.py",
128
+ "ops": [
129
+ {
130
+ "date": datetime.utcnow(),
131
+ "type": "migrate",
132
+ "script": "script",
133
+ "output": "output",
134
+ "success": True,
135
+ }
136
+ ],
132
137
  }
133
138
  db.migrations.insert_one(inserted)
134
139
 
135
- record = migrations.get('test', 'filename.py').record
140
+ record = migrations.get("test", "filename.py").record
136
141
 
137
- assert record['plugin'] == inserted['plugin']
138
- assert record['filename'] == inserted['filename']
142
+ assert record["plugin"] == inserted["plugin"]
143
+ assert record["filename"] == inserted["filename"]
139
144
 
140
- op = record['ops'][0]
141
- assert op['script'] == inserted['ops'][0]['script']
142
- assert op['output'] == inserted['ops'][0]['output']
143
- assert op['type'] == inserted['ops'][0]['type']
144
- assert op['success']
145
- assert_equal_dates(op['date'], inserted['ops'][0]['date'])
145
+ op = record["ops"][0]
146
+ assert op["script"] == inserted["ops"][0]["script"]
147
+ assert op["output"] == inserted["ops"][0]["output"]
148
+ assert op["type"] == inserted["ops"][0]["type"]
149
+ assert op["success"]
150
+ assert_equal_dates(op["date"], inserted["ops"][0]["date"])
146
151
 
147
152
 
148
153
  def test_migration_execute(mock, db):
149
- mock.add_migration('udata', 'migration.py', '''\
154
+ mock.add_migration(
155
+ "udata",
156
+ "migration.py",
157
+ """\
150
158
  import logging
151
159
 
152
160
  log = logging.getLogger(__name__)
@@ -154,94 +162,106 @@ def test_migration_execute(mock, db):
154
162
  def migrate(db):
155
163
  db.test.insert_one({'key': 'value'})
156
164
  log.info('test')
157
- ''')
165
+ """,
166
+ )
158
167
 
159
- output = migrations.get('udata', 'migration.py').execute()
168
+ output = migrations.get("udata", "migration.py").execute()
160
169
 
161
170
  inserted = db.test.find_one()
162
171
  assert inserted is not None
163
- assert inserted['key'] == 'value'
164
- assert output == [['info', 'test']]
172
+ assert inserted["key"] == "value"
173
+ assert output == [["info", "test"]]
165
174
 
166
175
  assert db.migrations.count_documents({}) == 1
167
176
  record = db.migrations.find_one()
168
- assert record['plugin'] == 'udata'
169
- assert record['filename'] == 'migration.py'
170
- assert len(record['ops']) == 1
177
+ assert record["plugin"] == "udata"
178
+ assert record["filename"] == "migration.py"
179
+ assert len(record["ops"]) == 1
171
180
 
172
- op = record['ops'][0]
173
- assert op['type'] == 'migrate'
174
- assert op['output'] == [['info', 'test']]
175
- assert op['state'] == {}
176
- assert isinstance(op['date'], datetime)
177
- assert op['success']
181
+ op = record["ops"][0]
182
+ assert op["type"] == "migrate"
183
+ assert op["output"] == [["info", "test"]]
184
+ assert op["state"] == {}
185
+ assert isinstance(op["date"], datetime)
186
+ assert op["success"]
178
187
 
179
188
 
180
189
  def test_migration_add_record(mock, db):
181
- mock.add_migration('test', 'filename.py', '''\
190
+ mock.add_migration(
191
+ "test",
192
+ "filename.py",
193
+ """\
182
194
  # whatever
183
195
 
184
196
  def migrate():
185
197
  pass
186
- ''')
198
+ """,
199
+ )
187
200
 
188
- expected_output = [['info', 'Recorded only']]
201
+ expected_output = [["info", "Recorded only"]]
189
202
 
190
- output = migrations.get('test', 'filename.py').execute(recordonly=True)
203
+ output = migrations.get("test", "filename.py").execute(recordonly=True)
191
204
 
192
205
  assert output == expected_output
193
206
 
194
207
  migration = db.migrations.find_one()
195
- assert migration['plugin'] == 'test'
196
- assert migration['filename'] == 'filename.py'
208
+ assert migration["plugin"] == "test"
209
+ assert migration["filename"] == "filename.py"
197
210
 
198
- op = migration['ops'][0]
199
- assert op['script'].startswith('# whatever\n')
200
- assert op['output'] == expected_output
201
- assert op['type'] == 'migrate'
202
- assert op['success']
211
+ op = migration["ops"][0]
212
+ assert op["script"].startswith("# whatever\n")
213
+ assert op["output"] == expected_output
214
+ assert op["type"] == "migrate"
215
+ assert op["success"]
203
216
 
204
217
 
205
218
  def test_record_migration(mock, db):
206
- mock.add_migration('test', 'filename.py', '''\
219
+ mock.add_migration(
220
+ "test",
221
+ "filename.py",
222
+ """\
207
223
  # whatever
208
224
 
209
225
  def migrate():
210
226
  pass
211
- ''')
227
+ """,
228
+ )
212
229
 
213
- expected_output = [['info', 'Recorded only']]
230
+ expected_output = [["info", "Recorded only"]]
214
231
 
215
- output = migrations.get('test', 'filename.py').execute(recordonly=True)
232
+ output = migrations.get("test", "filename.py").execute(recordonly=True)
216
233
 
217
234
  assert output == expected_output
218
235
 
219
236
  migration = db.migrations.find_one()
220
- assert migration['plugin'] == 'test'
221
- assert migration['filename'] == 'filename.py'
237
+ assert migration["plugin"] == "test"
238
+ assert migration["filename"] == "filename.py"
222
239
 
223
- op = migration['ops'][0]
224
- assert op['script'].startswith('# whatever\n')
225
- assert op['output'] == expected_output
226
- assert op['type'] == 'migrate'
227
- assert op['success']
240
+ op = migration["ops"][0]
241
+ assert op["script"].startswith("# whatever\n")
242
+ assert op["output"] == expected_output
243
+ assert op["type"] == "migrate"
244
+ assert op["success"]
228
245
 
229
246
 
230
247
  def test_execute_missing_plugin(db):
231
248
  with pytest.raises(migrations.MigrationError):
232
- migrations.get('test', 'filename.py').execute()
249
+ migrations.get("test", "filename.py").execute()
233
250
  assert db.migrations.find_one() is None
234
251
 
235
252
 
236
253
  def test_execute_missing_migration(db, mock):
237
- mock.ensure_plugin('test')
254
+ mock.ensure_plugin("test")
238
255
  with pytest.raises(migrations.MigrationError):
239
- migrations.get('test', 'filename.py').execute()
256
+ migrations.get("test", "filename.py").execute()
240
257
  assert db.migrations.find_one() is None
241
258
 
242
259
 
243
260
  def test_execute_migration_error(mock, db):
244
- mock.add_migration('udata', 'migration.py', '''\
261
+ mock.add_migration(
262
+ "udata",
263
+ "migration.py",
264
+ """\
245
265
  import logging
246
266
 
247
267
  log = logging.getLogger(__name__)
@@ -250,50 +270,55 @@ def test_execute_migration_error(mock, db):
250
270
  db.test.insert_one({'key': 'value'})
251
271
  log.info('test')
252
272
  raise ValueError('error')
253
- ''')
273
+ """,
274
+ )
254
275
 
255
276
  with pytest.raises(migrations.MigrationError) as excinfo:
256
- migrations.get('udata', 'migration.py').execute()
277
+ migrations.get("udata", "migration.py").execute()
257
278
 
258
279
  exc = excinfo.value
259
280
  assert isinstance(exc, migrations.MigrationError)
260
281
  assert isinstance(exc.exc, ValueError)
261
282
  assert exc.msg == "Error while executing migration"
262
- assert exc.output == [['info', 'test']]
283
+ assert exc.output == [["info", "test"]]
263
284
 
264
285
  # Without rollback DB is left as it is
265
286
  assert db.test.count_documents({}) == 1
266
287
  inserted = db.test.find_one()
267
288
  assert inserted is not None
268
- assert inserted['key'] == 'value'
289
+ assert inserted["key"] == "value"
269
290
 
270
291
  # Failed migration is recorded
271
292
  assert db.migrations.count_documents({}) == 1
272
293
  record = db.migrations.find_one()
273
- assert record['plugin'] == 'udata'
274
- assert record['filename'] == 'migration.py'
275
- assert len(record['ops']) == 1
294
+ assert record["plugin"] == "udata"
295
+ assert record["filename"] == "migration.py"
296
+ assert len(record["ops"]) == 1
276
297
 
277
- op = record['ops'][0]
278
- assert op['type'] == 'migrate'
279
- assert op['output'] == [['info', 'test']]
280
- assert op['state'] == {}
281
- assert isinstance(op['date'], datetime)
282
- assert not op['success']
298
+ op = record["ops"][0]
299
+ assert op["type"] == "migrate"
300
+ assert op["output"] == [["info", "test"]]
301
+ assert op["state"] == {}
302
+ assert isinstance(op["date"], datetime)
303
+ assert not op["success"]
283
304
 
284
305
 
285
306
  def test_execute_migration_error_with_rollback(mock, db):
286
- mock.add_migration('udata', 'migration.py', '''\
307
+ mock.add_migration(
308
+ "udata",
309
+ "migration.py",
310
+ """\
287
311
  def migrate(db):
288
312
  db.test.insert_one({'key': 'value'})
289
313
  raise ValueError('error')
290
314
 
291
315
  def rollback(db):
292
316
  db.rollback_test.insert_one({'key': 'value'})
293
- ''')
317
+ """,
318
+ )
294
319
 
295
320
  with pytest.raises(migrations.MigrationError) as excinfo:
296
- migrations.get('udata', 'migration.py').execute()
321
+ migrations.get("udata", "migration.py").execute()
297
322
 
298
323
  exc = excinfo.value
299
324
  assert isinstance(exc, migrations.RollbackError)
@@ -312,30 +337,33 @@ def test_execute_migration_error_with_rollback(mock, db):
312
337
  # DB is rollbacked if possible
313
338
  assert db.migrations.count_documents({}) == 1
314
339
  record = db.migrations.find_one()
315
- assert record['plugin'] == 'udata'
316
- assert record['filename'] == 'migration.py'
340
+ assert record["plugin"] == "udata"
341
+ assert record["filename"] == "migration.py"
317
342
  # Both failed migration and rollback are recorded
318
- assert len(record['ops']) == 2
343
+ assert len(record["ops"]) == 2
319
344
 
320
345
  # First the migration
321
- op = record['ops'][0]
322
- assert op['type'] == 'migrate'
323
- assert op['output'] == []
324
- assert op['state'] == {}
325
- assert isinstance(op['date'], datetime)
326
- assert not op['success']
346
+ op = record["ops"][0]
347
+ assert op["type"] == "migrate"
348
+ assert op["output"] == []
349
+ assert op["state"] == {}
350
+ assert isinstance(op["date"], datetime)
351
+ assert not op["success"]
327
352
 
328
353
  # Then the rollback
329
- op = record['ops'][1]
330
- assert op['type'] == 'rollback'
331
- assert op['output'] == []
332
- assert op['state'] == {}
333
- assert isinstance(op['date'], datetime)
334
- assert op['success']
354
+ op = record["ops"][1]
355
+ assert op["type"] == "rollback"
356
+ assert op["output"] == []
357
+ assert op["state"] == {}
358
+ assert isinstance(op["date"], datetime)
359
+ assert op["success"]
335
360
 
336
361
 
337
362
  def test_execute_migration_error_with_state_rollback(mock, db):
338
- mock.add_migration('udata', 'migration.py', '''\
363
+ mock.add_migration(
364
+ "udata",
365
+ "migration.py",
366
+ """\
339
367
  def migrate(db):
340
368
  db.test.insert_one({'key': 'first'})
341
369
  db._state['first'] = True
@@ -348,10 +376,11 @@ def test_execute_migration_error_with_state_rollback(mock, db):
348
376
  db.rollback_test.insert_one({'key': 'first'})
349
377
  if db._state.get('second', False):
350
378
  db.rollback_test.insert_one({'key': 'second'})
351
- ''')
379
+ """,
380
+ )
352
381
 
353
382
  with pytest.raises(migrations.MigrationError) as excinfo:
354
- migrations.get('udata', 'migration.py').execute()
383
+ migrations.get("udata", "migration.py").execute()
355
384
 
356
385
  exc = excinfo.value
357
386
  assert isinstance(exc, migrations.RollbackError)
@@ -370,30 +399,33 @@ def test_execute_migration_error_with_state_rollback(mock, db):
370
399
  # DB is rollbacked if possible
371
400
  assert db.migrations.count_documents({}) == 1
372
401
  record = db.migrations.find_one()
373
- assert record['plugin'] == 'udata'
374
- assert record['filename'] == 'migration.py'
402
+ assert record["plugin"] == "udata"
403
+ assert record["filename"] == "migration.py"
375
404
  # Both failed migration and rollback are recorded
376
- assert len(record['ops']) == 2
405
+ assert len(record["ops"]) == 2
377
406
 
378
407
  # First the migration
379
- op = record['ops'][0]
380
- assert op['type'] == 'migrate'
381
- assert op['output'] == []
382
- assert op['state'] == {'first': True}
383
- assert isinstance(op['date'], datetime)
384
- assert not op['success']
408
+ op = record["ops"][0]
409
+ assert op["type"] == "migrate"
410
+ assert op["output"] == []
411
+ assert op["state"] == {"first": True}
412
+ assert isinstance(op["date"], datetime)
413
+ assert not op["success"]
385
414
 
386
415
  # Then the rollback
387
- op = record['ops'][1]
388
- assert op['type'] == 'rollback'
389
- assert op['output'] == []
390
- assert op['state'] == {'first': True}
391
- assert isinstance(op['date'], datetime)
392
- assert op['success']
416
+ op = record["ops"][1]
417
+ assert op["type"] == "rollback"
418
+ assert op["output"] == []
419
+ assert op["state"] == {"first": True}
420
+ assert isinstance(op["date"], datetime)
421
+ assert op["success"]
393
422
 
394
423
 
395
424
  def test_execute_migration_error_with_rollback_error(mock, db):
396
- mock.add_migration('udata', 'migration.py', '''\
425
+ mock.add_migration(
426
+ "udata",
427
+ "migration.py",
428
+ """\
397
429
  def migrate(db):
398
430
  db.test.insert_one({'key': 'value'})
399
431
  raise ValueError('error')
@@ -401,10 +433,11 @@ def test_execute_migration_error_with_rollback_error(mock, db):
401
433
  def rollback(db):
402
434
  db.rollback_test.insert_one({'key': 'value'})
403
435
  raise ValueError('error')
404
- ''')
436
+ """,
437
+ )
405
438
 
406
439
  with pytest.raises(migrations.MigrationError) as excinfo:
407
- migrations.get('udata', 'migration.py').execute()
440
+ migrations.get("udata", "migration.py").execute()
408
441
 
409
442
  exc = excinfo.value
410
443
  assert isinstance(exc, migrations.RollbackError)
@@ -423,30 +456,33 @@ def test_execute_migration_error_with_rollback_error(mock, db):
423
456
  # DB is rollbacked if possible
424
457
  assert db.migrations.count_documents({}) == 1
425
458
  record = db.migrations.find_one()
426
- assert record['plugin'] == 'udata'
427
- assert record['filename'] == 'migration.py'
459
+ assert record["plugin"] == "udata"
460
+ assert record["filename"] == "migration.py"
428
461
  # Both failed migration and rollback are recorded
429
- assert len(record['ops']) == 2
462
+ assert len(record["ops"]) == 2
430
463
 
431
464
  # First the migration
432
- op = record['ops'][0]
433
- assert op['type'] == 'migrate'
434
- assert op['output'] == []
435
- assert op['state'] == {}
436
- assert isinstance(op['date'], datetime)
437
- assert not op['success']
465
+ op = record["ops"][0]
466
+ assert op["type"] == "migrate"
467
+ assert op["output"] == []
468
+ assert op["state"] == {}
469
+ assert isinstance(op["date"], datetime)
470
+ assert not op["success"]
438
471
 
439
472
  # Then the rollback
440
- op = record['ops'][1]
441
- assert op['type'] == 'rollback'
442
- assert op['output'] == []
443
- assert op['state'] == {}
444
- assert isinstance(op['date'], datetime)
445
- assert not op['success']
473
+ op = record["ops"][1]
474
+ assert op["type"] == "rollback"
475
+ assert op["output"] == []
476
+ assert op["state"] == {}
477
+ assert isinstance(op["date"], datetime)
478
+ assert not op["success"]
446
479
 
447
480
 
448
481
  def test_execute_migration_dry_run(mock, db):
449
- mock.add_migration('udata', 'migration.py', '''\
482
+ mock.add_migration(
483
+ "udata",
484
+ "migration.py",
485
+ """\
450
486
  import logging
451
487
 
452
488
  log = logging.getLogger(__name__)
@@ -454,9 +490,10 @@ def test_execute_migration_dry_run(mock, db):
454
490
  def migrate(db):
455
491
  db.test.insert_one({'key': 'value'})
456
492
  log.info('test')
457
- ''')
493
+ """,
494
+ )
458
495
 
459
- output = migrations.get('udata', 'migration.py').execute(dryrun=True)
496
+ output = migrations.get("udata", "migration.py").execute(dryrun=True)
460
497
 
461
498
  assert output == []
462
499
  assert db.test.find_one() is None
@@ -465,20 +502,22 @@ def test_execute_migration_dry_run(mock, db):
465
502
 
466
503
  def test_unrecord_migration(db):
467
504
  inserted = {
468
- 'plugin': 'test',
469
- 'filename': 'filename.py',
470
- 'ops': [{
471
- 'date': datetime.utcnow(),
472
- 'type': 'migrate',
473
- 'script': 'script',
474
- 'output': 'output',
475
- 'state': {},
476
- 'success': True,
477
- }]
505
+ "plugin": "test",
506
+ "filename": "filename.py",
507
+ "ops": [
508
+ {
509
+ "date": datetime.utcnow(),
510
+ "type": "migrate",
511
+ "script": "script",
512
+ "output": "output",
513
+ "state": {},
514
+ "success": True,
515
+ }
516
+ ],
478
517
  }
479
518
  db.migrations.insert_one(inserted)
480
519
 
481
- migration = migrations.get('test', 'filename.py')
520
+ migration = migrations.get("test", "filename.py")
482
521
 
483
522
  # Remove the migration record, return True
484
523
  assert migration.unrecord()