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/utils.py CHANGED
@@ -1,54 +1,54 @@
1
1
  import hashlib
2
2
  import math
3
3
  import re
4
+ from datetime import date, datetime
5
+ from math import ceil
6
+ from uuid import UUID, uuid4
7
+ from xml.sax.saxutils import escape
4
8
 
5
9
  import factory
6
-
7
10
  from bson import ObjectId
8
11
  from bson.errors import InvalidId
9
- from datetime import date, datetime
10
- from dateutil.relativedelta import relativedelta
11
12
  from dateutil.parser import parse as parse_dt
13
+ from dateutil.relativedelta import relativedelta
12
14
  from faker import Faker
13
15
  from faker.config import PROVIDERS
14
16
  from faker.providers import BaseProvider
15
17
  from faker.providers.lorem.la import Provider as LoremProvider
16
18
  from flask import abort
17
- from math import ceil
18
- from uuid import uuid4, UUID
19
- from xml.sax.saxutils import escape
20
19
 
21
20
 
22
21
  def get_by(lst, field, value):
23
- '''Find an object in a list given a field value'''
22
+ """Find an object in a list given a field value"""
24
23
  for row in lst:
25
- if ((isinstance(row, dict) and row.get(field) == value) or
26
- (getattr(row, field, None) == value)):
24
+ if (isinstance(row, dict) and row.get(field) == value) or (
25
+ getattr(row, field, None) == value
26
+ ):
27
27
  return row
28
28
 
29
29
 
30
30
  def multi_to_dict(multi):
31
- '''Transform a Werkzeug multidictionnary into a flat dictionnary'''
31
+ """Transform a Werkzeug multidictionnary into a flat dictionnary"""
32
32
  return dict(
33
- (key, value[0] if len(value) == 1 else value)
34
- for key, value in multi.to_dict(False).items()
33
+ (key, value[0] if len(value) == 1 else value) for key, value in multi.to_dict(False).items()
35
34
  )
36
35
 
37
36
 
38
- FIRST_CAP_RE = re.compile('(.)([A-Z][a-z]+)')
39
- ALL_CAP_RE = re.compile('([a-z0-9])([A-Z])')
37
+ FIRST_CAP_RE = re.compile("(.)([A-Z][a-z]+)")
38
+ ALL_CAP_RE = re.compile("([a-z0-9])([A-Z])")
40
39
  UUID_LENGTH = 36
41
40
 
42
41
 
43
42
  def camel_to_lodash(name):
44
- s1 = FIRST_CAP_RE.sub(r'\1_\2', name)
45
- return ALL_CAP_RE.sub(r'\1_\2', s1).lower()
43
+ s1 = FIRST_CAP_RE.sub(r"\1_\2", name)
44
+ return ALL_CAP_RE.sub(r"\1_\2", s1).lower()
46
45
 
47
46
 
48
47
  class Paginable(object):
