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
@@ -6,22 +6,25 @@ from flask import current_app
6
6
  from mongoengine import post_save
7
7
 
8
8
  from udata.app import cache
9
- from udata.models import db, Dataset, License, ResourceSchema, Schema
10
9
  from udata.core.dataset.constants import LEGACY_FREQUENCIES, UPDATE_FREQUENCIES
11
- from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
12
- from udata.core.dataset.factories import (
13
- ResourceFactory, DatasetFactory, CommunityResourceFactory, LicenseFactory, ResourceSchemaMockData
14
- )
15
10
  from udata.core.dataset.exceptions import (
16
- SchemasCatalogNotFoundException, SchemasCacheUnavailableException
11
+ SchemasCacheUnavailableException,
12
+ SchemasCatalogNotFoundException,
13
+ )
14
+ from udata.core.dataset.factories import (
15
+ CommunityResourceFactory,
16
+ DatasetFactory,
17
+ LicenseFactory,
18
+ ResourceFactory,
19
+ ResourceSchemaMockData,
17
20
  )
21
+ from udata.core.dataset.models import HarvestDatasetMetadata, HarvestResourceMetadata
18
22
  from udata.core.user.factories import UserFactory
23
+ from udata.models import Dataset, License, ResourceSchema, Schema, db
24
+ from udata.tests.helpers import assert_emit, assert_equal_dates, assert_not_emit
19
25
  from udata.utils import faker
20
- from udata.tests.helpers import (
21
- assert_emit, assert_not_emit, assert_equal_dates
22
- )
23
26
 
24
- pytestmark = pytest.mark.usefixtures('clean_db')
27
+ pytestmark = pytest.mark.usefixtures("clean_db")
25
28
 
26
29
 
27
30
  class DatasetModelTest:
@@ -71,13 +74,13 @@ class DatasetModelTest:
71
74
  dataset = DatasetFactory(owner=user, resources=[resource])
72
75
  expected_signals = (Dataset.on_resource_updated,)
73
76
 
74
- resource.description = 'New description'
77
+ resource.description = "New description"
75
78
 
76
79
  with assert_emit(*expected_signals):
77
80
  dataset.update_resource(resource)
78
81
  assert len(dataset.resources) == 1
79
82
  assert dataset.resources[0].id == resource.id
80
- assert dataset.resources[0].description == 'New description'
83
+ assert dataset.resources[0].description == "New description"
81
84
 
82
85
  def test_update_resource_missing_checksum_type(self):
83
86
  user = UserFactory()
@@ -127,149 +130,155 @@ class DatasetModelTest:
127
130
  assert dataset.next_update is None
128
131
 
129
132
  def test_next_update_hourly(self):
130
- dataset = DatasetFactory(frequency='hourly')
131
- assert_equal_dates(dataset.next_update,
132
- datetime.utcnow() + timedelta(hours=1))
133
+ dataset = DatasetFactory(frequency="hourly")
134
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(hours=1))
133
135
 
134
- @pytest.mark.parametrize('freq', ['fourTimesADay', 'threeTimesADay', 'semidaily', 'daily'])
136
+ @pytest.mark.parametrize("freq", ["fourTimesADay", "threeTimesADay", "semidaily", "daily"])
135
137
  def test_next_update_daily(self, freq):
136
138
  dataset = DatasetFactory(frequency=freq)
137
- assert_equal_dates(dataset.next_update,
138
- datetime.utcnow() + timedelta(days=1))
139
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=1))
139
140
 
140
- @pytest.mark.parametrize('freq', ['fourTimesAWeek', 'threeTimesAWeek', 'semiweekly', 'weekly'])
141
+ @pytest.mark.parametrize("freq", ["fourTimesAWeek", "threeTimesAWeek", "semiweekly", "weekly"])
141
142
  def test_next_update_weekly(self, freq):
142
143
  dataset = DatasetFactory(frequency=freq)
143
- assert_equal_dates(dataset.next_update,
144
- datetime.utcnow() + timedelta(days=7))
144
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=7))
145
145
 
146
146
  def test_next_update_biweekly(self):
147
- dataset = DatasetFactory(frequency='biweekly')
148
- assert_equal_dates(dataset.next_update,
149
- datetime.utcnow() + timedelta(weeks=2))
147
+ dataset = DatasetFactory(frequency="biweekly")
148
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(weeks=2))
150
149
 
151
150
  def test_next_update_quarterly(self):
152
- dataset = DatasetFactory(frequency='quarterly')
153
- assert_equal_dates(dataset.next_update,
154
- datetime.utcnow() + timedelta(days=365/4))
151
+ dataset = DatasetFactory(frequency="quarterly")
152
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 / 4))
155
153
 
156
- @pytest.mark.parametrize('freq', ['threeTimesAYear', 'semiannual', 'annual'])
154
+ @pytest.mark.parametrize("freq", ["threeTimesAYear", "semiannual", "annual"])
157
155
  def test_next_update_annual(self, freq):
