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

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

Potentially problematic release.


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

Files changed (425) hide show
  1. tasks/__init__.py +109 -107
  2. tasks/helpers.py +18 -18
  3. udata/__init__.py +4 -4
  4. udata/admin/views.py +5 -5
  5. udata/api/__init__.py +135 -124
  6. udata/api/commands.py +45 -37
  7. udata/api/errors.py +5 -4
  8. udata/api/fields.py +23 -21
  9. udata/api/oauth2.py +55 -74
  10. udata/api/parsers.py +15 -15
  11. udata/api/signals.py +1 -1
  12. udata/api_fields.py +137 -89
  13. udata/app.py +56 -54
  14. udata/assets.py +5 -5
  15. udata/auth/__init__.py +37 -26
  16. udata/auth/forms.py +23 -15
  17. udata/auth/helpers.py +1 -1
  18. udata/auth/mails.py +3 -3
  19. udata/auth/password_validation.py +19 -15
  20. udata/auth/views.py +94 -68
  21. udata/commands/__init__.py +71 -69
  22. udata/commands/cache.py +7 -7
  23. udata/commands/db.py +201 -140
  24. udata/commands/dcat.py +36 -30
  25. udata/commands/fixtures.py +100 -84
  26. udata/commands/images.py +21 -20
  27. udata/commands/info.py +17 -20
  28. udata/commands/init.py +10 -10
  29. udata/commands/purge.py +12 -13
  30. udata/commands/serve.py +41 -29
  31. udata/commands/static.py +16 -18
  32. udata/commands/test.py +20 -20
  33. udata/commands/tests/fixtures.py +26 -24
  34. udata/commands/worker.py +31 -33
  35. udata/core/__init__.py +12 -12
  36. udata/core/activity/__init__.py +0 -1
  37. udata/core/activity/api.py +59 -49
  38. udata/core/activity/models.py +28 -26
  39. udata/core/activity/signals.py +1 -1
  40. udata/core/activity/tasks.py +16 -10
  41. udata/core/badges/api.py +6 -6
  42. udata/core/badges/commands.py +14 -13
  43. udata/core/badges/fields.py +8 -5
  44. udata/core/badges/forms.py +7 -4
  45. udata/core/badges/models.py +16 -31
  46. udata/core/badges/permissions.py +1 -3
  47. udata/core/badges/signals.py +2 -2
  48. udata/core/badges/tasks.py +3 -2
  49. udata/core/badges/tests/test_commands.py +10 -10
  50. udata/core/badges/tests/test_model.py +24 -31
  51. udata/core/contact_point/api.py +19 -18
  52. udata/core/contact_point/api_fields.py +21 -14
  53. udata/core/contact_point/factories.py +2 -2
  54. udata/core/contact_point/forms.py +7 -6
  55. udata/core/contact_point/models.py +3 -5
  56. udata/core/dataservices/api.py +26 -21
  57. udata/core/dataservices/factories.py +13 -11
  58. udata/core/dataservices/models.py +35 -40
  59. udata/core/dataservices/permissions.py +4 -4
  60. udata/core/dataservices/rdf.py +40 -17
  61. udata/core/dataservices/tasks.py +4 -3
  62. udata/core/dataset/actions.py +10 -10
  63. udata/core/dataset/activities.py +21 -23
  64. udata/core/dataset/api.py +321 -298
  65. udata/core/dataset/api_fields.py +443 -271
  66. udata/core/dataset/apiv2.py +305 -229
  67. udata/core/dataset/commands.py +38 -36
  68. udata/core/dataset/constants.py +61 -54
  69. udata/core/dataset/csv.py +70 -74
  70. udata/core/dataset/events.py +39 -32
  71. udata/core/dataset/exceptions.py +8 -4
  72. udata/core/dataset/factories.py +57 -65
  73. udata/core/dataset/forms.py +87 -63
  74. udata/core/dataset/models.py +336 -280
  75. udata/core/dataset/permissions.py +9 -6
  76. udata/core/dataset/preview.py +15 -17
  77. udata/core/dataset/rdf.py +156 -122
  78. udata/core/dataset/search.py +92 -77
  79. udata/core/dataset/signals.py +1 -1
  80. udata/core/dataset/tasks.py +63 -54
  81. udata/core/discussions/actions.py +5 -5
  82. udata/core/discussions/api.py +124 -120
  83. udata/core/discussions/factories.py +2 -2
  84. udata/core/discussions/forms.py +9 -7
  85. udata/core/discussions/metrics.py +1 -3
  86. udata/core/discussions/models.py +25 -24
  87. udata/core/discussions/notifications.py +18 -14
  88. udata/core/discussions/permissions.py +3 -3
  89. udata/core/discussions/signals.py +4 -4
  90. udata/core/discussions/tasks.py +24 -28
  91. udata/core/followers/api.py +32 -33
  92. udata/core/followers/models.py +9 -9
  93. udata/core/followers/signals.py +3 -3
  94. udata/core/jobs/actions.py +7 -7
  95. udata/core/jobs/api.py +99 -92
  96. udata/core/jobs/commands.py +48 -49
  97. udata/core/jobs/forms.py +11 -11
  98. udata/core/jobs/models.py +6 -6
  99. udata/core/metrics/__init__.py +2 -2
  100. udata/core/metrics/commands.py +34 -30
  101. udata/core/metrics/models.py +2 -4
  102. udata/core/metrics/signals.py +1 -1
  103. udata/core/metrics/tasks.py +3 -3
  104. udata/core/organization/activities.py +12 -15
  105. udata/core/organization/api.py +167 -174
  106. udata/core/organization/api_fields.py +183 -124
  107. udata/core/organization/apiv2.py +32 -32
  108. udata/core/organization/commands.py +20 -22
  109. udata/core/organization/constants.py +11 -11
  110. udata/core/organization/csv.py +17 -15
  111. udata/core/organization/factories.py +8 -11
  112. udata/core/organization/forms.py +32 -26
  113. udata/core/organization/metrics.py +2 -1
  114. udata/core/organization/models.py +87 -67
  115. udata/core/organization/notifications.py +18 -14
  116. udata/core/organization/permissions.py +10 -11
  117. udata/core/organization/rdf.py +14 -14
  118. udata/core/organization/search.py +30 -28
  119. udata/core/organization/signals.py +7 -7
  120. udata/core/organization/tasks.py +42 -61
  121. udata/core/owned.py +38 -27
  122. udata/core/post/api.py +82 -81
  123. udata/core/post/constants.py +8 -5
  124. udata/core/post/factories.py +4 -4
  125. udata/core/post/forms.py +13 -14
  126. udata/core/post/models.py +20 -22
  127. udata/core/post/tests/test_api.py +30 -32
  128. udata/core/reports/api.py +8 -7
  129. udata/core/reports/constants.py +1 -3
  130. udata/core/reports/models.py +10 -10
  131. udata/core/reuse/activities.py +15 -19
  132. udata/core/reuse/api.py +123 -126
  133. udata/core/reuse/api_fields.py +120 -85
  134. udata/core/reuse/apiv2.py +11 -10
  135. udata/core/reuse/constants.py +23 -23
  136. udata/core/reuse/csv.py +18 -18
  137. udata/core/reuse/factories.py +5 -9
  138. udata/core/reuse/forms.py +24 -21
  139. udata/core/reuse/models.py +55 -51
  140. udata/core/reuse/permissions.py +2 -2
  141. udata/core/reuse/search.py +49 -46
  142. udata/core/reuse/signals.py +1 -1
  143. udata/core/reuse/tasks.py +4 -5
  144. udata/core/site/api.py +47 -50
  145. udata/core/site/factories.py +2 -2
  146. udata/core/site/forms.py +4 -5
  147. udata/core/site/models.py +94 -63
  148. udata/core/site/rdf.py +14 -14
  149. udata/core/spam/api.py +16 -9
  150. udata/core/spam/constants.py +4 -4
  151. udata/core/spam/fields.py +13 -7
  152. udata/core/spam/models.py +27 -20
  153. udata/core/spam/signals.py +1 -1
  154. udata/core/spam/tests/test_spam.py +6 -5
  155. udata/core/spatial/api.py +72 -80
  156. udata/core/spatial/api_fields.py +73 -58
  157. udata/core/spatial/commands.py +67 -64
  158. udata/core/spatial/constants.py +3 -3
  159. udata/core/spatial/factories.py +37 -54
  160. udata/core/spatial/forms.py +27 -26
  161. udata/core/spatial/geoids.py +17 -17
  162. udata/core/spatial/models.py +43 -47
  163. udata/core/spatial/tasks.py +2 -1
  164. udata/core/spatial/tests/test_api.py +115 -130
  165. udata/core/spatial/tests/test_fields.py +74 -77
  166. udata/core/spatial/tests/test_geoid.py +22 -22
  167. udata/core/spatial/tests/test_models.py +5 -7
  168. udata/core/spatial/translations.py +16 -16
  169. udata/core/storages/__init__.py +16 -18
  170. udata/core/storages/api.py +66 -64
  171. udata/core/storages/tasks.py +7 -7
  172. udata/core/storages/utils.py +15 -15
  173. udata/core/storages/views.py +5 -6
  174. udata/core/tags/api.py +17 -14
  175. udata/core/tags/csv.py +4 -4
  176. udata/core/tags/models.py +8 -5
  177. udata/core/tags/tasks.py +11 -13
  178. udata/core/tags/views.py +4 -4
  179. udata/core/topic/api.py +84 -73
  180. udata/core/topic/apiv2.py +157 -127
  181. udata/core/topic/factories.py +3 -4
  182. udata/core/topic/forms.py +12 -14
  183. udata/core/topic/models.py +14 -19
  184. udata/core/topic/parsers.py +26 -26
  185. udata/core/user/activities.py +30 -29
  186. udata/core/user/api.py +151 -152
  187. udata/core/user/api_fields.py +132 -100
  188. udata/core/user/apiv2.py +7 -7
  189. udata/core/user/commands.py +38 -38
  190. udata/core/user/factories.py +8 -9
  191. udata/core/user/forms.py +14 -11
  192. udata/core/user/metrics.py +2 -2
  193. udata/core/user/models.py +68 -69
  194. udata/core/user/permissions.py +4 -5
  195. udata/core/user/rdf.py +7 -8
  196. udata/core/user/tasks.py +2 -2
  197. udata/core/user/tests/test_user_model.py +24 -16
  198. udata/db/tasks.py +2 -1
  199. udata/entrypoints.py +35 -31
  200. udata/errors.py +2 -1
  201. udata/event/values.py +6 -6
  202. udata/factories.py +2 -2
  203. udata/features/identicon/api.py +5 -6
  204. udata/features/identicon/backends.py +48 -55
  205. udata/features/identicon/tests/test_backends.py +4 -5
  206. udata/features/notifications/__init__.py +0 -1
  207. udata/features/notifications/actions.py +9 -9
  208. udata/features/notifications/api.py +17 -13
  209. udata/features/territories/__init__.py +12 -10
  210. udata/features/territories/api.py +14 -15
  211. udata/features/territories/models.py +23 -28
  212. udata/features/transfer/actions.py +8 -11
  213. udata/features/transfer/api.py +84 -77
  214. udata/features/transfer/factories.py +2 -1
  215. udata/features/transfer/models.py +11 -12
  216. udata/features/transfer/notifications.py +19 -15
  217. udata/features/transfer/permissions.py +5 -5
  218. udata/forms/__init__.py +5 -2
  219. udata/forms/fields.py +164 -172
  220. udata/forms/validators.py +19 -22
  221. udata/forms/widgets.py +9 -13
  222. udata/frontend/__init__.py +31 -26
  223. udata/frontend/csv.py +68 -58
  224. udata/frontend/markdown.py +40 -44
  225. udata/harvest/actions.py +89 -77
  226. udata/harvest/api.py +294 -238
  227. udata/harvest/backends/__init__.py +4 -4
  228. udata/harvest/backends/base.py +128 -111
  229. udata/harvest/backends/dcat.py +80 -66
  230. udata/harvest/commands.py +56 -60
  231. udata/harvest/csv.py +8 -8
  232. udata/harvest/exceptions.py +6 -3
  233. udata/harvest/filters.py +24 -23
  234. udata/harvest/forms.py +27 -28
  235. udata/harvest/models.py +88 -80
  236. udata/harvest/notifications.py +15 -10
  237. udata/harvest/signals.py +13 -13
  238. udata/harvest/tasks.py +11 -10
  239. udata/harvest/tests/factories.py +23 -24
  240. udata/harvest/tests/test_actions.py +136 -166
  241. udata/harvest/tests/test_api.py +220 -214
  242. udata/harvest/tests/test_base_backend.py +117 -112
  243. udata/harvest/tests/test_dcat_backend.py +380 -308
  244. udata/harvest/tests/test_filters.py +33 -22
  245. udata/harvest/tests/test_models.py +11 -14
  246. udata/harvest/tests/test_notifications.py +6 -7
  247. udata/harvest/tests/test_tasks.py +7 -6
  248. udata/i18n.py +237 -78
  249. udata/linkchecker/backends.py +5 -11
  250. udata/linkchecker/checker.py +23 -22
  251. udata/linkchecker/commands.py +4 -6
  252. udata/linkchecker/models.py +6 -6
  253. udata/linkchecker/tasks.py +18 -20
  254. udata/mail.py +21 -21
  255. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  256. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  257. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  258. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  259. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  260. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  261. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  262. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  263. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  264. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  265. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  266. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  267. udata/migrations/2021-08-17-users-integrity.py +9 -8
  268. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  269. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  270. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  271. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  272. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  273. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  274. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  275. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  276. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  277. udata/migrations/__init__.py +123 -105
  278. udata/models/__init__.py +4 -4
  279. udata/mongo/__init__.py +13 -11
  280. udata/mongo/badges_field.py +3 -2
  281. udata/mongo/datetime_fields.py +13 -12
  282. udata/mongo/document.py +17 -16
  283. udata/mongo/engine.py +15 -16
  284. udata/mongo/errors.py +2 -1
  285. udata/mongo/extras_fields.py +30 -20
  286. udata/mongo/queryset.py +12 -12
  287. udata/mongo/slug_fields.py +38 -28
  288. udata/mongo/taglist_field.py +1 -2
  289. udata/mongo/url_field.py +5 -5
  290. udata/mongo/uuid_fields.py +4 -3
  291. udata/notifications/__init__.py +1 -1
  292. udata/notifications/mattermost.py +10 -9
  293. udata/rdf.py +167 -188
  294. udata/routing.py +40 -45
  295. udata/search/__init__.py +18 -19
  296. udata/search/adapter.py +17 -16
  297. udata/search/commands.py +44 -51
  298. udata/search/fields.py +13 -20
  299. udata/search/query.py +23 -18
  300. udata/search/result.py +9 -10
  301. udata/sentry.py +21 -19
  302. udata/settings.py +262 -198
  303. udata/sitemap.py +8 -6
  304. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
  305. udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
  306. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
  307. udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
  308. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
  309. udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
  310. udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
  311. udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
  312. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
  313. udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
  314. udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
  315. udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
  316. udata/static/common.js +1 -1
  317. udata/static/common.js.map +1 -1
  318. udata/storage/s3.py +20 -13
  319. udata/tags.py +4 -5
  320. udata/tasks.py +43 -42
  321. udata/tests/__init__.py +9 -6
  322. udata/tests/api/__init__.py +5 -6
  323. udata/tests/api/test_auth_api.py +395 -321
  324. udata/tests/api/test_base_api.py +31 -33
  325. udata/tests/api/test_contact_points.py +7 -9
  326. udata/tests/api/test_dataservices_api.py +211 -158
  327. udata/tests/api/test_datasets_api.py +823 -812
  328. udata/tests/api/test_follow_api.py +13 -15
  329. udata/tests/api/test_me_api.py +95 -112
  330. udata/tests/api/test_organizations_api.py +301 -339
  331. udata/tests/api/test_reports_api.py +35 -25
  332. udata/tests/api/test_reuses_api.py +134 -139
  333. udata/tests/api/test_swagger.py +5 -5
  334. udata/tests/api/test_tags_api.py +18 -25
  335. udata/tests/api/test_topics_api.py +94 -94
  336. udata/tests/api/test_transfer_api.py +53 -48
  337. udata/tests/api/test_user_api.py +128 -141
  338. udata/tests/apiv2/test_datasets.py +290 -198
  339. udata/tests/apiv2/test_me_api.py +10 -11
  340. udata/tests/apiv2/test_organizations.py +56 -74
  341. udata/tests/apiv2/test_swagger.py +5 -5
  342. udata/tests/apiv2/test_topics.py +69 -87
  343. udata/tests/cli/test_cli_base.py +8 -8
  344. udata/tests/cli/test_db_cli.py +21 -19
  345. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  346. udata/tests/dataset/test_csv_adapter.py +44 -35
  347. udata/tests/dataset/test_dataset_actions.py +2 -3
  348. udata/tests/dataset/test_dataset_commands.py +7 -8
  349. udata/tests/dataset/test_dataset_events.py +36 -29
  350. udata/tests/dataset/test_dataset_model.py +224 -217
  351. udata/tests/dataset/test_dataset_rdf.py +142 -131
  352. udata/tests/dataset/test_dataset_tasks.py +15 -15
  353. udata/tests/dataset/test_resource_preview.py +10 -13
  354. udata/tests/features/territories/__init__.py +9 -13
  355. udata/tests/features/territories/test_territories_api.py +71 -91
  356. udata/tests/forms/test_basic_fields.py +7 -7
  357. udata/tests/forms/test_current_user_field.py +39 -66
  358. udata/tests/forms/test_daterange_field.py +31 -39
  359. udata/tests/forms/test_dict_field.py +28 -26
  360. udata/tests/forms/test_extras_fields.py +102 -76
  361. udata/tests/forms/test_form_field.py +8 -8
  362. udata/tests/forms/test_image_field.py +33 -26
  363. udata/tests/forms/test_model_field.py +134 -123
  364. udata/tests/forms/test_model_list_field.py +7 -7
  365. udata/tests/forms/test_nested_model_list_field.py +117 -79
  366. udata/tests/forms/test_publish_as_field.py +36 -65
  367. udata/tests/forms/test_reference_field.py +34 -53
  368. udata/tests/forms/test_user_forms.py +23 -21
  369. udata/tests/forms/test_uuid_field.py +6 -10
  370. udata/tests/frontend/__init__.py +9 -6
  371. udata/tests/frontend/test_auth.py +7 -6
  372. udata/tests/frontend/test_csv.py +81 -96
  373. udata/tests/frontend/test_hooks.py +43 -43
  374. udata/tests/frontend/test_markdown.py +211 -191
  375. udata/tests/helpers.py +32 -37
  376. udata/tests/models.py +2 -2
  377. udata/tests/organization/test_csv_adapter.py +21 -16
  378. udata/tests/organization/test_notifications.py +11 -18
  379. udata/tests/organization/test_organization_model.py +13 -13
  380. udata/tests/organization/test_organization_rdf.py +29 -22
  381. udata/tests/organization/test_organization_tasks.py +16 -17
  382. udata/tests/plugin.py +76 -73
  383. udata/tests/reuse/test_reuse_model.py +21 -21
  384. udata/tests/reuse/test_reuse_task.py +11 -13
  385. udata/tests/search/__init__.py +11 -12
  386. udata/tests/search/test_adapter.py +60 -70
  387. udata/tests/search/test_query.py +16 -16
  388. udata/tests/search/test_results.py +10 -7
  389. udata/tests/site/test_site_api.py +11 -16
  390. udata/tests/site/test_site_metrics.py +20 -30
  391. udata/tests/site/test_site_model.py +4 -5
  392. udata/tests/site/test_site_rdf.py +94 -78
  393. udata/tests/test_activity.py +17 -17
  394. udata/tests/test_discussions.py +292 -299
  395. udata/tests/test_i18n.py +37 -40
  396. udata/tests/test_linkchecker.py +91 -85
  397. udata/tests/test_mail.py +13 -17
  398. udata/tests/test_migrations.py +219 -180
  399. udata/tests/test_model.py +164 -157
  400. udata/tests/test_notifications.py +17 -17
  401. udata/tests/test_owned.py +14 -14
  402. udata/tests/test_rdf.py +25 -23
  403. udata/tests/test_routing.py +89 -93
  404. udata/tests/test_storages.py +137 -128
  405. udata/tests/test_tags.py +44 -46
  406. udata/tests/test_topics.py +7 -7
  407. udata/tests/test_transfer.py +42 -49
  408. udata/tests/test_uris.py +160 -161
  409. udata/tests/test_utils.py +79 -71
  410. udata/tests/user/test_user_rdf.py +5 -9
  411. udata/tests/workers/test_jobs_commands.py +57 -58
  412. udata/tests/workers/test_tasks_routing.py +23 -29
  413. udata/tests/workers/test_workers_api.py +125 -131
  414. udata/tests/workers/test_workers_helpers.py +6 -6
  415. udata/tracking.py +4 -6
  416. udata/uris.py +45 -46
  417. udata/utils.py +68 -66
  418. udata/wsgi.py +1 -1
  419. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/METADATA +3 -2
  420. udata-9.1.2.dev30382.dist-info/RECORD +704 -0
  421. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  422. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
  423. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
  424. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
  425. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,4 @@
