udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30454__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of udata might be problematic. Click here for more details.

Files changed (413) hide show
  1. tasks/__init__.py +109 -107
  2. tasks/helpers.py +18 -18
  3. udata/__init__.py +4 -4
  4. udata/admin/views.py +5 -5
  5. udata/api/__init__.py +111 -134
  6. udata/api/commands.py +45 -37
  7. udata/api/errors.py +5 -4
  8. udata/api/fields.py +23 -21
  9. udata/api/oauth2.py +55 -74
  10. udata/api/parsers.py +15 -15
  11. udata/api/signals.py +1 -1
  12. udata/api_fields.py +137 -89
  13. udata/app.py +58 -55
  14. udata/assets.py +5 -5
  15. udata/auth/__init__.py +37 -26
  16. udata/auth/forms.py +23 -15
  17. udata/auth/helpers.py +1 -1
  18. udata/auth/mails.py +3 -3
  19. udata/auth/password_validation.py +19 -15
  20. udata/auth/views.py +94 -68
  21. udata/commands/__init__.py +71 -69
  22. udata/commands/cache.py +7 -7
  23. udata/commands/db.py +201 -140
  24. udata/commands/dcat.py +36 -30
  25. udata/commands/fixtures.py +100 -84
  26. udata/commands/images.py +21 -20
  27. udata/commands/info.py +17 -20
  28. udata/commands/init.py +10 -10
  29. udata/commands/purge.py +12 -13
  30. udata/commands/serve.py +41 -29
  31. udata/commands/static.py +16 -18
  32. udata/commands/test.py +20 -20
  33. udata/commands/tests/fixtures.py +26 -24
  34. udata/commands/worker.py +31 -33
  35. udata/core/__init__.py +12 -12
  36. udata/core/activity/__init__.py +0 -1
  37. udata/core/activity/api.py +59 -49
  38. udata/core/activity/models.py +28 -26
  39. udata/core/activity/signals.py +1 -1
  40. udata/core/activity/tasks.py +16 -10
  41. udata/core/badges/api.py +6 -6
  42. udata/core/badges/commands.py +14 -13
  43. udata/core/badges/fields.py +8 -5
  44. udata/core/badges/forms.py +7 -4
  45. udata/core/badges/models.py +16 -31
  46. udata/core/badges/permissions.py +1 -3
  47. udata/core/badges/signals.py +2 -2
  48. udata/core/badges/tasks.py +3 -2
  49. udata/core/badges/tests/test_commands.py +10 -10
  50. udata/core/badges/tests/test_model.py +24 -31
  51. udata/core/contact_point/api.py +19 -18
  52. udata/core/contact_point/api_fields.py +21 -14
  53. udata/core/contact_point/factories.py +2 -2
  54. udata/core/contact_point/forms.py +7 -6
  55. udata/core/contact_point/models.py +3 -5
  56. udata/core/dataservices/api.py +26 -21
  57. udata/core/dataservices/factories.py +13 -11
  58. udata/core/dataservices/models.py +35 -40
  59. udata/core/dataservices/permissions.py +4 -4
  60. udata/core/dataservices/rdf.py +40 -17
  61. udata/core/dataservices/tasks.py +4 -3
  62. udata/core/dataset/actions.py +10 -10
  63. udata/core/dataset/activities.py +21 -23
  64. udata/core/dataset/api.py +321 -298
  65. udata/core/dataset/api_fields.py +443 -271
  66. udata/core/dataset/apiv2.py +305 -229
  67. udata/core/dataset/commands.py +38 -36
  68. udata/core/dataset/constants.py +61 -54
  69. udata/core/dataset/csv.py +70 -74
  70. udata/core/dataset/events.py +39 -32
  71. udata/core/dataset/exceptions.py +8 -4
  72. udata/core/dataset/factories.py +57 -65
  73. udata/core/dataset/forms.py +87 -63
  74. udata/core/dataset/models.py +336 -280
  75. udata/core/dataset/permissions.py +9 -6
  76. udata/core/dataset/preview.py +15 -17
  77. udata/core/dataset/rdf.py +156 -122
  78. udata/core/dataset/search.py +92 -77
  79. udata/core/dataset/signals.py +1 -1
  80. udata/core/dataset/tasks.py +63 -54
  81. udata/core/discussions/actions.py +5 -5
  82. udata/core/discussions/api.py +124 -120
  83. udata/core/discussions/factories.py +2 -2
  84. udata/core/discussions/forms.py +9 -7
  85. udata/core/discussions/metrics.py +1 -3
  86. udata/core/discussions/models.py +25 -24
  87. udata/core/discussions/notifications.py +18 -14
  88. udata/core/discussions/permissions.py +3 -3
  89. udata/core/discussions/signals.py +4 -4
  90. udata/core/discussions/tasks.py +24 -28
  91. udata/core/followers/api.py +32 -33
  92. udata/core/followers/models.py +9 -9
  93. udata/core/followers/signals.py +3 -3
  94. udata/core/jobs/actions.py +7 -7
  95. udata/core/jobs/api.py +99 -92
  96. udata/core/jobs/commands.py +48 -49
  97. udata/core/jobs/forms.py +11 -11
  98. udata/core/jobs/models.py +6 -6
  99. udata/core/metrics/__init__.py +2 -2
  100. udata/core/metrics/commands.py +34 -30
  101. udata/core/metrics/models.py +2 -4
  102. udata/core/metrics/signals.py +1 -1
  103. udata/core/metrics/tasks.py +3 -3
  104. udata/core/organization/activities.py +12 -15
  105. udata/core/organization/api.py +167 -174
  106. udata/core/organization/api_fields.py +183 -124
  107. udata/core/organization/apiv2.py +32 -32
  108. udata/core/organization/commands.py +20 -22
  109. udata/core/organization/constants.py +11 -11
  110. udata/core/organization/csv.py +17 -15
  111. udata/core/organization/factories.py +8 -11
  112. udata/core/organization/forms.py +32 -26
  113. udata/core/organization/metrics.py +2 -1
  114. udata/core/organization/models.py +87 -67
  115. udata/core/organization/notifications.py +18 -14
  116. udata/core/organization/permissions.py +10 -11
  117. udata/core/organization/rdf.py +14 -14
  118. udata/core/organization/search.py +30 -28
  119. udata/core/organization/signals.py +7 -7
  120. udata/core/organization/tasks.py +42 -61
  121. udata/core/owned.py +38 -27
  122. udata/core/post/api.py +82 -81
  123. udata/core/post/constants.py +8 -5
  124. udata/core/post/factories.py +4 -4
  125. udata/core/post/forms.py +13 -14
  126. udata/core/post/models.py +20 -22
  127. udata/core/post/tests/test_api.py +30 -32
  128. udata/core/reports/api.py +8 -7
  129. udata/core/reports/constants.py +1 -3
  130. udata/core/reports/models.py +10 -10
  131. udata/core/reuse/activities.py +15 -19
  132. udata/core/reuse/api.py +123 -126
  133. udata/core/reuse/api_fields.py +120 -85
  134. udata/core/reuse/apiv2.py +11 -10
  135. udata/core/reuse/constants.py +23 -23
  136. udata/core/reuse/csv.py +18 -18
  137. udata/core/reuse/factories.py +5 -9
  138. udata/core/reuse/forms.py +24 -21
  139. udata/core/reuse/models.py +55 -51
  140. udata/core/reuse/permissions.py +2 -2
  141. udata/core/reuse/search.py +49 -46
  142. udata/core/reuse/signals.py +1 -1
  143. udata/core/reuse/tasks.py +4 -5
  144. udata/core/site/api.py +47 -50
  145. udata/core/site/factories.py +2 -2
  146. udata/core/site/forms.py +4 -5
  147. udata/core/site/models.py +94 -63
  148. udata/core/site/rdf.py +14 -14
  149. udata/core/spam/api.py +16 -9
  150. udata/core/spam/constants.py +4 -4
  151. udata/core/spam/fields.py +13 -7
  152. udata/core/spam/models.py +27 -20
  153. udata/core/spam/signals.py +1 -1
  154. udata/core/spam/tests/test_spam.py +6 -5
  155. udata/core/spatial/api.py +72 -80
  156. udata/core/spatial/api_fields.py +73 -58
  157. udata/core/spatial/commands.py +67 -64
  158. udata/core/spatial/constants.py +3 -3
  159. udata/core/spatial/factories.py +37 -54
  160. udata/core/spatial/forms.py +27 -26
  161. udata/core/spatial/geoids.py +17 -17
  162. udata/core/spatial/models.py +43 -47
  163. udata/core/spatial/tasks.py +2 -1
  164. udata/core/spatial/tests/test_api.py +115 -130
  165. udata/core/spatial/tests/test_fields.py +74 -77
  166. udata/core/spatial/tests/test_geoid.py +22 -22
  167. udata/core/spatial/tests/test_models.py +5 -7
  168. udata/core/spatial/translations.py +16 -16
  169. udata/core/storages/__init__.py +16 -18
  170. udata/core/storages/api.py +66 -64
  171. udata/core/storages/tasks.py +7 -7
  172. udata/core/storages/utils.py +15 -15
  173. udata/core/storages/views.py +5 -6
  174. udata/core/tags/api.py +17 -14
  175. udata/core/tags/csv.py +4 -4
  176. udata/core/tags/models.py +8 -5
  177. udata/core/tags/tasks.py +11 -13
  178. udata/core/tags/views.py +4 -4
  179. udata/core/topic/api.py +84 -73
  180. udata/core/topic/apiv2.py +157 -127
  181. udata/core/topic/factories.py +3 -4
  182. udata/core/topic/forms.py +12 -14
  183. udata/core/topic/models.py +14 -19
  184. udata/core/topic/parsers.py +26 -26
  185. udata/core/user/activities.py +30 -29
  186. udata/core/user/api.py +151 -152
  187. udata/core/user/api_fields.py +132 -100
  188. udata/core/user/apiv2.py +7 -7
  189. udata/core/user/commands.py +38 -38
  190. udata/core/user/factories.py +8 -9
  191. udata/core/user/forms.py +14 -11
  192. udata/core/user/metrics.py +2 -2
  193. udata/core/user/models.py +68 -69
  194. udata/core/user/permissions.py +4 -5
  195. udata/core/user/rdf.py +7 -8
  196. udata/core/user/tasks.py +2 -2
  197. udata/core/user/tests/test_user_model.py +24 -16
  198. udata/cors.py +99 -0
  199. udata/db/tasks.py +2 -1
  200. udata/entrypoints.py +35 -31
  201. udata/errors.py +2 -1
  202. udata/event/values.py +6 -6
  203. udata/factories.py +2 -2
  204. udata/features/identicon/api.py +5 -6
  205. udata/features/identicon/backends.py +48 -55
  206. udata/features/identicon/tests/test_backends.py +4 -5
  207. udata/features/notifications/__init__.py +0 -1
  208. udata/features/notifications/actions.py +9 -9
  209. udata/features/notifications/api.py +17 -13
  210. udata/features/territories/__init__.py +12 -10
  211. udata/features/territories/api.py +14 -15
  212. udata/features/territories/models.py +23 -28
  213. udata/features/transfer/actions.py +8 -11
  214. udata/features/transfer/api.py +84 -77
  215. udata/features/transfer/factories.py +2 -1
  216. udata/features/transfer/models.py +11 -12
  217. udata/features/transfer/notifications.py +19 -15
  218. udata/features/transfer/permissions.py +5 -5
  219. udata/forms/__init__.py +5 -2
  220. udata/forms/fields.py +164 -172
  221. udata/forms/validators.py +19 -22
  222. udata/forms/widgets.py +9 -13
  223. udata/frontend/__init__.py +31 -26
  224. udata/frontend/csv.py +68 -58
  225. udata/frontend/markdown.py +40 -44
  226. udata/harvest/actions.py +89 -77
  227. udata/harvest/api.py +294 -238
  228. udata/harvest/backends/__init__.py +4 -4
  229. udata/harvest/backends/base.py +128 -111
  230. udata/harvest/backends/dcat.py +80 -66
  231. udata/harvest/commands.py +56 -60
  232. udata/harvest/csv.py +8 -8
  233. udata/harvest/exceptions.py +6 -3
  234. udata/harvest/filters.py +24 -23
  235. udata/harvest/forms.py +27 -28
  236. udata/harvest/models.py +88 -80
  237. udata/harvest/notifications.py +15 -10
  238. udata/harvest/signals.py +13 -13
  239. udata/harvest/tasks.py +11 -10
  240. udata/harvest/tests/factories.py +23 -24
  241. udata/harvest/tests/test_actions.py +136 -166
  242. udata/harvest/tests/test_api.py +220 -214
  243. udata/harvest/tests/test_base_backend.py +117 -112
  244. udata/harvest/tests/test_dcat_backend.py +380 -308
  245. udata/harvest/tests/test_filters.py +33 -22
  246. udata/harvest/tests/test_models.py +11 -14
  247. udata/harvest/tests/test_notifications.py +6 -7
  248. udata/harvest/tests/test_tasks.py +7 -6
  249. udata/i18n.py +237 -78
  250. udata/linkchecker/backends.py +5 -11
  251. udata/linkchecker/checker.py +23 -22
  252. udata/linkchecker/commands.py +4 -6
  253. udata/linkchecker/models.py +6 -6
  254. udata/linkchecker/tasks.py +18 -20
  255. udata/mail.py +21 -21
  256. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  257. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  258. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  259. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  260. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  261. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  262. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  263. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  264. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  265. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  266. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  267. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  268. udata/migrations/2021-08-17-users-integrity.py +9 -8
  269. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  270. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  271. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  272. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  273. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  274. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  275. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  276. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  277. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  278. udata/migrations/__init__.py +123 -105
  279. udata/models/__init__.py +4 -4
  280. udata/mongo/__init__.py +13 -11
  281. udata/mongo/badges_field.py +3 -2
  282. udata/mongo/datetime_fields.py +13 -12
  283. udata/mongo/document.py +17 -16
  284. udata/mongo/engine.py +15 -16
  285. udata/mongo/errors.py +2 -1
  286. udata/mongo/extras_fields.py +30 -20
  287. udata/mongo/queryset.py +12 -12
  288. udata/mongo/slug_fields.py +38 -28
  289. udata/mongo/taglist_field.py +1 -2
  290. udata/mongo/url_field.py +5 -5
  291. udata/mongo/uuid_fields.py +4 -3
  292. udata/notifications/__init__.py +1 -1
  293. udata/notifications/mattermost.py +10 -9
  294. udata/rdf.py +167 -188
  295. udata/routing.py +40 -45
  296. udata/search/__init__.py +18 -19
  297. udata/search/adapter.py +17 -16
  298. udata/search/commands.py +44 -51
  299. udata/search/fields.py +13 -20
  300. udata/search/query.py +23 -18
  301. udata/search/result.py +9 -10
  302. udata/sentry.py +21 -19
  303. udata/settings.py +262 -198
  304. udata/sitemap.py +8 -6
  305. udata/storage/s3.py +20 -13
  306. udata/tags.py +4 -5
  307. udata/tasks.py +43 -42
  308. udata/tests/__init__.py +9 -6
  309. udata/tests/api/__init__.py +8 -6
  310. udata/tests/api/test_auth_api.py +395 -321
  311. udata/tests/api/test_base_api.py +33 -35
  312. udata/tests/api/test_contact_points.py +7 -9
  313. udata/tests/api/test_dataservices_api.py +211 -158
  314. udata/tests/api/test_datasets_api.py +823 -812
  315. udata/tests/api/test_follow_api.py +13 -15
  316. udata/tests/api/test_me_api.py +95 -112
  317. udata/tests/api/test_organizations_api.py +301 -339
  318. udata/tests/api/test_reports_api.py +35 -25
  319. udata/tests/api/test_reuses_api.py +134 -139
  320. udata/tests/api/test_swagger.py +5 -5
  321. udata/tests/api/test_tags_api.py +18 -25
  322. udata/tests/api/test_topics_api.py +94 -94
  323. udata/tests/api/test_transfer_api.py +53 -48
  324. udata/tests/api/test_user_api.py +128 -141
  325. udata/tests/apiv2/test_datasets.py +290 -198
  326. udata/tests/apiv2/test_me_api.py +10 -11
  327. udata/tests/apiv2/test_organizations.py +56 -74
  328. udata/tests/apiv2/test_swagger.py +5 -5
  329. udata/tests/apiv2/test_topics.py +69 -87
  330. udata/tests/cli/test_cli_base.py +8 -8
  331. udata/tests/cli/test_db_cli.py +21 -19
  332. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  333. udata/tests/dataset/test_csv_adapter.py +44 -35
  334. udata/tests/dataset/test_dataset_actions.py +2 -3
  335. udata/tests/dataset/test_dataset_commands.py +7 -8
  336. udata/tests/dataset/test_dataset_events.py +36 -29
  337. udata/tests/dataset/test_dataset_model.py +224 -217
  338. udata/tests/dataset/test_dataset_rdf.py +142 -131
  339. udata/tests/dataset/test_dataset_tasks.py +15 -15
  340. udata/tests/dataset/test_resource_preview.py +10 -13
  341. udata/tests/features/territories/__init__.py +9 -13
  342. udata/tests/features/territories/test_territories_api.py +71 -91
  343. udata/tests/forms/test_basic_fields.py +7 -7
  344. udata/tests/forms/test_current_user_field.py +39 -66
  345. udata/tests/forms/test_daterange_field.py +31 -39
  346. udata/tests/forms/test_dict_field.py +28 -26
  347. udata/tests/forms/test_extras_fields.py +102 -76
  348. udata/tests/forms/test_form_field.py +8 -8
  349. udata/tests/forms/test_image_field.py +33 -26
  350. udata/tests/forms/test_model_field.py +134 -123
  351. udata/tests/forms/test_model_list_field.py +7 -7
  352. udata/tests/forms/test_nested_model_list_field.py +117 -79
  353. udata/tests/forms/test_publish_as_field.py +36 -65
  354. udata/tests/forms/test_reference_field.py +34 -53
  355. udata/tests/forms/test_user_forms.py +23 -21
  356. udata/tests/forms/test_uuid_field.py +6 -10
  357. udata/tests/frontend/__init__.py +9 -6
  358. udata/tests/frontend/test_auth.py +7 -6
  359. udata/tests/frontend/test_csv.py +81 -96
  360. udata/tests/frontend/test_hooks.py +43 -43
  361. udata/tests/frontend/test_markdown.py +211 -191
  362. udata/tests/helpers.py +32 -37
  363. udata/tests/models.py +2 -2
  364. udata/tests/organization/test_csv_adapter.py +21 -16
  365. udata/tests/organization/test_notifications.py +11 -18
  366. udata/tests/organization/test_organization_model.py +13 -13
  367. udata/tests/organization/test_organization_rdf.py +29 -22
  368. udata/tests/organization/test_organization_tasks.py +16 -17
  369. udata/tests/plugin.py +79 -73
  370. udata/tests/reuse/test_reuse_model.py +21 -21
  371. udata/tests/reuse/test_reuse_task.py +11 -13
  372. udata/tests/search/__init__.py +11 -12
  373. udata/tests/search/test_adapter.py +60 -70
  374. udata/tests/search/test_query.py +16 -16
  375. udata/tests/search/test_results.py +10 -7
  376. udata/tests/site/test_site_api.py +11 -16
  377. udata/tests/site/test_site_metrics.py +20 -30
  378. udata/tests/site/test_site_model.py +4 -5
  379. udata/tests/site/test_site_rdf.py +94 -78
  380. udata/tests/test_activity.py +17 -17
  381. udata/tests/test_cors.py +62 -0
  382. udata/tests/test_discussions.py +292 -299
  383. udata/tests/test_i18n.py +37 -40
  384. udata/tests/test_linkchecker.py +91 -85
  385. udata/tests/test_mail.py +13 -17
  386. udata/tests/test_migrations.py +219 -180
  387. udata/tests/test_model.py +164 -157
  388. udata/tests/test_notifications.py +17 -17
  389. udata/tests/test_owned.py +14 -14
  390. udata/tests/test_rdf.py +25 -23
  391. udata/tests/test_routing.py +89 -93
  392. udata/tests/test_storages.py +137 -128
  393. udata/tests/test_tags.py +44 -46
  394. udata/tests/test_topics.py +7 -7
  395. udata/tests/test_transfer.py +42 -49
  396. udata/tests/test_uris.py +160 -161
  397. udata/tests/test_utils.py +79 -71
  398. udata/tests/user/test_user_rdf.py +5 -9
  399. udata/tests/workers/test_jobs_commands.py +57 -58
  400. udata/tests/workers/test_tasks_routing.py +23 -29
  401. udata/tests/workers/test_workers_api.py +125 -131
  402. udata/tests/workers/test_workers_helpers.py +6 -6
  403. udata/tracking.py +4 -6
  404. udata/uris.py +45 -46
  405. udata/utils.py +68 -66
  406. udata/wsgi.py +1 -1
  407. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/METADATA +7 -3
  408. udata-9.1.2.dev30454.dist-info/RECORD +706 -0
  409. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  410. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
  411. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
  412. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
  413. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
