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,189 +1,279 @@
1
1
  from datetime import datetime
2
- from flask import url_for
3
2
 
4
- from udata.core.dataset.models import ResourceMixin
5
- from udata.tests.api import APITestCase
3
+ from flask import url_for
6
4
 
7
5
  from udata.core.dataset.apiv2 import DEFAULT_PAGE_SIZE
8
6
  from udata.core.dataset.factories import (
9
- DatasetFactory, ResourceFactory, CommunityResourceFactory)
10
- from udata.core.organization.factories import OrganizationFactory, Member
11
- from udata.models import db, Dataset
7
+ CommunityResourceFactory,
8
+ DatasetFactory,
9
+ ResourceFactory,
10
+ )
11
+ from udata.core.dataset.models import ResourceMixin
12
+ from udata.core.organization.factories import Member, OrganizationFactory
13
+ from udata.models import Dataset, db
14
+ from udata.tests.api import APITestCase
12
15
  from udata.tests.helpers import assert_not_emit
13
16
 
14
- class DatasetAPIV2Test(APITestCase):
15
17
 
18
+ class DatasetAPIV2Test(APITestCase):
16
19
  def test_get_dataset(self):
17
20
  resources = [ResourceFactory() for _ in range(2)]
18
21
  dataset = DatasetFactory(resources=resources)
19
22
 
20
- response = self.get(url_for('apiv2.dataset', dataset=dataset))
23
+ response = self.get(url_for("apiv2.dataset", dataset=dataset))
21
24
  self.assert200(response)
22
25
  data = response.json
23
- assert data['resources']['rel'] == 'subsection'
24
- assert data['resources']['href'] == url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, _external=True)
25
- assert data['resources']['type'] == 'GET'
26
- assert data['resources']['total'] == len(resources)
27
- assert data['community_resources']['rel'] == 'subsection'
28
- assert data['community_resources']['href'] == url_for('api.community_resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, _external=True)
29
- assert data['community_resources']['type'] == 'GET'
30
- assert data['community_resources']['total'] == 0
26
+ assert data["resources"]["rel"] == "subsection"
27
+ assert data["resources"]["href"] == url_for(
28
+ "apiv2.resources",
29
+ dataset=dataset.id,
30
+ page=1,
31
+ page_size=DEFAULT_PAGE_SIZE,
32
+ _external=True,
33
+ )
34
+ assert data["resources"]["type"] == "GET"
35
+ assert data["resources"]["total"] == len(resources)
36
+ assert data["community_resources"]["rel"] == "subsection"
37
+ assert data["community_resources"]["href"] == url_for(
38
+ "api.community_resources",
39
+ dataset=dataset.id,
40
+ page=1,
41
+ page_size=DEFAULT_PAGE_SIZE,
42
+ _external=True,
43
+ )
44
+ assert data["community_resources"]["type"] == "GET"
45
+ assert data["community_resources"]["total"] == 0
31
46
 
32
47
 
33
48
  class DatasetResourceAPIV2Test(APITestCase):
34
-
35
49
  def test_get_specific(self):
36
- '''Should fetch serialized resource from the API based on rid'''
50
+ """Should fetch serialized resource from the API based on rid"""
37
51
  resources = [ResourceFactory() for _ in range(7)]
38
- specific_resource = ResourceFactory(id='817204ac-2202-8b4a-98e7-4284d154d10c', title='my-resource')
52
+ specific_resource = ResourceFactory(
53
+ id="817204ac-2202-8b4a-98e7-4284d154d10c", title="my-resource"
54
+ )
39
55
  resources.append(specific_resource)
40
56
  dataset = DatasetFactory(resources=resources)
41
- response = self.get(url_for('apiv2.resource', rid=specific_resource.id))
57
+ response = self.get(url_for("apiv2.resource", rid=specific_resource.id))
42
58
  self.assert200(response)
43
59
  data = response.json
44
- assert data['dataset_id'] == str(dataset.id)
45
- assert data['resource']['id'] == str(specific_resource.id)
46
- assert data['resource']['title'] == specific_resource.title
47
- response = self.get(url_for('apiv2.resource', rid='111111ac-1111-1b1a-11e1-1111d111d11c'))
60
+ assert data["dataset_id"] == str(dataset.id)
61
+ assert data["resource"]["id"] == str(specific_resource.id)
62
+ assert data["resource"]["title"] == specific_resource.title
63
+ response = self.get(url_for("apiv2.resource", rid="111111ac-1111-1b1a-11e1-1111d111d11c"))
48
64
  self.assert404(response)
49
65
  com_resource = CommunityResourceFactory()
50
- response = self.get(url_for('apiv2.resource', rid=com_resource.id))
66
+ response = self.get(url_for("apiv2.resource", rid=com_resource.id))
51
67
  self.assert200(response)
52
68
  data = response.json
53
- assert data['dataset_id'] is None
54
- assert data['resource']['id'] == str(com_resource.id)
55
- assert data['resource']['title'] == com_resource.title
69
+ assert data["dataset_id"] is None
70
+ assert data["resource"]["id"] == str(com_resource.id)
71
+ assert data["resource"]["title"] == com_resource.title
56
72
 
57
73
  def test_get(self):
58
- '''Should fetch 1 page of resources from the API'''
74
+ """Should fetch 1 page of resources from the API"""
59
75
  resources = [ResourceFactory() for _ in range(7)]
60
76
  dataset = DatasetFactory(resources=resources)
61
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE))
77
+ response = self.get(
78
+ url_for("apiv2.resources", dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE)
79
+ )
62
80
  self.assert200(response)
