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/rdf.py CHANGED
@@ -1,71 +1,80 @@
1
- '''
1
+ """
2
2
  This module centralize udata-wide RDF helpers and configuration
3
- '''
4
- from html.parser import HTMLParser
3
+ """
4
+
5
5
  import logging
6
6
  import re
7
+ from html.parser import HTMLParser
7
8
 
8
- from flask import request, url_for, abort, current_app
9
-
9
+ from flask import abort, current_app, request, url_for
10
10
  from rdflib import Graph, Literal, URIRef
11
- from rdflib.resource import Resource as RdfResource
12
11
  from rdflib.namespace import (
13
- Namespace, NamespaceManager, DCTERMS, SKOS, FOAF, XSD, RDFS, RDF
12
+ DCTERMS,
13
+ FOAF,
14
+ RDF,
15
+ RDFS,
16
+ SKOS,
17
+ XSD,
18
+ Namespace,
19
+ NamespaceManager,
14
20
  )
15
- from rdflib.util import SUFFIX_FORMAT_MAP, guess_format as raw_guess_format
21
+ from rdflib.resource import Resource as RdfResource
22
+ from rdflib.util import SUFFIX_FORMAT_MAP
23
+ from rdflib.util import guess_format as raw_guess_format
24
+
16
25
  from udata import uris
17
26
  from udata.core.contact_point.models import ContactPoint
27
+ from udata.frontend.markdown import parse_html
18
28
  from udata.models import Schema
19
29
  from udata.mongo.errors import FieldValidationError
20
- from udata.frontend.markdown import parse_html
21
30
  from udata.tags import slug as slugify_tag
22
31
 
23
32
  log = logging.getLogger(__name__)
24
33
 
25
34
  # Extra Namespaces
26
- ADMS = Namespace('http://www.w3.org/ns/adms#')
27
- DCAT = Namespace('http://www.w3.org/ns/dcat#')
28
- DCATAP = Namespace('http://data.europa.eu/r5r/')
29
- HYDRA = Namespace('http://www.w3.org/ns/hydra/core#')
30
- SCHEMA = Namespace('http://schema.org/')
31
- SCV = Namespace('http://purl.org/NET/scovo#')
32
- SPDX = Namespace('http://spdx.org/rdf/terms#')
33
- VCARD = Namespace('http://www.w3.org/2006/vcard/ns#')
34
- FREQ = Namespace('http://purl.org/cld/freq/')
35
- EUFREQ = Namespace('http://publications.europa.eu/resource/authority/frequency/') # noqa: E501
36
- EUFORMAT = Namespace('http://publications.europa.eu/resource/authority/file-type/')
37
- IANAFORMAT = Namespace('https://www.iana.org/assignments/media-types/')
35
+ ADMS = Namespace("http://www.w3.org/ns/adms#")
36
+ DCAT = Namespace("http://www.w3.org/ns/dcat#")
37
+ DCATAP = Namespace("http://data.europa.eu/r5r/")
38
+ HYDRA = Namespace("http://www.w3.org/ns/hydra/core#")
39
+ SCHEMA = Namespace("http://schema.org/")
40
+ SCV = Namespace("http://purl.org/NET/scovo#")
41
+ SPDX = Namespace("http://spdx.org/rdf/terms#")
42
+ VCARD = Namespace("http://www.w3.org/2006/vcard/ns#")
43
+ FREQ = Namespace("http://purl.org/cld/freq/")
44
+ EUFREQ = Namespace("http://publications.europa.eu/resource/authority/frequency/") # noqa: E501
45
+ EUFORMAT = Namespace("http://publications.europa.eu/resource/authority/file-type/")
46
+ IANAFORMAT = Namespace("https://www.iana.org/assignments/media-types/")
38
47
  DCT = DCTERMS # More common usage
39
- VCARD = Namespace('http://www.w3.org/2006/vcard/ns#')
48
+ VCARD = Namespace("http://www.w3.org/2006/vcard/ns#")
40
49
 
41
50
  namespace_manager = NamespaceManager(Graph())
42
- namespace_manager.bind('dcat', DCAT)
43
- namespace_manager.bind('dcatap', DCATAP)
44
- namespace_manager.bind('dct', DCT)
45
- namespace_manager.bind('foaf', FOAF)
46
- namespace_manager.bind('foaf', FOAF)
47
- namespace_manager.bind('hydra', HYDRA)
48
- namespace_manager.bind('rdfs', RDFS)
49
- namespace_manager.bind('scv', SCV)
50
- namespace_manager.bind('skos', SKOS)
51
- namespace_manager.bind('vcard', VCARD)
52
- namespace_manager.bind('xsd', XSD)
53
- namespace_manager.bind('freq', FREQ)
51
+ namespace_manager.bind("dcat", DCAT)
52
+ namespace_manager.bind("dcatap", DCATAP)
53
+ namespace_manager.bind("dct", DCT)
54
+ namespace_manager.bind("foaf", FOAF)
55
+ namespace_manager.bind("foaf", FOAF)
56
+ namespace_manager.bind("hydra", HYDRA)
57
+ namespace_manager.bind("rdfs", RDFS)
58
+ namespace_manager.bind("scv", SCV)
59
+ namespace_manager.bind("skos", SKOS)
60
+ namespace_manager.bind("vcard", VCARD)
61
+ namespace_manager.bind("xsd", XSD)
62
+ namespace_manager.bind("freq", FREQ)
54
63
 
55
64
  # Support JSON-LD in format detection
56
65
  FORMAT_MAP = SUFFIX_FORMAT_MAP.copy()
57
- FORMAT_MAP['json'] = 'json-ld'
58
- FORMAT_MAP['jsonld'] = 'json-ld'
59
- FORMAT_MAP['xml'] = 'xml'
66
+ FORMAT_MAP["json"] = "json-ld"
67
+ FORMAT_MAP["jsonld"] = "json-ld"
68
+ FORMAT_MAP["xml"] = "xml"
60
69
 
61
70
  # Map serialization formats to MIME types
62
71
  RDF_MIME_TYPES = {
63
- 'xml': 'application/rdf+xml',
64
- 'n3': 'text/n3',
65
- 'turtle': 'application/x-turtle',
66
- 'nt': 'application/n-triples',
67
- 'json-ld': 'application/ld+json',
68
- 'trig': 'application/trig',
72
+ "xml": "application/rdf+xml",
73
+ "n3": "text/n3",
74
+ "turtle": "application/x-turtle",
75
+ "nt": "application/n-triples",
76
+ "json-ld": "application/ld+json",
77
+ "trig": "application/trig",
69
78
  # Available but not activated
70
79
  # 'nquads': 'application/n-quads',
71
80
  # 'trix': 'text/xml',
@@ -73,16 +82,16 @@ RDF_MIME_TYPES = {
73
82
 
74
83
  # Map accepted MIME types to known formats
75
84
  ACCEPTED_MIME_TYPES = {
76
- 'application/rdf+xml': 'xml',
77
- 'application/xml': 'xml',
78
- 'text/n3': 'n3',
79
- 'application/x-turtle': 'turtle',
80
- 'text/turtle': 'turtle',
81
- 'application/n-triples': 'nt',
82
- 'application/ld+json': 'json-ld',
83
- 'application/json': 'json-ld',
84
- 'application/trig': 'trig',
85
- 'text/xml': 'xml',
85
+ "application/rdf+xml": "xml",
86
+ "application/xml": "xml",
87
+ "text/n3": "n3",
88
+ "application/x-turtle": "turtle",
89
+ "text/turtle": "turtle",
90
+ "application/n-triples": "nt",
91
+ "application/ld+json": "json-ld",
92
+ "application/json": "json-ld",
93
+ "application/trig": "trig",
94
+ "text/xml": "xml",
86
95
  # Available but not activated
87
96
  # 'application/n-quads': 'nquads',
88
97
  # 'text/xml': 'trix',
@@ -90,19 +99,19 @@ ACCEPTED_MIME_TYPES = {
90
99
 
91
100
  # Map formats to default used extensions
92
101
  RDF_EXTENSIONS = {
93
- 'xml': 'xml',
94
- 'n3': 'n3',
95
- 'turtle': 'ttl',
96
- 'nt': 'nt',
97
- 'trig': 'trig',
98
- 'json-ld': 'json',
102
+ "xml": "xml",
103
+ "n3": "n3",
104
+ "turtle": "ttl",
105
+ "nt": "nt",
106
+ "trig": "trig",
107
+ "json-ld": "json",
99
108
  # Available but not activated
100
109
  # 'nquads': 'nq',
101
110
  # 'trix': 'trix',
102
111
  }
103
112
 
104
113
  # Includes control characters, unicode surrogate characters and unicode end-of-plane non-characters
105
- ILLEGAL_XML_CHARS = '[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]'
114
+ ILLEGAL_XML_CHARS = "[\x00-\x08\x0b\x0c\x0e-\x1f\ud800-\udfff\ufffe\uffff]"
106
115
 
107
116
  # Map High Value Datasets URIs to keyword categories
108
117
  EU_HVD_CATEGORIES = {
@@ -111,26 +120,27 @@ EU_HVD_CATEGORIES = {
111
120
  "http://data.europa.eu/bna/c_ac64a52d": "Géospatiales",
112
121
  "http://data.europa.eu/bna/c_b79e35eb": "Mobilité",
113
122
  "http://data.europa.eu/bna/c_dd313021": "Observation de la terre et environnement",
114
- "http://data.europa.eu/bna/c_e1da4e07": "Statistiques"
123
+ "http://data.europa.eu/bna/c_e1da4e07": "Statistiques",
115
124
  }
116
- HVD_LEGISLATION = 'http://data.europa.eu/eli/reg_impl/2023/138/oj'
125
+ HVD_LEGISLATION = "http://data.europa.eu/eli/reg_impl/2023/138/oj"
117
126
  TAG_TO_EU_HVD_CATEGORIES = {slugify_tag(EU_HVD_CATEGORIES[uri]): uri for uri in EU_HVD_CATEGORIES}
118
127
 
128
+
119
129
  def guess_format(string):
120
- '''Guess format given an extension or a mime-type'''
130
+ """Guess format given an extension or a mime-type"""
121
131
  if string in ACCEPTED_MIME_TYPES:
122
132
  return ACCEPTED_MIME_TYPES[string]
123
133
  return raw_guess_format(string, FORMAT_MAP)
124
134
 
125
135
 
126
- def negociate_content(default='json-ld'):
127
- '''Perform a content negociation on the format given the Accept header'''
136
+ def negociate_content(default="json-ld"):
137
+ """Perform a content negociation on the format given the Accept header"""
128
138
  mimetype = request.accept_mimetypes.best_match(ACCEPTED_MIME_TYPES.keys())
129
139
  return ACCEPTED_MIME_TYPES.get(mimetype, default)
130
140
 
131
141
 
132
142
  def want_rdf():
133
- '''Check wether client prefer RDF over the default HTML'''
143
+ """Check wether client prefer RDF over the default HTML"""
134
144
  mimetype = request.accept_mimetypes.best
135
145
  return mimetype in ACCEPTED_MIME_TYPES
136
146
 
@@ -138,97 +148,56 @@ def want_rdf():
138
148
  # JSON-LD context used for udata DCAT representation
139
149
  CONTEXT = {
140
150
  # Namespaces
141
- '@vocab': 'http://www.w3.org/ns/dcat#',
142
- 'dcat': 'http://www.w3.org/ns/dcat#',
143
- 'dct': 'http://purl.org/dc/terms/',
144
- 'foaf': 'http://xmlns.com/foaf/0.1/',
145
- 'org': 'http://www.w3.org/ns/org#',
146
- 'rdfs': 'http://www.w3.org/2000/01/rdf-schema#',
147
- 'skos': 'http://www.w3.org/2004/02/skos/core#',
148
- 'spdx': 'http://spdx.org/rdf/terms#',
149
- 'vcard': 'http://www.w3.org/2006/vcard/ns#',
150
- 'schema': 'http://schema.org/',
151
- 'hydra': 'http://www.w3.org/ns/hydra/core#',
152
- 'freq': 'http://purl.org/cld/freq/',
151
+ "@vocab": "http://www.w3.org/ns/dcat#",
152
+ "dcat": "http://www.w3.org/ns/dcat#",
153
+ "dct": "http://purl.org/dc/terms/",
154
+ "foaf": "http://xmlns.com/foaf/0.1/",
155
+ "org": "http://www.w3.org/ns/org#",
156
+ "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
157
+ "skos": "http://www.w3.org/2004/02/skos/core#",
158
+ "spdx": "http://spdx.org/rdf/terms#",
159
+ "vcard": "http://www.w3.org/2006/vcard/ns#",
160
+ "schema": "http://schema.org/",
161
+ "hydra": "http://www.w3.org/ns/hydra/core#",
162
+ "freq": "http://purl.org/cld/freq/",
153
163
  # Aliased field
154
- 'downloadURL': {
155
- '@id': 'dcat:downloadURL',
156
- '@type': '@id'
157
- },
158
- 'accessURL': {
159
- '@id': 'dcat:accessURL',
160
- '@type': '@id'
161
- },
162
- 'dataset': {
163
- '@id': 'dcat:dataset',
164
- '@type': '@id'
165
- },
166
- 'distribution': {
167
- '@id': 'dcat:distribution',
168
- '@type': '@id'
169
- },
170
- 'title': 'dct:title',
171
- 'description': 'dct:description',
172
- 'issued': {
173
- '@id': 'dct:issued',
174
- '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
175
- },
176
- 'modified': {
177
- '@id': 'dct:modified',
178
- '@type': 'http://www.w3.org/2001/XMLSchema#dateTime'
179
- },
180
- 'language': 'dct:language',
181
- 'license': 'dct:license',
182
- 'rights': 'dct:rights',
183
- 'spatial': 'dct:spatial',
184
- 'identifier': 'dct:identifier',
185
- 'temporal': 'dct:temporal',
186
- 'format': 'dct:format',
187
- 'accrualPeriodicity': 'dct:accrualPeriodicity',
188
- 'homepage': {
189
- '@id': 'foaf:homepage',
190
- '@type': '@id'
191
- },
192
- 'publisher': {
193
- '@id': 'dct:publisher',
194
- '@type': '@id'
195
- },
196
- 'fn': 'vcard:fn',
197
- 'hasEmail': 'vcard:email',
198
- 'subOrganizationOf': 'org:subOrganizationOf',
199
- 'checksum': 'spdx:checksum',
200
- 'algorithm': {
201
- '@id': 'spdx:algorithm',
202
- '@type': '@id'
203
- },
204
- 'checksumValue': 'spdx:checksumValue',
205
- 'label': 'rdfs:label',
206
- 'name': 'foaf:name',
207
- 'startDate': 'schema:startDate',
208
- 'endDate': 'schema:endDate',
209
- 'view': {
210
- '@id': 'hydra:view',
211
- '@type': '@id'
212
- },
213
- 'first': {
214
- '@id': 'hydra:first',
215
- '@type': '@id'
216
- },
217
- 'last': {
218
- '@id': 'hydra:last',
219
- '@type': '@id'
220
- },
221
- 'next': {
222
- '@id': 'hydra:next',
223
- '@type': '@id'
224
- },
225
- 'previous': {
226
- '@id': 'hydra:previous',
227
- '@type': '@id'
228
- },
229
- 'totalItems': 'hydra:totalItems',
164
+ "downloadURL": {"@id": "dcat:downloadURL", "@type": "@id"},
165
+ "accessURL": {"@id": "dcat:accessURL", "@type": "@id"},
166
+ "dataset": {"@id": "dcat:dataset", "@type": "@id"},
167
+ "distribution": {"@id": "dcat:distribution", "@type": "@id"},
168
+ "title": "dct:title",
169
+ "description": "dct:description",
170
+ "issued": {"@id": "dct:issued", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"},
171
+ "modified": {"@id": "dct:modified", "@type": "http://www.w3.org/2001/XMLSchema#dateTime"},
172
+ "language": "dct:language",
173
+ "license": "dct:license",
174
+ "rights": "dct:rights",
175
+ "spatial": "dct:spatial",
176
+ "identifier": "dct:identifier",
177
+ "temporal": "dct:temporal",
178
+ "format": "dct:format",
179
+ "accrualPeriodicity": "dct:accrualPeriodicity",
180
+ "homepage": {"@id": "foaf:homepage", "@type": "@id"},
181
+ "publisher": {"@id": "dct:publisher", "@type": "@id"},
182
+ "fn": "vcard:fn",
183
+ "hasEmail": "vcard:email",
184
+ "subOrganizationOf": "org:subOrganizationOf",
185
+ "checksum": "spdx:checksum",
186
+ "algorithm": {"@id": "spdx:algorithm", "@type": "@id"},
187
+ "checksumValue": "spdx:checksumValue",
188
+ "label": "rdfs:label",
189
+ "name": "foaf:name",
190
+ "startDate": "schema:startDate",
191
+ "endDate": "schema:endDate",
192
+ "view": {"@id": "hydra:view", "@type": "@id"},
193
+ "first": {"@id": "hydra:first", "@type": "@id"},
194
+ "last": {"@id": "hydra:last", "@type": "@id"},
195
+ "next": {"@id": "hydra:next", "@type": "@id"},
196
+ "previous": {"@id": "hydra:previous", "@type": "@id"},
197
+ "totalItems": "hydra:totalItems",
230
198
  }
231
199
 
200
+
232
201
  def serialize_value(value):
233
202
  if isinstance(value, (URIRef, Literal)):
234
203
  return value.toPython()
@@ -240,6 +209,7 @@ def rdf_value(obj, predicate, default=None):
240
209
  value = obj.value(predicate)
241
210
  return serialize_value(value) if value else default
242
211
 
212
+
243
213
  class HTMLDetector(HTMLParser):
244
214
  def __init__(self, *args, **kwargs):
245
215
  HTMLParser.__init__(self, *args, **kwargs)
@@ -259,7 +229,7 @@ def is_html(text):
259
229
 
260
230
 
261
231
  def sanitize_html(text):
262
- text = text.toPython() if isinstance(text, Literal) else ''
232
+ text = text.toPython() if isinstance(text, Literal) else ""
263
233
  if is_html(text):
264
234
  return parse_html(text)
265
235
  else:
@@ -267,28 +237,29 @@ def sanitize_html(text):
267
237
 
268
238
 
269
239
  def url_from_rdf(rdf, prop):
270
- '''
240
+ """
271
241
  Try to extract An URL from a resource property.