udata/tests/plugin.py CHANGED
@@ -1,14 +1,13 @@
1
- import pytest
2
1
  import shlex
3
-
4
2
  from contextlib import contextmanager
5
3
  from urllib.parse import urlparse
6
4
 
7
- from flask import json, template_rendered, url_for, current_app
5
+ import pytest
6
+ from flask import current_app, json, template_rendered, url_for
8
7
  from flask.testing import FlaskClient
8
+ from flask_principal import Identity, identity_changed
9
9
  from lxml import etree
10
10
  from werkzeug.urls import url_encode
11
- from flask_principal import Identity, identity_changed
12
11
 
13
12
  from udata import settings
14
13
  from udata.app import create_app
@@ -20,10 +19,10 @@ from .helpers import assert200, assert_command_ok
20
19
 
21
20
  class TestClient(FlaskClient):
22
21
  def _build_url(self, url, kwargs):
23
- if 'qs' not in kwargs:
22
+ if "qs" not in kwargs:
24
23
  return url
25
- qs = kwargs.pop('qs')
26
- return '?'.join([url, url_encode(qs)])
24
+ qs = kwargs.pop("qs")
25
+ return "?".join([url, url_encode(qs)])
27
26
 
28
27
  def get(self, url, **kwargs):
29
28
  url = self._build_url(url, kwargs)