1
1
  import os
2
-
3
2
  from datetime import datetime
4
3
 
5
4
  from flask import json
@@ -7,40 +6,39 @@ from werkzeug.datastructures import FileStorage
7
6
 
8
7
  from udata.api import api, fields
9
8
 
10
- from . import utils, chunks
11
-
9
+ from . import chunks, utils
12
10
 
13
- META = 'meta.json'
11
+ META = "meta.json"
14
12
 
15
- IMAGES_MIMETYPES = ('image/jpeg', 'image/png', 'image/webp')
13
+ IMAGES_MIMETYPES = ("image/jpeg", "image/png", "image/webp")
16
14
 
17
15
 
18
- uploaded_image_fields = api.model('UploadedImage', {
19
- 'success': fields.Boolean(
20
- description='Whether the upload succeeded or not.',
21
- readonly=True, default=True),
22
- 'image': fields.ImageField(),
23
- })
16
+ uploaded_image_fields = api.model(
17
+ "UploadedImage",
18
+ {
19
+ "success": fields.Boolean(
20
+ description="Whether the upload succeeded or not.", readonly=True, default=True
21
+ ),
22
+ "image": fields.ImageField(),
23
+ },
24
+ )
24
25
 
25
- chunk_status_fields = api.model('UploadStatus', {
26
- 'success': fields.Boolean,
27
- 'error': fields.String
28
- })
26
+ chunk_status_fields = api.model("UploadStatus", {"success": fields.Boolean, "error": fields.String})
29
27
 