158
156
  dataset = DatasetFactory(frequency=freq)
159
- assert_equal_dates(dataset.next_update,
160
- datetime.utcnow() + timedelta(days=365))
157
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365))
161
158
 
162
159
  def test_next_update_biennial(self):
163
- dataset = DatasetFactory(frequency='biennial')
164
- assert_equal_dates(dataset.next_update,
165
- datetime.utcnow() + timedelta(days=365*2))
160
+ dataset = DatasetFactory(frequency="biennial")
161
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 2))
166
162
 
167
163
  def test_next_update_triennial(self):
168
- dataset = DatasetFactory(frequency='triennial')
169
- assert_equal_dates(dataset.next_update,
170
- datetime.utcnow() + timedelta(days=365*3))
164
+ dataset = DatasetFactory(frequency="triennial")
165
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 3))
171
166
 
172
167
  def test_next_update_quinquennial(self):
173
- dataset = DatasetFactory(frequency='quinquennial')
174
- assert_equal_dates(dataset.next_update,
175
- datetime.utcnow() + timedelta(days=365*5))
168
+ dataset = DatasetFactory(frequency="quinquennial")
169
+ assert_equal_dates(dataset.next_update, datetime.utcnow() + timedelta(days=365 * 5))
176
170
 
177
- @pytest.mark.parametrize('freq', ['continuous', 'punctual', 'irregular', 'unknown'])
171
+ @pytest.mark.parametrize("freq", ["continuous", "punctual", "irregular", "unknown"])
178
172
  def test_next_update_undefined(self, freq):
179
173
  dataset = DatasetFactory(frequency=freq)
180
174
  assert dataset.next_update is None
181
175
 
182
176
  def test_quality_default(self):
183
- dataset = DatasetFactory(description='')
177
+ dataset = DatasetFactory(description="")
184
178
  assert dataset.quality == {
185
- 'license': False,
186
- 'temporal_coverage': False,
187
- 'spatial': False,
188
- 'update_frequency': False,
189
- 'dataset_description_quality': False,
190
- 'score': 0
179
+ "license": False,
180
+ "temporal_coverage": False,
181
+ "spatial": False,
182
+ "update_frequency": False,
183
+ "dataset_description_quality": False,
184
+ "score": 0,
191
185
  }
192
186
 
193
- @pytest.mark.parametrize('freq', UPDATE_FREQUENCIES)
187
+ @pytest.mark.parametrize("freq", UPDATE_FREQUENCIES)
194
188
  def test_quality_frequency_update(self, freq):
195
- dataset = DatasetFactory(description='', frequency=freq)
196
- if freq == 'unknown':
197
- assert dataset.quality['update_frequency'] is False
198
- assert 'update_fulfilled_in_time' not in dataset.quality
189
+ dataset = DatasetFactory(description="", frequency=freq)
190
+ if freq == "unknown":
191
+ assert dataset.quality["update_frequency"] is False
192
+ assert "update_fulfilled_in_time" not in dataset.quality
199
193
  return
200
- assert dataset.quality['update_frequency'] is True
201
- assert dataset.quality['update_fulfilled_in_time'] is True
202
- assert dataset.quality['score'] == Dataset.normalize_score(2)
194
+ assert dataset.quality["update_frequency"] is True
195
+ assert dataset.quality["update_fulfilled_in_time"] is True
196
+ assert dataset.quality["score"] == Dataset.normalize_score(2)
203
197
 
204
198
  def test_quality_frequency_update_one_day_late(self):
205
199
  dataset = DatasetFactory(
206
- description='', frequency="daily",
207
- last_modified_internal=datetime.utcnow() - timedelta(days=1, hours=1))
208
- assert dataset.quality['update_frequency'] is True
209
- assert dataset.quality['update_fulfilled_in_time'] is True
210
- assert dataset.quality['score'] == Dataset.normalize_score(2)
200
+ description="",
201
+ frequency="daily",
202
+ last_modified_internal=datetime.utcnow() - timedelta(days=1, hours=1),
203
+ )
204
+ assert dataset.quality["update_frequency"] is True
205
+ assert dataset.quality["update_fulfilled_in_time"] is True
206
+ assert dataset.quality["score"] == Dataset.normalize_score(2)
211
207
 
212
208
  def test_quality_frequency_update_two_days_late(self):
213
209
  dataset = DatasetFactory(
214
- description='', frequency="daily",
215
- last_modified_internal=datetime.utcnow() - timedelta(days=2, hours=1))
216
- assert dataset.quality['update_frequency'] is True
217
- assert dataset.quality['update_fulfilled_in_time'] is False
218
- assert dataset.quality['score'] == Dataset.normalize_score(1)
210
+ description="",
211
+ frequency="daily",
212
+ last_modified_internal=datetime.utcnow() - timedelta(days=2, hours=1),
213
+ )
214
+ assert dataset.quality["update_frequency"] is True
215
+ assert dataset.quality["update_fulfilled_in_time"] is False
216
+ assert dataset.quality["score"] == Dataset.normalize_score(1)
219
217
 
