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
udata/forms/validators.py CHANGED
@@ -1,8 +1,7 @@
1
1
  from urlextract import URLExtract
2
-
3
2
  from wtforms import validators
4
3
  from wtforms.validators import * # noqa
5
- from wtforms.validators import ValidationError, StopValidation # noqa
4
+ from wtforms.validators import StopValidation, ValidationError # noqa
6
5
 
7
6
 
8
7
  def _(s):
@@ -10,10 +9,11 @@ def _(s):
10
9
 
11
10
 
12
11
  class NoURLs(object):
13
- '''
12
+ """
14
13
  Check no url is present on this field
15
- '''
16
- def __init__(self, message=''):
14
+ """
15
+
16
+ def __init__(self, message=""):
17
17
  self.extractor = URLExtract()
18
18
  self.message = message
19
19
 
@@ -23,10 +23,11 @@ class NoURLs(object):
23
23
 
24
24
 
25
25
  class RequiredIf(validators.DataRequired):
26
- '''
26
+ """
27
27
  A validator which makes a field required
28
28
  only if another field is set and has a truthy value.
29
- '''
29
+ """
30
+
30
31
  def __init__(self, other_field_name, *args, **kwargs):
31
32
  self.other_field_name = other_field_name
32
33
  super(RequiredIf, self).__init__(*args, **kwargs)
@@ -34,16 +35,16 @@ class RequiredIf(validators.DataRequired):
34
35
  def __call__(self, form, field):
35
36
  other_field = form._fields.get(self.other_field_name)
36
37
  if other_field is None:
37
- raise Exception(
38
- 'No field named "%s" in form' % self.other_field_name)
38
+ raise Exception('No field named "%s" in form' % self.other_field_name)
39
39
  if bool(other_field.data):
40
40
  super(RequiredIf, self).__call__(form, field)
41
41
 
42
42
 
43
43
  class Requires(object):
44
- '''
44
+ """
45
45
  A validator which makes a field required another field.
46
- '''
46
+ """
47
+
47
48
  def __init__(self, other_field_name, *args, **kwargs):
48
49
  self.other_field_name = other_field_name
49
50
  super(Requires, self).__init__(*args, **kwargs)
@@ -53,32 +54,28 @@ class Requires(object):
53
54
  return
54
55
  other_field = form._fields.get(self.other_field_name)
55
56
  if other_field is None:
56
- raise Exception(
57
- 'No field named "%s" in form' % self.other_field_name)
57
+ raise Exception('No field named "%s" in form' % self.other_field_name)
58
58
  if not bool(other_field.data):
59
59
  msg = field._('This field requires "%(name)s" to be set')
60
- raise validators.ValidationError(
61
- msg % {'name': field._(other_field.label.text)})
60
+ raise validators.ValidationError(msg % {"name": field._(other_field.label.text)})
62
61
 
63
62
 
64
63
  class RequiredIfVal(validators.DataRequired):