63
81
  data = response.json
64
- assert len(data['data']) == len(resources)
65
- assert data['total'] == len(resources)
66
- assert data['page'] == 1
67
- assert data['page_size'] == DEFAULT_PAGE_SIZE
68
- assert data['next_page'] == None
69
- assert data['previous_page'] is None
82
+ assert len(data["data"]) == len(resources)
83
+ assert data["total"] == len(resources)
84
+ assert data["page"] == 1
85
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
86
+ assert data["next_page"] == None
87
+ assert data["previous_page"] is None
70
88
 
71
89
  def test_get_missing_param(self):
72
- '''Should fetch 1 page of resources from the API using its default parameters'''
90
+ """Should fetch 1 page of resources from the API using its default parameters"""
73
91
  resources = [ResourceFactory() for _ in range(7)]
74
92
  dataset = DatasetFactory(resources=resources)
75
- response = self.get(url_for('apiv2.resources', dataset=dataset.id))
93
+ response = self.get(url_for("apiv2.resources", dataset=dataset.id))
76
94
  self.assert200(response)
77
95
  data = response.json
78
- assert len(data['data']) == len(resources)
79
- assert data['total'] == len(resources)
80
- assert data['page'] == 1
81
- assert data['page_size'] == DEFAULT_PAGE_SIZE
82
- assert data['next_page'] == None
83
- assert data['previous_page'] is None
96
+ assert len(data["data"]) == len(resources)
97
+ assert data["total"] == len(resources)
98
+ assert data["page"] == 1
99
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
100
+ assert data["next_page"] == None
101
+ assert data["previous_page"] is None
84
102
 
85
103
  def test_get_next_page(self):
86
- '''Should fetch 2 pages of resources from the API'''
104
+ """Should fetch 2 pages of resources from the API"""
87
105
  resources = [ResourceFactory() for _ in range(80)]
88
106
  dataset = DatasetFactory(resources=resources)
89
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE))
107
+ response = self.get(
108
+ url_for("apiv2.resources", dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE)
109
+ )
90
110
  self.assert200(response)
91
111
  data = response.json
92
- assert len(data['data']) == DEFAULT_PAGE_SIZE
93
- assert data['total'] == len(resources)
94
- assert data['page'] == 1
95
- assert data['page_size'] == DEFAULT_PAGE_SIZE
96
- assert data['next_page'] == url_for('apiv2.resources', dataset=dataset.id, page=2, page_size=DEFAULT_PAGE_SIZE, _external=True)
97
- assert data['previous_page'] is None
98
-
99
- response = self.get(data['next_page'])
112
+ assert len(data["data"]) == DEFAULT_PAGE_SIZE
113
+ assert data["total"] == len(resources)
114
+ assert data["page"] == 1
115
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
116
+ assert data["next_page"] == url_for(
117
+ "apiv2.resources",
118
+ dataset=dataset.id,
119
+ page=2,
120
+ page_size=DEFAULT_PAGE_SIZE,
121
+ _external=True,
122
+ )
123
+ assert data["previous_page"] is None
124
+
125
+ response = self.get(data["next_page"])
100
126
  self.assert200(response)