49
- '''
48
+ """
50
49
  A simple helper mixin for pagination
51
- '''
50
+ """
51
+
52
52
  @property
53
53
  def pages(self):
54
54
  if self.page_size:
@@ -75,14 +75,14 @@ class Paginable(object):
75
75
  def page_end(self):
76
76
  return min(self.total, self.page_size * self.page)
77
77
 
78
- def iter_pages(self, left_edge=2, left_current=2, right_current=5,
79
- right_edge=2):
78
+ def iter_pages(self, left_edge=2, left_current=2, right_current=5, right_edge=2):
80
79
  last = 0
81
80
  for num in range(1, self.pages + 1):
82
- if (num <= left_edge or
83
- (num > self.page - left_current - 1 and
84
- num < self.page + right_current) or
85
- num > self.pages - right_edge):
81
+ if (
82
+ num <= left_edge
83
+ or (num > self.page - left_current - 1 and num < self.page + right_current)
84
+ or num > self.pages - right_edge
85
+ ):
86
86
  if last + 1 != num:
87
87
  yield None
88
88
  yield num
@@ -90,7 +90,8 @@ class Paginable(object):
90
90
 
91
91
 
92
92
  class Paginator(Paginable):
93
- '''A simple paginable implementation'''
93
+ """A simple paginable implementation"""
94
+
94
95
  def __init__(self, page, page_size, total):
95
96
  self.page = page
96
97
  self.page_size = page_size
@@ -98,7 +99,7 @@ class Paginator(Paginable):
98
99
 
99
100
 
100
101
  def daterange_start(value):
101
- '''Parse a date range start boundary'''
102
+ """Parse a date range start boundary"""
102
103
  if not value:
103
104
  return None
104
105
  elif isinstance(value, datetime):
@@ -107,7 +108,7 @@ def daterange_start(value):
107
108
  return value
108
109
 
109
110
  result = parse_dt(value).date()
110
- dashes = value.count('-')
111
+ dashes = value.count("-")
111
112
 
112
113
  if dashes >= 2:
113
114
  return result
@@ -120,7 +121,7 @@ def daterange_start(value):
120
121
 
121
122
 
122
123
  def daterange_end(value):
123
- '''Parse a date range end boundary'''
124
+ """Parse a date range end boundary"""
124
125
  if not value:
125
126
  return None
126
127
  elif isinstance(value, datetime):
@@ -129,7 +130,7 @@ def daterange_end(value):
129
130
  return value
130
131
 
131
132
  result = parse_dt(value).date()
132
- dashes = value.count('-')
133
+ dashes = value.count("-")
133
134
 
134
135
  if dashes >= 2:
135
136
  # Full date
@@ -146,22 +147,18 @@ def to_naive_datetime(given_date):
146
147
  if isinstance(given_date, str):
147
148
  given_date = parse_dt(given_date)
148
149
  if isinstance(given_date, date) and not isinstance(given_date, datetime):
149
- return datetime(
150
- given_date.year,
151
- given_date.month,
152
- given_date.day
153
- )
150
+ return datetime(given_date.year, given_date.month, given_date.day)
154
151
  elif isinstance(given_date, datetime):
155
152
  return given_date.replace(tzinfo=None)
156
153
  return given_date
157
154
 
158
155
 
159
156
  def to_iso(dt):
160
- '''
157
+ """
161
158
  Format a date or datetime into an ISO-8601 string
162
159
 
163
160
  Support dates before 1900.
164
- '''
161
+ """
165
162
  if isinstance(dt, datetime):
166
163
  return to_iso_datetime(dt)
167
164
  elif isinstance(dt, date):
@@ -169,43 +166,46 @@ def to_iso(dt):
169
166
 
170
167
 
171
168
  def to_iso_date(dt):
172
- '''
169
+ """
173
170
  Format a date or datetime into an ISO-8601 date string.
174
171
 
175
172
  Support dates before 1900.
176
- '''
173
+ """
177
174
  if dt:
178
- return '{dt.year:04d}-{dt.month:02d}-{dt.day:02d}'.format(dt=dt)
175
+ return "{dt.year:04d}-{dt.month:02d}-{dt.day:02d}".format(dt=dt)
179
176
 
180
177
 
181
178
  def to_iso_datetime(dt):
182
- '''
179
+ """
183
180
  Format a date or datetime into an ISO-8601 datetime string.
184
181
 
185
182
  Time is set to 00:00:00 for dates.
186
183
 
187
184
  Support dates before 1900.
188
- '''
185
+ """
189
186
  if dt:
190
187
  date_str = to_iso_date(dt)
191
- time_str = '{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}'.format(
192
- dt=dt) if isinstance(dt, datetime) else '00:00:00'
193
- return 'T'.join((date_str, time_str))
188
+ time_str = (
189
+ "{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}".format(dt=dt)
190
+ if isinstance(dt, datetime)
191
+ else "00:00:00"
192
+ )
193
+ return "T".join((date_str, time_str))
194
194
 
195
195
 
196
196
  def to_bool(value):
197
- '''
197
+ """
198
198
  Transform a value into a boolean with the following rules:
199
199
 
200
200
  - a boolean is returned untouched
201
201
  - a string value should match any casinf of 'true' to be True
202
202
  - an integer should be superior to zero to be True
203
203
  - all other values are False