65
- '''
64
+ """
66
65
  A validator which makes a field required
67
66
  only if another field is set and has a specified value.
68
- '''
67
+ """
68
+
69
69
  def __init__(self, other_field_name, expected_value, *args, **kwargs):
70
70
  self.other_field_name = other_field_name
71
71
  self.expected_values = (
72
- expected_value
73
- if isinstance(expected_value, (list, tuple))
74
- else (expected_value,)
72
+ expected_value if isinstance(expected_value, (list, tuple)) else (expected_value,)
75
73
  )
76
74
  super(RequiredIfVal, self).__init__(*args, **kwargs)
77
75
 
78
76
  def __call__(self, form, field):
79
77
  other_field = form._fields.get(self.other_field_name)
80
78
  if other_field is None:
81
- raise Exception(
82
- 'No field named "%s" in form' % self.other_field_name)
79
+ raise Exception('No field named "%s" in form' % self.other_field_name)
83
80
  if other_field.data in self.expected_values:
84
81
  super(RequiredIfVal, self).__call__(form, field)
udata/forms/widgets.py CHANGED
@@ -10,14 +10,10 @@ class WidgetHelper(object):
10
10
 
11
11
  def __call__(self, field, **kwargs):
12
12
  # Handle extra classes
13
- classes = (kwargs.pop('class', '') or kwargs.pop('class_', '')).split()
14
- extra_classes = (
15
- self.classes
16
- if isinstance(self.classes, (list, tuple))
17
- else [self.classes]
18
- )
13
+ classes = (kwargs.pop("class", "") or kwargs.pop("class_", "")).split()
14
+ extra_classes = self.classes if isinstance(self.classes, (list, tuple)) else [self.classes]
19
15
  classes.extend([cls for cls in extra_classes if cls not in classes])
20
- kwargs['class'] = ' '.join(classes)
16
+ kwargs["class"] = " ".join(classes)
21
17
 
22
18
  # Handle defaults
23
19
  for key, value in self.attributes.items():
@@ -35,19 +31,19 @@ class TextArea(WidgetHelper, widgets.TextArea):
35
31
 
36
32
 
37
33
  class SelectPicker(WidgetHelper, widgets.Select):
38
- classes = 'selectpicker'
34
+ classes = "selectpicker"
39
35
 
40
36
 
41
37
  class MarkdownEditor(WidgetHelper, widgets.TextArea):
42
- classes = 'md'
43
- attributes = {'rows': 8}
38
+ classes = "md"
39
+ attributes = {"rows": 8}
44
40
 
45
41
 
46
42
  class DateRangePicker(WidgetHelper, widgets.HiddenInput):
47
- classes = 'dtpicker'
43
+ classes = "dtpicker"
48
44
 
49
45
  def __call__(self, field, **kwargs):
50
46
  if field.data:
51
- kwargs['data-start-date'] = field.data.start
52
- kwargs['data-end-date'] = field.data.end
47
+ kwargs["data-start-date"] = field.data.start
48
+ kwargs["data-end-date"] = field.data.end
53
49
  return super(DateRangePicker, self).__call__(field, **kwargs)
@@ -1,23 +1,23 @@
1
1
  import inspect
2
2
  import logging
3
- import pkg_resources
4
-
5
- from time import time
6
3
  from importlib import import_module
4
+ from time import time
5
+
6
+ import pkg_resources
7
+ from flask import current_app
7
8
  from jinja2 import pass_context
8
9
  from markupsafe import Markup
9
- from flask import current_app
10
10
 
11
11
  from udata import assets, entrypoints
12
12
  from udata.i18n import I18nBlueprint
13
13
 
14
- from .markdown import UdataCleaner, init_app as init_markdown
15
-
14
+ from .markdown import UdataCleaner
15
+ from .markdown import init_app as init_markdown
16
16
 
17
17
  log = logging.getLogger(__name__)
18
18
 
19
19
 
20
- hook = I18nBlueprint('hook', __name__)
20
+ hook = I18nBlueprint("hook", __name__)
21
21
 
22
22
  _template_hooks = {}
23
23
 
@@ -27,15 +27,15 @@ def package_version(name):
27
27
  return pkg_resources.get_distribution(name).version
28
28
 
29
29
 
30
- @hook.app_template_global(name='static')
30
+ @hook.app_template_global(name="static")
31
31
  def static_global(filename, _burst=True, **kwargs):
32
- if current_app.config['DEBUG'] or current_app.config['TESTING']:
32
+ if current_app.config["DEBUG"] or current_app.config["TESTING"]:
33
33
  burst = time()
34
34
  else:
35
- burst = package_version('udata')
35
+ burst = package_version("udata")
36
36
  if _burst:
37
- kwargs['_'] = burst
38
- return assets.cdn_for('static', filename=filename, **kwargs)
37
+ kwargs["_"] = burst
38
+ return assets.cdn_for("static", filename=filename, **kwargs)
39
39
 
40
40
 
41
41
  def _wrapper(func, name=None, when=None):
@@ -50,8 +50,10 @@ def template_hook(func_or_name, when=None):
50
50
  if callable(func_or_name):
51
51
  return _wrapper(func_or_name)
52
52
  elif isinstance(func_or_name, str):
53
+
53
54
  def wrapper(func):
54
55
  return _wrapper(func, func_or_name, when=when)
56
+
55
57
  return wrapper
56
58
 
57
59
 
@@ -67,11 +69,13 @@ class HookRenderer:
67
69
  self.kwargs = kwargs
68
70
 
69
71
  def __html__(self):
70
- return Markup(''.join(
71
- f(self.ctx, *self.args, **self.kwargs)
72
- for f, w in self.funcs
73
- if w is None or w(self.ctx)
74
- ))
72
+ return Markup(
73
+ "".join(
74
+ f(self.ctx, *self.args, **self.kwargs)
75
+ for f, w in self.funcs
76
+ if w is None or w(self.ctx)
77
+ )
78
+ )
75
79
 
76
80
  def __iter__(self):
77
81
  for func, when in self.funcs:
@@ -82,20 +86,21 @@ class HookRenderer:
82
86
  @pass_context
83
87
  def render_template_hook(ctx, name, *args, **kwargs):
84
88
  if not has_template_hook(name):
85
- return ''
89
+ return ""
86
90
  return HookRenderer(_template_hooks[name], ctx, *args, **kwargs)
87
91
 
88
92
 
89
93
  @hook.app_context_processor
90
94
  def inject_hooks():
91
95
  return {
92
- 'hook': render_template_hook,
93
- 'has_hook': has_template_hook,
96
+ "hook": render_template_hook,
97
+ "has_hook": has_template_hook,
94
98
  }
95
99
 
96
100
 
97
101
  class SafeMarkup(Markup):
98
- '''Markup object bypasses Jinja's escaping. This override allows to sanitize the resulting html.'''
102
+ """Markup object bypasses Jinja's escaping. This override allows to sanitize the resulting html."""
103
+
99
104
  def __new__(cls, base, *args, **kwargs):