101
127
  data = response.json
102
- assert len(data['data']) == len(resources) - DEFAULT_PAGE_SIZE
103
- assert data['total'] == len(resources)
104
- assert data['page'] == 2
105
- assert data['page_size'] == DEFAULT_PAGE_SIZE
106
- assert data['next_page'] == None
107
- assert data['previous_page'] == url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, _external=True)
128
+ assert len(data["data"]) == len(resources) - DEFAULT_PAGE_SIZE
129
+ assert data["total"] == len(resources)
130
+ assert data["page"] == 2
131
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
132
+ assert data["next_page"] == None
133
+ assert data["previous_page"] == url_for(
134
+ "apiv2.resources",
135
+ dataset=dataset.id,
136
+ page=1,
137
+ page_size=DEFAULT_PAGE_SIZE,
138
+ _external=True,
139
+ )
108
140
 
109
141
  def test_get_specific_type(self):
110
- '''Should fetch resources of type main from the API'''
142
+ """Should fetch resources of type main from the API"""
111
143
  nb_resources__of_specific_type = 80
112
144
  resources = [ResourceFactory() for _ in range(40)]
113
- resources += [ResourceFactory(type='main') for _ in range(nb_resources__of_specific_type)]
145
+ resources += [ResourceFactory(type="main") for _ in range(nb_resources__of_specific_type)]
114
146
  dataset = DatasetFactory(resources=resources)
115
147
  # Try without resource type filter
116
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE))
148
+ response = self.get(
149
+ url_for("apiv2.resources", dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE)
150
+ )
117
151
  self.assert200(response)
118
152
  data = response.json
119
- assert len(data['data']) == DEFAULT_PAGE_SIZE
120
- assert data['total'] == len(resources)
121
- assert data['page'] == 1
122
- assert data['page_size'] == DEFAULT_PAGE_SIZE
123
- assert data['next_page'] == url_for('apiv2.resources', dataset=dataset.id, page=2, page_size=DEFAULT_PAGE_SIZE, _external=True)
124
- assert data['previous_page'] is None
153
+ assert len(data["data"]) == DEFAULT_PAGE_SIZE
154
+ assert data["total"] == len(resources)
155
+ assert data["page"] == 1
156
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
157
+ assert data["next_page"] == url_for(
158
+ "apiv2.resources",
159
+ dataset=dataset.id,
160
+ page=2,
161
+ page_size=DEFAULT_PAGE_SIZE,
162
+ _external=True,
163
+ )
164
+ assert data["previous_page"] is None
125
165
 
126
166
  # Try with resource type filter
127
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, type='main'))
167
+ response = self.get(
168
+ url_for(
169
+ "apiv2.resources",
170
+ dataset=dataset.id,
171
+ page=1,
172
+ page_size=DEFAULT_PAGE_SIZE,
173
+ type="main",
174
+ )
175
+ )
128
176
  self.assert200(response)
129
177
  data = response.json
130
- assert len(data['data']) == DEFAULT_PAGE_SIZE
131
- assert data['total'] == nb_resources__of_specific_type
132
- assert data['page'] == 1
133
- assert data['page_size'] == DEFAULT_PAGE_SIZE
134
- assert data['next_page'] == url_for('apiv2.resources', dataset=dataset.id, page=2, page_size=DEFAULT_PAGE_SIZE, type='main', _external=True)
135
- assert data['previous_page'] is None
136
-
137
- response = self.get(data['next_page'])
178
+ assert len(data["data"]) == DEFAULT_PAGE_SIZE
179
+ assert data["total"] == nb_resources__of_specific_type
180
+ assert data["page"] == 1
181
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
182
+ assert data["next_page"] == url_for(
183
+ "apiv2.resources",
184
+ dataset=dataset.id,
185
+ page=2,
186
+ page_size=DEFAULT_PAGE_SIZE,
187
+ type="main",
188
+ _external=True,
189
+ )
190
+ assert data["previous_page"] is None
191
+
192
+ response = self.get(data["next_page"])
138
193
  self.assert200(response)