@@ -46,18 +45,18 @@ class TestClient(FlaskClient):
46
45
  with self.session_transaction() as session:
47
46
  # Since flask-security-too 4.0.0, the user.fs_uniquifier is used instead of user.id for auth
48
47
  user_id = getattr(user, current_app.login_manager.id_attribute)()
49
- session['user_id'] = user_id
50
- session['_fresh'] = True
51
- session['_id'] = current_app.login_manager._session_identifier_generator()
48
+ session["user_id"] = user_id
49
+ session["_fresh"] = True
50
+ session["_id"] = current_app.login_manager._session_identifier_generator()
52
51
  current_app.login_manager._update_request_context_with_user(user)
53
52
  identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
54
53
  return user
55
54
 
56
55
  def logout(self):
57
56
  with self.session_transaction() as session:
58
- del session['user_id']
59
- del session['_fresh']
60
- del session['_id']
57
+ del session["user_id"]
58
+ del session["_fresh"]
59
+ del session["_id"]
61
60
 
62
61
 
63
62
  @pytest.fixture
@@ -70,57 +69,58 @@ def app(request):
70
69
 
71
70
  @pytest.fixture(autouse=True)
72
71
  def _load_frontend(request, _configure_application):
73
- '''
72
+ """
74
73
  Use `pytest.mark.frontend` to specify that frontend/api should be loaded
75
74
  Pass an optionnal list of modules as parameter to restrict loaded modules.
76
75
 
77
76
  Handle backward compatibility with Class.modules attribute too
78
- '''
79
- if 'app' not in request.fixturenames:
77
+ """
78
+ if "app" not in request.fixturenames:
80
79
  return
81
80
 
82
- app = request.getfixturevalue('app')
83
- marker = request.node.get_closest_marker('frontend')
81
+ app = request.getfixturevalue("app")
82
+ marker = request.node.get_closest_marker("frontend")
84
83
  modules = set(marker.args[0] if marker and marker.args else [])
85
- if getattr(request.cls, 'modules', None):
84
+ if getattr(request.cls, "modules", None):
86
85
  modules |= set(request.cls.modules)
87
86
 
88
- if marker or hasattr(request.cls, 'modules'):
89
- from udata import frontend, api
87
+ if marker or hasattr(request.cls, "modules"):
88
+ from udata import api, frontend
89
+
90
90
  api.init_app(app)
91
91
  frontend.init_app(app, modules)
92
92
 
93
93
 
94
94
  @pytest.fixture
95
95
  def client(app):
96
- '''
96
+ """
97
97
  Fixes https://github.com/pytest-dev/pytest-flask/issues/42