100
105
  cleaner = UdataCleaner()
101
106
  return super().__new__(cls, cleaner.clean(base), *args, **kwargs)
@@ -103,12 +108,12 @@ class SafeMarkup(Markup):
103
108
 
104
109
  def _load_views(app, module):
105
110
  views = module if inspect.ismodule(module) else import_module(module)
106
- blueprint = getattr(views, 'blueprint', None)
111
+ blueprint = getattr(views, "blueprint", None)
107
112
  if blueprint:
108
113
  app.register_blueprint(blueprint)
109
114
 
110
115
 
111
- VIEWS = ['core.storages', 'core.tags', 'admin']
116
+ VIEWS = ["core.storages", "core.tags", "admin"]
112
117
 
113
118
 
114
119
  def init_app(app, views=None):
@@ -117,16 +122,16 @@ def init_app(app, views=None):
117
122
  init_markdown(app)
118
123
 
119
124
  for view in views:
120
- _load_views(app, 'udata.{}.views'.format(view))
125
+ _load_views(app, "udata.{}.views".format(view))
121
126
 
122
127
  # Load hook blueprint
123
128
  app.register_blueprint(hook)
124
129
 
125
130
  # Load all plugins views and blueprints
126
- for module in entrypoints.get_enabled('udata.views', app).values():
131
+ for module in entrypoints.get_enabled("udata.views", app).values():
127
132
  _load_views(app, module)
128
133
 
129
134
  # Load all plugins views and blueprints
130
- for module in entrypoints.get_enabled('udata.front', app).values():
135
+ for module in entrypoints.get_enabled("udata.front", app).values():
131
136
  front_module = module if inspect.ismodule(module) else import_module(module)
132
137
  front_module.init_app(app)
udata/frontend/csv.py CHANGED
@@ -1,29 +1,26 @@
1
+ import csv
2
+ import itertools
1
3
  import logging
2
-
4
+ from datetime import date, datetime
3
5
  from io import StringIO
4
- import itertools
5
- import csv
6
-
7
- from datetime import datetime, date
8
6
 
9
7
  from flask import Response, stream_with_context
10
8
 
11
9
  from udata.mongo import db
12
10
  from udata.utils import recursive_get
13
11
 
14
-
15
12
  log = logging.getLogger(__name__)
16
13
 
17
14
  _adapters = {}
18
15
 
19
16
  CONFIG = {
20
- 'delimiter': ';',
21
- 'quotechar': '"',
17
+ "delimiter": ";",
18
+ "quotechar": '"',
22
19
  }
23
20
 
24
21
 
25
22
  def safestr(value):
26
- '''Ensure type to string serialization'''
23
+ """Ensure type to string serialization"""
27
24
  if not value or isinstance(value, (int, float, bool)):
28
25
  return value
29
26
  elif isinstance(value, (date, datetime)):
@@ -33,7 +30,8 @@ def safestr(value):
33
30
 
34
31
 
35
32
  class Adapter(object):
36
- '''A Base model CSV adapter'''
33
+ """A Base model CSV adapter"""
34
+
37
35
  fields = None
38
36
 
39
37
  def __init__(self, queryset):
@@ -43,7 +41,7 @@ class Adapter(object):
43
41
  def get_fields(self):
44
42
  if not self._fields:
45
43
  if not isinstance(self.fields, (list, tuple)):
46
- raise ValueError('Unsupported fields format')
44
+ raise ValueError("Unsupported fields format")
47
45
  self._fields = []
48
46
  for field in itertools.chain(self.fields, self.dynamic_fields()):
49
47
  name = field if isinstance(field, str) else field[0]
@@ -58,39 +56,46 @@ class Adapter(object):
58
56
  else:
59
57
  field_tuple = (name, self.getter(*field))
60
58
  except Exception as e: # Catch all errors intentionally.