220
218
  def test_quality_description_length(self):
221
- dataset = DatasetFactory(description='a' * (current_app.config.get('QUALITY_DESCRIPTION_LENGTH') - 1))
222
- assert dataset.quality['dataset_description_quality'] is False
223
- assert dataset.quality['score'] == 0
224
- dataset = DatasetFactory(description='a' * (current_app.config.get('QUALITY_DESCRIPTION_LENGTH') + 1))
225
- assert dataset.quality['dataset_description_quality'] is True
226
- assert dataset.quality['score'] == Dataset.normalize_score(1)
219
+ dataset = DatasetFactory(
220
+ description="a" * (current_app.config.get("QUALITY_DESCRIPTION_LENGTH") - 1)
221
+ )
222
+ assert dataset.quality["dataset_description_quality"] is False
223
+ assert dataset.quality["score"] == 0
224
+ dataset = DatasetFactory(
225
+ description="a" * (current_app.config.get("QUALITY_DESCRIPTION_LENGTH") + 1)
226
+ )
227
+ assert dataset.quality["dataset_description_quality"] is True
228
+ assert dataset.quality["score"] == Dataset.normalize_score(1)
227
229
 
228
230
  def test_quality_has_open_formats(self):
229
- dataset = DatasetFactory(description='', )
230
- dataset.add_resource(ResourceFactory(format='pdf'))
231
- assert not dataset.quality['has_open_format']
232
- assert dataset.quality['score'] == Dataset.normalize_score(2)
231
+ dataset = DatasetFactory(
232
+ description="",
233
+ )
234
+ dataset.add_resource(ResourceFactory(format="pdf"))
235
+ assert not dataset.quality["has_open_format"]
236
+ assert dataset.quality["score"] == Dataset.normalize_score(2)
233
237
 
234
238
  def test_quality_has_opened_formats(self):
235
- dataset = DatasetFactory(description='', )
236
- dataset.add_resource(ResourceFactory(format='pdf'))
237
- dataset.add_resource(ResourceFactory(format='csv'))
238
- assert dataset.quality['has_open_format']
239
- assert dataset.quality['score'] == Dataset.normalize_score(3)
239
+ dataset = DatasetFactory(
240
+ description="",
241
+ )
242
+ dataset.add_resource(ResourceFactory(format="pdf"))
243
+ dataset.add_resource(ResourceFactory(format="csv"))
244
+ assert dataset.quality["has_open_format"]
245
+ assert dataset.quality["score"] == Dataset.normalize_score(3)
240
246
 
241
247
  def test_quality_has_undefined_and_closed_format(self):
242
- dataset = DatasetFactory(description='', )
248
+ dataset = DatasetFactory(
249
+ description="",
250
+ )
243
251
  dataset.add_resource(ResourceFactory(format=None))
244
- dataset.add_resource(ResourceFactory(format='xls'))
245
- assert not dataset.quality['has_open_format']
246
- assert dataset.quality['score'] == Dataset.normalize_score(2)
252
+ dataset.add_resource(ResourceFactory(format="xls"))
253
+ assert not dataset.quality["has_open_format"]
254
+ assert dataset.quality["score"] == Dataset.normalize_score(2)
247
255
 
248
256
  def test_quality_all(self):
249
257
  user = UserFactory()
250
- dataset = DatasetFactory(owner=user, frequency='weekly',
251
- tags=['foo', 'bar'], description='a' * 42)
252
- dataset.add_resource(ResourceFactory(format='pdf'))
253
- assert dataset.quality['score'] == Dataset.normalize_score(4)
258
+ dataset = DatasetFactory(
259
+ owner=user, frequency="weekly", tags=["foo", "bar"], description="a" * 42
260
+ )
261
+ dataset.add_resource(ResourceFactory(format="pdf"))
262
+ assert dataset.quality["score"] == Dataset.normalize_score(4)
254
263
  assert sorted(dataset.quality.keys()) == [
255
- 'all_resources_available',
256
- 'dataset_description_quality',
257
- 'has_open_format',
258
- 'has_resources',
259
- 'license',
260
- 'resources_documentation',
261
- 'score',
262
- 'spatial',
263
- 'temporal_coverage',
264
- 'update_frequency',
265
- 'update_fulfilled_in_time'
264
+ "all_resources_available",
265
+ "dataset_description_quality",
266
+ "has_open_format",
267
+ "has_resources",
268
+ "license",
269
+ "resources_documentation",
270
+ "score",
271
+ "spatial",
272
+ "temporal_coverage",
273
+ "update_frequency",
274
+ "update_fulfilled_in_time",
266
275
  ]
267
276
 
268
277
  def test_tags_normalized(self):
269
- tags = [' one another!', ' one another!', 'This IS a "tag"…']
278
+ tags = [" one another!", " one another!", 'This IS a "tag"…']
270
279
  dataset = DatasetFactory(tags=tags)
