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,77 +1,70 @@
1
1
  import pytest
2
-
3
2
  from flask import url_for
4
3
 
5
4
  from udata.core.dataset.factories import DatasetFactory
6
5
  from udata.core.reuse.factories import ReuseFactory
7
6
  from udata.core.tags.tasks import count_tags
8
- from udata.utils import faker
9
7
  from udata.tests.helpers import assert200
8
+ from udata.utils import faker
10
9
 
11
10
 
12
11
  @pytest.mark.frontend
13
12
  class TagsAPITest:
14
13
  def test_suggest_tags_api(self, api):
15
- '''It should suggest tags'''
14
+ """It should suggest tags"""
16
15
  for i in range(3):
17
- tags = [faker.word(), faker.word(), 'test',
18
- 'test-{0}'.format(i)]
16
+ tags = [faker.word(), faker.word(), "test", "test-{0}".format(i)]
19
17
  ReuseFactory(tags=tags, visible=True)
20
18
  DatasetFactory(tags=tags, visible=True)
21
19
 
22
20
  count_tags()
23
21
 
24
- response = api.get(url_for('api.suggest_tags'),
25
- qs={'q': 'tes', 'size': '5'})
22
+ response = api.get(url_for("api.suggest_tags"), qs={"q": "tes", "size": "5"})
26
23
  assert200(response)
27
24
 
28
25
  assert len(response.json) <= 5
29
26
  assert len(response.json) > 1
30
- assert response.json[0]['text'] == 'test'
27
+ assert response.json[0]["text"] == "test"
31
28
 
32
29
  for suggestion in response.json:
33
- assert 'text' in suggestion
34
- assert 'tes' in suggestion['text']
30
+ assert "text" in suggestion
31
+ assert "tes" in suggestion["text"]
35
32
 
36
33
  def test_suggest_tags_api_with_unicode(self, api):
37
- '''It should suggest tags'''
34
+ """It should suggest tags"""
38
35
  for i in range(3):
39
- tags = [faker.word(), faker.word(), 'testé',
40
- 'testé-{0}'.format(i)]
36
+ tags = [faker.word(), faker.word(), "testé", "testé-{0}".format(i)]
41
37
  ReuseFactory(tags=tags, visible=True)
42
38
  DatasetFactory(tags=tags, visible=True)
43
39
 
44
40
  count_tags()
45
41
 
46
- response = api.get(url_for('api.suggest_tags'),
47
- qs={'q': 'testé', 'size': '5'})
42
+ response = api.get(url_for("api.suggest_tags"), qs={"q": "testé", "size": "5"})
48
43
  assert200(response)
49
44
 
50
45
  assert len(response.json) <= 5
51
46
  assert len(response.json) > 1
52
- assert response.json[0]['text'] == 'teste'
47
+ assert response.json[0]["text"] == "teste"
53
48
 
54
49
  for suggestion in response.json:
55
- assert 'text' in suggestion
56
- assert 'teste' in suggestion['text']
50
+ assert "text" in suggestion
51
+ assert "teste" in suggestion["text"]
57
52
 
58
53
  def test_suggest_tags_api_no_match(self, api):
59
- '''It should not provide tag suggestion if no match'''
54
+ """It should not provide tag suggestion if no match"""
60
55
  for i in range(3):
61
- tags = ['aaaa', 'aaaa-{0}'.format(i)]
56
+ tags = ["aaaa", "aaaa-{0}".format(i)]
62
57
  ReuseFactory(tags=tags, visible=True)
63
58
  DatasetFactory(tags=tags, visible=True)
64
59
 
65
60
  count_tags()
66
61
 
67
- response = api.get(url_for('api.suggest_tags'),
68
- qs={'q': 'bbbb', 'size': '5'})
62
+ response = api.get(url_for("api.suggest_tags"), qs={"q": "bbbb", "size": "5"})
69
63
  assert200(response)
70
64
  assert len(response.json) is 0
71
65
 
72
66
  def test_suggest_tags_api_empty(self, api):
73
- '''It should not provide tag suggestion if no data'''
74
- response = api.get(url_for('api.suggest_tags'),
75
- qs={'q': 'bbbb', 'size': '5'})
67
+ """It should not provide tag suggestion if no data"""
68
+ response = api.get(url_for("api.suggest_tags"), qs={"q": "bbbb", "size": "5"})
76
69
  assert200(response)