139
194
  data = response.json
140
- assert len(data['data']) == nb_resources__of_specific_type - DEFAULT_PAGE_SIZE
141
- assert data['total'] == nb_resources__of_specific_type
142
- assert data['page'] == 2
143
- assert data['page_size'] == DEFAULT_PAGE_SIZE
144
- assert data['next_page'] == None
145
- assert data['previous_page'] == url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, type='main', _external=True)
195
+ assert len(data["data"]) == nb_resources__of_specific_type - DEFAULT_PAGE_SIZE
196
+ assert data["total"] == nb_resources__of_specific_type
197
+ assert data["page"] == 2
198
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
199
+ assert data["next_page"] == None
200
+ assert data["previous_page"] == url_for(
201
+ "apiv2.resources",
202
+ dataset=dataset.id,
203
+ page=1,
204
+ page_size=DEFAULT_PAGE_SIZE,
205
+ type="main",
206
+ _external=True,
207
+ )
146
208
 
147
209
  def test_get_with_query_string(self):
148
- '''Should fetch resources according to query string from the API'''
210
+ """Should fetch resources according to query string from the API"""
149
211
  nb_resources_with_specific_title = 20
150
212
  resources = [ResourceFactory() for _ in range(40)]
151
213
  for i in range(nb_resources_with_specific_title):
152
- resources += [ResourceFactory(title='primary-{0}'.format(i)) if i % 2 else ResourceFactory(title='secondary-{0}'.format(i))]
214
+ resources += [
215
+ ResourceFactory(title="primary-{0}".format(i))
216
+ if i % 2
217
+ else ResourceFactory(title="secondary-{0}".format(i))
218
+ ]
153
219
  dataset = DatasetFactory(resources=resources)
154
220
 
155
221
  # Try without query string filter
156
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE))
222
+ response = self.get(
223
+ url_for("apiv2.resources", dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE)
224
+ )
157
225
  self.assert200(response)
158
226
  data = response.json
159
- assert len(data['data']) == DEFAULT_PAGE_SIZE
160
- assert data['total'] == len(resources)
161
- assert data['page'] == 1
162
- assert data['page_size'] == DEFAULT_PAGE_SIZE
163
- assert data['next_page'] == url_for('apiv2.resources', dataset=dataset.id, page=2, page_size=DEFAULT_PAGE_SIZE, _external=True)
164
- assert data['previous_page'] is None
227
+ assert len(data["data"]) == DEFAULT_PAGE_SIZE
228
+ assert data["total"] == len(resources)
229
+ assert data["page"] == 1
230
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
231
+ assert data["next_page"] == url_for(
232
+ "apiv2.resources",
233
+ dataset=dataset.id,
234
+ page=2,
235
+ page_size=DEFAULT_PAGE_SIZE,
236
+ _external=True,
237
+ )
238
+ assert data["previous_page"] is None
165
239
 
166
240
  # Try with query string filter
167
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, q='primary'))
241
+ response = self.get(
242
+ url_for(
243
+ "apiv2.resources",
244
+ dataset=dataset.id,
245
+ page=1,
246
+ page_size=DEFAULT_PAGE_SIZE,
247
+ q="primary",
248
+ )
249
+ )
168
250
  self.assert200(response)
169
251
  data = response.json
170
- assert len(data['data']) == 10
171
- assert data['total'] == 10
172
- assert data['page'] == 1
173
- assert data['page_size'] == DEFAULT_PAGE_SIZE
174
- assert data['next_page'] is None
175
- assert data['previous_page'] is None
252
+ assert len(data["data"]) == 10
253
+ assert data["total"] == 10
254
+ assert data["page"] == 1
255
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
256
+ assert data["next_page"] is None
257
+ assert data["previous_page"] is None
176
258
 
177
259
  # Try with query string filter to check case-insensitivity