271
280
  assert len(dataset.tags) == 2
272
- assert dataset.tags[1] == 'this-is-a-tag'
281
+ assert dataset.tags[1] == "this-is-a-tag"
273
282
 
274
283
  def test_legacy_frequencies(self):
275
284
  for oldFreq, newFreq in LEGACY_FREQUENCIES.items():
@@ -287,8 +296,8 @@ class DatasetModelTest:
287
296
  unexpected_signals = Dataset.after_save, Dataset.on_update
288
297
 
289
298
  with assert_not_emit(*unexpected_signals), assert_emit(post_save):
290
- dataset.title = 'New title'
291
- dataset.save(signal_kwargs={'ignores': ['post_save']})
299
+ dataset.title = "New title"
300
+ dataset.save(signal_kwargs={"ignores": ["post_save"]})
292
301
 
293
302
  def test_dataset_without_private(self):
294
303
  dataset = DatasetFactory()
@@ -310,10 +319,10 @@ class ResourceModelTest:
310
319
 
311
320
  def test_bad_url(self):
312
321
  with pytest.raises(db.ValidationError):
313
- DatasetFactory(resources=[ResourceFactory(url='not-an-url')])
322
+ DatasetFactory(resources=[ResourceFactory(url="not-an-url")])
314
323
 
315
324
  def test_url_is_stripped(self):
316
- url = 'http://www.somewhere.com/with/spaces/ '
325
+ url = "http://www.somewhere.com/with/spaces/ "
317
326
  dataset = DatasetFactory(resources=[ResourceFactory(url=url)])
318
327
  assert dataset.resources[0].url == url.strip()
319
328
 
@@ -324,8 +333,8 @@ class ResourceModelTest:
324
333
  unexpected_signals = Dataset.after_save, Dataset.on_update
325
334
 
326
335
  with assert_not_emit(*unexpected_signals), assert_emit(post_save):
327
- resource.title = 'New title'
328
- resource.save(signal_kwargs={'ignores': ['post_save']})
336
+ resource.title = "New title"
337
+ resource.save(signal_kwargs={"ignores": ["post_save"]})
329
338
 
330
339
 
331
340
  class LicenseModelTest:
@@ -335,12 +344,12 @@ class LicenseModelTest:
335
344
  LicenseFactory.create_batch(3)
336
345
 
337
346
  def test_not_found(self):
338
- found = License.guess('should not be found')
347
+ found = License.guess("should not be found")
339
348
  assert found is None
340
349
 
341
350
  def test_not_found_with_default(self):
342
351
  license = LicenseFactory()
343
- found = License.guess('should not be found', default=license)
352
+ found = License.guess("should not be found", default=license)
344
353
  assert found.id == license.id
345
354
 
346
355
  def test_none(self):
@@ -348,7 +357,7 @@ class LicenseModelTest:
348
357
  assert found is None
349
358
 
350
359
  def test_empty_string(self):
351
- found = License.guess('')
360
+ found = License.guess("")
352
361
  assert found is None
353
362
 
354
363
  def test_exact_match_by_id(self):
@@ -358,14 +367,14 @@ class LicenseModelTest:
358
367
  assert license.id == found.id
359
368
 
360
369
  def test_imatch_by_id(self):
361
- license = LicenseFactory(id='CAPS-ID')
370
+ license = LicenseFactory(id="CAPS-ID")
362
371
  found = License.guess(license.id)
363
372
  assert isinstance(found, License)
364
373
  assert license.id == found.id
365
374
 
366
375
  def test_exact_match_by_id_with_spaces(self):
367
376
  license = LicenseFactory()
368
- found = License.guess(' {0} '.format(license.id))
377
+ found = License.guess(" {0} ".format(license.id))
369
378
  assert isinstance(found, License)
370
379
  assert license.id == found.id
371
380
 
@@ -376,30 +385,30 @@ class LicenseModelTest:
376
385
  assert license.id == found.id
377
386
 
378
387
  def test_match_by_url_with_final_slash(self):
379
- license = LicenseFactory(url='https://example.com/license')
380
- found = License.guess('https://example.com/license/')
388
+ license = LicenseFactory(url="https://example.com/license")
389
+ found = License.guess("https://example.com/license/")
381
390
  assert isinstance(found, License)
382
391
  assert license.id == found.id
383
392
 
384
393
  def test_match_by_url_without_final_slash(self):
385
- license = LicenseFactory(url='https://example.com/license/')
386
- found = License.guess('https://example.com/license')
394
+ license = LicenseFactory(url="https://example.com/license/")
395
+ found = License.guess("https://example.com/license")
387
396
  assert isinstance(found, License)
388
397
  assert license.id == found.id
389
398
 
390
399
  def test_match_by_url_not_too_fuzzy(self):