30
28
 
31
29
  image_parser = api.parser()
32
- image_parser.add_argument('file', type=FileStorage, location='files')
33
- image_parser.add_argument('bbox', type=str, location='form')
30
+ image_parser.add_argument("file", type=FileStorage, location="files")
31
+ image_parser.add_argument("bbox", type=str, location="form")
34
32
 
35
33
 
36
34
  upload_parser = api.parser()
37
- upload_parser.add_argument('file', type=FileStorage, location='files')
38
- upload_parser.add_argument('uuid', type=str, location='form')
39
- upload_parser.add_argument('filename', type=str, location='form')
40
- upload_parser.add_argument('partindex', type=int, location='form')
41
- upload_parser.add_argument('partbyteoffset', type=int, location='form')
42
- upload_parser.add_argument('totalparts', type=int, location='form')
43
- upload_parser.add_argument('chunksize', type=int, location='form')
35
+ upload_parser.add_argument("file", type=FileStorage, location="files")
36
+ upload_parser.add_argument("uuid", type=str, location="form")
37
+ upload_parser.add_argument("filename", type=str, location="form")
38
+ upload_parser.add_argument("partindex", type=int, location="form")
39
+ upload_parser.add_argument("partbyteoffset", type=int, location="form")
40
+ upload_parser.add_argument("totalparts", type=int, location="form")
41
+ upload_parser.add_argument("chunksize", type=int, location="form")
44
42
 