98
- '''
98
+ """
99
99
  return app.test_client()
100
100
 
101
101
 
102
102
  def get_settings(request):
103
- '''
103
+ """
104
104
  Extract settings from the current test request
105
- '''
106
- marker = request.node.get_closest_marker('settings')
105
+ """
106
+ marker = request.node.get_closest_marker("settings")
107
107
  if marker:
108
108
  return marker.args[0]
109
- _settings = getattr(request.cls, 'settings', settings.Testing)
109
+ _settings = getattr(request.cls, "settings", settings.Testing)
110
110
  # apply the options(plugins) marker from pytest_flask as soon as app is created
111
111
  # https://github.com/pytest-dev/pytest-flask/blob/a62ea18cb0fe89e3f3911192ab9ea4f9b12f8a16/pytest_flask/plugin.py#L126
112
112
  # this lets us have default settings for plugins applied while testing
113
- plugins = getattr(_settings, 'PLUGINS', [])
114
- for options in request.node.iter_markers('options'):
115
- option = options.kwargs.get('plugins', []) or options.kwargs.get('PLUGINS', [])
113
+ plugins = getattr(_settings, "PLUGINS", [])
114
+ for options in request.node.iter_markers("options"):
115
+ option = options.kwargs.get("plugins", []) or options.kwargs.get("PLUGINS", [])
116
116
  plugins += option