391
- LicenseFactory(url='https://example.com/licensea')
392
- found = License.guess('https://example.com/licenseb')
400
+ LicenseFactory(url="https://example.com/licensea")
401
+ found = License.guess("https://example.com/licenseb")
393
402
  assert found is None
394
403
 
395
404
  def test_match_by_url_scheme_mismatch(self):
396
- license = LicenseFactory(url='https://example.com/license')
397
- found = License.guess('http://example.com/license')
405
+ license = LicenseFactory(url="https://example.com/license")
406
+ found = License.guess("http://example.com/license")
398
407
  assert isinstance(found, License)
399
408
  assert license.id == found.id
400
409
 
401
410
  def test_imatch_by_url(self):
402
- url = '%s/CAPS.php' % faker.uri()
411
+ url = "%s/CAPS.php" % faker.uri()
403
412
  license = LicenseFactory(url=url)
404
413
  found = License.guess(license.url)
405
414
  assert isinstance(found, License)
@@ -413,16 +422,16 @@ class LicenseModelTest:
413
422
  assert license.id == found.id
414
423
 
415
424
  def test_imatch_by_alternate_url(self):
416
- alternate_url = '%s/CAPS.php' % faker.uri()
425
+ alternate_url = "%s/CAPS.php" % faker.uri()
417
426
  license = LicenseFactory(alternate_urls=[alternate_url])
418
427
  found = License.guess(alternate_url)
419
428
  assert isinstance(found, License)
420
429
  assert license.id == found.id
421
430
 
422
431
  def test_match_by_alternate_url_scheme_slash_mismatch(self):
423
- alternate_url = 'https://example.com/license'
432
+ alternate_url = "https://example.com/license"
424
433
  license = LicenseFactory(alternate_urls=[alternate_url])
425
- found = License.guess('http://example.com/license/')
434
+ found = License.guess("http://example.com/license/")
426
435
  assert isinstance(found, License)
427
436
  assert license.id == found.id
428
437
 
@@ -440,25 +449,25 @@ class LicenseModelTest:
440
449
 
441
450
  def test_exact_match_by_title_with_spaces(self):
442
451
  license = LicenseFactory()
443
- found = License.guess(' {0} '.format(license.title))
452
+ found = License.guess(" {0} ".format(license.title))
444
453
  assert isinstance(found, License)
445
454
  assert license.id == found.id
446
455
 
447
456
  def test_match_by_title_with_low_edit_distance(self):
448
- license = LicenseFactory(title='License')
449
- found = License.guess('Licence')
457
+ license = LicenseFactory(title="License")
458
+ found = License.guess("Licence")
450
459
  assert isinstance(found, License)
451
460
  assert license.id == found.id
452
461
 
453
462
  def test_match_by_title_with_extra_inner_space(self):
454
- license = LicenseFactory(title='License ODBl')
455
- found = License.guess('License ODBl') # 2 spaces instead of 1
463
+ license = LicenseFactory(title="License ODBl")
464
+ found = License.guess("License ODBl") # 2 spaces instead of 1
456
465
  assert isinstance(found, License)
457
466
  assert license.id == found.id
458
467
 
459
468
  def test_match_by_title_with_mismatching_case(self):
460
- license = LicenseFactory(title='License ODBl')
461
- found = License.guess('License ODBL')
469
+ license = LicenseFactory(title="License ODBl")
470
+ found = License.guess("License ODBL")
462
471
  assert isinstance(found, License)
463
472
  assert license.id == found.id
464
473
 
@@ -472,38 +481,38 @@ class LicenseModelTest:
472
481
  def test_exact_match_by_alternate_title_with_spaces(self):
473
482
  alternate_title = faker.sentence()
474
483
  license = LicenseFactory(alternate_titles=[alternate_title])
475
- found = License.guess(' {0} '.format(alternate_title))
484
+ found = License.guess(" {0} ".format(alternate_title))
476
485
  assert isinstance(found, License)
477
486
  assert license.id == found.id
478
487
 
479
488
  def test_match_by_alternate_title_with_low_edit_distance(self):
480
- license = LicenseFactory(alternate_titles=['License'])
481
- found = License.guess('Licence')
489
+ license = LicenseFactory(alternate_titles=["License"])
490
+ found = License.guess("Licence")
482
491
  assert isinstance(found, License)
483
492
  assert license.id == found.id
484
493
 
485
494
  def test_match_by_alternate_title_with_extra_inner_space(self):
486
- license = LicenseFactory(alternate_titles=['License ODBl'])
487
- found = License.guess('License ODBl') # 2 spaces instead of 1
495
+ license = LicenseFactory(alternate_titles=["License ODBl"])
496
+ found = License.guess("License ODBl") # 2 spaces instead of 1
488
497
  assert isinstance(found, License)
489
498
  assert license.id == found.id
490
499
 
491
500
  def test_match_by_alternate_title_with_mismatching_case(self):