77
70
  assert len(response.json) is 0
@@ -6,7 +6,7 @@ from udata.core.spatial.models import spatial_granularities
6
6
  from udata.core.topic.factories import TopicFactory
7
7
  from udata.core.topic.models import Topic
8
8
  from udata.core.user.factories import UserFactory
9
- from udata.models import Member, Discussion
9
+ from udata.models import Discussion, Member
10
10
  from udata.tests.api.test_datasets_api import SAMPLE_GEOM
11
11
  from udata.tests.features.territories import create_geozones_fixtures
12
12
 
@@ -17,124 +17,121 @@ class TopicsAPITest(APITestCase):
17
17
  modules = []
18
18
 
19
19
  def test_topic_api_list(self):
20
- '''It should fetch a topic list from the API'''
20
+ """It should fetch a topic list from the API"""
21
21
  owner = UserFactory()
22
22
  org = OrganizationFactory()
23
23
  paca, _, _ = create_geozones_fixtures()
24
24
 
25
- tag_topic = TopicFactory(tags=['energy'])
26
- name_topic = TopicFactory(name='topic-for-query')
25
+ tag_topic = TopicFactory(tags=["energy"])
26
+ name_topic = TopicFactory(name="topic-for-query")
27
27
  private_topic = TopicFactory(private=True)
28
28
  geozone_topic = TopicFactory(spatial=SpatialCoverageFactory(zones=[paca.id]))
29
- granularity_topic = TopicFactory(
30
- spatial=SpatialCoverageFactory(granularity='country')
31
- )
29
+ granularity_topic = TopicFactory(spatial=SpatialCoverageFactory(granularity="country"))
32
30
  owner_topic = TopicFactory(owner=owner)
33
31
  org_topic = TopicFactory(organization=org)
34
32
 
35
- response = self.get(url_for('api.topics'))
33
+ response = self.get(url_for("api.topics"))
36
34
  self.assert200(response)
37
- self.assertEqual(len(response.json['data']), 6)
35
+ self.assertEqual(len(response.json["data"]), 6)
38
36
 
39
- response = self.get(url_for('api.topics', q='topic-for'))
37
+ response = self.get(url_for("api.topics", q="topic-for"))
40
38
  self.assert200(response)
41
- self.assertEqual(len(response.json['data']), 1)
42
- self.assertEqual(response.json['data'][0]['id'], str(name_topic.id))
39
+ self.assertEqual(len(response.json["data"]), 1)
40
+ self.assertEqual(response.json["data"][0]["id"], str(name_topic.id))
43
41
 
44
- response = self.get(url_for('api.topics', tag='energy'))
42
+ response = self.get(url_for("api.topics", tag="energy"))
45
43
  self.assert200(response)
46
- self.assertEqual(len(response.json['data']), 1)
47
- self.assertEqual(response.json['data'][0]['id'], str(tag_topic.id))
48
- datasets = response.json['data'][0]['datasets']
44
+ self.assertEqual(len(response.json["data"]), 1)
45
+ self.assertEqual(response.json["data"][0]["id"], str(tag_topic.id))
46
+ datasets = response.json["data"][0]["datasets"]
49
47
  self.assertEqual(len(datasets), 3)
50
48
  for dataset, expected in zip(datasets, [d.fetch() for d in tag_topic.datasets]):
51
- self.assertEqual(dataset['id'], str(expected.id))
52
- self.assertEqual(dataset['title'], str(expected.title))
53
- self.assertIsNotNone(dataset['page'])
54
- self.assertIsNotNone(dataset['uri'])
55
- reuses = response.json['data'][0]['reuses']
49
+ self.assertEqual(dataset["id"], str(expected.id))
50
+ self.assertEqual(dataset["title"], str(expected.title))
51
+ self.assertIsNotNone(dataset["page"])
52
+ self.assertIsNotNone(dataset["uri"])
53
+ reuses = response.json["data"][0]["reuses"]
56
54
  for reuse, expected in zip(reuses, [r.fetch() for r in tag_topic.reuses]):
57
- self.assertEqual(reuse['id'], str(expected.id))
58
- self.assertEqual(reuse['title'], str(expected.title))
59
- self.assertIsNotNone(reuse['page'])
60
- self.assertIsNotNone(reuse['uri'])
55
+ self.assertEqual(reuse["id"], str(expected.id))
56
+ self.assertEqual(reuse["title"], str(expected.title))
57
+ self.assertIsNotNone(reuse["page"])
58
+ self.assertIsNotNone(reuse["uri"])
61
59
  self.assertEqual(len(reuses), 3)