117
- setattr(_settings, 'PLUGINS', plugins)
117
+ setattr(_settings, "PLUGINS", plugins)
118
118
  return _settings
119
119
 
120
120
 
121
121
  def drop_db(app):
122
- '''Clear the database'''
123
- parsed_url = urlparse(app.config['MONGODB_HOST'])
122
+ """Clear the database"""
123
+ parsed_url = urlparse(app.config["MONGODB_HOST"])
124
124
 
125
125
  # drop the leading /
126
126
  db_name = parsed_url.path[1:]
@@ -133,19 +133,20 @@ def clean_db(app):
133
133
  yield
134
134
 
135
135
 
136
- @pytest.fixture(name='db')
136
+ @pytest.fixture(name="db")
137
137
  def raw_db(app, clean_db):
138
- '''Access to raw PyMongo DB client'''
138
+ """Access to raw PyMongo DB client"""
139
139
  from mongoengine.connection import get_db
140
+
140
141
  yield get_db()
141
142
  drop_db(app)
142
143
 
143
144
 
144
145
  @pytest.fixture
145
146
  def enable_resource_event(app):
146
- '''Enable resource event'''
147
- app.config['PUBLISH_ON_RESOURCE_EVENTS'] = True
148
- app.config['RESOURCES_ANALYSER_URI'] = 'http://local.dev'
147
+ """Enable resource event"""
148
+ app.config["PUBLISH_ON_RESOURCE_EVENTS"] = True
149
+ app.config["RESOURCES_ANALYSER_URI"] = "http://local.dev"
149
150
 
150
151
 
151
152
  class ApiClient(object):
@@ -165,42 +166,45 @@ class ApiClient(object):
165
166
  yield self._user
166
167
 
167
168
  def perform(self, verb, url, **kwargs):
168
- headers = kwargs.pop('headers', {})
169
- headers['Content-Type'] = 'application/json'
169
+ headers = kwargs.pop("headers", {})
170
+ headers["Content-Type"] = "application/json"
170
171
 
171
- data = kwargs.get('data')
172
+ data = kwargs.get("data")
172
173
  if data is not None:
173
174
  data = json.dumps(data)
174
- headers['Content-Length'] = len(data)
175
- kwargs['data'] = data
175
+ headers["Content-Length"] = len(data)
176
+ kwargs["data"] = data
176
177
 
177
178
  if self._user:
178
- headers['X-API-KEY'] = kwargs.get('X-API-KEY', self._user.apikey)
179
+ headers["X-API-KEY"] = kwargs.get("X-API-KEY", self._user.apikey)
179
180
 