492
- license = LicenseFactory(alternate_titles=['License ODBl'])
493
- found = License.guess('License ODBL')
501
+ license = LicenseFactory(alternate_titles=["License ODBl"])
502
+ found = License.guess("License ODBL")
494
503
  assert isinstance(found, License)
495
504
  assert license.id == found.id
496
505
 
497
506
  def test_match_by_alternate_title_with_multiple_candidates_from_one_licence(self):
498
- license = LicenseFactory(alternate_titles=['Licence Ouverte v2', 'Licence Ouverte v2.0'])
499
- found = License.guess('Licence Ouverte v2.0')
507
+ license = LicenseFactory(alternate_titles=["Licence Ouverte v2", "Licence Ouverte v2.0"])
508
+ found = License.guess("Licence Ouverte v2.0")
500
509
  assert isinstance(found, License)
501
510
  assert license.id == found.id
502
511
 
503
512
  def test_no_with_multiple_alternate_titles_from_different_licences(self):
504
- LicenseFactory(alternate_titles=['Licence Ouverte v2'])
505
- LicenseFactory(alternate_titles=['Licence Ouverte v2.0'])
506
- found = License.guess('Licence Ouverte v2.0')
513
+ LicenseFactory(alternate_titles=["Licence Ouverte v2"])
514
+ LicenseFactory(alternate_titles=["Licence Ouverte v2.0"])
515
+ found = License.guess("Licence Ouverte v2.0")
507
516
  assert found is None
508
517
 
509
518
  def test_prioritize_title_over_alternate_title(self):
@@ -516,61 +525,52 @@ class LicenseModelTest:
516
525
 
517
526
  def test_multiple_strings(self):
518
527
  license = LicenseFactory()
519
- found = License.guess('should not match', license.id)
528
+ found = License.guess("should not match", license.id)
520
529
  assert isinstance(found, License)
521
530
  assert license.id == found.id
522
531
 
523
532
 
524
533
  class ResourceSchemaTest:
525
- @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/notfound')
534
+ @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/notfound")
526
535
  def test_resource_schema_objects_404_endpoint(self, rmock):
527
- rmock.get('https://example.com/notfound', status_code=404)
536
+ rmock.get("https://example.com/notfound", status_code=404)
528
537
  with pytest.raises(SchemasCatalogNotFoundException):
529
538
  ResourceSchema.all()
530
539
 
531
- @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
540
+ @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
532
541
  def test_resource_schema_objects_timeout_no_cache(self, client, rmock):
533
- rmock.get('https://example.com/schemas', exc=requests.exceptions.ConnectTimeout)
542
+ rmock.get("https://example.com/schemas", exc=requests.exceptions.ConnectTimeout)
534
543
  with pytest.raises(SchemasCacheUnavailableException):
535
544
  ResourceSchema.all()
536
545
 
537
- @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
546
+ @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
538
547
  def test_resource_schema_objects(self, app, rmock):
539
- rmock.get('https://example.com/schemas', json={
540
- "schemas": [
541
- {
542
- "name": "etalab/schema-irve",
543
- "title": "Schéma IRVE",
544
- "versions": [
545
- {
546
- "version_name": "1.0.0"
547
- },
548
- {
549
- "version_name": "1.0.1"
550
- },
551
- {
552
- "version_name": "1.0.2"
553
- }
554
- ]
555
- }
556
- ]
557
- })
548
+ rmock.get(
549
+ "https://example.com/schemas",
550
+ json={
551
+ "schemas": [
552
+ {
553
+ "name": "etalab/schema-irve",
554
+ "title": "Schéma IRVE",
555
+ "versions": [
556
+ {"version_name": "1.0.0"},
557
+ {"version_name": "1.0.1"},
558
+ {"version_name": "1.0.2"},
559
+ ],
560
+ }
561
+ ]
562
+ },
563
+ )
558
564
 
559
565
  assert ResourceSchema.all() == [
560
566
  {
561
567
  "name": "etalab/schema-irve",
562
568
  "title": "Schéma IRVE",
563
569
  "versions": [
564
- {
565
- "version_name": "1.0.0"
566
- },
567
- {
568
- "version_name": "1.0.1"
569
- },
570
- {
571
- "version_name": "1.0.2"
572
- }
573
- ]
570
+ {"version_name": "1.0.0"},
571
+ {"version_name": "1.0.1"},
572
+ {"version_name": "1.0.2"},
573
+ ],
574
574
  }
575
575
  ]
576
576
 
@@ -578,90 +578,96 @@ class ResourceSchemaTest:
578
578
  def test_resource_schema_objects_no_catalog_url(self):
579
579
  assert ResourceSchema.all() == []
580
580
 
581
- @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
581
+ @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
582
582
  def test_resource_schema_objects_w_cache(self, rmock, mocker):
583
- cache_mock_set = mocker.patch.object(cache, 'set')
583
+ cache_mock_set = mocker.patch.object(cache, "set")
584
584
 
585
585
  # fill cache