45
43
 
46
44
  class UploadStatus(Exception):
@@ -51,22 +49,24 @@ class UploadStatus(Exception):
51
49
 
52
50
 
53
51
  class UploadProgress(UploadStatus):
54
- '''Raised on successful chunk uploaded'''
52
+ """Raised on successful chunk uploaded"""
53
+
55
54
  pass
56
55
 
57
56
 
58
57
  class UploadError(UploadStatus):
59
- '''Raised on any upload error'''
58
+ """Raised on any upload error"""
59
+
60
60
  def __init__(self, error=None):
61
61
  super(UploadError, self).__init__(ok=False, error=error)
62
62
 
63
63
 
64
64
  def on_upload_status(status):
65
- '''Not an error, just raised when chunk is processed'''
65
+ """Not an error, just raised when chunk is processed"""
66
66
  if status.ok:
67
- return {'success': True}, 200
67
+ return {"success": True}, 200
68
68
  else:
69
- return {'success': False, 'error': status.error}, 400
69
+ return {"success": False, "error": status.error}, 400
70
70
 
71
71
 
72
72
  @api.errorhandler(UploadStatus)
@@ -74,7 +74,7 @@ def on_upload_status(status):
74
74
  @api.errorhandler(UploadProgress)
75
75
  @api.marshal_with(chunk_status_fields, code=200)