62
60
 
63
- response = self.get(url_for('api.topics', include_private='true'))
61
+ response = self.get(url_for("api.topics", include_private="true"))
64
62
  self.assert200(response)
65
- self.assertEqual(len(response.json['data']), 7)
66
- self.assertIn(str(private_topic.id), [t['id'] for t in response.json['data']])
63
+ self.assertEqual(len(response.json["data"]), 7)
64
+ self.assertIn(str(private_topic.id), [t["id"] for t in response.json["data"]])
67
65
 
68
- response = self.get(url_for('api.topics', geozone=paca.id))
66
+ response = self.get(url_for("api.topics", geozone=paca.id))
69
67
  self.assert200(response)
70
- self.assertEqual(len(response.json['data']), 1)
71
- self.assertIn(str(geozone_topic.id), [t['id'] for t in response.json['data']])
68
+ self.assertEqual(len(response.json["data"]), 1)
69
+ self.assertIn(str(geozone_topic.id), [t["id"] for t in response.json["data"]])
72
70
 
73
- response = self.get(url_for('api.topics', granularity='country'))
71
+ response = self.get(url_for("api.topics", granularity="country"))
74
72
  self.assert200(response)
75
- self.assertEqual(len(response.json['data']), 1)
76
- self.assertIn(str(granularity_topic.id), [t['id'] for t in response.json['data']])
73
+ self.assertEqual(len(response.json["data"]), 1)
74
+ self.assertIn(str(granularity_topic.id), [t["id"] for t in response.json["data"]])
77
75
 
78
- response = self.get(url_for('api.topics', owner=owner.id))
76
+ response = self.get(url_for("api.topics", owner=owner.id))
79
77
  self.assert200(response)
80
- self.assertEqual(len(response.json['data']), 1)
81
- self.assertIn(str(owner_topic.id), [t['id'] for t in response.json['data']])
78
+ self.assertEqual(len(response.json["data"]), 1)
79
+ self.assertIn(str(owner_topic.id), [t["id"] for t in response.json["data"]])
82
80
 
83
- response = self.get(url_for('api.topics', organization=org.id))
81
+ response = self.get(url_for("api.topics", organization=org.id))
84
82
  self.assert200(response)
85
- self.assertEqual(len(response.json['data']), 1)
86
- self.assertIn(str(org_topic.id), [t['id'] for t in response.json['data']])
87
-
83
+ self.assertEqual(len(response.json["data"]), 1)
84
+ self.assertIn(str(org_topic.id), [t["id"] for t in response.json["data"]])
88
85
 
89
86
  def test_topic_api_get(self):
90
- '''It should fetch a topic from the API'''
87
+ """It should fetch a topic from the API"""
91
88
  topic = TopicFactory()
92
- response = self.get(url_for('api.topic', topic=topic))
89
+ response = self.get(url_for("api.topic", topic=topic))
93
90
  self.assert200(response)
94
91
 
95
92
  data = response.json
96
- self.assertIn('spatial', data)
93
+ self.assertIn("spatial", data)
97
94
 
98
- for dataset, expected in zip(data['datasets'], [d.fetch() for d in topic.datasets]):
99
- self.assertEqual(dataset['id'], str(expected.id))
100
- self.assertEqual(dataset['title'], str(expected.title))
101
- self.assertIsNotNone(dataset['page'])
102
- self.assertIsNotNone(dataset['uri'])
95
+ for dataset, expected in zip(data["datasets"], [d.fetch() for d in topic.datasets]):
96
+ self.assertEqual(dataset["id"], str(expected.id))
97
+ self.assertEqual(dataset["title"], str(expected.title))
98
+ self.assertIsNotNone(dataset["page"])
99
+ self.assertIsNotNone(dataset["uri"])
103
100
 