586
- rmock.get('https://example.com/schemas', json=ResourceSchemaMockData.get_mock_data())
586
+ rmock.get("https://example.com/schemas", json=ResourceSchemaMockData.get_mock_data())
587
587
  ResourceSchema.all()
588
588
  assert cache_mock_set.called
589
589
 
590
- mocker.patch.object(cache, 'get', return_value=ResourceSchemaMockData.get_mock_data()['schemas'])
591
- rmock.get('https://example.com/schemas', status_code=500)
592
- assert ResourceSchemaMockData.get_all_schemas_from_mock_data(with_datapackage_info=False) == ResourceSchema.all()
590
+ mocker.patch.object(
591
+ cache, "get", return_value=ResourceSchemaMockData.get_mock_data()["schemas"]
592
+ )
593
+ rmock.get("https://example.com/schemas", status_code=500)
594
+ assert (
595
+ ResourceSchemaMockData.get_all_schemas_from_mock_data(with_datapackage_info=False)
596
+ == ResourceSchema.all()
597
+ )
593
598
  assert rmock.call_count == 2
594
599
 
595
- @pytest.mark.options(SCHEMA_CATALOG_URL='https://example.com/schemas')
600
+ @pytest.mark.options(SCHEMA_CATALOG_URL="https://example.com/schemas")
596
601
  def test_resource_schema_validation(self, rmock):
597
- rmock.get('https://example.com/schemas', json=ResourceSchemaMockData.get_mock_data())
602
+ rmock.get("https://example.com/schemas", json=ResourceSchemaMockData.get_mock_data())
598
603
 
599
604
  resource = ResourceFactory()
600
605
 
601
- resource.schema = Schema(name='etalab/schema-irve-statique')
606
+ resource.schema = Schema(name="etalab/schema-irve-statique")
602
607
  resource.validate()
603
608
 
604
- resource.schema = Schema(url='https://example.com')
609
+ resource.schema = Schema(url="https://example.com")
605
610
  resource.validate()
606
611
 
607
- resource.schema = Schema(name='some-name', url='https://example.com')
612
+ resource.schema = Schema(name="some-name", url="https://example.com")
608
613
  resource.validate()
609
614
 
610
- resource.schema = Schema(name='etalab/schema-irve-statique')
615
+ resource.schema = Schema(name="etalab/schema-irve-statique")
611
616
  resource.schema.clean(check_schema_in_catalog=True)
612
617
 
613
- resource.schema = Schema(url='https://example.com')
618
+ resource.schema = Schema(url="https://example.com")
614
619
  resource.schema.clean(check_schema_in_catalog=True)
615
620
 
616
- resource.schema = Schema(name='some-name', url='https://example.com')
621
+ resource.schema = Schema(name="some-name", url="https://example.com")
617
622
  resource.schema.clean(check_schema_in_catalog=True)
618
623
 
619
624
  # Check that no exception is raised when we do not ask for schema check for schema errors
620
- resource.schema = Schema(name='some-name')
625
+ resource.schema = Schema(name="some-name")
621
626
  resource.validate()
622
627
 
623
- resource.schema = Schema(name='etalab/schema-irve-statique', version='1337.42.0')
628
+ resource.schema = Schema(name="etalab/schema-irve-statique", version="1337.42.0")
624
629
  resource.validate()
625
630
 
626
631
  with pytest.raises(db.ValidationError):
627
- resource.schema = Schema(version='2.0.0')
632
+ resource.schema = Schema(version="2.0.0")
628
633
  resource.validate()
629
634
 
630
635
  with pytest.raises(db.ValidationError):
631
- resource.schema = Schema(name='some-name')
636
+ resource.schema = Schema(name="some-name")
632
637
  resource.schema.clean(check_schema_in_catalog=True)
633
638
 
634
639
  with pytest.raises(db.ValidationError):
635
- resource.schema = Schema(name='etalab/schema-irve-statique', version='1337.42.0')
640
+ resource.schema = Schema(name="etalab/schema-irve-statique", version="1337.42.0")
636
641
  resource.schema.clean(check_schema_in_catalog=True)
637
642
 
638
643
  with pytest.raises(db.ValidationError):
639
- resource.schema = Schema(version='2.0.0')
644
+ resource.schema = Schema(version="2.0.0")
640
645
  resource.schema.clean(check_schema_in_catalog=True)
641
646
 
647
+
642
648
  class HarvestMetadataTest:
643
649
  def test_harvest_dataset_metadata_validate_success(self):
644
650
  dataset = DatasetFactory()
645
651
 