204
- '''
204
+ """
205
205
  if isinstance(value, bool):
206
206
  return value
207
207
  elif isinstance(value, str):
208
- return value.lower() == 'true' or value.lower() == 't'
208
+ return value.lower() == "true" or value.lower() == "t"
209
209
  elif isinstance(value, int):
210
210
  return value > 0
211
211
  else:
@@ -213,34 +213,34 @@ def to_bool(value):
213
213
 
214
214
 
215
215
  def clean_string(value):
216
- '''
216
+ """
217
217
  Clean an user input string (Prevent it from containing XSS)
218
- '''
218
+ """
219
219
  return escape(value)
220
220
 
221
221
 
222
222
  def not_none_dict(d):
223
- '''Filter out None values from a dict'''
223
+ """Filter out None values from a dict"""
224
224
  return {k: v for k, v in d.items() if v is not None}
225
225
 
226
226
 
227
227
  def hash_url(url):
228
- '''Hash an URL to make it indexable'''
229
- return hashlib.sha1(url.encode('utf-8')).hexdigest() if url else None
228
+ """Hash an URL to make it indexable"""
229
+ return hashlib.sha1(url.encode("utf-8")).hexdigest() if url else None
230
230
 
231
231
 
232
232
  def recursive_get(obj, key):
233
- '''
233
+ """
234
234
  Get an attribute or a key recursively.
235
235
 
236
236
  :param obj: The object to fetch attribute or key on
237
237
  :type obj: object|dict
238
238
  :param key: Either a string in dotted-notation ar an array of string
239
239
  :type key: string|list|tuple
240
- '''
240
+ """
241
241
  if not obj or not key:
242
242
  return
243
- parts = key.split('.') if isinstance(key, str) else key
243
+ parts = key.split(".") if isinstance(key, str) else key
244
244
  key = parts.pop(0)
245
245
  if isinstance(obj, dict):
246
246
  value = obj.get(key, None)
@@ -250,7 +250,7 @@ def recursive_get(obj, key):
250
250
 
251
251
 
252
252
  def unique_string(length=UUID_LENGTH):
253
- '''Generate a unique string'''
253
+ """Generate a unique string"""
254
254
  # We need a string at least as long as length
255
255
  string = str(uuid4()) * int(math.ceil(length / float(UUID_LENGTH)))
256
256
  return string[:length] if length else string
@@ -263,7 +263,7 @@ def is_uuid(uuid_string, version=4):
263
263
  # to prevent this, we check the genuine version (without dashes)
264
264
  # with the generated hex code. They should be similar.
265
265
  uid = UUID(uuid_string, version=version)
266
- return uid.hex == uuid_string.replace('-', '')
266
+ return uid.hex == uuid_string.replace("-", "")
267
267
  except ValueError:
268
268
  return False
269
269
 
@@ -271,9 +271,9 @@ def is_uuid(uuid_string, version=4):
271
271
  # This is the default providers list
272
272
  # We remove the lorum one to replace it
273
273
  # with a unicode enabled one below
274
- PROVIDERS.remove('faker.providers.lorem')
274
+ PROVIDERS.remove("faker.providers.lorem")
275
275
 
276
- faker = Faker('fr_FR') # Use a unicode/utf-8 based locale
276
+ faker = Faker("fr_FR") # Use a unicode/utf-8 based locale
277
277
 
278
278
 
279
279
  def faker_provider(provider):
@@ -284,27 +284,29 @@ def faker_provider(provider):
284
284
 
285
285
  @faker_provider
286
286
  class UDataProvider(BaseProvider):
287
- '''
287
+ """
288
288
  A Faker provider for udata missing requirements.
289
289
 
290
290
  Might be conributed to upstream Faker project