178
- response = self.get(url_for('apiv2.resources', dataset=dataset.id, page=1, page_size=DEFAULT_PAGE_SIZE, q='PriMarY'))
260
+ response = self.get(
261
+ url_for(
262
+ "apiv2.resources",
263
+ dataset=dataset.id,
264
+ page=1,
265
+ page_size=DEFAULT_PAGE_SIZE,
266
+ q="PriMarY",
267
+ )
268
+ )
179
269
  self.assert200(response)
180
270
  data = response.json
181
- assert len(data['data']) == 10
182
- assert data['total'] == 10
183
- assert data['page'] == 1
184
- assert data['page_size'] == DEFAULT_PAGE_SIZE
185
- assert data['next_page'] is None
186
- assert data['previous_page'] is None
271
+ assert len(data["data"]) == 10
272
+ assert data["total"] == 10
273
+ assert data["page"] == 1
274
+ assert data["page_size"] == DEFAULT_PAGE_SIZE
275
+ assert data["next_page"] is None
276
+ assert data["previous_page"] is None
187
277
 
188
278
 
189
279
  class DatasetExtrasAPITest(APITestCase):
@@ -194,108 +284,108 @@ class DatasetExtrasAPITest(APITestCase):
194
284
  self.dataset = DatasetFactory(owner=self.user)
195
285
 
196
286
  def test_get_dataset_extras(self):
197
- Dataset.extras.register('check::date', db.DateTimeField)
198
- self.dataset.extras = {'test::extra': 'test-value', 'check::date': datetime.fromisoformat('2024-04-14 08:42:00')}
287
+ Dataset.extras.register("check::date", db.DateTimeField)
288
+ self.dataset.extras = {
289
+ "test::extra": "test-value",
290
+ "check::date": datetime.fromisoformat("2024-04-14 08:42:00"),
291
+ }
199
292
  self.dataset.save()
200
- response = self.get(url_for('apiv2.dataset_extras', dataset=self.dataset))
293
+ response = self.get(url_for("apiv2.dataset_extras", dataset=self.dataset))
201
294
  self.assert200(response)
202
295
  data = response.json
203
- assert data['test::extra'] == 'test-value'
204
- assert data['check::date'] == '2024-04-14T08:42:00'
296
+ assert data["test::extra"] == "test-value"
297
+ assert data["check::date"] == "2024-04-14T08:42:00"
205
298
 
206
299
  def test_update_dataset_extras(self):
207
300
  self.dataset.extras = {
208
- 'test::extra': 'test-value',
209
- 'test::extra-second': 'test-value-second',
210
- 'test::none-will-be-deleted': 'test-value',
301
+ "test::extra": "test-value",
302
+ "test::extra-second": "test-value-second",
303
+ "test::none-will-be-deleted": "test-value",
211
304
  }
212
305
  self.dataset.save()
213
306
 
214
- data = ['test::extra-second', 'another::key']
215
- response = self.put(url_for('apiv2.dataset_extras', dataset=self.dataset), data)
307
+ data = ["test::extra-second", "another::key"]
308
+ response = self.put(url_for("apiv2.dataset_extras", dataset=self.dataset), data)
216
309
  self.assert400(response)
217
- assert response.json['message'] == 'Wrong payload format, dict expected'
310
+ assert response.json["message"] == "Wrong payload format, dict expected"
218
311
 
219
312
  data = {
220
- 'test::extra-second': 'test-value-changed',
221
- 'another::key': 'another-value',
222
- 'test::none': None,
223
- 'test::none-will-be-deleted': None,
313
+ "test::extra-second": "test-value-changed",
314
+ "another::key": "another-value",
315
+ "test::none": None,
316
+ "test::none-will-be-deleted": None,
224
317
  }
225
318
 
226
319
  # We don't expect post save signals on extras update
227
320
  unexpected_signals = Dataset.after_save, Dataset.on_update
228
321
  with assert_not_emit(*unexpected_signals):
229
- response = self.put(url_for('apiv2.dataset_extras', dataset=self.dataset), data)
322
+ response = self.put(url_for("apiv2.dataset_extras", dataset=self.dataset), data)
230
323
  self.assert200(response)
231
324
 
232
325
  self.dataset.reload()