61
- log.exception('Error exporting CSV for {name}: {error_class} {error}'.format(
62
- name=self.__class__.__name__, error_class=e.__class__.__name__, error=e), stack_info=True)
59
+ log.exception(
60
+ "Error exporting CSV for {name}: {error_class} {error}".format(
61
+ name=self.__class__.__name__, error_class=e.__class__.__name__, error=e
62
+ ),
63
+ stack_info=True,
64
+ )
63
65
  self._fields.append(field_tuple)
64
66
  return self._fields
65
67
 
66
68
  def getter(self, name, getter=None):
67
69
  if not getter:
68
- method = 'field_{0}'.format(name)
69
- return (getattr(self, method)
70
- if hasattr(self, method)
71
- else lambda o: recursive_get(o, name))
72
- return ((lambda o: recursive_get(o, getter))
73
- if isinstance(getter, str) else getter)
70
+ method = "field_{0}".format(name)
71
+ return (
72
+ getattr(self, method) if hasattr(self, method) else lambda o: recursive_get(o, name)
73
+ )
74
+ return (lambda o: recursive_get(o, getter)) if isinstance(getter, str) else getter
74
75
 
75
76
  def header(self):
76
- '''Generate the CSV header row'''
77
+ """Generate the CSV header row"""
77
78
  return [name for name, getter in self.get_fields()]
78
79
 
79
80
  def rows(self):
80
- '''Iterate over queryset objects'''
81
+ """Iterate over queryset objects"""
81
82
  return (self.to_row(o) for o in self.queryset)
82
83
 
83
84
  def to_row(self, obj):
84
- '''Convert an object into a flat csv row'''
85
+ """Convert an object into a flat csv row"""
85
86
  row = []
86
87
  for name, getter in self.get_fields():
87
- content = ''
88
+ content = ""
88
89
  if getter is not None:
89
90
  try:
90
91
  content = safestr(getter(obj))
91
92
  except Exception as e: # Catch all errors intentionally.
92
- log.exception('Error exporting CSV for {name}: {error_class} {error}'.format(
93
- name=self.__class__.__name__, error_class=e.__class__.__name__, error=e), stack_info=True)
93
+ log.exception(
94
+ "Error exporting CSV for {name}: {error_class} {error}".format(
95
+ name=self.__class__.__name__, error_class=e.__class__.__name__, error=e
96
+ ),
97
+ stack_info=True,
98
+ )
94
99
  row.append(content)
95
100
  return row
96
101
 
@@ -107,17 +112,17 @@ class NestedAdapter(Adapter):
107
112
  self._nested_fields = None
108
113
 
109
114
  def header(self):
110
- '''Generate the CSV header row'''
111
- return (super(NestedAdapter, self).header() +
112
- [name for name, getter in self.get_nested_fields()])
115
+ """Generate the CSV header row"""
116
+ return super(NestedAdapter, self).header() + [
117
+ name for name, getter in self.get_nested_fields()
118
+ ]
113
119
 
114
120
  def get_nested_fields(self):
115
121
  if not self._nested_fields:
116
122
  if not isinstance(self.nested_fields, (list, tuple)):
117
- raise ValueError('Unsupported nested fields format')
123
+ raise ValueError("Unsupported nested fields format")
118
124
  self._nested_fields = []
119
- for field in itertools.chain(self.nested_fields,
120
- self.nested_dynamic_fields()):
125
+ for field in itertools.chain(self.nested_fields, self.nested_dynamic_fields()):
121
126
  name = field if isinstance(field, str) else field[0]
122
127
  # Retrieving (dynamically) fields is prone to errors,
123
128
  # we don't want to break the CSV generation for a unique
@@ -130,33 +135,39 @@ class NestedAdapter(Adapter):
130
135
  else:
131
136
  field_tuple = (name, self.getter(*field))
132
137
  except Exception as e: # Catch all errors intentionally.
133
- log.exception('Error exporting CSV for {name}: {error_class} {error}'.format(
134
- name=self.__class__.__name__, error_class=e.__class__.__name__, error=e), stack_info=True)
138
+ log.exception(
139
+ "Error exporting CSV for {name}: {error_class} {error}".format(
140
+ name=self.__class__.__name__, error_class=e.__class__.__name__, error=e
141
+ ),
142
+ stack_info=True,
143
+ )
135
144
  self._nested_fields.append(field_tuple)
136
145
  return self._nested_fields
137
146
 
138
147
  def get_queryset(self):
139
- return ((o, n)
140
- for o in self.queryset
141
- for n in getattr(o, self.attribute))
148
+ return ((o, n) for o in self.queryset for n in getattr(o, self.attribute))
142
149
 