104
- for reuse, expected in zip(data['reuses'], [r.fetch() for r in topic.reuses]):
105
- self.assertEqual(reuse['id'], str(expected.id))
106
- self.assertEqual(reuse['title'], str(expected.title))
107
- self.assertIsNotNone(reuse['page'])
108
- self.assertIsNotNone(reuse['uri'])
101
+ for reuse, expected in zip(data["reuses"], [r.fetch() for r in topic.reuses]):
102
+ self.assertEqual(reuse["id"], str(expected.id))
103
+ self.assertEqual(reuse["title"], str(expected.title))
104
+ self.assertIsNotNone(reuse["page"])
105
+ self.assertIsNotNone(reuse["uri"])
109
106
 
110
- self.assertIsNotNone(data.get('created_at'))
111
- self.assertIsNotNone(data.get('last_modified'))
107
+ self.assertIsNotNone(data.get("created_at"))
108
+ self.assertIsNotNone(data.get("last_modified"))
112
109
 
113
110
  def test_topic_api_create(self):
114
- '''It should create a topic from the API'''
111
+ """It should create a topic from the API"""
115
112
  data = TopicFactory.as_dict()
116
- data['datasets'] = [str(d.id) for d in data['datasets']]
117
- data['reuses'] = [str(r.id) for r in data['reuses']]
113
+ data["datasets"] = [str(d.id) for d in data["datasets"]]
114
+ data["reuses"] = [str(r.id) for r in data["reuses"]]
118
115
  self.login()
119
- response = self.post(url_for('api.topics'), data)
116
+ response = self.post(url_for("api.topics"), data)
120
117
  self.assert201(response)
121
118
  self.assertEqual(Topic.objects.count(), 1)
122
119
  topic = Topic.objects.first()
123
- for dataset, expected in zip(topic.datasets, data['datasets']):
120
+ for dataset, expected in zip(topic.datasets, data["datasets"]):
124
121
  self.assertEqual(str(dataset.id), expected)
125
- for reuse, expected in zip(topic.reuses, data['reuses']):
122
+ for reuse, expected in zip(topic.reuses, data["reuses"]):
126
123
  self.assertEqual(str(reuse.id), expected)
127
124
 
128
125
  def test_topic_api_create_as_org(self):
129
- '''It should create a topic as organization from the API'''
126
+ """It should create a topic as organization from the API"""
130
127
  data = TopicFactory.as_dict()
131
- data['datasets'] = [str(d.id) for d in data['datasets']]
132
- data['reuses'] = [str(r.id) for r in data['reuses']]
128
+ data["datasets"] = [str(d.id) for d in data["datasets"]]
129
+ data["reuses"] = [str(r.id) for r in data["reuses"]]
133
130
  user = self.login()
134
- member = Member(user=user, role='editor')
131
+ member = Member(user=user, role="editor")
135
132
  org = OrganizationFactory(members=[member])
136
- data['organization'] = str(org.id)
137
- response = self.post(url_for('api.topics'), data)
133
+ data["organization"] = str(org.id)
134
+ response = self.post(url_for("api.topics"), data)
138
135
  self.assert201(response)
139
136
  self.assertEqual(Topic.objects.count(), 1)
140
137
 
@@ -146,15 +143,15 @@ class TopicsAPITest(APITestCase):
146
143
  paca, _, _ = create_geozones_fixtures()
147
144
  granularity = spatial_granularities[0][0]
148
145
  data = TopicFactory.as_dict()