272
242
  It can be expressed in many forms as a URIRef or a Literal
273
- '''
243
+ """
274
244
  value = rdf.value(prop)
275
245
  if isinstance(value, (URIRef, Literal)):
276
246
  return value.toPython()
277
247
  elif isinstance(value, RdfResource):
278
248
  return value.identifier.toPython()
279
249
 
250
+
280
251
  def theme_labels_from_rdf(rdf):
281
- '''
252
+ """
282
253
  Get theme labels to use as keywords.
283
254
  Map HVD keywords from known URIs resources if HVD support is activated.
284
- '''
255
+ """
285
256
  for theme in rdf.objects(DCAT.theme):
286
257
  if isinstance(theme, RdfResource):
287
258
  uri = theme.identifier.toPython()
288
- if current_app.config['HVD_SUPPORT'] and uri in EU_HVD_CATEGORIES:
259
+ if current_app.config["HVD_SUPPORT"] and uri in EU_HVD_CATEGORIES:
289
260
  label = EU_HVD_CATEGORIES[uri]
290
261
  # Additionnally yield hvd keyword
291
- yield 'hvd'
262
+ yield "hvd"
292
263
  else:
293
264
  label = rdf_value(theme, SKOS.prefLabel)
294
265
  else:
@@ -296,37 +267,45 @@ def theme_labels_from_rdf(rdf):
296
267
  if label:
297
268
  yield label
298
269
 
270
+
299
271
  def themes_from_rdf(rdf):
300
272
  tags = [tag.toPython() for tag in rdf.objects(DCAT.keyword)]
301
273
  tags += theme_labels_from_rdf(rdf)
302
274
  return list(set(tags))
303
275
 
276
+
304
277
  def contact_point_from_rdf(rdf, dataset):
305
278
  contact_point = rdf.value(DCAT.contactPoint)
306
279
  if contact_point:
307
- name = rdf_value(contact_point, VCARD.fn) or ''
308
- email = (rdf_value(contact_point, VCARD.hasEmail)
309
- or rdf_value(contact_point, VCARD.email)
310
- or rdf_value(contact_point, DCAT.email))
280
+ name = rdf_value(contact_point, VCARD.fn) or ""
281
+ email = (
282
+ rdf_value(contact_point, VCARD.hasEmail)
283
+ or rdf_value(contact_point, VCARD.email)
284
+ or rdf_value(contact_point, DCAT.email)
285
+ )
311
286
  if not email:
312
287
  return
313
- email = email.replace('mailto:', '').strip()
288
+ email = email.replace("mailto:", "").strip()
314
289
  if dataset.organization:
315
290
  contact_point = ContactPoint.objects(
316
- name=name, email=email, organization=dataset.organization).first()
317
- return (contact_point or
318
- ContactPoint(name=name, email=email, organization=dataset.organization).save())
291
+ name=name, email=email, organization=dataset.organization
292
+ ).first()
293
+ return (
294
+ contact_point
295
+ or ContactPoint(name=name, email=email, organization=dataset.organization).save()
296
+ )
319
297
  elif dataset.owner:
320
298
  contact_point = ContactPoint.objects(
321
- name=name, email=email, owner=dataset.owner).first()
322
- return (contact_point or
323
- ContactPoint(name=name, email=email, owner=dataset.owner).save())
299
+ name=name, email=email, owner=dataset.owner
300
+ ).first()
301
+ return contact_point or ContactPoint(name=name, email=email, owner=dataset.owner).save()
302
+
324
303
 
325
304
  def remote_url_from_rdf(rdf):
326
- '''
305
+ """
327
306
  Return DCAT.landingPage if found and uri validation succeeds.
328
307
  Use RDF identifier as fallback if uri validation succeeds.
329
- '''
308
+ """
330
309
  landing_page = url_from_rdf(rdf, DCAT.landingPage)
331
310
  uri = rdf.identifier.toPython()
332
311
  for candidate in [landing_page, uri]:
@@ -337,11 +316,12 @@ def remote_url_from_rdf(rdf):
337
316
  except uris.ValidationError:
338
317
  pass
339
318
 
319
+
340
320
  def schema_from_rdf(rdf):
341
- '''
321
+ """
342
322
  Try to extract a schema from a conformsTo property.
343
323
  Currently the "issued" property is not harvest.
344
- '''
324
+ """
345
325
  resource = rdf.value(DCT.conformsTo)
346
326
  if not resource:
347
327
  return None
@@ -380,20 +360,21 @@ def schema_from_rdf(rdf):
380
360
  log.warning(f"Invalid schema inside RDF {e}")
381
361
  return None
382
362
 
383
- def escape_xml_illegal_chars(val, replacement='?'):
363
+
364
+ def escape_xml_illegal_chars(val, replacement="?"):
384
365
  illegal_xml_chars_RE = re.compile(ILLEGAL_XML_CHARS)
385
366
  return illegal_xml_chars_RE.sub(replacement, val)
386
367
 
387
368
 
388
369
  def paginate_catalog(catalog, graph, datasets, format, rdf_catalog_endpoint, **values):
389
370
  if not format:
390
- raise ValueError('Pagination requires format')
371
+ raise ValueError("Pagination requires format")
391
372
  catalog.add(RDF.type, HYDRA.Collection)
392
373
  catalog.set(HYDRA.totalItems, Literal(datasets.total))
393
374
  kwargs = {
394
- 'format': format,
395
- 'page_size': datasets.page_size,
396
- '_external': True,
375
+ "format": format,
376
+ "page_size": datasets.page_size,
377
+ "_external": True,
397
378
  }
398
379
 
399
380
  kwargs.update(values)
@@ -419,18 +400,16 @@ def paginate_catalog(catalog, graph, datasets, format, rdf_catalog_endpoint, **v
419
400
 
420
401
 
421
402
  def graph_response(graph, format):
422
- '''
403
+ """
423
404
  Return a proper flask response for a RDF resource given an expected format.
424
- '''
405
+ """
425
406
  fmt = guess_format(format)
426
407
  if not fmt:
427
408
  abort(404)
428
- headers = {
429
- 'Content-Type': RDF_MIME_TYPES[fmt]
430
- }
409
+ headers = {"Content-Type": RDF_MIME_TYPES[fmt]}
431
410
  kwargs = {}
432
- if fmt == 'json-ld':
433
- kwargs['context'] = CONTEXT
411
+ if fmt == "json-ld":
412
+ kwargs["context"] = CONTEXT
434
413
  if isinstance(graph, RdfResource):
435
414
  graph = graph.graph
436
415
  return escape_xml_illegal_chars(graph.serialize(format=fmt, **kwargs)), 200, headers