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

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

Potentially problematic release.


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

Files changed (413) hide show
  1. tasks/__init__.py +109 -107
  2. tasks/helpers.py +18 -18
  3. udata/__init__.py +4 -4
  4. udata/admin/views.py +5 -5
  5. udata/api/__init__.py +111 -134
  6. udata/api/commands.py +45 -37
  7. udata/api/errors.py +5 -4
  8. udata/api/fields.py +23 -21
  9. udata/api/oauth2.py +55 -74
  10. udata/api/parsers.py +15 -15
  11. udata/api/signals.py +1 -1
  12. udata/api_fields.py +137 -89
  13. udata/app.py +58 -55
  14. udata/assets.py +5 -5
  15. udata/auth/__init__.py +37 -26
  16. udata/auth/forms.py +23 -15
  17. udata/auth/helpers.py +1 -1
  18. udata/auth/mails.py +3 -3
  19. udata/auth/password_validation.py +19 -15
  20. udata/auth/views.py +94 -68
  21. udata/commands/__init__.py +71 -69
  22. udata/commands/cache.py +7 -7
  23. udata/commands/db.py +201 -140
  24. udata/commands/dcat.py +36 -30
  25. udata/commands/fixtures.py +100 -84
  26. udata/commands/images.py +21 -20
  27. udata/commands/info.py +17 -20
  28. udata/commands/init.py +10 -10
  29. udata/commands/purge.py +12 -13
  30. udata/commands/serve.py +41 -29
  31. udata/commands/static.py +16 -18
  32. udata/commands/test.py +20 -20
  33. udata/commands/tests/fixtures.py +26 -24
  34. udata/commands/worker.py +31 -33
  35. udata/core/__init__.py +12 -12
  36. udata/core/activity/__init__.py +0 -1
  37. udata/core/activity/api.py +59 -49
  38. udata/core/activity/models.py +28 -26
  39. udata/core/activity/signals.py +1 -1
  40. udata/core/activity/tasks.py +16 -10
  41. udata/core/badges/api.py +6 -6
  42. udata/core/badges/commands.py +14 -13
  43. udata/core/badges/fields.py +8 -5
  44. udata/core/badges/forms.py +7 -4
  45. udata/core/badges/models.py +16 -31
  46. udata/core/badges/permissions.py +1 -3
  47. udata/core/badges/signals.py +2 -2
  48. udata/core/badges/tasks.py +3 -2
  49. udata/core/badges/tests/test_commands.py +10 -10
  50. udata/core/badges/tests/test_model.py +24 -31
  51. udata/core/contact_point/api.py +19 -18
  52. udata/core/contact_point/api_fields.py +21 -14
  53. udata/core/contact_point/factories.py +2 -2
  54. udata/core/contact_point/forms.py +7 -6
  55. udata/core/contact_point/models.py +3 -5
  56. udata/core/dataservices/api.py +26 -21
  57. udata/core/dataservices/factories.py +13 -11
  58. udata/core/dataservices/models.py +35 -40
  59. udata/core/dataservices/permissions.py +4 -4
  60. udata/core/dataservices/rdf.py +40 -17
  61. udata/core/dataservices/tasks.py +4 -3
  62. udata/core/dataset/actions.py +10 -10
  63. udata/core/dataset/activities.py +21 -23
  64. udata/core/dataset/api.py +321 -298
  65. udata/core/dataset/api_fields.py +443 -271
  66. udata/core/dataset/apiv2.py +305 -229
  67. udata/core/dataset/commands.py +38 -36
  68. udata/core/dataset/constants.py +61 -54
  69. udata/core/dataset/csv.py +70 -74
  70. udata/core/dataset/events.py +39 -32
  71. udata/core/dataset/exceptions.py +8 -4
  72. udata/core/dataset/factories.py +57 -65
  73. udata/core/dataset/forms.py +87 -63
  74. udata/core/dataset/models.py +336 -280
  75. udata/core/dataset/permissions.py +9 -6
  76. udata/core/dataset/preview.py +15 -17
  77. udata/core/dataset/rdf.py +156 -122
  78. udata/core/dataset/search.py +92 -77
  79. udata/core/dataset/signals.py +1 -1
  80. udata/core/dataset/tasks.py +63 -54
  81. udata/core/discussions/actions.py +5 -5
  82. udata/core/discussions/api.py +124 -120
  83. udata/core/discussions/factories.py +2 -2
  84. udata/core/discussions/forms.py +9 -7
  85. udata/core/discussions/metrics.py +1 -3
  86. udata/core/discussions/models.py +25 -24
  87. udata/core/discussions/notifications.py +18 -14
  88. udata/core/discussions/permissions.py +3 -3
  89. udata/core/discussions/signals.py +4 -4
  90. udata/core/discussions/tasks.py +24 -28
  91. udata/core/followers/api.py +32 -33
  92. udata/core/followers/models.py +9 -9
  93. udata/core/followers/signals.py +3 -3
  94. udata/core/jobs/actions.py +7 -7
  95. udata/core/jobs/api.py +99 -92
  96. udata/core/jobs/commands.py +48 -49
  97. udata/core/jobs/forms.py +11 -11
  98. udata/core/jobs/models.py +6 -6
  99. udata/core/metrics/__init__.py +2 -2
  100. udata/core/metrics/commands.py +34 -30
  101. udata/core/metrics/models.py +2 -4
  102. udata/core/metrics/signals.py +1 -1
  103. udata/core/metrics/tasks.py +3 -3
  104. udata/core/organization/activities.py +12 -15
  105. udata/core/organization/api.py +167 -174
  106. udata/core/organization/api_fields.py +183 -124
  107. udata/core/organization/apiv2.py +32 -32
  108. udata/core/organization/commands.py +20 -22
  109. udata/core/organization/constants.py +11 -11
  110. udata/core/organization/csv.py +17 -15
  111. udata/core/organization/factories.py +8 -11
  112. udata/core/organization/forms.py +32 -26
  113. udata/core/organization/metrics.py +2 -1
  114. udata/core/organization/models.py +87 -67
  115. udata/core/organization/notifications.py +18 -14
  116. udata/core/organization/permissions.py +10 -11
  117. udata/core/organization/rdf.py +14 -14
  118. udata/core/organization/search.py +30 -28
  119. udata/core/organization/signals.py +7 -7
  120. udata/core/organization/tasks.py +42 -61
  121. udata/core/owned.py +38 -27
  122. udata/core/post/api.py +82 -81
  123. udata/core/post/constants.py +8 -5
  124. udata/core/post/factories.py +4 -4
  125. udata/core/post/forms.py +13 -14
  126. udata/core/post/models.py +20 -22
  127. udata/core/post/tests/test_api.py +30 -32
  128. udata/core/reports/api.py +8 -7
  129. udata/core/reports/constants.py +1 -3
  130. udata/core/reports/models.py +10 -10
  131. udata/core/reuse/activities.py +15 -19
  132. udata/core/reuse/api.py +123 -126
  133. udata/core/reuse/api_fields.py +120 -85
  134. udata/core/reuse/apiv2.py +11 -10
  135. udata/core/reuse/constants.py +23 -23
  136. udata/core/reuse/csv.py +18 -18
  137. udata/core/reuse/factories.py +5 -9
  138. udata/core/reuse/forms.py +24 -21
  139. udata/core/reuse/models.py +55 -51
  140. udata/core/reuse/permissions.py +2 -2
  141. udata/core/reuse/search.py +49 -46
  142. udata/core/reuse/signals.py +1 -1
  143. udata/core/reuse/tasks.py +4 -5
  144. udata/core/site/api.py +47 -50
  145. udata/core/site/factories.py +2 -2
  146. udata/core/site/forms.py +4 -5
  147. udata/core/site/models.py +94 -63
  148. udata/core/site/rdf.py +14 -14
  149. udata/core/spam/api.py +16 -9
  150. udata/core/spam/constants.py +4 -4
  151. udata/core/spam/fields.py +13 -7
  152. udata/core/spam/models.py +27 -20
  153. udata/core/spam/signals.py +1 -1
  154. udata/core/spam/tests/test_spam.py +6 -5
  155. udata/core/spatial/api.py +72 -80
  156. udata/core/spatial/api_fields.py +73 -58
  157. udata/core/spatial/commands.py +67 -64
  158. udata/core/spatial/constants.py +3 -3
  159. udata/core/spatial/factories.py +37 -54
  160. udata/core/spatial/forms.py +27 -26
  161. udata/core/spatial/geoids.py +17 -17
  162. udata/core/spatial/models.py +43 -47
  163. udata/core/spatial/tasks.py +2 -1
  164. udata/core/spatial/tests/test_api.py +115 -130
  165. udata/core/spatial/tests/test_fields.py +74 -77
  166. udata/core/spatial/tests/test_geoid.py +22 -22
  167. udata/core/spatial/tests/test_models.py +5 -7
  168. udata/core/spatial/translations.py +16 -16
  169. udata/core/storages/__init__.py +16 -18
  170. udata/core/storages/api.py +66 -64
  171. udata/core/storages/tasks.py +7 -7
  172. udata/core/storages/utils.py +15 -15
  173. udata/core/storages/views.py +5 -6
  174. udata/core/tags/api.py +17 -14
  175. udata/core/tags/csv.py +4 -4
  176. udata/core/tags/models.py +8 -5
  177. udata/core/tags/tasks.py +11 -13
  178. udata/core/tags/views.py +4 -4
  179. udata/core/topic/api.py +84 -73
  180. udata/core/topic/apiv2.py +157 -127
  181. udata/core/topic/factories.py +3 -4
  182. udata/core/topic/forms.py +12 -14
  183. udata/core/topic/models.py +14 -19
  184. udata/core/topic/parsers.py +26 -26
  185. udata/core/user/activities.py +30 -29
  186. udata/core/user/api.py +151 -152
  187. udata/core/user/api_fields.py +132 -100
  188. udata/core/user/apiv2.py +7 -7
  189. udata/core/user/commands.py +38 -38
  190. udata/core/user/factories.py +8 -9
  191. udata/core/user/forms.py +14 -11
  192. udata/core/user/metrics.py +2 -2
  193. udata/core/user/models.py +68 -69
  194. udata/core/user/permissions.py +4 -5
  195. udata/core/user/rdf.py +7 -8
  196. udata/core/user/tasks.py +2 -2
  197. udata/core/user/tests/test_user_model.py +24 -16
  198. udata/cors.py +99 -0
  199. udata/db/tasks.py +2 -1
  200. udata/entrypoints.py +35 -31
  201. udata/errors.py +2 -1
  202. udata/event/values.py +6 -6
  203. udata/factories.py +2 -2
  204. udata/features/identicon/api.py +5 -6
  205. udata/features/identicon/backends.py +48 -55
  206. udata/features/identicon/tests/test_backends.py +4 -5
  207. udata/features/notifications/__init__.py +0 -1
  208. udata/features/notifications/actions.py +9 -9
  209. udata/features/notifications/api.py +17 -13
  210. udata/features/territories/__init__.py +12 -10
  211. udata/features/territories/api.py +14 -15
  212. udata/features/territories/models.py +23 -28
  213. udata/features/transfer/actions.py +8 -11
  214. udata/features/transfer/api.py +84 -77
  215. udata/features/transfer/factories.py +2 -1
  216. udata/features/transfer/models.py +11 -12
  217. udata/features/transfer/notifications.py +19 -15
  218. udata/features/transfer/permissions.py +5 -5
  219. udata/forms/__init__.py +5 -2
  220. udata/forms/fields.py +164 -172
  221. udata/forms/validators.py +19 -22
  222. udata/forms/widgets.py +9 -13
  223. udata/frontend/__init__.py +31 -26
  224. udata/frontend/csv.py +68 -58
  225. udata/frontend/markdown.py +40 -44
  226. udata/harvest/actions.py +89 -77
  227. udata/harvest/api.py +294 -238
  228. udata/harvest/backends/__init__.py +4 -4
  229. udata/harvest/backends/base.py +128 -111
  230. udata/harvest/backends/dcat.py +80 -66
  231. udata/harvest/commands.py +56 -60
  232. udata/harvest/csv.py +8 -8
  233. udata/harvest/exceptions.py +6 -3
  234. udata/harvest/filters.py +24 -23
  235. udata/harvest/forms.py +27 -28
  236. udata/harvest/models.py +88 -80
  237. udata/harvest/notifications.py +15 -10
  238. udata/harvest/signals.py +13 -13
  239. udata/harvest/tasks.py +11 -10
  240. udata/harvest/tests/factories.py +23 -24
  241. udata/harvest/tests/test_actions.py +136 -166
  242. udata/harvest/tests/test_api.py +220 -214
  243. udata/harvest/tests/test_base_backend.py +117 -112
  244. udata/harvest/tests/test_dcat_backend.py +380 -308
  245. udata/harvest/tests/test_filters.py +33 -22
  246. udata/harvest/tests/test_models.py +11 -14
  247. udata/harvest/tests/test_notifications.py +6 -7
  248. udata/harvest/tests/test_tasks.py +7 -6
  249. udata/i18n.py +237 -78
  250. udata/linkchecker/backends.py +5 -11
  251. udata/linkchecker/checker.py +23 -22
  252. udata/linkchecker/commands.py +4 -6
  253. udata/linkchecker/models.py +6 -6
  254. udata/linkchecker/tasks.py +18 -20
  255. udata/mail.py +21 -21
  256. udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
  257. udata/migrations/2020-08-24-add-fs-filename.py +9 -8
  258. udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
  259. udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
  260. udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
  261. udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
  262. udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
  263. udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
  264. udata/migrations/2021-08-17-follow-integrity.py +5 -4
  265. udata/migrations/2021-08-17-harvest-integrity.py +13 -12
  266. udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
  267. udata/migrations/2021-08-17-transfer-integrity.py +5 -4
  268. udata/migrations/2021-08-17-users-integrity.py +9 -8
  269. udata/migrations/2021-12-14-reuse-topics.py +7 -6
  270. udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
  271. udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
  272. udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
  273. udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
  274. udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
  275. udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
  276. udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
  277. udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
  278. udata/migrations/__init__.py +123 -105
  279. udata/models/__init__.py +4 -4
  280. udata/mongo/__init__.py +13 -11
  281. udata/mongo/badges_field.py +3 -2
  282. udata/mongo/datetime_fields.py +13 -12
  283. udata/mongo/document.py +17 -16
  284. udata/mongo/engine.py +15 -16
  285. udata/mongo/errors.py +2 -1
  286. udata/mongo/extras_fields.py +30 -20
  287. udata/mongo/queryset.py +12 -12
  288. udata/mongo/slug_fields.py +38 -28
  289. udata/mongo/taglist_field.py +1 -2
  290. udata/mongo/url_field.py +5 -5
  291. udata/mongo/uuid_fields.py +4 -3
  292. udata/notifications/__init__.py +1 -1
  293. udata/notifications/mattermost.py +10 -9
  294. udata/rdf.py +167 -188
  295. udata/routing.py +40 -45
  296. udata/search/__init__.py +18 -19
  297. udata/search/adapter.py +17 -16
  298. udata/search/commands.py +44 -51
  299. udata/search/fields.py +13 -20
  300. udata/search/query.py +23 -18
  301. udata/search/result.py +9 -10
  302. udata/sentry.py +21 -19
  303. udata/settings.py +262 -198
  304. udata/sitemap.py +8 -6
  305. udata/storage/s3.py +20 -13
  306. udata/tags.py +4 -5
  307. udata/tasks.py +43 -42
  308. udata/tests/__init__.py +9 -6
  309. udata/tests/api/__init__.py +8 -6
  310. udata/tests/api/test_auth_api.py +395 -321
  311. udata/tests/api/test_base_api.py +33 -35
  312. udata/tests/api/test_contact_points.py +7 -9
  313. udata/tests/api/test_dataservices_api.py +211 -158
  314. udata/tests/api/test_datasets_api.py +823 -812
  315. udata/tests/api/test_follow_api.py +13 -15
  316. udata/tests/api/test_me_api.py +95 -112
  317. udata/tests/api/test_organizations_api.py +301 -339
  318. udata/tests/api/test_reports_api.py +35 -25
  319. udata/tests/api/test_reuses_api.py +134 -139
  320. udata/tests/api/test_swagger.py +5 -5
  321. udata/tests/api/test_tags_api.py +18 -25
  322. udata/tests/api/test_topics_api.py +94 -94
  323. udata/tests/api/test_transfer_api.py +53 -48
  324. udata/tests/api/test_user_api.py +128 -141
  325. udata/tests/apiv2/test_datasets.py +290 -198
  326. udata/tests/apiv2/test_me_api.py +10 -11
  327. udata/tests/apiv2/test_organizations.py +56 -74
  328. udata/tests/apiv2/test_swagger.py +5 -5
  329. udata/tests/apiv2/test_topics.py +69 -87
  330. udata/tests/cli/test_cli_base.py +8 -8
  331. udata/tests/cli/test_db_cli.py +21 -19
  332. udata/tests/dataservice/test_dataservice_tasks.py +8 -12
  333. udata/tests/dataset/test_csv_adapter.py +44 -35
  334. udata/tests/dataset/test_dataset_actions.py +2 -3
  335. udata/tests/dataset/test_dataset_commands.py +7 -8
  336. udata/tests/dataset/test_dataset_events.py +36 -29
  337. udata/tests/dataset/test_dataset_model.py +224 -217
  338. udata/tests/dataset/test_dataset_rdf.py +142 -131
  339. udata/tests/dataset/test_dataset_tasks.py +15 -15
  340. udata/tests/dataset/test_resource_preview.py +10 -13
  341. udata/tests/features/territories/__init__.py +9 -13
  342. udata/tests/features/territories/test_territories_api.py +71 -91
  343. udata/tests/forms/test_basic_fields.py +7 -7
  344. udata/tests/forms/test_current_user_field.py +39 -66
  345. udata/tests/forms/test_daterange_field.py +31 -39
  346. udata/tests/forms/test_dict_field.py +28 -26
  347. udata/tests/forms/test_extras_fields.py +102 -76
  348. udata/tests/forms/test_form_field.py +8 -8
  349. udata/tests/forms/test_image_field.py +33 -26
  350. udata/tests/forms/test_model_field.py +134 -123
  351. udata/tests/forms/test_model_list_field.py +7 -7
  352. udata/tests/forms/test_nested_model_list_field.py +117 -79
  353. udata/tests/forms/test_publish_as_field.py +36 -65
  354. udata/tests/forms/test_reference_field.py +34 -53
  355. udata/tests/forms/test_user_forms.py +23 -21
  356. udata/tests/forms/test_uuid_field.py +6 -10
  357. udata/tests/frontend/__init__.py +9 -6
  358. udata/tests/frontend/test_auth.py +7 -6
  359. udata/tests/frontend/test_csv.py +81 -96
  360. udata/tests/frontend/test_hooks.py +43 -43
  361. udata/tests/frontend/test_markdown.py +211 -191
  362. udata/tests/helpers.py +32 -37
  363. udata/tests/models.py +2 -2
  364. udata/tests/organization/test_csv_adapter.py +21 -16
  365. udata/tests/organization/test_notifications.py +11 -18
  366. udata/tests/organization/test_organization_model.py +13 -13
  367. udata/tests/organization/test_organization_rdf.py +29 -22
  368. udata/tests/organization/test_organization_tasks.py +16 -17
  369. udata/tests/plugin.py +79 -73
  370. udata/tests/reuse/test_reuse_model.py +21 -21
  371. udata/tests/reuse/test_reuse_task.py +11 -13
  372. udata/tests/search/__init__.py +11 -12
  373. udata/tests/search/test_adapter.py +60 -70
  374. udata/tests/search/test_query.py +16 -16
  375. udata/tests/search/test_results.py +10 -7
  376. udata/tests/site/test_site_api.py +11 -16
  377. udata/tests/site/test_site_metrics.py +20 -30
  378. udata/tests/site/test_site_model.py +4 -5
  379. udata/tests/site/test_site_rdf.py +94 -78
  380. udata/tests/test_activity.py +17 -17
  381. udata/tests/test_cors.py +62 -0
  382. udata/tests/test_discussions.py +292 -299
  383. udata/tests/test_i18n.py +37 -40
  384. udata/tests/test_linkchecker.py +91 -85
  385. udata/tests/test_mail.py +13 -17
  386. udata/tests/test_migrations.py +219 -180
  387. udata/tests/test_model.py +164 -157
  388. udata/tests/test_notifications.py +17 -17
  389. udata/tests/test_owned.py +14 -14
  390. udata/tests/test_rdf.py +25 -23
  391. udata/tests/test_routing.py +89 -93
  392. udata/tests/test_storages.py +137 -128
  393. udata/tests/test_tags.py +44 -46
  394. udata/tests/test_topics.py +7 -7
  395. udata/tests/test_transfer.py +42 -49
  396. udata/tests/test_uris.py +160 -161
  397. udata/tests/test_utils.py +79 -71
  398. udata/tests/user/test_user_rdf.py +5 -9
  399. udata/tests/workers/test_jobs_commands.py +57 -58
  400. udata/tests/workers/test_tasks_routing.py +23 -29
  401. udata/tests/workers/test_workers_api.py +125 -131
  402. udata/tests/workers/test_workers_helpers.py +6 -6
  403. udata/tracking.py +4 -6
  404. udata/uris.py +45 -46
  405. udata/utils.py +68 -66
  406. udata/wsgi.py +1 -1
  407. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/METADATA +7 -3
  408. udata-9.1.2.dev30454.dist-info/RECORD +706 -0
  409. udata-9.1.2.dev30355.dist-info/RECORD +0 -704
  410. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/LICENSE +0 -0
  411. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/WHEEL +0 -0
  412. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/entry_points.txt +0 -0
  413. {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30454.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,9 @@
1
1
  import pytest
2
-
3
2
  from bleach._vendor import html5lib
4
3
  from flask import render_template_string
5
4
 
5
+ from udata.frontend.markdown import EXCERPT_TOKEN, md, parse_html
6
6
  from udata.utils import faker
7
- from udata.frontend.markdown import md, parse_html, EXCERPT_TOKEN
8
7
 
9
8
  parser = html5lib.HTMLParser(tree=html5lib.getTreeBuilder("dom"))
10
9
 
@@ -17,319 +16,340 @@ def assert_md_equal(value, expected):
17
16
 
18
17
  @pytest.fixture
19
18
  def assert_md(app):
20
- def assertion(text, expected, url='/'):
19
+ def assertion(text, expected, url="/"):
21
20
  __tracebackhide__ = True
22
21
  with app.test_request_context(url):
23
- result = render_template_string('{{ text|markdown }}', text=text)
22
+ result = render_template_string("{{ text|markdown }}", text=text)
24
23
  assert_md_equal(result, expected)
24
+
25
25
  return assertion
26
26
 
27
27
 
28
28
  @pytest.fixture
29
29
  def md2dom(app):
30
- def helper(text, expected=None, url='/'):
30
+ def helper(text, expected=None, url="/"):
31
31
  __tracebackhide__ = True
32
32
  with app.test_request_context(url):
33
- result = render_template_string('{{ text|markdown }}', text=text)
33
+ result = render_template_string("{{ text|markdown }}", text=text)
34
34
  if expected:
35
35
  assert_md_equal(result, expected)
36
36
  return parser.parse(result)
37
+
37
38
  return helper
38
39
 
39
40
 
40
41
  @pytest.mark.frontend
41
42
  class MarkdownTest:
42
43
  def test_excerpt_is_not_removed(self, app):
43
- with app.test_request_context('/'):
44
+ with app.test_request_context("/"):
44
45
  assert_md_equal(md(EXCERPT_TOKEN), EXCERPT_TOKEN)
45
46
 
46
47
  def test_markdown_filter_with_none(self, app):
47
- '''Markdown filter should not fails with None'''
48
+ """Markdown filter should not fails with None"""
48
49
  text = None
49
- with app.test_request_context('/'):
50
- result = render_template_string('{{ text|markdown }}', text=text)
50
+ with app.test_request_context("/"):
51
+ result = render_template_string("{{ text|markdown }}", text=text)
51
52
 
52
- assert result == ''
53
+ assert result == ""
53
54
 
54
55
  def test_markdown_links_nofollow(self, md2dom):
55
- '''Markdown filter should render links as nofollow'''
56
+ """Markdown filter should render links as nofollow"""
56
57
  text = '[example](http://example.net/ "Title")'
57
58
  dom = md2dom(text)
58
- el = dom.getElementsByTagName('a')[0]
59
- assert el.getAttribute('rel') == 'nofollow'
60
- assert el.getAttribute('href') == 'http://example.net/'
61
- assert el.getAttribute('title') == 'Title'
62
- assert el.firstChild.data == 'example'
59
+ el = dom.getElementsByTagName("a")[0]
60
+ assert el.getAttribute("rel") == "nofollow"
61
+ assert el.getAttribute("href") == "http://example.net/"
62
+ assert el.getAttribute("title") == "Title"
63
+ assert el.firstChild.data == "example"
63
64
 
64
65
  def test_markdown_linkify(self, md2dom):
65
- '''Markdown filter should transform urls to anchors'''
66
- text = 'http://example.net/'
66
+ """Markdown filter should transform urls to anchors"""
67
+ text = "http://example.net/"
67
68
  dom = md2dom(text)
68
- el = dom.getElementsByTagName('a')[0]
69
- assert el.getAttribute('rel') == 'nofollow'
70
- assert el.getAttribute('href') == 'http://example.net/'
71
- assert el.firstChild.data == 'http://example.net/'
69
+ el = dom.getElementsByTagName("a")[0]
70
+ assert el.getAttribute("rel") == "nofollow"
71
+ assert el.getAttribute("href") == "http://example.net/"
72
+ assert el.firstChild.data == "http://example.net/"
72
73
 
73
74
  def test_markdown_autolink(self, md2dom):
74
- '''Markdown filter should transform urls to anchors'''
75
- text = '<http://example.net/>'
75
+ """Markdown filter should transform urls to anchors"""
76
+ text = "<http://example.net/>"
76
77
  dom = md2dom(text)
77
- el = dom.getElementsByTagName('a')[0]
78
- assert el.getAttribute('rel') == 'nofollow'
79
- assert el.getAttribute('href') == 'http://example.net/'
80
- assert el.firstChild.data == 'http://example.net/'
78
+ el = dom.getElementsByTagName("a")[0]
79
+ assert el.getAttribute("rel") == "nofollow"
80
+ assert el.getAttribute("href") == "http://example.net/"
81
+ assert el.firstChild.data == "http://example.net/"
81
82
 
82
83
  def test_markdown_linkify_angle_brackets(self, md2dom):
83
- '''Markdown filter should transform urls to anchors'''
84
- text = '<http://example.net/path>'
84
+ """Markdown filter should transform urls to anchors"""
85
+ text = "<http://example.net/path>"
85
86
  dom = md2dom(text)
86
- el = dom.getElementsByTagName('a')[0]
87
- assert el.getAttribute('rel') == 'nofollow'
88
- assert el.getAttribute('href') == 'http://example.net/path'
89
- assert el.firstChild.data == 'http://example.net/path'
90
-
91
- @pytest.mark.parametrize('link,expected', [
92
- ('/', 'http://local.test/'), ('bar', 'http://local.test/bar'),
93
- ('/?tag=test&sort=-followers', 'http://local.test/?tag=test&sort=-followers')
94
- ])
87
+ el = dom.getElementsByTagName("a")[0]
88
+ assert el.getAttribute("rel") == "nofollow"
89
+ assert el.getAttribute("href") == "http://example.net/path"
90
+ assert el.firstChild.data == "http://example.net/path"
91
+
92
+ @pytest.mark.parametrize(
93
+ "link,expected",
94
+ [
95
+ ("/", "http://local.test/"),
96
+ ("bar", "http://local.test/bar"),
97
+ ("/?tag=test&sort=-followers", "http://local.test/?tag=test&sort=-followers"),
98
+ ],
99
+ )
95
100
  def test_markdown_linkify_relative(self, md2dom, link, expected):
96
- '''Markdown filter should transform relative urls to external ones'''
97
- text = f'[foo]({link})'
101
+ """Markdown filter should transform relative urls to external ones"""
102
+ text = f"[foo]({link})"
98
103
  dom = md2dom(text)
99
- el = dom.getElementsByTagName('a')[0]
100
- assert el.getAttribute('rel') == ''
101
- assert el.getAttribute('href') == expected
102
- assert el.getAttribute('data-tooltip') == ''
103
- assert el.firstChild.data == 'foo'
104
+ el = dom.getElementsByTagName("a")[0]
105
+ assert el.getAttribute("rel") == ""
106
+ assert el.getAttribute("href") == expected
107
+ assert el.getAttribute("data-tooltip") == ""
108
+ assert el.firstChild.data == "foo"
104
109
 
105
110
  def test_markdown_linkify_https(self, md2dom):
106
- '''Markdown filter should transform relative urls with HTTPS'''
107
- text = '[foo](/foo)'
108
- dom = md2dom(text, url='https://local.test')
109
- el = dom.getElementsByTagName('a')[0]
110
- assert el.getAttribute('rel') == ''
111
- assert el.getAttribute('href') == 'https://local.test/foo'
112
- assert el.getAttribute('data-tooltip') == ''
113
- assert el.firstChild.data == 'foo'
111
+ """Markdown filter should transform relative urls with HTTPS"""
112
+ text = "[foo](/foo)"
113
+ dom = md2dom(text, url="https://local.test")
114
+ el = dom.getElementsByTagName("a")[0]
115
+ assert el.getAttribute("rel") == ""
116
+ assert el.getAttribute("href") == "https://local.test/foo"
117
+ assert el.getAttribute("data-tooltip") == ""
118
+ assert el.firstChild.data == "foo"
114
119
 
115
120
  def test_markdown_linkify_ftp(self, md2dom):
116
- '''Markdown filter should transform ftp urls'''
117
- text = '[foo](ftp://random.net)'
121
+ """Markdown filter should transform ftp urls"""
122
+ text = "[foo](ftp://random.net)"
118
123
  dom = md2dom(text)
119
- el = dom.getElementsByTagName('a')[0]
120
- assert el.getAttribute('href') == 'ftp://random.net'
121
- assert el.firstChild.data == 'foo'
124
+ el = dom.getElementsByTagName("a")[0]
125
+ assert el.getAttribute("href") == "ftp://random.net"
126
+ assert el.firstChild.data == "foo"
122
127
 
123
128
  def test_markdown_linkify_relative_with_tooltip(self, app):
124
- '''Markdown filter should transform + add tooltip'''
125
- text = '[foo](/)'
126
- with app.test_request_context('/'):
127
- result = render_template_string(
128
- '{{ text|markdown(source_tooltip=True) }}', text=text)
129
+ """Markdown filter should transform + add tooltip"""
130
+ text = "[foo](/)"
131
+ with app.test_request_context("/"):
132
+ result = render_template_string("{{ text|markdown(source_tooltip=True) }}", text=text)
129
133
  parsed = parser.parse(result)
130
- el = parsed.getElementsByTagName('a')[0]
131
- assert el.getAttribute('rel') == ''
132
- assert el.getAttribute('href') == 'http://local.test/'
133
- assert el.getAttribute('data-tooltip') == 'Source'
134
- assert el.firstChild.data == 'foo'
134
+ el = parsed.getElementsByTagName("a")[0]
135
+ assert el.getAttribute("rel") == ""
136
+ assert el.getAttribute("href") == "http://local.test/"
137
+ assert el.getAttribute("data-tooltip") == "Source"
138
+ assert el.firstChild.data == "foo"
135
139
 
136
140
  def test_markdown_not_linkify_mails(self, md2dom):
137
- '''Markdown filter should not transform emails to anchors'''
138
- text = 'coucou@cmoi.fr'
139
- dom = md2dom(text, '<p>coucou@cmoi.fr</p>')
140
- assert dom.getElementsByTagName('a') == []
141
+ """Markdown filter should not transform emails to anchors"""
142
+ text = "coucou@cmoi.fr"
143
+ dom = md2dom(text, "<p>coucou@cmoi.fr</p>")
144
+ assert dom.getElementsByTagName("a") == []
141
145
 
142
146
  def test_markdown_linkify_within_pre(self, assert_md):
143
- '''Markdown filter should not transform urls into <pre> anchors'''
144
- text = '<pre>http://example.net/</pre>'
145
- assert_md(text, '<pre>http://example.net/</pre>')
147
+ """Markdown filter should not transform urls into <pre> anchors"""
148
+ text = "<pre>http://example.net/</pre>"
149
+ assert_md(text, "<pre>http://example.net/</pre>")
146
150
 
147
151
  def test_markdown_linkify_email_within_pre(self, assert_md):
148
- '''Markdown filter should not transform emails into <pre> anchors'''
149
- text = '<pre>coucou@cmoi.fr</pre>'
150
- assert_md(text, '<pre>coucou@cmoi.fr</pre>')
152
+ """Markdown filter should not transform emails into <pre> anchors"""
153
+ text = "<pre>coucou@cmoi.fr</pre>"
154
+ assert_md(text, "<pre>coucou@cmoi.fr</pre>")
151
155
 
152
156
  def test_bleach_sanitize(self, assert_md):
153
- '''Markdown filter should sanitize evil code'''
154
- text = 'an <script>evil()</script>'
155
- assert_md(text, '<p>an &lt;script&gt;evil()&lt;/script&gt;</p>')
157
+ """Markdown filter should sanitize evil code"""
158
+ text = "an <script>evil()</script>"
159
+ assert_md(text, "<p>an &lt;script&gt;evil()&lt;/script&gt;</p>")
156
160
 
157
161
  def test_soft_break(self, assert_md):
158
- '''Markdown should treat soft breaks as br tag'''
159
- text = 'line 1\nline 2'
160
- assert_md(text, '<p>line 1<br>\nline 2</p>')
162
+ """Markdown should treat soft breaks as br tag"""
163
+ text = "line 1\nline 2"
164
+ assert_md(text, "<p>line 1<br>\nline 2</p>")
161
165
 
162
166
  def test_gfm_tables(self, assert_md):
163
- '''Should render GFM tables'''
164
- text = '\n'.join((
165
- '| first | second |',
166
- '|-------|--------|',
167
- '| value | value |',
168
- ))
169
- expected = '\n'.join((
170
- '<table>',
171
- '<thead>',
172
- '<tr>',
173
- '<th>first</th>',
174
- '<th>second</th>',
175
- '</tr>',
176
- '</thead>',
177
- '<tbody>',
178
- '<tr>',
179
- '<td>value</td>',
180
- '<td>value</td>',
181
- '</tr>',
182
- '</tbody>',
183
- '</table>'
184
- ))
167
+ """Should render GFM tables"""
168
+ text = "\n".join(
169
+ (
170
+ "| first | second |",
171
+ "|-------|--------|",
172
+ "| value | value |",
173
+ )
174
+ )
175
+ expected = "\n".join(
176
+ (
177
+ "<table>",
178
+ "<thead>",
179
+ "<tr>",
180
+ "<th>first</th>",
181
+ "<th>second</th>",
182
+ "</tr>",
183
+ "</thead>",
184
+ "<tbody>",
185
+ "<tr>",
186
+ "<td>value</td>",
187
+ "<td>value</td>",
188
+ "</tr>",
189
+ "</tbody>",
190
+ "</table>",
191
+ )
192
+ )
185
193
  assert_md(text, expected)
186
194
 
187
195
  def test_gfm_strikethrough(self, assert_md):
188
- '''Should render GFM strikethrough (extension)'''
189
- text = '~~Hi~~ Hello, world!'
190
- assert_md(text, '<p><del>Hi</del> Hello, world!</p>')
196
+ """Should render GFM strikethrough (extension)"""
197
+ text = "~~Hi~~ Hello, world!"
198
+ assert_md(text, "<p><del>Hi</del> Hello, world!</p>")
191
199
 
192
200
  def test_gfm_tagfilter(self, assert_md):
193
- '''It should handle GFM tagfilter extension'''
201
+ """It should handle GFM tagfilter extension"""
194
202
  # Test extracted from https://github.github.com/gfm/#disallowed-raw-html-extension-
195
- text = '\n'.join((
196
- '<strong> <title></title> <style></style> <em></em></strong>',
197
- '<blockquote>',
198
- ' <xmp> is disallowed. <XMP> is also disallowed.',
199
- '</blockquote>',
200
- ))
201
- expected = '\n'.join((
202
- '<p><strong> &lt;title&gt;&lt;/title&gt; &lt;style&gt;&lt;/style&gt; <em></em></strong></p>',
203
- '<blockquote>',
204
- ' &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.',
205
- '</blockquote>',
206
- ))
203
+ text = "\n".join(
204
+ (
205
+ "<strong> <title></title> <style></style> <em></em></strong>",
206
+ "<blockquote>",
207
+ " <xmp> is disallowed. <XMP> is also disallowed.",
208
+ "</blockquote>",
209
+ )
210
+ )
211
+ expected = "\n".join(
212
+ (
213
+ "<p><strong> &lt;title&gt;&lt;/title&gt; &lt;style&gt;&lt;/style&gt; <em></em></strong></p>",
214
+ "<blockquote>",
215
+ " &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.",
216
+ "</blockquote>",
217
+ )
218
+ )
207
219
  assert_md(text, expected)
208
220
 
209
221
  def test_gfm_tagfilter_legit(self, assert_md):
210
- '''It should not filter legit markup'''
211
- text = '\n'.join((
212
- '> This is a blockquote',
213
- '> with <script>evil()</script> inside',
214
- ))
215
- expected = '\n'.join((
216
- '<blockquote><p>This is a blockquote<br>',
217
- 'with &lt;script&gt;evil()&lt;/script&gt; inside</p>',
218
- '</blockquote>',
219
- ))
222
+ """It should not filter legit markup"""
223
+ text = "\n".join(
224
+ (
225
+ "> This is a blockquote",
226
+ "> with <script>evil()</script> inside",
227
+ )
228
+ )
229
+ expected = "\n".join(
230
+ (
231
+ "<blockquote><p>This is a blockquote<br>",
232
+ "with &lt;script&gt;evil()&lt;/script&gt; inside</p>",
233
+ "</blockquote>",
234
+ )
235
+ )
220
236
  assert_md(text, expected)
221
237
 
222
238
  def test_collapsible(self, assert_md):
223
- '''It should not escape the collabsible HTML elem'''
224
- text = '\n'.join((
225
- '<details>',
226
- '<summary>TITLE</summary>',
227
- 'BODY CONTENT',
228
- '</details>',
229
- ))
230
- expected = '\n'.join((
231
- '<details>',
232
- '<summary>TITLE</summary>',
233
- 'BODY CONTENT',
234
- '</details>',
235
- ))
239
+ """It should not escape the collabsible HTML elem"""
240
+ text = "\n".join(
241
+ (
242
+ "<details>",
243
+ "<summary>TITLE</summary>",
244
+ "BODY CONTENT",
245
+ "</details>",
246
+ )
247
+ )
248
+ expected = "\n".join(
249
+ (
250
+ "<details>",
251
+ "<summary>TITLE</summary>",
252
+ "BODY CONTENT",
253
+ "</details>",
254
+ )
255
+ )
236
256
  assert_md(text, expected)
237
257
 
258
+
238
259
  @pytest.mark.frontend
239
260
  class MdStripTest:
240
261
  def test_mdstrip_filter(self, app):
241
- '''mdstrip should truncate the text before rendering'''
242
- text = '1 2 3 4 5 6 7 8 9 0'
243
- with app.test_request_context('/'):
244
- result = render_template_string('{{ text|mdstrip(7) }}', text=text)
262
+ """mdstrip should truncate the text before rendering"""
263
+ text = "1 2 3 4 5 6 7 8 9 0"
264
+ with app.test_request_context("/"):
265
+ result = render_template_string("{{ text|mdstrip(7) }}", text=text)
245
266
 
246
- assert result == '1 2 3…'
267
+ assert result == "1 2 3…"
247
268
 
248
269
  def test_mdstrip_filter_does_not_truncate_without_size(self, app):
249
- '''mdstrip should not truncate by default'''
250
- text = 'aaaa ' * 300
251
- with app.test_request_context('/'):
252
- result = render_template_string('{{ text|mdstrip }}', text=text)
270
+ """mdstrip should not truncate by default"""
271
+ text = "aaaa " * 300
272
+ with app.test_request_context("/"):
273
+ result = render_template_string("{{ text|mdstrip }}", text=text)
253
274
 
254
275
  assert result.strip() == text.strip()
255
276
 
256
277
  def test_mdstrip_filter_with_none(self, app):
257
- '''mdstrip filter should not fails with None'''
278
+ """mdstrip filter should not fails with None"""
258
279
  text = None
259
- with app.test_request_context('/'):
260
- result = render_template_string('{{ text|mdstrip }}', text=text)
280
+ with app.test_request_context("/"):
281
+ result = render_template_string("{{ text|mdstrip }}", text=text)
261
282
 
262
- assert result == ''
283
+ assert result == ""
263
284
 
264
285
  def test_mdstrip_filter_with_excerpt(self, app):
265
- '''mdstrip should truncate on token if shorter than required size'''
266
- text = ''.join(['excerpt', EXCERPT_TOKEN, 'aaaa ' * 10])
267
- with app.test_request_context('/'):
268
- result = render_template_string(
269
- '{{ text|mdstrip(20) }}', text=text)
286
+ """mdstrip should truncate on token if shorter than required size"""
287
+ text = "".join(["excerpt", EXCERPT_TOKEN, "aaaa " * 10])
288
+ with app.test_request_context("/"):
289
+ result = render_template_string("{{ text|mdstrip(20) }}", text=text)
270
290
 
271
- assert result == 'excerpt'
291
+ assert result == "excerpt"
272
292
 
273
293
  def test_mdstrip_does_not_truncate_in_tags(self, app):
274
- '''mdstrip should not truncate in middle of a tag'''
275
- text = '![Legend](http://www.somewhere.com/image.jpg) Here. aaaaa'
276
- with app.test_request_context('/'):
277
- result = render_template_string('{{ text|mdstrip(5) }}', text=text)
294
+ """mdstrip should not truncate in middle of a tag"""
295
+ text = "![Legend](http://www.somewhere.com/image.jpg) Here. aaaaa"
296
+ with app.test_request_context("/"):
297
+ result = render_template_string("{{ text|mdstrip(5) }}", text=text)
278
298
 
279
- assert result.strip() == 'Here…'
299
+ assert result.strip() == "Here…"
280
300
 
281
301
  def test_mdstrip_returns_unsafe_string(self, app):
282
- '''mdstrip should returns html compliants strings'''
283
- text = '&é<script>'
284
- with app.test_request_context('/'):
285
- unsafe = render_template_string('{{ text|mdstrip }}', text=text)
286
- safe = render_template_string('{{ text|mdstrip|safe }}', text=text)
302
+ """mdstrip should returns html compliants strings"""
303
+ text = "&é<script>"
304
+ with app.test_request_context("/"):
305
+ unsafe = render_template_string("{{ text|mdstrip }}", text=text)
306
+ safe = render_template_string("{{ text|mdstrip|safe }}", text=text)
287
307
 
288
- assert unsafe.strip() == '&amp;é&lt;script&gt;'
289
- assert safe.strip() == '&é<script>'
308
+ assert unsafe.strip() == "&amp;é&lt;script&gt;"
309
+ assert safe.strip() == "&é<script>"
290
310
 
291
311
  def test_mdstrip_custom_end(self, app):
292
- '''mdstrip should allow a custom ending string'''
293
- text = '1234567890'
312
+ """mdstrip should allow a custom ending string"""
313
+ text = "1234567890"
294
314
  template = '{{ text|mdstrip(5, "$") }}'
295
- with app.test_request_context('/'):
315
+ with app.test_request_context("/"):
296
316
  result = render_template_string(template, text=text)
297
317
 
298
- assert result.strip() == '1234$'
318
+ assert result.strip() == "1234$"
299
319
 
300
320
 
301
321
  class HtmlToMarkdownTest:
302
322
  def test_string_is_untouched(self):
303
- assert parse_html('foo') == 'foo'
323
+ assert parse_html("foo") == "foo"
304
324
 
305
325
  def test_empty_string_is_untouched(self):
306
- assert parse_html('') == ''
326
+ assert parse_html("") == ""
307
327
 
308
328
  def test_none_is_empty_string(self):
309
- assert parse_html(None) == ''
329
+ assert parse_html(None) == ""
310
330
 
311
331
  def test_parse_basic_html(self):
312
332
  text = faker.paragraph()
313
- html = '<div>{0}</div>'.format(text)
333
+ html = "<div>{0}</div>".format(text)
314
334
 
315
335
  assert parse_html(html) == text
316
336
 
317
337
  def test_content_is_stripped(self):
318
338
  text = faker.paragraph()
319
- spacer = '\n ' * 3
339
+ spacer = "\n " * 3
320
340
  assert parse_html(spacer + text + spacer) == text
321
341
 
322
342
  def test_parse_html_anchors(self):
323
343
  html = '<a href="http://somewhere.com">title</a>'
324
- assert parse_html(html) == '[title](http://somewhere.com)'
344
+ assert parse_html(html) == "[title](http://somewhere.com)"
325
345
 
326
346
  def test_parse_html_anchors_with_link_title(self):
327
- url = 'http://somewhere.com/some/path'
347
+ url = "http://somewhere.com/some/path"
328
348
  html = '<a href="{0}">{0}</a>'.format(url)
329
- assert parse_html(html) == '<{0}>'.format(url)
349
+ assert parse_html(html) == "<{0}>".format(url)
330
350
 
331
351
  def test_parse_html_anchors_with_attribute(self):
332
- url = 'http://somewhere.com/some/path'
352
+ url = "http://somewhere.com/some/path"
333
353
  html = '<a href="{0}" target="_blank" title="a title">title</a>'
334
354
  expected = '[title]({0} "a title")'
335
355