180
- kwargs['headers'] = headers
181
+ kwargs["headers"] = headers
181
182
  method = getattr(self.client, verb)
182
183
  return method(url, **kwargs)
183
184
 
184
185
  def get(self, url, *args, **kwargs):
185
- return self.perform('get', url, *args, **kwargs)
186
+ return self.perform("get", url, *args, **kwargs)
186
187
 
187
188
  def post(self, url, data=None, json=True, *args, **kwargs):
188
189
  if not json:
189
190
  return self.client.post(url, data or {}, *args, **kwargs)
190
- return self.perform('post', url, data=data or {}, *args, **kwargs)
191
+ return self.perform("post", url, data=data or {}, *args, **kwargs)
191
192
 
192
193
  def put(self, url, data=None, json=True, *args, **kwargs):
193
194
  if not json:
194
195
  return self.client.put(url, data or {}, *args, **kwargs)
195
- return self.perform('put', url, data=data or {}, *args, **kwargs)
196
+ return self.perform("put", url, data=data or {}, *args, **kwargs)
196
197
 
197
198
  def patch(self, url, data=None, json=True, *args, **kwargs):
198
199
  if not json:
199
200
  return self.client.patch(url, data or {}, *args, **kwargs)
200
- return self.perform('patch', url, data=data or {}, *args, **kwargs)
201
+ return self.perform("patch", url, data=data or {}, *args, **kwargs)
201
202
 
202
203
  def delete(self, url, data=None, *args, **kwargs):
203
- return self.perform('delete', url, data=data or {}, *args, **kwargs)
204
+ return self.perform("delete", url, data=data or {}, *args, **kwargs)
205
+
206
+ def options(self, url, data=None, *args, **kwargs):
207
+ return self.perform("options", url, data=data or {}, *args, **kwargs)
204
208
 
205
209
 
206
210
  @pytest.fixture
@@ -209,17 +213,16 @@ def api(client):
209
213
  return api_client
210
214
 
211
215
 
212
- @pytest.fixture(name='cli')
216
+ @pytest.fixture(name="cli")
213
217
  def cli_fixture(app):
214
-
215
218
  def mock_runner(*args, **kwargs):
216
219
  from udata.commands import cli
217
220
 
218
- if len(args) == 1 and ' ' in args[0]:
221
+ if len(args) == 1 and " " in args[0]:
219
222
  args = shlex.split(args[0])
220
223
  runner = app.test_cli_runner()
221
224
  result = runner.invoke(cli, args, catch_exceptions=False)
222
- if kwargs.get('check', True):
225
+ if kwargs.get("check", True):
223
226
  assert_command_ok(result)
224
227
  return result
225
228
 
@@ -228,20 +231,20 @@ def cli_fixture(app):
228
231
 
229
232
  @pytest.fixture
230
233
  def instance_path(app, tmpdir):
231
- '''Use temporary application instance_path'''
234
+ """Use temporary application instance_path"""
232
235
  from udata.core import storages
233
236
  from udata.core.storages.views import blueprint
234
237
 
235
238
  app.instance_path = str(tmpdir)
236
- app.config['FS_ROOT'] = str(tmpdir / 'fs')
239
+ app.config["FS_ROOT"] = str(tmpdir / "fs")
237
240
  # Force local storage:
238
- for s in 'resources', 'avatars', 'logos', 'images', 'chunks', 'tmp':
239
- key = '{0}_FS_{{0}}'.format(s.upper())
240
- app.config[key.format('BACKEND')] = 'local'
241
- app.config.pop(key.format('ROOT'), None)
241
+ for s in "resources", "avatars", "logos", "images", "chunks", "tmp":
242
+ key = "{0}_FS_{{0}}".format(s.upper())
243
+ app.config[key.format("BACKEND")] = "local"
244
+ app.config.pop(key.format("ROOT"), None)
242
245
 
243
246
  storages.init_app(app)
244
- app.register_blueprint(blueprint, name='test-storage')
247
+ app.register_blueprint(blueprint, name="test-storage")
245
248
 
246
249
  return tmpdir
247
250
 
@@ -277,8 +280,9 @@ class TemplateRecorder:
277
280
 
278
281
  used_templates.append(template)
279
282
 