76
76
  def api_upload_status(status):
77
- '''API Upload response handler'''
77
+ """API Upload response handler"""
78
78
  return on_upload_status(status)
79
79
 
80
80
 
@@ -91,34 +91,40 @@ def get_file_size(file):
91
91
 
92
92
  def save_chunk(file, args):
93
93
  # Check file size
94
- if get_file_size(file) != args['chunksize']:
95
- raise UploadProgress(ok=False, error='Chunk size mismatch')
96
- filename = chunk_filename(args['uuid'], args['partindex'])
94
+ if get_file_size(file) != args["chunksize"]:
95
+ raise UploadProgress(ok=False, error="Chunk size mismatch")
96
+ filename = chunk_filename(args["uuid"], args["partindex"])
97
97
  chunks.save(file, filename=filename)
98
- meta_filename = chunk_filename(args['uuid'], META)
99
- chunks.write(meta_filename, json.dumps({
100
- 'uuid': str(args['uuid']),
101
- 'filename': args['filename'],
102
- 'totalparts': args['totalparts'],
103
- 'lastchunk': datetime.utcnow(),
104
- }), overwrite=True)
98
+ meta_filename = chunk_filename(args["uuid"], META)
99
+ chunks.write(
100
+ meta_filename,
101
+ json.dumps(
102
+ {
103
+ "uuid": str(args["uuid"]),
104
+ "filename": args["filename"],
105
+ "totalparts": args["totalparts"],
106
+ "lastchunk": datetime.utcnow(),
107
+ }
108
+ ),
109
+ overwrite=True,
110
+ )
105
111
  raise UploadProgress()
