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,230 +1,241 @@
1
- import pytest
2
-
3
1
  from datetime import datetime, timedelta
4
2
  from io import BytesIO
3
+ from os.path import basename
5
4
  from uuid import uuid4
6
5
 
7
- from flask import url_for, json
6
+ import pytest
7
+ from flask import json, url_for
8
+ from werkzeug.test import EnvironBuilder
9
+ from werkzeug.wrappers import Request
8
10
 
9
11
  from udata.core import storages
10
12
  from udata.core.storages import utils
11
- from udata.core.storages.api import chunk_filename, META
13
+ from udata.core.storages.api import META, chunk_filename
12
14
  from udata.core.storages.tasks import purge_chunks
13
15
  from udata.utils import faker
14
16
 
15
17
  from .helpers import assert200, assert400
16
18
 
17
- from os.path import basename
18
-
19
- from werkzeug.test import EnvironBuilder
20
- from werkzeug.wrappers import Request
21
-
22
19
 
23
20
  class StorageUtilsTest:
24
- '''
21
+ """
25
22
  Perform all tests on a file of size 2 * CHUNCK_SIZE = 2 * (2 ** 16).
26
23
  Expected values are precomputed with shell `md5sum`, `sha1sum`...
27
- '''
24
+ """
25
+
28
26
  @pytest.fixture(autouse=True)
29
27
  def write_file(self, tmpdir):
30
- tmpfile = tmpdir.join('test.txt')
31
- tmpfile.write_binary(b'a' * 2 * (2 ** 16))
28
+ tmpfile = tmpdir.join("test.txt")
29
+ tmpfile.write_binary(b"a" * 2 * (2**16))
32
30
  self.file = self.filestorage(str(tmpfile))
33
31
 
34
32
  def filestorage(self, filename):
35
- data = open(filename, 'rb')
36
- builder = EnvironBuilder(method='POST', data={
37
- 'file': (data, basename(filename))
38
- })
33
+ data = open(filename, "rb")
34
+ builder = EnvironBuilder(method="POST", data={"file": (data, basename(filename))})
39
35
  env = builder.get_environ()
40
36
  req = Request(env)
41
- return req.files['file']
37
+ return req.files["file"]
42
38
 
43
39
  def test_sha1(self):
44
40
  # Output of sha1sum
45
- expected = 'ce5653590804baa9369f72d483ed9eba72f04d29'
41
+ expected = "ce5653590804baa9369f72d483ed9eba72f04d29"
46
42
  assert utils.sha1(self.file) == expected
47
43
 
48
44
  def test_md5(self):
49
- expected = '81615449a98aaaad8dc179b3bec87f38' # Output of md5sum
45
+ expected = "81615449a98aaaad8dc179b3bec87f38" # Output of md5sum
50
46
  assert utils.md5(self.file) == expected
51
47
 
52
48
  def test_crc32(self):
53
- expected = 'CA975130' # Output of cksfv
49
+ expected = "CA975130" # Output of cksfv
54
50
  assert utils.crc32(self.file) == expected
55
51
 
56
52
  def test_mime(self):
57
- assert utils.mime('test.txt') == 'text/plain'
58
- assert utils.mime('test') is None
53
+ assert utils.mime("test.txt") == "text/plain"
54
+ assert utils.mime("test") is None
59
55
 
60
56
  def test_extension_default(self, app):
61
- assert utils.extension('test.txt') == 'txt'
62
- assert utils.extension('prefix/test.txt') == 'txt'
63
- assert utils.extension('prefix.with.dot/test.txt') == 'txt'
57
+ assert utils.extension("test.txt") == "txt"
58
+ assert utils.extension("prefix/test.txt") == "txt"
59
+ assert utils.extension("prefix.with.dot/test.txt") == "txt"
64
60
 
65
61
  def test_extension_compound(self, app):
66
- assert utils.extension('test.tar.gz') == 'tar.gz'
67
- assert utils.extension('prefix.with.dot/test.tar.gz') == 'tar.gz'
62
+ assert utils.extension("test.tar.gz") == "tar.gz"
63
+ assert utils.extension("prefix.with.dot/test.tar.gz") == "tar.gz"
68
64
 
69
65
  def test_extension_compound_with_allowed_extension(self, app):
70
- assert utils.extension('test.2022.csv.tar.gz') == 'csv.tar.gz'
71
- assert utils.extension('prefix.with.dot/test.2022.csv.tar.gz') == 'csv.tar.gz'
66
+ assert utils.extension("test.2022.csv.tar.gz") == "csv.tar.gz"
67
+ assert utils.extension("prefix.with.dot/test.2022.csv.tar.gz") == "csv.tar.gz"
72
68
 
73
69
  def test_extension_compound_without_allowed_extension(self, app):
74
- assert utils.extension('test.2022.tar.gz') == 'tar.gz'
75
- assert utils.extension('prefix.with.dot/test.2022.tar.gz') == 'tar.gz'
70
+ assert utils.extension("test.2022.tar.gz") == "tar.gz"
71
+ assert utils.extension("prefix.with.dot/test.2022.tar.gz") == "tar.gz"
76
72
 
77
73
  def test_no_extension(self, app):
78
- assert utils.extension('test') is None
79
- assert utils.extension('prefix/test') is None
74
+ assert utils.extension("test") is None
75
+ assert utils.extension("prefix/test") is None
80
76
 
81
77
  def test_normalize_no_changes(self):
82
- assert utils.normalize('test.txt') == 'test.txt'
78
+ assert utils.normalize("test.txt") == "test.txt"
83
79
 
84
80
  def test_normalize_spaces(self):
85
- expected = 'test-with-spaces.txt'
86
- assert utils.normalize('test with spaces.txt') == expected
81
+ expected = "test-with-spaces.txt"
82
+ assert utils.normalize("test with spaces.txt") == expected
87
83
 
88
84
  def test_normalize_to_lower(self):
89
- assert utils.normalize('Test.TXT') == 'test.txt'
85
+ assert utils.normalize("Test.TXT") == "test.txt"
90
86
 
91
87
  def test_normalize_special_chars(self):
92
- assert utils.normalize('éàü@€.txt') == 'eau-eur.txt'
88
+ assert utils.normalize("éàü@€.txt") == "eau-eur.txt"
93
89
 
94
90
 
95
- @pytest.mark.usefixtures('app')
91
+ @pytest.mark.usefixtures("app")
96
92
  class ConfigurableAllowedExtensionsTest:
97
93
  def test_has_default(self):
98
- assert 'csv' in storages.CONFIGURABLE_AUTHORIZED_TYPES
99
- assert 'xml' in storages.CONFIGURABLE_AUTHORIZED_TYPES
100
- assert 'json' in storages.CONFIGURABLE_AUTHORIZED_TYPES
101
- assert 'exe' not in storages.CONFIGURABLE_AUTHORIZED_TYPES
102
- assert 'bat' not in storages.CONFIGURABLE_AUTHORIZED_TYPES
94
+ assert "csv" in storages.CONFIGURABLE_AUTHORIZED_TYPES
95
+ assert "xml" in storages.CONFIGURABLE_AUTHORIZED_TYPES
96
+ assert "json" in storages.CONFIGURABLE_AUTHORIZED_TYPES
97
+ assert "exe" not in storages.CONFIGURABLE_AUTHORIZED_TYPES
98
+ assert "bat" not in storages.CONFIGURABLE_AUTHORIZED_TYPES
103
99
 
104
- @pytest.mark.options(ALLOWED_RESOURCES_EXTENSIONS=['csv', 'json'])
100
+ @pytest.mark.options(ALLOWED_RESOURCES_EXTENSIONS=["csv", "json"])
105
101
  def test_with_config(self):
106
- assert 'csv' in storages.CONFIGURABLE_AUTHORIZED_TYPES
107
- assert 'json' in storages.CONFIGURABLE_AUTHORIZED_TYPES
108
- assert 'xml' not in storages.CONFIGURABLE_AUTHORIZED_TYPES
109
- assert 'exe' not in storages.CONFIGURABLE_AUTHORIZED_TYPES
110
- assert 'bat' not in storages.CONFIGURABLE_AUTHORIZED_TYPES
102
+ assert "csv" in storages.CONFIGURABLE_AUTHORIZED_TYPES
103
+ assert "json" in storages.CONFIGURABLE_AUTHORIZED_TYPES
104
+ assert "xml" not in storages.CONFIGURABLE_AUTHORIZED_TYPES
105
+ assert "exe" not in storages.CONFIGURABLE_AUTHORIZED_TYPES
106
+ assert "bat" not in storages.CONFIGURABLE_AUTHORIZED_TYPES
111
107
 
112
108
 
113
- @pytest.mark.usefixtures('instance_path')
109
+ @pytest.mark.usefixtures("instance_path")
114
110
  class StorageUploadViewTest:
115
111
  def test_standard_upload(self, client):
116
112
  client.login()
117
113
  response = client.post(
118
- url_for('test-storage.upload', name='resources'),
119
- {'file': (BytesIO(b'aaa'), 'Test with spaces.TXT')})
114
+ url_for("test-storage.upload", name="resources"),
115
+ {"file": (BytesIO(b"aaa"), "Test with spaces.TXT")},
116
+ )
120
117
 
121
118
  assert200(response)
122
- assert response.json['success']
123
- assert 'url' in response.json
124
- assert 'size' in response.json
125
- assert 'sha1' in response.json
126
- assert 'filename' in response.json
127
- filename = response.json['filename']
128
- assert filename.endswith('test-with-spaces.txt')
119
+ assert response.json["success"]
120
+ assert "url" in response.json
121
+ assert "size" in response.json
122
+ assert "sha1" in response.json
123
+ assert "filename" in response.json
124
+ filename = response.json["filename"]
125
+ assert filename.endswith("test-with-spaces.txt")
129
126
  expected = storages.resources.url(filename, external=True)
130
- assert response.json['url'] == expected
131
- assert response.json['mime'] == 'text/plain'
127
+ assert response.json["url"] == expected
128
+ assert response.json["mime"] == "text/plain"
132
129
 
133
130
  def test_chunked_upload(self, client):
134
131
  client.login()
135
- url = url_for('test-storage.upload', name='tmp')
132
+ url = url_for("test-storage.upload", name="tmp")
136
133
  uuid = str(uuid4())
137
134
  parts = 4
138
135
 
139
136
  for i in range(parts):
140
- response = client.post(url, {
141
- 'file': (BytesIO(b'a'), 'blob'),
142
- 'uuid': uuid,
143
- 'filename': 'Test with spaces.TXT',
144
- 'partindex': i,
145
- 'partbyteoffset': 0,
146
- 'totalfilesize': parts,
147
- 'totalparts': parts,
148
- 'chunksize': 1,
149
- })
137
+ response = client.post(
138
+ url,
139
+ {
140
+ "file": (BytesIO(b"a"), "blob"),
141
+ "uuid": uuid,
142
+ "filename": "Test with spaces.TXT",
143
+ "partindex": i,
144
+ "partbyteoffset": 0,
145
+ "totalfilesize": parts,
146
+ "totalparts": parts,
147
+ "chunksize": 1,
148
+ },
149
+ )
150
150
 
151
151
  assert200(response)
152
- assert response.json['success']
153
- assert 'filename' not in response.json
154
- assert 'url' not in response.json
155
- assert 'size' not in response.json
156
- assert 'sha1' not in response.json
157
- assert 'url' not in response.json
158
-
159
- response = client.post(url, {
160
- 'uuid': uuid,
161
- 'filename': 'Test with spaces.TXT',
162
- 'totalfilesize': parts,
163
- 'totalparts': parts,
164
- })
165
- assert 'filename' in response.json
166
- assert 'url' in response.json
167
- assert 'size' in response.json
168
- assert response.json['size'] == parts
169
- assert 'sha1' in response.json
170
- expected_filename = 'test-with-spaces.txt'
171
- filename = response.json['filename']
152
+ assert response.json["success"]
153
+ assert "filename" not in response.json
154
+ assert "url" not in response.json
155
+ assert "size" not in response.json
156
+ assert "sha1" not in response.json
157
+ assert "url" not in response.json
158
+
159
+ response = client.post(
160
+ url,
161
+ {
162
+ "uuid": uuid,
163
+ "filename": "Test with spaces.TXT",
164
+ "totalfilesize": parts,
165
+ "totalparts": parts,
166
+ },
167
+ )
168
+ assert "filename" in response.json
169
+ assert "url" in response.json
170
+ assert "size" in response.json
171
+ assert response.json["size"] == parts
172
+ assert "sha1" in response.json
173
+ expected_filename = "test-with-spaces.txt"
174
+ filename = response.json["filename"]
172
175
  assert filename.endswith(expected_filename)
173
176
  expected_url = storages.tmp.url(filename, external=True)
174
- assert response.json['url'] == expected_url
175
- assert response.json['mime'] == 'text/plain'
176
- assert storages.tmp.read(filename) == b'aaaa'
177
+ assert response.json["url"] == expected_url
178
+ assert response.json["mime"] == "text/plain"
179
+ assert storages.tmp.read(filename) == b"aaaa"
177
180
  assert list(storages.chunks.list_files()) == []
178
181
 
179
182
  def test_chunked_upload_bad_chunk(self, client):
180
183
  client.login()
181
- url = url_for('test-storage.upload', name='tmp')
184
+ url = url_for("test-storage.upload", name="tmp")
182
185
  uuid = str(uuid4())
183
186
  parts = 4
184
187
 
185
- response = client.post(url, {
186
- 'file': (BytesIO(b'a'), 'blob'),
187
- 'uuid': uuid,
188
- 'filename': 'test.txt',
189
- 'partindex': 0,
190
- 'partbyteoffset': 0,
191
- 'totalfilesize': parts,
192
- 'totalparts': parts,
193
- 'chunksize': 10, # Does not match
194
- })
188
+ response = client.post(
189
+ url,
190
+ {
191
+ "file": (BytesIO(b"a"), "blob"),
192
+ "uuid": uuid,
193
+ "filename": "test.txt",
194
+ "partindex": 0,
195
+ "partbyteoffset": 0,
196
+ "totalfilesize": parts,
197
+ "totalparts": parts,
198
+ "chunksize": 10, # Does not match
199
+ },
200
+ )
195
201
 
196
202
  assert400(response)
197
- assert not response.json['success']
198
- assert 'filename' not in response.json
199
- assert 'url' not in response.json
200
- assert 'size' not in response.json
201
- assert 'sha1' not in response.json
202
- assert 'url' not in response.json
203
+ assert not response.json["success"]
204
+ assert "filename" not in response.json
205
+ assert "url" not in response.json
206
+ assert "size" not in response.json
207
+ assert "sha1" not in response.json
208
+ assert "url" not in response.json
203
209
 
204
210
  assert list(storages.chunks.list_files()) == []
205
211
 
206
212
  def test_upload_resource_bad_request(self, client):
207
213
  client.login()
208
214
  response = client.post(
209
- url_for('test-storage.upload', name='tmp'),
210
- {'bad': (BytesIO(b'aaa'), 'test.txt')})
215
+ url_for("test-storage.upload", name="tmp"), {"bad": (BytesIO(b"aaa"), "test.txt")}
216
+ )
211
217
 
212
218
  assert400(response)
213
- assert not response.json['success']
214
- assert 'error' in response.json
219
+ assert not response.json["success"]
220
+ assert "error" in response.json
215
221
 
216
222
 
217
- @pytest.mark.usefixtures('instance_path')
223
+ @pytest.mark.usefixtures("instance_path")
218
224
  class ChunksRetentionTest:
219
225
  def create_chunks(self, uuid, nb=3, last=None):
220
226
  for i in range(nb):
221
227
  storages.chunks.write(chunk_filename(uuid, i), faker.word())
222
- storages.chunks.write(chunk_filename(uuid, META), json.dumps({
223
- 'uuid': str(uuid),
224
- 'filename': faker.file_name(),
225
- 'totalparts': nb + 1,
226
- 'lastchunk': last or datetime.utcnow(),
227
- }))
228
+ storages.chunks.write(
229
+ chunk_filename(uuid, META),
230
+ json.dumps(
231
+ {
232
+ "uuid": str(uuid),
233
+ "filename": faker.file_name(),
234
+ "totalparts": nb + 1,
235
+ "lastchunk": last or datetime.utcnow(),
236
+ }
237
+ ),
238
+ )
228
239
 
229
240
  @pytest.mark.options(UPLOAD_MAX_RETENTION=0)
230
241
  def test_chunks_cleanup_after_max_retention(self, client):
@@ -244,9 +255,7 @@ class ChunksRetentionTest:
244
255
  self.create_chunks(expired_uuid, nb=parts, last=expired)
245
256
  self.create_chunks(active_uuid, nb=parts, last=not_expired)
246
257
  purge_chunks.apply()
247
- expected = set([
248
- chunk_filename(active_uuid, i) for i in range(parts)
249
- ])
258
+ expected = set([chunk_filename(active_uuid, i) for i in range(parts)])
250
259
  expected.add(chunk_filename(active_uuid, META))
251
260
  assert set(storages.chunks.list_files()) == expected
252
261
  assert not storages.chunks.exists(expired_uuid) # Directory should be removed too
udata/tests/test_tags.py CHANGED
@@ -1,17 +1,16 @@
1
1
  import logging
2
- import pytest
3
2
  from io import StringIO
4
3
 
4
+ import pytest
5
5
  from flask import url_for
6
6
 
7
- from udata.frontend import csv
8
-
9
- from udata.tests.helpers import assert200
10
7
  from udata.core.dataset.factories import DatasetFactory
11
8
  from udata.core.reuse.factories import ReuseFactory
12
9
  from udata.core.tags.models import Tag
13
10
  from udata.core.tags.tasks import count_tags
14
- from udata.tags import tags_list, normalize, slug
11
+ from udata.frontend import csv
12
+ from udata.tags import normalize, slug, tags_list
13
+ from udata.tests.helpers import assert200
15
14
 
16
15
  log = logging.getLogger(__name__)
17
16
 
@@ -21,42 +20,42 @@ MAX_TAG_LENGTH = 32
21
20
 
22
21
  @pytest.mark.frontend
23
22
  class TagsTests:
24
- modules = ['core.tags']
23
+ modules = ["core.tags"]
25
24
 
26
25
  def test_csv(self, client):
27
- Tag.objects.create(name='datasets-only', counts={'datasets': 15})
28
- Tag.objects.create(name='reuses-only', counts={'reuses': 10})
29
- Tag.objects.create(name='both', counts={'reuses': 10, 'datasets': 15})
26
+ Tag.objects.create(name="datasets-only", counts={"datasets": 15})
27
+ Tag.objects.create(name="reuses-only", counts={"reuses": 10})
28
+ Tag.objects.create(name="both", counts={"reuses": 10, "datasets": 15})
30
29
 
31
- response = client.get(url_for('tags.csv'))
30
+ response = client.get(url_for("tags.csv"))
32
31
  assert200(response)
33
- assert response.mimetype == 'text/csv'
34
- assert response.charset == 'utf-8'
32
+ assert response.mimetype == "text/csv"
33
+ assert response.charset == "utf-8"
35
34
 
36
- csvfile = StringIO(response.data.decode('utf8'))
35
+ csvfile = StringIO(response.data.decode("utf8"))
37
36
  reader = reader = csv.get_reader(csvfile)
38
37
  header = next(reader)
39
38
  rows = list(reader)
40
39
 
41
- assert header == ['name', 'datasets', 'reuses', 'total']
40
+ assert header == ["name", "datasets", "reuses", "total"]
42
41
  assert len(rows) is 3
43
- assert rows[0] == ['both', '15', '10', '25']
44
- assert rows[1] == ['datasets-only', '15', '0', '15']
45
- assert rows[2] == ['reuses-only', '0', '10', '10']
42
+ assert rows[0] == ["both", "15", "10", "25"]
43
+ assert rows[1] == ["datasets-only", "15", "0", "15"]
44
+ assert rows[2] == ["reuses-only", "0", "10", "10"]
46
45
 
47
46
  def test_count(self):
48
47
  for i in range(1, 4):
49
48
  # Tags should be normalized and deduplicated.
50
- tags = ['Tag "{0}"'.format(j) for j in range(i)] + ['tag-0']
49
+ tags = ['Tag "{0}"'.format(j) for j in range(i)] + ["tag-0"]
51
50
  DatasetFactory(tags=tags, visible=True)
52
51
  ReuseFactory(tags=tags, visible=True)
53
52
 
54
53
  count_tags.run()
55
54
 
56
55
  expected = {
57
- 'tag-0': 3,
58
- 'tag-1': 2,
59
- 'tag-2': 1,
56
+ "tag-0": 3,
57
+ "tag-1": 2,
58
+ "tag-2": 1,
60
59
  }
61
60
 
62
61
  assert len(Tag.objects) == len(expected)
@@ -64,51 +63,50 @@ class TagsTests:
64
63
  for name, count in expected.items():
65
64
  tag = Tag.objects.get(name=name)
66
65
  assert tag.total == 2 * count
67
- assert tag.counts['datasets'] == count
68
- assert tag.counts['reuses'] == count
66
+ assert tag.counts["datasets"] == count
67
+ assert tag.counts["reuses"] == count
69
68
 
70
69
 
71
70
  class TagsUtilsTest:
72
-
73
71
  def test_tags_list(self):
74
- assert tags_list('') == []
75
- assert tags_list('a') == ['a']
76
- assert sorted(tags_list('a, b, c')) == ['a', 'b', 'c']
77
- assert sorted(tags_list('a b, c d, e')) == ['a-b', 'c-d', 'e']
72
+ assert tags_list("") == []
73
+ assert tags_list("a") == ["a"]
74
+ assert sorted(tags_list("a, b, c")) == ["a", "b", "c"]
75
+ assert sorted(tags_list("a b, c d, e")) == ["a-b", "c-d", "e"]
78
76
 
79
77
  def test_tags_list_strip(self):
80
- assert sorted(tags_list('a, b , ,,, c')) == ['a', 'b', 'c']
81
- assert sorted(tags_list(' a b , c d, e ')) == ['a-b', 'c-d', 'e']
78
+ assert sorted(tags_list("a, b , ,,, c")) == ["a", "b", "c"]
79
+ assert sorted(tags_list(" a b , c d, e ")) == ["a-b", "c-d", "e"]
82
80
 
83
81
  def test_tags_list_deduplication(self):
84
- assert sorted(tags_list('a b, c d, a b , e')) == ['a-b', 'c-d', 'e']
82
+ assert sorted(tags_list("a b, c d, a b , e")) == ["a-b", "c-d", "e"]
85
83
 
86
84
  def test_slug_empty(self):
87
- assert slug('') == ''
85
+ assert slug("") == ""
88
86
 
89
87
  def test_slug_several_words(self):
90
- assert slug('la claire fontaine') == 'la-claire-fontaine'
88
+ assert slug("la claire fontaine") == "la-claire-fontaine"
91
89
 
92
90
  def test_slug_accents(self):
93
- assert slug('école publique') == 'ecole-publique'
91
+ assert slug("école publique") == "ecole-publique"
94
92
 
95
93
  def test_slug_case(self):
96
- assert slug('EcoLe publiquE') == 'ecole-publique'
94
+ assert slug("EcoLe publiquE") == "ecole-publique"
97
95
 
98
96
  def test_slug_consecutive_spaces(self):
99
- assert slug('ecole publique') == 'ecole-publique'
97
+ assert slug("ecole publique") == "ecole-publique"
100
98
 
101
99
  def test_slug_special_characters(self):
102
- assert slug('ecole-publique') == 'ecole-publique'
103
- assert slug('ecole publique.') == 'ecole-publique'
104
- assert slug('ecole publique-') == 'ecole-publique'
105
- assert slug('ecole publique_') == 'ecole-publique'
100
+ assert slug("ecole-publique") == "ecole-publique"
101
+ assert slug("ecole publique.") == "ecole-publique"
102
+ assert slug("ecole publique-") == "ecole-publique"
103
+ assert slug("ecole publique_") == "ecole-publique"
106
104
 
107
105
  @pytest.mark.options(TAG_MAX_LENGTH=MAX_TAG_LENGTH)
108
106
  def test_normalize(self, app):
109
- assert normalize('') == ''
110
- assert normalize('a') == ''
111
- assert normalize('aa') == ''
112
- assert normalize('aaa') == 'aaa'
113
- assert normalize('a' * (MAX_TAG_LENGTH + 1)) == 'a' * MAX_TAG_LENGTH
114
- assert normalize('aAa a') == 'aaa-a'
107
+ assert normalize("") == ""
108
+ assert normalize("a") == ""
109
+ assert normalize("aa") == ""
110
+ assert normalize("aaa") == "aaa"
111
+ assert normalize("a" * (MAX_TAG_LENGTH + 1)) == "a" * MAX_TAG_LENGTH
112
+ assert normalize("aAa a") == "aaa-a"
@@ -1,22 +1,23 @@
1
1
  import pytest
2
2
 
3
- from udata.search import reindex
4
- from udata.core.topic.factories import TopicFactory
5
3
  from udata.core.dataset.factories import DatasetFactory
4
+ from udata.core.topic.factories import TopicFactory
5
+ from udata.search import reindex
6
6
 
7
7
 
8
8
  @pytest.fixture
9
9
  def job_reindex(mocker):
10
- return mocker.patch.object(reindex, 'delay')
10
+ return mocker.patch.object(reindex, "delay")
11
11
 
12
12
 
13
13
  @pytest.fixture
14
14
  def job_reindex_undelayed(mocker):
15
15
  """Mock the reindex.delay fn to access the underlying reindex fn"""
16
- return mocker.patch.object(reindex, 'delay', side_effect=reindex)
16
+ return mocker.patch.object(reindex, "delay", side_effect=reindex)
17
+
17
18
 
19
+ pytestmark = pytest.mark.usefixtures("clean_db")
18
20
 
19
- pytestmark = pytest.mark.usefixtures('clean_db')
20
21
 
21
22
  class TopicModelTest:
22
23
  # allows url_for with correct context when calling reindex
@@ -26,7 +27,7 @@ class TopicModelTest:
26
27
  topic = TopicFactory(datasets=[])
27
28
  dataset = DatasetFactory()
28
29
 
29
- topic.name = 'new_name'
30
+ topic.name = "new_name"
30
31
  topic.save()
31
32
  job_reindex.assert_not_called()
32
33
 
@@ -44,4 +45,3 @@ class TopicModelTest:
44
45
  # creates a topic with datasets, thus calls reindex
45
46
  TopicFactory()
46
47
  job_reindex_undelayed.assert_called()
47
-