280
- msg = 'Template %s not used. Templates were used: %s' % (
281
- name, ' '.join(repr(used_templates))
283
+ msg = "Template %s not used. Templates were used: %s" % (
284
+ name,
285
+ " ".join(repr(used_templates)),
282
286
  )
283
287
  raise AssertionError(msg)
284
288
 
@@ -305,6 +309,7 @@ def templates():
305
309
  @pytest.fixture
306
310
  def httpretty():
307
311
  import httpretty
312
+
308
313
  httpretty.reset()
309
314
  httpretty.enable()
310
315
  yield httpretty
@@ -313,8 +318,9 @@ def httpretty():
313
318
 
314
319
  @pytest.fixture
315
320
  def rmock():
316
- '''A requests-mock fixture'''
321
+ """A requests-mock fixture"""
317
322
  import requests_mock
323
+
318
324
  with requests_mock.Mocker() as m:
319
325
  m.ANY = requests_mock.ANY
320
326
  yield m
@@ -322,7 +328,7 @@ def rmock():
322
328
 
323
329
  class SitemapClient:
324
330
  # Needed for lxml XPath not supporting default namespace
325
- NAMESPACES = {'s': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
331
+ NAMESPACES = {"s": "http://www.sitemaps.org/schemas/sitemap/0.9"}
326
332
  MISMATCH = 'URL "{0}" {1} mismatch: expected "{2}" found "{3}"'
327
333
 
328
334
  def __init__(self, client):
@@ -330,8 +336,8 @@ class SitemapClient:
330
336
  self._sitemap = None
331
337
 
332
338
  def fetch(self, secure=False):
333
- base_url = '{0}://local.test'.format('https' if secure else 'http')
334
- response = self.client.get('sitemap.xml', base_url=base_url)
339
+ base_url = "{0}://local.test".format("https" if secure else "http")
340
+ response = self.client.get("sitemap.xml", base_url=base_url)
335
341
  assert200(response)
336
342
  self._sitemap = etree.fromstring(response.data)
337
343
  return self._sitemap
@@ -346,21 +352,21 @@ class SitemapClient:
346
352
  return result[0] if result else None
347
353
 
348
354
  def assert_url(self, url, priority, changefreq):
349
- '''
355
+ """
350
356
  Check than a URL is present in the sitemap
351
357
  with given `priority` and `changefreq`
352
- '''
358
+ """
353
359
  __tracebackhide__ = True
354
- r = url.xpath('s:priority', namespaces=self.NAMESPACES)
360
+ r = url.xpath("s:priority", namespaces=self.NAMESPACES)
355
361
  assert len(r) == 1, 'URL "{0}" should have one priority'.format(url)
356
362
  found = r[0].text
357
- msg = self.MISMATCH.format(url, 'priority', priority, found)
363
+ msg = self.MISMATCH.format(url, "priority", priority, found)
358
364
  assert found == str(priority), msg
359
365
 
360
- r = url.xpath('s:changefreq', namespaces=self.NAMESPACES)
366
+ r = url.xpath("s:changefreq", namespaces=self.NAMESPACES)
361
367
  assert len(r) == 1, 'URL "{0}" should have one changefreq'.format(url)
362
368
  found = r[0].text
363
- msg = self.MISMATCH.format(url, 'changefreq', changefreq, found)
369
+ msg = self.MISMATCH.format(url, "changefreq", changefreq, found)
364
370
  assert found == changefreq, msg
365
371
 
366
372
 
@@ -1,17 +1,16 @@
1
1
  from datetime import datetime
2
2
 
3
- from udata.models import Reuse
4
-
5
3
  from udata.core.dataset import tasks as dataset_tasks
4
+ from udata.core.dataset.factories import DatasetFactory
5
+ from udata.core.discussions.factories import DiscussionFactory
6
6
  from udata.core.organization.factories import OrganizationFactory
7
7
  from udata.core.reuse.factories import ReuseFactory, VisibleReuseFactory
8
- from udata.core.dataset.factories import DatasetFactory
9
8
  from udata.core.user.factories import UserFactory
10
- from udata.core.discussions.factories import DiscussionFactory
11
9
  from udata.i18n import gettext as _
10
+ from udata.models import Reuse
12
11
  from udata.tests.helpers import assert_emit
13
12
 
14
- from .. import TestCase, DBTestMixin
13
+ from .. import DBTestMixin, TestCase
15
14
 
16
15
 
17
16
  class ReuseModelTest(TestCase, DBTestMixin):
@@ -39,8 +38,10 @@ class ReuseModelTest(TestCase, DBTestMixin):
39
38
  user = UserFactory()
40
39
  org = OrganizationFactory()
41
40
  reuses = [ReuseFactory(owner=user), ReuseFactory(organization=org)]
42
- excluded = [ReuseFactory(owner=UserFactory()),
43
- ReuseFactory(organization=OrganizationFactory())]
41
+ excluded = [
42
+ ReuseFactory(owner=UserFactory()),
43
+ ReuseFactory(organization=OrganizationFactory()),
44
+ ]
44
45
 
45
46
  result = Reuse.objects.owned_by(org, user)
46
47
 
@@ -53,10 +54,10 @@ class ReuseModelTest(TestCase, DBTestMixin):
53
54
 
54
55
  def test_tags_normalized(self):
55
56
  user = UserFactory()
56
- tags = [' one another!', ' one another!', 'This IS a "tag"…']
57
+ tags = [" one another!", " one another!", 'This IS a "tag"…']
57
58
  reuse = ReuseFactory(owner=user, tags=tags)
58
59
  self.assertEqual(len(reuse.tags), 2)
59
- self.assertEqual(reuse.tags[1], 'this-is-a-tag')
60
+ self.assertEqual(reuse.tags[1], "this-is-a-tag")
60
61
 
61
62
  def test_send_on_delete(self):
62
63
  reuse = ReuseFactory()
@@ -72,18 +73,18 @@ class ReuseModelTest(TestCase, DBTestMixin):
72
73
  reuse.count_datasets()
73
74
  reuse.count_discussions()
74
75
 
75
- assert reuse.get_metrics()['datasets'] == 1
76
- assert reuse.get_metrics()['discussions'] == 1
76
+ assert reuse.get_metrics()["datasets"] == 1
77
+ assert reuse.get_metrics()["discussions"] == 1
77
78
 
78
79
  with assert_emit(Reuse.on_update):
79
80
  reuse.datasets.append(dataset)
80
81
  reuse.save()
81
82
 
82
83
  reuse.count_datasets()
83
- assert reuse.get_metrics()['datasets'] == 2
84
+ assert reuse.get_metrics()["datasets"] == 2
84
85
 
85
86
  dataset.count_reuses()
86
- assert dataset.get_metrics()['reuses'] == 1
87
+ assert dataset.get_metrics()["reuses"] == 1
87
88
 
88
89
  with assert_emit(Reuse.on_update):
89
90
  reuse.datasets.remove(dataset)
@@ -91,17 +92,17 @@ class ReuseModelTest(TestCase, DBTestMixin):
91
92
 
92
93
  dataset_tasks.update_datasets_reuses_metrics()
93
94
  dataset.reload()
94
- assert dataset.get_metrics()['reuses'] == 0
95
+ assert dataset.get_metrics()["reuses"] == 0
95
96
 
96
97
  def test_reuse_type(self):
97
- reuse = ReuseFactory(type='api')
98
- self.assertEqual(reuse.type, 'api')
99
- self.assertEqual(reuse.type_label, 'API')
98
+ reuse = ReuseFactory(type="api")
99
+ self.assertEqual(reuse.type, "api")
100
+ self.assertEqual(reuse.type_label, "API")
100
101
 
101
102
  def test_reuse_topic(self):
102
- reuse = ReuseFactory(topic='health')
103
- self.assertEqual(reuse.topic, 'health')
104
- self.assertEqual(reuse.topic_label, _('Health'))
103
+ reuse = ReuseFactory(topic="health")
104
+ self.assertEqual(reuse.topic, "health")
105
+ self.assertEqual(reuse.topic_label, _("Health"))
105
106
 
106
107
  def test_reuse_without_private(self):
107
108
  reuse = ReuseFactory()
@@ -114,4 +115,3 @@ class ReuseModelTest(TestCase, DBTestMixin):
114
115
  reuse.private = True
115
116
  reuse.save()
116
117
  self.assertEqual(reuse.private, True)
117
-
@@ -1,31 +1,29 @@
1
1
  from flask import url_for
2
2
 
3
- from udata.tests.api import APITestCase
4
-
5
3
  from udata.core import storages
6
- from udata.tests.helpers import create_test_image
7
- from udata.models import Reuse, Transfer
8
- from udata.core.user.factories import AdminFactory, UserFactory
9
- from udata.core.reuse.factories import ReuseFactory
10
4
  from udata.core.reuse import tasks
5
+ from udata.core.reuse.factories import ReuseFactory
6
+ from udata.core.user.factories import AdminFactory, UserFactory
7
+ from udata.models import Reuse, Transfer
8
+ from udata.tests.api import APITestCase
9
+ from udata.tests.helpers import create_test_image
11
10
 
12
11
 
13
12
  class ReuseTasksTest(APITestCase):
14
13
  def test_purge_reuses(self):
15
- reuse = ReuseFactory(title='test-reuse')
14
+ reuse = ReuseFactory(title="test-reuse")
16
15
 
17
16
  # Upload reuse's image
18
17
  file = create_test_image()
19
18
  user = AdminFactory()
20
19
  self.login(user)
21
20
  response = self.post(
22
- url_for('api.reuse_image', reuse=reuse),
23
- {'file': (file, 'test.png')},
24
- json=False)
21
+ url_for("api.reuse_image", reuse=reuse), {"file": (file, "test.png")}, json=False
22
+ )
25
23
  self.assert200(response)
26
24
 
27
25
  # Delete reuse
28
- response = self.delete(url_for('api.reuse', reuse=reuse))
26
+ response = self.delete(url_for("api.reuse", reuse=reuse))
29
27
  self.assert204(response)
30
28
 
31
29
  user = UserFactory()
@@ -33,7 +31,7 @@ class ReuseTasksTest(APITestCase):
33
31
  owner=user,
34
32
  recipient=user,
35
33
  subject=reuse,
36
- comment='comment',
34
+ comment="comment",
37
35
  )
38
36
 
39
37
  tasks.purge_reuses()
@@ -43,5 +41,5 @@ class ReuseTasksTest(APITestCase):
43
41
  # Check reuse's image is deleted
44
42
  self.assertEqual(list(storages.images.list_files()), [])
45
43
 
46
- deleted_reuse = Reuse.objects(title='test-reuse').first()
44
+ deleted_reuse = Reuse.objects(title="test-reuse").first()
47
45
  self.assertIsNone(deleted_reuse)
@@ -1,15 +1,14 @@
1
1
  import factory
2
-
3
2
  from factory.mongoengine import MongoEngineFactory
4
3
 
5
4
  from udata import search
6
5
  from udata.mongo import db
7
6
 
8
-
9
7
  #############################################################################
10
8
  # Fake object for testing #
11
9
  #############################################################################
12
10
 
11
+
13
12
  class FakeSearchable(db.Document):
14
13
  title = db.StringField()
15
14
  description = db.StringField()
@@ -17,7 +16,7 @@ class FakeSearchable(db.Document):
17
16
  other = db.ListField(db.StringField())
18
17
  indexable = db.BooleanField(default=True)
19
18
 
20
- meta = {'allow_inheritance': True}
19
+ meta = {"allow_inheritance": True}
21
20
 
22
21
  def __unicode__(self):
23
22
  return self.title
@@ -26,11 +25,11 @@ class FakeSearchable(db.Document):
26
25
  return self.title
27
26
 
28
27
  def __html__(self):
29
- return '<span>{0}</span>'.format(self.title)
28
+ return "<span>{0}</span>".format(self.title)
30
29
 
31
30
 
32
31
  class FakeFactory(MongoEngineFactory):
33
- title = factory.Faker('sentence')
32
+ title = factory.Faker("sentence")
34
33
 
35
34
  class Meta:
36
35
  model = FakeSearchable
@@ -39,14 +38,14 @@ class FakeFactory(MongoEngineFactory):
39
38
  @search.register
40
39
  class FakeSearch(search.ModelSearchAdapter):
41
40
  model = FakeSearchable
42
- search_url = 'mock://test.com/fakeable/'
41
+ search_url = "mock://test.com/fakeable/"
43
42
  filters = {
44
- 'tag': search.Filter(),
45
- 'other': search.Filter(),
43
+ "tag": search.Filter(),
44
+ "other": search.Filter(),
46
45
  }
47
46
  sorts = {
48
- 'title': 'title.raw',
49
- 'description': 'description.raw',
47
+ "title": "title.raw",
48
+ "description": "description.raw",
50
49
  }
51
50
 
52
51
  @classmethod
@@ -56,6 +55,6 @@ class FakeSearch(search.ModelSearchAdapter):
56
55
  @classmethod
57
56
  def serialize(cls, fake):
58
57
  return {
59
- 'title': fake.title,
60
- 'description': fake.description,
58
+ "title": fake.title,
59
+ "description": fake.description,
61
60
  }