106
112
 
107
113
 
108
114
  def combine_chunks(storage, args, prefix=None):
109
- '''
115
+ """
110
116
  Combine a chunked file into a whole file again.
111
117
  Goes through each part, in order,
112
118
  and appends that part's bytes to another destination file.
113
119
  Chunks are stored in the chunks storage.
114
- '''
115
- uuid = args['uuid']
120
+ """
121
+ uuid = args["uuid"]
116
122
  # Normalize filename including extension
117
- target = utils.normalize(args['filename'])
123
+ target = utils.normalize(args["filename"])
118
124
  if prefix:
119
125
  target = os.path.join(prefix, target)
120
- with storage.open(target, 'wb') as out:
121
- for i in range(args['totalparts']):
126
+ with storage.open(target, "wb") as out:
127
+ for i in range(args["totalparts"]):
122
128
  partname = chunk_filename(uuid, i)
123
129
  out.write(chunks.read(partname))
124
130
  chunks.delete(partname)
@@ -128,8 +134,8 @@ def combine_chunks(storage, args, prefix=None):
128
134
 
129
135
  def handle_upload(storage, prefix=None):
130
136
  args = upload_parser.parse_args()
131
- is_chunk = args['totalparts'] and args['totalparts'] > 1
132
- uploaded_file = args['file']
137
+ is_chunk = args["totalparts"] and args["totalparts"] > 1
138
+ uploaded_file = args["file"]
133
139
 
134
140
  if is_chunk:
135
141
  if uploaded_file:
@@ -137,34 +143,30 @@ def handle_upload(storage, prefix=None):
137
143
  else:
138
144
  fs_filename = combine_chunks(storage, args, prefix=prefix)
139
145
  elif not uploaded_file:
140
- raise UploadError('Missing file parameter')
146
+ raise UploadError("Missing file parameter")
141
147
  else:
142
148
  # Normalize filename including extension
143
149
  filename = utils.normalize(uploaded_file.filename)
144
- fs_filename = storage.save(
145
- uploaded_file,
146
- prefix=prefix,
147
- filename=filename
148
- )
150
+ fs_filename = storage.save(uploaded_file, prefix=prefix, filename=filename)
149
151
 
150
152
  metadata = storage.metadata(fs_filename)
151
- metadata['last_modified_internal'] = metadata.pop('modified')
152
- metadata['fs_filename'] = fs_filename
153
- checksum = metadata.pop('checksum')
154
- algo, checksum = checksum.split(':', 1)
153
+ metadata["last_modified_internal"] = metadata.pop("modified")
154
+ metadata["fs_filename"] = fs_filename
155
+ checksum = metadata.pop("checksum")
156
+ algo, checksum = checksum.split(":", 1)
155
157
  metadata[algo] = checksum
156
- metadata['format'] = utils.extension(fs_filename)
158
+ metadata["format"] = utils.extension(fs_filename)
157
159
  return metadata
158
160
 
159
161
 
160
162
  def parse_uploaded_image(field):
161
- '''Parse an uploaded image and save into a db.ImageField()'''
163
+ """Parse an uploaded image and save into a db.ImageField()"""
162
164
  args = image_parser.parse_args()
163
165
 
164
- image = args['file']
166
+ image = args["file"]
165
167
  if image.mimetype not in IMAGES_MIMETYPES:
166
- api.abort(400, 'Unsupported image format')
167
- bbox = args.get('bbox', None)
168
+ api.abort(400, "Unsupported image format")
169
+ bbox = args.get("bbox", None)
168
170
  if bbox:
169
- bbox = [int(float(c)) for c in bbox.split(',')]
171
+ bbox = [int(float(c)) for c in bbox.split(",")]
170
172
  field.save(image, bbox=bbox)
@@ -1,6 +1,6 @@
1
1
  from datetime import datetime, timedelta
2
- from dateutil.parser import parse
3
2
 
3
+ from dateutil.parser import parse
4
4
  from flask import current_app, json
5
5
 
6
6
  from udata.core.storages import chunks
@@ -10,14 +10,14 @@ from udata.tasks import get_logger, job
10
10
  log = get_logger(__name__)
11
11
 
12
12
 
13
- @job('purge-chunks')
13
+ @job("purge-chunks")
14
14
  def purge_chunks(self):
15
- log.info('Purging uploaded chunks')
16
- max_retention = timedelta(seconds=current_app.config['UPLOAD_MAX_RETENTION'])
15
+ log.info("Purging uploaded chunks")
16
+ max_retention = timedelta(seconds=current_app.config["UPLOAD_MAX_RETENTION"])
17
17
  meta_files = (f for f in chunks.list_files() if f.endswith(META))
18
18
  for filename in meta_files:
19
19
  metadata = json.loads(chunks.read(filename))
20
- if datetime.utcnow() - parse(metadata['lastchunk']) >= max_retention:
21
- uuid = metadata['uuid']
22
- log.info('Removing %s expired chunks', uuid)
20
+ if datetime.utcnow() - parse(metadata["lastchunk"]) >= max_retention:
21
+ uuid = metadata["uuid"]
22
+ log.info("Removing %s expired chunks", uuid)
23
23
  chunks.delete(uuid)
@@ -6,15 +6,15 @@ import zlib
6
6
  from flask import current_app
7
7
  from slugify import Slugify
8
8
 
9
- CHUNK_SIZE = 2 ** 16
9
+ CHUNK_SIZE = 2**16
10
10
 
11
11
 
12
- slugify = Slugify(separator='-', to_lower=True, safe_chars='.')
12
+ slugify = Slugify(separator="-", to_lower=True, safe_chars=".")
13
13
 
14
14
 
15
15
  def hash(file, hasher):
16
16
  blk_size_to_read = hasher.block_size * CHUNK_SIZE
17
- while (True):
17
+ while True:
18
18
  read_data = file.read(blk_size_to_read)
19
19
  if not read_data:
20
20
  break
@@ -23,28 +23,28 @@ def hash(file, hasher):
23
23
 
24
24
 
25
25
  def sha1(file):
26
- '''Perform a SHA1 digest on file'''
26
+ """Perform a SHA1 digest on file"""
27
27
  return hash(file, hashlib.sha1())
28
28
 
29
29
 
30
30
  def md5(file):
31
- '''Perform a MD5 digest on a file'''
31
+ """Perform a MD5 digest on a file"""
32
32
  return hash(file, hashlib.md5())
33
33
 
34
34
 
35
35
  def crc32(file):
36
- '''Perform a CRC digest on a file'''
36
+ """Perform a CRC digest on a file"""
37
37
  value = zlib.crc32(file.read())
38
- return '%08X' % (value & 0xFFFFFFFF)
38
+ return "%08X" % (value & 0xFFFFFFFF)
39
39
 
40
40
 
41
41
  def mime(url):
42
- '''Get the mimetype from an url or a filename'''
42
+ """Get the mimetype from an url or a filename"""
43
43
  return mimetypes.guess_type(url)[0]
44
44
 
45
45
 
46
46
  def extension(filename):
47
- '''
47
+ """
48
48
  Properly extract the extension from filename.