291
- '''
291
+ """
292
+
292
293
  def unique_string(self, length=UUID_LENGTH):
293
- '''Generate a unique string'''
294
+ """Generate a unique string"""
294
295
  return unique_string(length)
295
296
 
296
297
 
297
298
  @faker_provider # Replace the default lorem provider with a unicode one
298
299
  class UnicodeLoremProvider(LoremProvider):
299
- '''A Lorem provider that forces unicode in words'''
300
- word_list = [w + 'é' for w in LoremProvider.word_list]
300
+ """A Lorem provider that forces unicode in words"""
301
+
302
+ word_list = [w + "é" for w in LoremProvider.word_list]
301
303
 
302
304
 
303
305
  def safe_unicode(string):
304
- '''Safely transform any object into utf8 decoded str'''
306
+ """Safely transform any object into utf8 decoded str"""
305
307
  if string is None:
306
308
  return None
307
- return string.decode('utf8') if isinstance(string, bytes) else str(string)
309
+ return string.decode("utf8") if isinstance(string, bytes) else str(string)
308
310
 
309
311
 
310
312
  def id_or_404(object_id):
udata/wsgi.py CHANGED
@@ -1,3 +1,3 @@
1
- from udata.app import standalone, create_app
1
+ from udata.app import create_app, standalone
2
2
 
3
3
  app = standalone(create_app())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: udata
3
- Version: 9.1.2.dev30355
3
+ Version: 9.1.2.dev30454
4
4
  Summary: Open data portal
5
5
  Home-page: https://github.com/opendatateam/udata
6
6
  Author: Opendata Team
@@ -53,7 +53,6 @@ Requires-Dist: flask ==2.1.2
53
53
  Requires-Dist: flask-babel ==4.0.0
54
54
  Requires-Dist: flask-caching ==2.0.2
55
55
  Requires-Dist: flask-cdn ==1.5.3
56
- Requires-Dist: flask-cors ==3.0.8
57
56
  Requires-Dist: flask-gravatar ==0.5.0
58
57
  Requires-Dist: flask-login ==0.6.2
59
58
  Requires-Dist: flask-mail ==0.9.1
@@ -85,6 +84,7 @@ Requires-Dist: netaddr ==0.7.19
85
84
  Requires-Dist: packaging ==24.1
86
85
  Requires-Dist: passlib ==1.7.4
87
86
  Requires-Dist: pillow ==9.2.0
87
+ Requires-Dist: ply ==3.11
88
88
  Requires-Dist: prompt-toolkit ==3.0.47
89
89
  Requires-Dist: pycparser ==2.2
90
90
  Requires-Dist: pydenticon ==0.3.1
@@ -94,8 +94,10 @@ Requires-Dist: python-dateutil ==2.8.2
94
94
  Requires-Dist: pytz ==2024.1
95
95
  Requires-Dist: rdflib ==6.0.0
96
96
  Requires-Dist: redis ==4.5.2
97
+ Requires-Dist: referencing ==0.35.1
97
98
  Requires-Dist: regex ==2024.5.15
98
99
  Requires-Dist: requests ==2.24.0
100
+ Requires-Dist: rpds-py ==0.19.0
99
101
  Requires-Dist: s3transfer ==0.6.2
100
102
  Requires-Dist: six ==1.16.0
101
103
  Requires-Dist: speaklater ==1.3
@@ -137,6 +139,8 @@ It is collectively taken care of by members of the
137
139
 
138
140
  ## Current (in progress)
139
141
 
142
+ - Add linter and formatter with `pyproject.toml` config, add lint and formatting step in CI, add pre-commit hook to lint and format, update docs and lint and format the code [#3085](https://github.com/opendatateam/udata/pull/3085)
143
+ - Revamp CORS: remove flask-cors to always returns 204 on OPTIONS request [#3074](https://github.com/opendatateam/udata/pull/3074)
140
144
  - Update pinned dependencies according to project dependencies, without updating any project dependencies [#3089](https://github.com/opendatateam/udata/pull/3089)
141
145
  - Add "run" button to harvesters (configurable with `HARVEST_ENABLE_MANUAL_RUN`) [#3092](https://github.com/opendatateam/udata/pull/3092)
142
146
 
@@ -160,7 +164,7 @@ It is collectively taken care of by members of the
160
164
  - Prevent tagging as spam owners' messages [#3071](https://github.com/opendatateam/udata/pull/3071)[#3076](https://github.com/opendatateam/udata/pull/3076)
161
165
  - Add api endpoint /me/org_topics/ [#3070](https://github.com/opendatateam/udata/pull/3070)
162
166
  - Expose dataservices in RDF catalog [#3058](https://github.com/opendatateam/udata/pull/3058) [#3075](https://github.com/opendatateam/udata/pull/3075)
163
- - CORS: always returns 204 on OPTIONS request [#3046](https://github.com/opendatateam/udata/pull/3046)
167
+ - CORS: always returns 204 on OPTIONS request [#3046](https://github.com/opendatateam/udata/pull/3046)
164
168
 
165
169
  ## 9.0.0 (2024-06-07)
166
170