233
- assert self.dataset.extras['test::extra'] == 'test-value'
234
- assert self.dataset.extras['test::extra-second'] == 'test-value-changed'
235
- assert self.dataset.extras['another::key'] == 'another-value'
236
- assert 'test::none' not in self.dataset.extras
237
- assert 'test::none-will-be-deleted' not in self.dataset.extras
326
+ assert self.dataset.extras["test::extra"] == "test-value"
327
+ assert self.dataset.extras["test::extra-second"] == "test-value-changed"
328
+ assert self.dataset.extras["another::key"] == "another-value"
329
+ assert "test::none" not in self.dataset.extras
330
+ assert "test::none-will-be-deleted" not in self.dataset.extras
238
331
 
239
332
  def test_delete_dataset_extras(self):
240
- self.dataset.extras = {'test::extra': 'test-value', 'another::key': 'another-value'}
333
+ self.dataset.extras = {"test::extra": "test-value", "another::key": "another-value"}
241
334
  self.dataset.save()
242
335
 
243
- data = {'another::key': 'another-value'}
244
- response = self.delete(url_for('apiv2.dataset_extras', dataset=self.dataset), data)
336
+ data = {"another::key": "another-value"}
337
+ response = self.delete(url_for("apiv2.dataset_extras", dataset=self.dataset), data)
245
338
  self.assert400(response)
246
- assert response.json['message'] == 'Wrong payload format, list expected'
339
+ assert response.json["message"] == "Wrong payload format, list expected"
247
340
 
248
- data = ['another::key']
341
+ data = ["another::key"]
249
342
 
250
343
  # We don't expect post save signals on extras update
251
344
  unexpected_signals = Dataset.after_save, Dataset.on_update
252
345
  with assert_not_emit(*unexpected_signals):
253
- response = self.delete(url_for('apiv2.dataset_extras', dataset=self.dataset), data)
346
+ response = self.delete(url_for("apiv2.dataset_extras", dataset=self.dataset), data)
254
347
  self.assert204(response)
255
348
 
256
349
  self.dataset.reload()
257
350
  assert len(self.dataset.extras) == 1
258
- assert self.dataset.extras['test::extra'] == 'test-value'
351
+ assert self.dataset.extras["test::extra"] == "test-value"
259
352
 
260
353
  def test_dataset_custom_extras_str(self):
261
- member = Member(user=self.user, role='admin')
354
+ member = Member(user=self.user, role="admin")
262
355
  org = OrganizationFactory(members=[member])
263
356
  org.extras = {
264
357
  "custom": [
265
358
  {
266
359
  "title": "color",
267
360
  "description": "the banner color of the dataset (Hex code)",
268
- "type": "str"
361
+ "type": "str",
269
362
  }
270
363
  ]
271
364
  }
272
365
  org.save()
273
366
  dataset = DatasetFactory(organization=org)
274
367
 
275
- data = {
276
- 'custom:test': 'FFFFFFF'
277
- }
278
- response = self.put(url_for('apiv2.dataset_extras', dataset=dataset), data)
368
+ data = {"custom:test": "FFFFFFF"}
369
+ response = self.put(url_for("apiv2.dataset_extras", dataset=dataset), data)
279
370
  self.assert400(response)
280
- assert 'Dataset\'s organization did not define the requested custom metadata' in response.json['message']
371
+ assert (
372
+ "Dataset's organization did not define the requested custom metadata"
373
+ in response.json["message"]
374
+ )
281
375
 
282
- data = {
283
- 'custom:color': 123
284
- }
285
- response = self.put(url_for('apiv2.dataset_extras', dataset=dataset), data)
376
+ data = {"custom:color": 123}
377
+ response = self.put(url_for("apiv2.dataset_extras", dataset=dataset), data)
286
378
  self.assert400(response)
287
- assert 'Custom metadata is not of the right type' in response.json['message']
379
+ assert "Custom metadata is not of the right type" in response.json["message"]
288
380
 
289
- data = {
290
- 'custom:color': 'FFFFFFF'
291
- }
292
- response = self.put(url_for('apiv2.dataset_extras', dataset=dataset), data)
381
+ data = {"custom:color": "FFFFFFF"}
382
+ response = self.put(url_for("apiv2.dataset_extras", dataset=dataset), data)
293
383
  self.assert200(response)