49
49
  We keep the last extension except for archive extensions, where we check
50
50
  previous extensions as well.
@@ -55,23 +55,23 @@ def extension(filename):
55
55
  - test.2022.zip -> zip
56
56
  - test.2022.csv.tar.gz -> csv.tar.gz
57
57
  - test.geojson.csv -> csv
58
- '''
58
+ """
59
59
  filename = os.path.basename(filename)
60
60
  extension = None
61
61
 
62
- while '.' in filename:
62
+ while "." in filename:
63
63
  filename, ext = os.path.splitext(filename)
64
- if ext.startswith('.'):
64
+ if ext.startswith("."):
65
65
  ext = ext[1:]
66
66
 
67
- if extension and ext not in current_app.config['ALLOWED_RESOURCES_EXTENSIONS']:
67
+ if extension and ext not in current_app.config["ALLOWED_RESOURCES_EXTENSIONS"]:
68
68
  # We don't want to add this extension if one has already been detected
69
69
  # and this one is not in the allowed resources extensions list.
70
70
  break
71
71
 
72
- extension = ext if not extension else ext + '.' + extension
72
+ extension = ext if not extension else ext + "." + extension
73
73
 
74
- if ext not in current_app.config['ALLOWED_ARCHIVE_EXTENSIONS']:
74
+ if ext not in current_app.config["ALLOWED_ARCHIVE_EXTENSIONS"]:
75
75
  # We don't want to continue the loop if this ext is not an allowed archived extension
76
76
  break
77
77
 
@@ -1,11 +1,10 @@
1
+ import flask_storage as fs
1
2
  from flask import Blueprint, jsonify
2
3
  from flask_security import login_required
3
- import flask_storage as fs
4
-
5
- from .api import handle_upload, on_upload_status, UploadStatus
6
4
 
5
+ from .api import UploadStatus, handle_upload, on_upload_status
7
6
 
8
- blueprint = Blueprint('storage', __name__)
7
+ blueprint = Blueprint("storage", __name__)
9
8
 
10
9
 
11
10
  @blueprint.app_errorhandler(UploadStatus)
@@ -15,8 +14,8 @@ def jsonify_upload_status(status):
15
14
 
16
15
 
17
16
  @login_required
18
- @blueprint.route('/upload/<name>/', methods=['POST'])
17
+ @blueprint.route("/upload/<name>/", methods=["POST"])
19
18
  def upload(name):
20
- '''Handle upload on POST if authorized.'''
19
+ """Handle upload on POST if authorized."""
21
20
  storage = fs.by_name(name)
22
21
  return jsonify(success=True, **handle_upload(storage))
udata/core/tags/api.py CHANGED
@@ -1,28 +1,31 @@
1
- from udata.api import api, API
2
-
3
- from udata.tags import slug # TODO: merge this into this package
1
+ from udata.api import API, api
4
2
  from udata.models import Tag
3
+ from udata.tags import slug # TODO: merge this into this package
5
4
 
6
5
  DEFAULT_SIZE = 8
7
6
 
8
- ns = api.namespace('tags', 'Tags related operations')
7
+ ns = api.namespace("tags", "Tags related operations")
9
8
 
10
9
  parser = api.parser()
11
10
  parser.add_argument(
12
- 'q', type=str, help='The string to autocomplete/suggest',
13
- location='args', required=True)
11
+ "q", type=str, help="The string to autocomplete/suggest", location="args", required=True
12
+ )
14
13
  parser.add_argument(
15
- 'size', type=int, help='The amount of suggestion to fetch',
16
- location='args', default=DEFAULT_SIZE)
14
+ "size",
15
+ type=int,
16
+ help="The amount of suggestion to fetch",
17
+ location="args",
18
+ default=DEFAULT_SIZE,
19
+ )
17
20
 
18
21
 
19
- @ns.route('/suggest/', endpoint='suggest_tags')
22
+ @ns.route("/suggest/", endpoint="suggest_tags")
20
23
  class SuggestTagsAPI(API):
21
- @api.doc('suggest_tags')
24
+ @api.doc("suggest_tags")
22
25
  @api.expect(parser)
23
26
  def get(self):
24
- '''Suggest tags'''
27
+ """Suggest tags"""
25
28
  args = parser.parse_args()
26
- q = slug(args['q'])
27
- results = [{'text': i.name} for i in Tag.objects(name__icontains=q).limit(args['size'])]
28
- return sorted(results, key=lambda o: len(o['text']))
29
+ q = slug(args["q"])
30
+ results = [{"text": i.name} for i in Tag.objects(name__icontains=q).limit(args["size"])]
31
+ return sorted(results, key=lambda o: len(o["text"]))
udata/core/tags/csv.py CHANGED
@@ -10,8 +10,8 @@ def counts(name):
10
10
  @csv.adapter(Tag)
11
11
  class TagCsvAdapter(csv.Adapter):
12
12
  fields = (
13
- 'name',
14
- counts('datasets'),
15
- counts('reuses'),
16
- 'total',
13
+ "name",
14
+ counts("datasets"),
15
+ counts("reuses"),
16
+ "total",
17
17
  )
udata/core/tags/models.py CHANGED
@@ -5,21 +5,24 @@ from udata.mongo import db
5
5
  log = logging.getLogger(__name__)
6
6
 
7
7
 
8
- __all__ = ('Tag', )
8
+ __all__ = ("Tag",)
9
9
 
10
10
 
11
11
  class Tag(db.Document):
12
- '''
12
+ """
13
13
  This collection is auto-populated every hour map-reducing tag properties
14
14
  from Datasets dans Reuses.
15
- '''
15
+ """
16
+
16
17
  name = db.StringField(required=True, unique=True)