149
- data['datasets'] = [str(d.id) for d in data['datasets']]
150
- data['reuses'] = [str(r.id) for r in data['reuses']]
151
- data['spatial'] = {
152
- 'zones': [paca.id],
153
- 'geom': SAMPLE_GEOM,
154
- 'granularity': granularity,
146
+ data["datasets"] = [str(d.id) for d in data["datasets"]]
147
+ data["reuses"] = [str(r.id) for r in data["reuses"]]
148
+ data["spatial"] = {
149
+ "zones": [paca.id],
150
+ "geom": SAMPLE_GEOM,
151
+ "granularity": granularity,
155
152
  }
156
153
  self.login()
157
- response = self.post(url_for('api.topics'), data)
154
+ response = self.post(url_for("api.topics"), data)
158
155
  self.assert201(response)
159
156
  self.assertEqual(Topic.objects.count(), 1)
160
157
  topic = Topic.objects.first()
@@ -163,58 +160,61 @@ class TopicsAPITest(APITestCase):
163
160
  self.assertEqual(topic.spatial.granularity, granularity)
164
161
 
165
162
  def test_topic_api_update(self):
166
- '''It should update a topic from the API'''
163
+ """It should update a topic from the API"""
167
164
  owner = self.login()
168
165
  topic = TopicFactory(owner=owner)
169
166
  data = topic.to_dict()
170
- data['description'] = 'new description'
171
- response = self.put(url_for('api.topic', topic=topic), data)
167
+ data["description"] = "new description"
168
+ response = self.put(url_for("api.topic", topic=topic), data)
172
169
  self.assert200(response)
173
170
  self.assertEqual(Topic.objects.count(), 1)
174
171
  topic = Topic.objects.first()
175
- self.assertEqual(topic.description, 'new description')
172
+ self.assertEqual(topic.description, "new description")
176
173
  self.assertGreater(topic.last_modified, topic.created_at)
177
174
 
178
175
  def test_topic_api_update_perm(self):
179
- '''It should not update a topic from the API'''
176
+ """It should not update a topic from the API"""
180
177
  owner = UserFactory()
181
178
  topic = TopicFactory(owner=owner)
182
179
  user = self.login()
183
180
  data = topic.to_dict()
184
- data['owner'] = user.to_dict()
185
- response = self.put(url_for('api.topic', topic=topic), data)
181
+ data["owner"] = user.to_dict()
182
+ response = self.put(url_for("api.topic", topic=topic), data)
186
183
  self.assert403(response)
187
184
 
188
185
  def test_topic_api_delete(self):
189
- '''It should delete a topic from the API'''
186
+ """It should delete a topic from the API"""
190
187
  owner = self.login()
191
188
  topic = TopicFactory(owner=owner)
192
189
 
193
190
  with self.api_user():
194
- response = self.post(url_for('api.discussions'), {
195
- 'title': 'test title',
196
- 'comment': 'bla bla',
197
- 'subject': {
198
- 'class': 'Topic',
199
- 'id': topic.id,
200
- }
201
- })
191
+ response = self.post(
192
+ url_for("api.discussions"),
193
+ {
194
+ "title": "test title",
195
+ "comment": "bla bla",
196
+ "subject": {
197
+ "class": "Topic",
198
+ "id": topic.id,
199
+ },
200
+ },
201
+ )
202
202
  self.assert201(response)
203
203
 
204
204
  discussions = Discussion.objects(subject=topic)
205
205
  self.assertEqual(len(discussions), 1)
206
206
 
207
207
  with self.api_user():
208
- response = self.delete(url_for('api.topic', topic=topic))
208
+ response = self.delete(url_for("api.topic", topic=topic))
209
209
  self.assertStatus(response, 204)
210
210
 
211
211
  self.assertEqual(Topic.objects.count(), 0)
212
212
  self.assertEqual(Discussion.objects.count(), 0)
213
213
 
214
214
  def test_topic_api_delete_perm(self):
215
- '''It should not delete a topic from the API'''
215
+ """It should not delete a topic from the API"""
216
216
  owner = UserFactory()
217
217
  topic = TopicFactory(owner=owner)
218
218
  with self.api_user():
219
- response = self.delete(url_for('api.topic', topic=topic))
219
+ response = self.delete(url_for("api.topic", topic=topic))
220
220
  self.assertStatus(response, 403)
@@ -1,11 +1,10 @@
1
1
  from bson import ObjectId
2
- from mock import patch
3
-
4
2
  from flask import url_for
3
+ from mock import patch
5
4
 
6
5
  from udata.core.dataset.factories import DatasetFactory
7
- from udata.features.transfer.factories import TransferFactory
8
6
  from udata.core.user.factories import UserFactory
7
+ from udata.features.transfer.factories import TransferFactory
9
8
  from udata.utils import faker
10
9
 
11
10
  from . import APITestCase
@@ -14,7 +13,7 @@ from . import APITestCase
14
13
  class TransferAPITest(APITestCase):
15
14
  modules = []
16
15
 
17
- @patch('udata.features.transfer.api.request_transfer')
16
+ @patch("udata.features.transfer.api.request_transfer")
18
17
  def test_request_dataset_transfer(self, action):
19
18
  user = self.login()
20
19
  recipient = UserFactory()
@@ -22,23 +21,23 @@ class TransferAPITest(APITestCase):
22
21
  comment = faker.sentence()
23
22
 
24
23
  action.return_value = TransferFactory(
25
- owner=user,
26
- recipient=recipient,
27
- subject=dataset,
28
- comment=comment
24
+ owner=user, recipient=recipient, subject=dataset, comment=comment
29
25
  )
30
26
 
31
- response = self.post(url_for('api.transfers'), {
32
- 'subject': {
33
- 'class': 'Dataset',
34
- 'id': str(dataset.id),
35
- },
36
- 'recipient': {
37
- 'class': 'User',
38
- 'id': str(recipient.id),
27
+ response = self.post(
28
+ url_for("api.transfers"),
29
+ {
30
+ "subject": {
31
+ "class": "Dataset",
32
+ "id": str(dataset.id),
33
+ },
34
+ "recipient": {
35
+ "class": "User",
36
+ "id": str(recipient.id),
37
+ },
38
+ "comment": comment,
39
39
  },
40
- 'comment': comment
41
- })
40
+ )
42
41
 
43
42
  self.assert201(response)
44
43
 
@@ -46,60 +45,66 @@ class TransferAPITest(APITestCase):
46
45
 
47
46
  data = response.json
48
47
 
49
- self.assertEqual(data['recipient']['id'], str(recipient.id))
50
- self.assertEqual(data['recipient']['class'], 'User')
48
+ self.assertEqual(data["recipient"]["id"], str(recipient.id))
49
+ self.assertEqual(data["recipient"]["class"], "User")
51
50
 
52
- self.assertEqual(data['subject']['id'], str(dataset.id))
53
- self.assertEqual(data['subject']['class'], 'Dataset')
51
+ self.assertEqual(data["subject"]["id"], str(dataset.id))
52
+ self.assertEqual(data["subject"]["class"], "Dataset")
54
53
 
55
- self.assertEqual(data['owner']['id'], str(user.id))
56
- self.assertEqual(data['owner']['class'], 'User')
54
+ self.assertEqual(data["owner"]["id"], str(user.id))
55
+ self.assertEqual(data["owner"]["class"], "User")
57
56
 
58
- self.assertEqual(data['comment'], comment)
59
- self.assertEqual(data['status'], 'pending')
57
+ self.assertEqual(data["comment"], comment)
58
+ self.assertEqual(data["status"], "pending")
60
59
 
61
60
  def test_400_on_bad_subject(self):
62
61
  user = self.login()
63
62
  recipient = UserFactory()
64
63
  comment = faker.sentence()
65
64
 
66
- response = self.post(url_for('api.transfers'), {
67
- 'subject': {
68
- 'class': 'Dataset',
69
- 'id': str(ObjectId()),
70
- },
71
- 'recipient': {
72
- 'class': 'User',
73
- 'id': str(recipient.id),
65
+ response = self.post(
66
+ url_for("api.transfers"),
67
+ {
68
+ "subject": {
69
+ "class": "Dataset",
70
+ "id": str(ObjectId()),
71
+ },
72
+ "recipient": {
73
+ "class": "User",
74
+ "id": str(recipient.id),
75
+ },
76
+ "comment": comment,
74
77
  },
75
- 'comment': comment
76
- })
78
+ )
77
79
 
78
80
  self.assert400(response)
79
81
 
80
82
  data = response.json
81
83
 
82
- self.assertIn('subject', data['errors'])
84
+ self.assertIn("subject", data["errors"])
83
85
 
84
86
  def test_400_on_bad_recipient(self):
85
87
  user = self.login()
86
88
  dataset = DatasetFactory(owner=user)
87
89
  comment = faker.sentence()
88
90
 
89
- response = self.post(url_for('api.transfers'), {
90
- 'subject': {
91
- 'class': 'Dataset',
92
- 'id': str(dataset.id),
91
+ response = self.post(
92
+ url_for("api.transfers"),
93
+ {
94
+ "subject": {
95
+ "class": "Dataset",
96
+ "id": str(dataset.id),
97
+ },
98
+ "recipient": {
99
+ "class": "User",
100
+ "id": str(ObjectId()),
101
+ },
102
+ "comment": comment,
93
103
  },
94
- 'recipient': {
95
- 'class': 'User',
96
- 'id': str(ObjectId()),
97
- },
98
- 'comment': comment
99
- })
104
+ )
100
105
 
101
106
  self.assert400(response)
102
107
 
103
108
  data = response.json
104
109
 
105
- self.assertIn('recipient', data['errors'])
110
+ self.assertIn("recipient", data["errors"])