294
384
  dataset.reload()
295
- assert dataset.extras['custom:color'] == 'FFFFFFF'
385
+ assert dataset.extras["custom:color"] == "FFFFFFF"
296
386
 
297
387
  def test_dataset_custom_extras_choices(self):
298
- member = Member(user=self.user, role='admin')
388
+ member = Member(user=self.user, role="admin")
299
389
  org = OrganizationFactory(members=[member])
300
390
  org.extras = {
301
391
  "custom": [
@@ -303,27 +393,23 @@ class DatasetExtrasAPITest(APITestCase):
303
393
  "title": "color",
304
394
  "description": "the colors of the dataset (Hex code)",
305
395
  "type": "choice",
306
- "choices": ["yellow", "blue"]
396
+ "choices": ["yellow", "blue"],
307
397
  }
308
398
  ]
309
399
  }
310
400
  org.save()
311
401
  dataset = DatasetFactory(organization=org)
312
402
 
313
- data = {
314
- 'custom:color': 'FFFFFFF'
315
- }
316
- response = self.put(url_for('apiv2.dataset_extras', dataset=dataset), data)
403
+ data = {"custom:color": "FFFFFFF"}
404
+ response = self.put(url_for("apiv2.dataset_extras", dataset=dataset), data)
317
405
  self.assert400(response)
318
- assert 'Custom metadata choice is not defined by organization' in response.json['message']
406
+ assert "Custom metadata choice is not defined by organization" in response.json["message"]
319
407
 
320
- data = {
321
- 'custom:color': 'yellow'
322
- }
323
- response = self.put(url_for('apiv2.dataset_extras', dataset=dataset), data)
408
+ data = {"custom:color": "yellow"}
409
+ response = self.put(url_for("apiv2.dataset_extras", dataset=dataset), data)
324
410
  self.assert200(response)
325
411
  dataset.reload()
326
- assert dataset.extras['custom:color'] == 'yellow'
412
+ assert dataset.extras["custom:color"] == "yellow"
327
413
 
328
414
 
329
415
  class DatasetResourceExtrasAPITest(APITestCase):
@@ -334,75 +420,81 @@ class DatasetResourceExtrasAPITest(APITestCase):
334
420
  self.dataset = DatasetFactory(owner=self.user)
335
421
 
336
422
  def test_get_ressource_extras(self):
337
- '''It should fetch a resource from the API'''
338
- ResourceMixin.extras.register('check:date', db.DateTimeField)
423
+ """It should fetch a resource from the API"""
424
+ ResourceMixin.extras.register("check:date", db.DateTimeField)
339
425
 
340
426
  resource = ResourceFactory()
341
- resource.extras = {'test::extra': 'test-value', 'check:date': datetime(2023, 4, 20, 13, 57, 31, 289000)}
427
+ resource.extras = {
428
+ "test::extra": "test-value",
429
+ "check:date": datetime(2023, 4, 20, 13, 57, 31, 289000),
430
+ }
342
431
  self.dataset.resources.append(resource)
343
432
  self.dataset.save()
344
- response = self.get(url_for('apiv2.resource_extras', dataset=self.dataset,
345
- rid=resource.id))
433
+ response = self.get(url_for("apiv2.resource_extras", dataset=self.dataset, rid=resource.id))
346
434
  self.assert200(response)
347
435
  data = response.json
348
- assert data['test::extra'] == 'test-value'
349
- assert data['check:date'] == '2023-04-20T13:57:31.289000'
436
+ assert data["test::extra"] == "test-value"
437
+ assert data["check:date"] == "2023-04-20T13:57:31.289000"
350
438
 
351
439
  def test_update_resource_extras(self):
352
440
  resource = ResourceFactory()
353
441
  resource.extras = {
354
- 'test::extra': 'test-value',
355
- 'test::extra-second': 'test-value-second',
356
- 'test::none-will-be-deleted': 'test-value',
442
+ "test::extra": "test-value",
443
+ "test::extra-second": "test-value-second",
444
+ "test::none-will-be-deleted": "test-value",
357
445
  }
358
446
  self.dataset.resources.append(resource)