17
18
  counts = db.DictField()
18
19
  total = db.IntField(default=0)
19
20
 
20
21
  meta = {
21
- 'indexes': ['name', '-total'],
22
- 'ordering': ['-total', ],
22
+ "indexes": ["name", "-total"],
23
+ "ordering": [
24
+ "-total",
25
+ ],
23
26
  }
24
27
 
25
28
  def clean(self):
udata/core/tags/tasks.py CHANGED
@@ -7,15 +7,15 @@ from .models import Tag
7
7
 
8
8
  log = logging.getLogger(__name__)
9
9
 
10
- map_tags = '''
10
+ map_tags = """
11
11
  function() {
12
12
  this.tags.forEach(function(tag) {
13
13
  emit(tag, 1);
14
14
  });
15
15
  }
16
- '''
16
+ """
17
17
 
18
- reduce_tags = '''
18
+ reduce_tags = """
19
19
  function(key, values) {
20
20
  var total = 0;
21
21
  for(var i = 0; i < values.length; i++) {
@@ -23,23 +23,21 @@ function(key, values) {
23
23
  }
24
24
  return total;
25
25
  }
26
- '''
26
+ """
27
27
 
28
28
  TAGGED = {
29
- 'datasets': Dataset,
30
- 'reuses': Reuse,
29
+ "datasets": Dataset,
30
+ "reuses": Reuse,
31
31
  }
32
32
 
33
33
 
34
- @job('count-tags')
34
+ @job("count-tags")
35
35
  def count_tags(self):
36
- '''Count tag occurences by type and update the tag collection'''
36
+ """Count tag occurences by type and update the tag collection"""
37
37
  for key, model in TAGGED.items():
38
- collection = '{0}_tags'.format(key)
39
- results = (model.objects(tags__exists=True)
40
- .map_reduce(map_tags, reduce_tags, collection))
38
+ collection = "{0}_tags".format(key)
39
+ results = model.objects(tags__exists=True).map_reduce(map_tags, reduce_tags, collection)
41
40
  for result in results:
42
- tag, created = Tag.objects.get_or_create(name=result.key,
43
- auto_save=False)
41
+ tag, created = Tag.objects.get_or_create(name=result.key, auto_save=False)
44
42
  tag.counts[key] = int(result.value) if result.value else 0
45
43
  tag.save()
udata/core/tags/views.py CHANGED
@@ -9,10 +9,10 @@ from .models import Tag
9
9
  log = logging.getLogger(__name__)
10
10
 
11
11
 
12
- blueprint = I18nBlueprint('tags', __name__)
12
+ blueprint = I18nBlueprint("tags", __name__)
13
13
 
14
14
 
15
- @blueprint.route('/tags.csv', endpoint='csv')
15
+ @blueprint.route("/tags.csv", endpoint="csv")
16
16
  def tags_csv():
17
- adapter = TagCsvAdapter(Tag.objects.order_by('-total'))
18
- return csv.stream(adapter, 'tags')
17
+ adapter = TagCsvAdapter(Tag.objects.order_by("-total"))
18
+ return csv.stream(adapter, "tags")