143
150
  def rows(self):
144
- '''Iterate over queryset objects'''
145
- return (self.nested_row(o, n)
146
- for o in self.queryset
147
- for n in getattr(o, self.attribute, []))
151
+ """Iterate over queryset objects"""
152
+ return (
153
+ self.nested_row(o, n) for o in self.queryset for n in getattr(o, self.attribute, [])
154
+ )
148
155
 
149
156
  def nested_row(self, obj, nested):
150
- '''Convert an object into a flat csv row'''
157
+ """Convert an object into a flat csv row"""
151
158
  row = self.to_row(obj)
152
159
  for name, getter in self.get_nested_fields():
153
- content = ''
160
+ content = ""
154
161
  if getter is not None:
155
162
  try:
156
163
  content = safestr(getter(nested))
157
164
  except Exception as e: # Catch all errors intentionally.
158
- log.exception('Error exporting CSV for {name}: {error_class} {error}'.format(
159
- name=self.__class__.__name__, error_class=e.__class__.__name__, error=e), stack_info=True)
165
+ log.exception(
166
+ "Error exporting CSV for {name}: {error_class} {error}".format(
167
+ name=self.__class__.__name__, error_class=e.__class__.__name__, error=e
168
+ ),
169
+ stack_info=True,
170
+ )
160
171
  row.append(content)
161
172
  return row
162
173
 
@@ -165,10 +176,12 @@ class NestedAdapter(Adapter):
165
176
 
166
177
 
167
178
  def adapter(model):
168
- '''Register an adapter class for a given model'''
179
+ """Register an adapter class for a given model"""
180
+
169
181
  def inner(cls):
170
182
  _adapters[model] = cls
171
183
  return cls
184
+
172
185
  return inner
173
186
 
174
187
 
@@ -181,24 +194,21 @@ def _metric_getter(key):
181
194
 
182
195
 
183
196
  def metric_fields(cls):
184
- return [
185
- ('metric.{0}'.format(key), _metric_getter(key))
186
- for key in cls.__metrics_keys__
187
- ]
197
+ return [("metric.{0}".format(key), _metric_getter(key)) for key in cls.__metrics_keys__]
188
198
 
189
199
 
190
200
  def get_writer(out):
191
- '''Get a preconfigured CSV writer for a given output file'''
201
+ """Get a preconfigured CSV writer for a given output file"""
192
202
  return csv.writer(out, quoting=csv.QUOTE_NONNUMERIC, **CONFIG)
193
203
 
194
204
 
195
205
  def get_reader(infile):
196
- '''Get a preconfigured CSV reader for a given input file'''
206
+ """Get a preconfigured CSV reader for a given input file"""
197
207
  return csv.reader(infile, **CONFIG)
198
208
 
199
209
 
200
210
  def yield_rows(adapter):
201
- '''Yield a dataset catalog line by line'''
211
+ """Yield a dataset catalog line by line"""
202
212
  csvfile = StringIO()
203
213
  writer = get_writer(csvfile)
204
214
  # Generate header
@@ -223,20 +233,20 @@ def stream(queryset_or_adapter, basename=None):
223
233
  adapter = queryset_or_adapter
224
234
  elif isinstance(queryset_or_adapter, (list, tuple)):
225
235
  if not queryset_or_adapter:
226
- raise ValueError(
227
- 'Type detection is not possible with an empty list')
236
+ raise ValueError("Type detection is not possible with an empty list")
228
237
  cls = _adapters.get(queryset_or_adapter[0].__class__)
229
238
  adapter = cls(queryset_or_adapter)
230
239
  elif isinstance(queryset_or_adapter, db.BaseQuerySet):
231
240
  cls = _adapters.get(queryset_or_adapter._document)
232
241
  adapter = cls(queryset_or_adapter)
233
242
  else:
234
- raise ValueError('Unsupported object type')
243
+ raise ValueError("Unsupported object type")
235
244
 
236
- timestamp = datetime.utcnow().strftime('%Y-%m-%d-%H-%M')
245
+ timestamp = datetime.utcnow().strftime("%Y-%m-%d-%H-%M")
237
246
  headers = {
238
- 'Content-Disposition': 'attachment; filename={0}-{1}.csv'.format(
239
- basename or 'export', timestamp),
247
+ "Content-Disposition": "attachment; filename={0}-{1}.csv".format(
248
+ basename or "export", timestamp
249
+ ),
240
250
  }
241
251
  streamer = stream_with_context(yield_rows(adapter))
242
252
  return Response(streamer, mimetype="text/csv", headers=headers)