359
447
  self.dataset.save()
360
448
 
361
- data = ['test::extra-second', 'another::key']
362
- response = self.put(url_for('apiv2.resource_extras', dataset=self.dataset,
363
- rid=resource.id), data)
449
+ data = ["test::extra-second", "another::key"]
450
+ response = self.put(
451
+ url_for("apiv2.resource_extras", dataset=self.dataset, rid=resource.id), data
452
+ )
364
453
  self.assert400(response)
365
- assert response.json['message'] == 'Wrong payload format, dict expected'
454
+ assert response.json["message"] == "Wrong payload format, dict expected"
366
455
 
367
456
  data = {
368
- 'test::extra-second': 'test-value-changed',
369
- 'another::key': 'another-value',
370
- 'test::none': None,
371
- 'test::none-will-be-deleted': None,
457
+ "test::extra-second": "test-value-changed",
458
+ "another::key": "another-value",
459
+ "test::none": None,
460
+ "test::none-will-be-deleted": None,
372
461
  }
373
462
  # We don't expect post save signals on extras update
374
463
  unexpected_signals = Dataset.after_save, Dataset.on_update
375
464
  with assert_not_emit(*unexpected_signals):
376
- response = self.put(url_for('apiv2.resource_extras', dataset=self.dataset,
377
- rid=resource.id), data)
465
+ response = self.put(
466
+ url_for("apiv2.resource_extras", dataset=self.dataset, rid=resource.id), data
467
+ )
378
468
  self.assert200(response)
379
469
 
380
470
  self.dataset.reload()
381
- assert self.dataset.resources[0].extras['test::extra'] == 'test-value'
382
- assert self.dataset.resources[0].extras['test::extra-second'] == 'test-value-changed'
383
- assert self.dataset.resources[0].extras['another::key'] == 'another-value'
384
- assert 'test::none' not in self.dataset.resources[0].extras
385
- assert 'test::none-will-be-deleted' not in self.dataset.resources[0].extras
471
+ assert self.dataset.resources[0].extras["test::extra"] == "test-value"
472
+ assert self.dataset.resources[0].extras["test::extra-second"] == "test-value-changed"
473
+ assert self.dataset.resources[0].extras["another::key"] == "another-value"
474
+ assert "test::none" not in self.dataset.resources[0].extras
475
+ assert "test::none-will-be-deleted" not in self.dataset.resources[0].extras
386
476
 
387
477
  def test_delete_resource_extras(self):
388
478
  resource = ResourceFactory()
389
- resource.extras = {'test::extra': 'test-value', 'another::key': 'another-value'}
479
+ resource.extras = {"test::extra": "test-value", "another::key": "another-value"}
390
480
  self.dataset.resources.append(resource)
391
481
  self.dataset.save()
392
482
 
393
- data = {'another::key': 'another-value'}
394
- response = self.delete(url_for('apiv2.resource_extras', dataset=self.dataset,
395
- rid=resource.id), data)
483
+ data = {"another::key": "another-value"}
484
+ response = self.delete(
485
+ url_for("apiv2.resource_extras", dataset=self.dataset, rid=resource.id), data
486
+ )
396
487
  self.assert400(response)
397
- assert response.json['message'] == 'Wrong payload format, list expected'
488
+ assert response.json["message"] == "Wrong payload format, list expected"
398
489
 
399
- data = ['another::key']
490
+ data = ["another::key"]
400
491
  # We don't expect post save signals on extras update
401
492
  unexpected_signals = Dataset.after_save, Dataset.on_update
402
493
  with assert_not_emit(*unexpected_signals):
403
- response = self.delete(url_for('apiv2.resource_extras', dataset=self.dataset,
404
- rid=resource.id), data)
494
+ response = self.delete(
495
+ url_for("apiv2.resource_extras", dataset=self.dataset, rid=resource.id), data
496
+ )
405
497
  self.assert204(response)
406
498
  self.dataset.reload()
407
499
  assert len(self.dataset.resources[0].extras) == 1
408
- assert self.dataset.resources[0].extras['test::extra'] == 'test-value'
500
+ assert self.dataset.resources[0].extras["test::extra"] == "test-value"