646
652
  harvest_metadata = HarvestDatasetMetadata(
647
- backend='DCAT',
653
+ backend="DCAT",
648
654
  created_at=datetime.utcnow(),
649
655
  modified_at=datetime.utcnow(),
650
- source_id='source_id',
651
- remote_id='remote_id',
652
- domain='domain.gouv.fr',
656
+ source_id="source_id",
657
+ remote_id="remote_id",
658
+ domain="domain.gouv.fr",
653
659
  last_update=datetime.utcnow(),
654
- remote_url='http://domain.gouv.fr/dataset/remote_url',
655
- uri='http://domain.gouv.fr/dataset/uri',
656
- dct_identifier='http://domain.gouv.fr/dataset/identifier',
660
+ remote_url="http://domain.gouv.fr/dataset/remote_url",
661
+ uri="http://domain.gouv.fr/dataset/uri",
662
+ dct_identifier="http://domain.gouv.fr/dataset/identifier",
657
663
  archived_at=datetime.utcnow(),
658
- archived='not-on-remote'
664
+ archived="not-on-remote",
659
665
  )
660
666
  dataset.harvest = harvest_metadata
661
667
  dataset.save()
662
668
 
663
669
  def test_harvest_dataset_metadata_validation_error(self):
664
- harvest_metadata = HarvestDatasetMetadata(created_at='maintenant')
670
+ harvest_metadata = HarvestDatasetMetadata(created_at="maintenant")
665
671
  dataset = DatasetFactory()
666
672
  dataset.harvest = harvest_metadata
667
673
  with pytest.raises(db.ValidationError):
@@ -670,7 +676,7 @@ class HarvestMetadataTest:
670
676
  def test_harvest_dataset_metadata_no_validation_dynamic(self):
671
677
  # Adding a dynamic field (not defined in HarvestDatasetMetadata) does not raise error
672
678
  # at validation time
673
- harvest_metadata = HarvestDatasetMetadata(dynamic_created_at='maintenant')
679
+ harvest_metadata = HarvestDatasetMetadata(dynamic_created_at="maintenant")
674
680
  dataset = DatasetFactory()
675
681
  dataset.harvest = harvest_metadata
676
682
  dataset.save()
@@ -679,8 +685,7 @@ class HarvestMetadataTest:
679
685
  dataset = DatasetFactory()
680
686
 
681
687
  harvest_metadata = HarvestDatasetMetadata(
682
- created_at=datetime.utcnow(),
683
- modified_at=datetime.utcnow()+timedelta(days=1)
688
+ created_at=datetime.utcnow(), modified_at=datetime.utcnow() + timedelta(days=1)
684
689
  )
685
690
  dataset.harvest = harvest_metadata
686
691
  dataset.save()
@@ -703,13 +708,13 @@ class HarvestMetadataTest:
703
708
  harvest_metadata = HarvestResourceMetadata(
704
709
  created_at=datetime.utcnow(),
705
710
  modified_at=datetime.utcnow(),
706
- uri='http://domain.gouv.fr/dataset/uri'
711
+ uri="http://domain.gouv.fr/dataset/uri",
707
712
  )
708
713
  resource.harvest = harvest_metadata
709
714
  resource.validate()
710
715
 
711
716
  def test_harvest_resource_metadata_validation_error(self):
712
- harvest_metadata = HarvestResourceMetadata(created_at='maintenant')
717
+ harvest_metadata = HarvestResourceMetadata(created_at="maintenant")
713
718
  resource = ResourceFactory()
714
719
  resource.harvest = harvest_metadata
715
720
  with pytest.raises(db.ValidationError):
@@ -718,14 +723,16 @@ class HarvestMetadataTest:
718
723
  def test_harvest_resource_metadata_no_validation_dynamic(self):
719
724
  # Adding a dynamic field (not defined in HarvestResourceMetadata) does not raise error
720
725
  # at validation time
721
- harvest_metadata = HarvestResourceMetadata(dynamic_created_at='maintenant')
726
+ harvest_metadata = HarvestResourceMetadata(dynamic_created_at="maintenant")
722
727
  resource = ResourceFactory()
723
728
  resource.harvest = harvest_metadata
724
729
  resource.validate()
725
730
 
726
731
  def test_harvest_resource_metadata_future_modifed_at(self):
727
732
  resource = ResourceFactory()
728
- harvest_metadata = HarvestResourceMetadata(modified_at=datetime.utcnow()+timedelta(days=1))
733
+ harvest_metadata = HarvestResourceMetadata(
734
+ modified_at=datetime.utcnow() + timedelta(days=1)
735
+ )
729
736
  resource.harvest = harvest_metadata
730
737
  resource.validate()
731
738
 
@@ -740,8 +747,8 @@ class HarvestMetadataTest:
740
747
  assert resource.last_modified == harvest_metadata.modified_at
741
748
 
742
749
  def test_resource_metadata_extra_modifed_at(self):
743
- resource = ResourceFactory(filetype='remote')
744
- resource.extras.update({'analysis:last-modified-at': datetime(2023,1,1)})
750
+ resource = ResourceFactory(filetype="remote")
751
+ resource.extras.update({"analysis:last-modified-at": datetime(2023, 1, 1)})
745
752
  resource.validate()
746
753
 
747
- assert resource.last_modified == resource.extras['analysis:last-modified-at']
754
+ assert resource.last_modified == resource.extras["analysis:last-modified-at"]