reader 3.17__tar.gz → 3.19.dev0__tar.gz

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.
Files changed (240) hide show
  1. {reader-3.17 → reader-3.19.dev0}/CHANGES.rst +33 -0
  2. {reader-3.17/src/reader.egg-info → reader-3.19.dev0}/PKG-INFO +11 -40
  3. {reader-3.17 → reader-3.19.dev0}/docs/api.rst +17 -0
  4. {reader-3.17 → reader-3.19.dev0}/docs/conf.py +0 -14
  5. {reader-3.17 → reader-3.19.dev0}/docs/install.rst +3 -1
  6. {reader-3.17 → reader-3.19.dev0}/pyproject.toml +29 -31
  7. reader-3.19.dev0/run.sh +125 -0
  8. {reader-3.17 → reader-3.19.dev0}/src/reader/__init__.py +4 -1
  9. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/__init__.py +2 -7
  10. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_lazy.py +1 -2
  11. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/requests/_lazy.py +1 -2
  12. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/cli_status.py +2 -2
  13. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/enclosure_tags.py +4 -2
  14. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_base.py +1 -1
  15. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_entries.py +6 -6
  16. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_feeds.py +6 -4
  17. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_search.py +12 -11
  18. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_sql_utils.py +2 -3
  19. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_sqlite_utils.py +15 -4
  20. {reader-3.17 → reader-3.19.dev0}/src/reader/_types.py +3 -7
  21. {reader-3.17 → reader-3.19.dev0}/src/reader/_update.py +1 -2
  22. {reader-3.17 → reader-3.19.dev0}/src/reader/core.py +39 -87
  23. {reader-3.17 → reader-3.19.dev0}/src/reader/exceptions.py +15 -81
  24. {reader-3.17 → reader-3.19.dev0}/src/reader/types.py +74 -22
  25. {reader-3.17 → reader-3.19.dev0/src/reader.egg-info}/PKG-INFO +11 -40
  26. {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/SOURCES.txt +0 -6
  27. reader-3.19.dev0/src/reader.egg-info/requires.txt +27 -0
  28. {reader-3.17 → reader-3.19.dev0}/tests/conftest.py +1 -0
  29. {reader-3.17 → reader-3.19.dev0}/tests/data/full.atom.py +5 -11
  30. {reader-3.17 → reader-3.19.dev0}/tests/data/full.json.py +3 -3
  31. {reader-3.17 → reader-3.19.dev0}/tests/data/full.rss.py +3 -3
  32. {reader-3.17 → reader-3.19.dev0}/tests/test_parser.py +10 -29
  33. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_cli_status.py +2 -1
  34. {reader-3.17 → reader-3.19.dev0}/tests/test_reader.py +5 -0
  35. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_hooks.py +14 -4
  36. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_update.py +17 -0
  37. {reader-3.17 → reader-3.19.dev0}/tests/utils.py +33 -43
  38. reader-3.19.dev0/tox.ini +40 -0
  39. reader-3.17/docs/.DS_Store +0 -0
  40. reader-3.17/docs/Makefile +0 -20
  41. reader-3.17/docs/make.bat +0 -36
  42. reader-3.17/run.sh +0 -188
  43. reader-3.17/scripts/.coverage +0 -0
  44. reader-3.17/scripts/generate_import_all.py +0 -15
  45. reader-3.17/src/reader.egg-info/requires.txt +0 -67
  46. reader-3.17/tests/test_test_utils.py +0 -36
  47. reader-3.17/tox.ini +0 -40
  48. {reader-3.17 → reader-3.19.dev0}/LICENSE +0 -0
  49. {reader-3.17 → reader-3.19.dev0}/MANIFEST.in +0 -0
  50. {reader-3.17 → reader-3.19.dev0}/README.rst +0 -0
  51. {reader-3.17 → reader-3.19.dev0}/docs/app.rst +0 -0
  52. {reader-3.17 → reader-3.19.dev0}/docs/changelog.rst +0 -0
  53. {reader-3.17 → reader-3.19.dev0}/docs/cli.rst +0 -0
  54. {reader-3.17 → reader-3.19.dev0}/docs/config.rst +0 -0
  55. {reader-3.17 → reader-3.19.dev0}/docs/contributing.rst +0 -0
  56. {reader-3.17 → reader-3.19.dev0}/docs/dev-app.rst +0 -0
  57. {reader-3.17 → reader-3.19.dev0}/docs/dev.rst +0 -0
  58. {reader-3.17 → reader-3.19.dev0}/docs/guide.rst +0 -0
  59. {reader-3.17 → reader-3.19.dev0}/docs/images/redesign-01.png +0 -0
  60. {reader-3.17 → reader-3.19.dev0}/docs/index.rst +0 -0
  61. {reader-3.17 → reader-3.19.dev0}/docs/internal.rst +0 -0
  62. {reader-3.17 → reader-3.19.dev0}/docs/plugins.rst +0 -0
  63. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/dillo.png +0 -0
  64. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-feed.png +0 -0
  65. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-v2-dark.png +0 -0
  66. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-v2-filters-light.png +0 -0
  67. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries.png +0 -0
  68. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entry-one.png +0 -0
  69. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entry-two.png +0 -0
  70. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/feeds.png +0 -0
  71. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/lynx.png +0 -0
  72. {reader-3.17 → reader-3.19.dev0}/docs/screenshots/search.png +0 -0
  73. {reader-3.17 → reader-3.19.dev0}/docs/tutorial.rst +0 -0
  74. {reader-3.17 → reader-3.19.dev0}/docs/why.rst +0 -0
  75. {reader-3.17 → reader-3.19.dev0}/examples/config.yaml +0 -0
  76. {reader-3.17 → reader-3.19.dev0}/examples/custom_headers.py +0 -0
  77. {reader-3.17 → reader-3.19.dev0}/examples/feed_slugs.py +0 -0
  78. {reader-3.17 → reader-3.19.dev0}/examples/parser_only.py +0 -0
  79. {reader-3.17 → reader-3.19.dev0}/examples/podcast.py +0 -0
  80. {reader-3.17 → reader-3.19.dev0}/examples/terminal.py +0 -0
  81. {reader-3.17 → reader-3.19.dev0}/scripts/backup.sh +0 -0
  82. {reader-3.17 → reader-3.19.dev0}/scripts/bench.py +0 -0
  83. {reader-3.17 → reader-3.19.dev0}/scripts/debug_storage_stats.py +0 -0
  84. {reader-3.17 → reader-3.19.dev0}/scripts/jscontrols.html +0 -0
  85. {reader-3.17 → reader-3.19.dev0}/scripts/jscontrols.py +0 -0
  86. {reader-3.17 → reader-3.19.dev0}/scripts/lines.sh +0 -0
  87. {reader-3.17 → reader-3.19.dev0}/scripts/release.py +0 -0
  88. {reader-3.17 → reader-3.19.dev0}/setup.cfg +0 -0
  89. {reader-3.17 → reader-3.19.dev0}/src/reader/__main__.py +0 -0
  90. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/__init__.py +0 -0
  91. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/api_thing.py +0 -0
  92. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/cli.py +0 -0
  93. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/static/controls.js +0 -0
  94. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/static/style.css +0 -0
  95. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/add_entry.html +0 -0
  96. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/entries.html +0 -0
  97. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/entry.html +0 -0
  98. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/feeds.html +0 -0
  99. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/layout.html +0 -0
  100. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/macros.html +0 -0
  101. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/metadata.html +0 -0
  102. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/tags.html +0 -0
  103. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/__init__.py +0 -0
  104. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/forms.py +0 -0
  105. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/static/style.css +0 -0
  106. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/static/theme.js +0 -0
  107. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/entries.html +0 -0
  108. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/layout.html +0 -0
  109. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/macros.html +0 -0
  110. {reader-3.17 → reader-3.19.dev0}/src/reader/_app/wsgi.py +0 -0
  111. {reader-3.17 → reader-3.19.dev0}/src/reader/_cli.py +0 -0
  112. {reader-3.17 → reader-3.19.dev0}/src/reader/_config.py +0 -0
  113. {reader-3.17 → reader-3.19.dev0}/src/reader/_hash_utils.py +0 -0
  114. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_http_utils.py +0 -0
  115. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_url_utils.py +0 -0
  116. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/feedparser.py +0 -0
  117. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/file.py +0 -0
  118. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/http.py +0 -0
  119. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/jsonfeed.py +0 -0
  120. {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/requests/__init__.py +0 -0
  121. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/__init__.py +0 -0
  122. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/preview_feed_list.py +0 -0
  123. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/share.py +0 -0
  124. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/sqlite_releases.py +0 -0
  125. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/templates/preview_feed_list.html +0 -0
  126. {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/timer.py +0 -0
  127. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/__init__.py +0 -0
  128. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_changes.py +0 -0
  129. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_html_utils.py +0 -0
  130. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_schema.py +0 -0
  131. {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_tags.py +0 -0
  132. {reader-3.17 → reader-3.19.dev0}/src/reader/_utils.py +0 -0
  133. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/__init__.py +0 -0
  134. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/__init__.py +0 -0
  135. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/api.py +0 -0
  136. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
  137. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
  138. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
  139. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
  140. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
  141. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
  142. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
  143. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
  144. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
  145. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/encodings.py +0 -0
  146. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/exceptions.py +0 -0
  147. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/html.py +0 -0
  148. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/http.py +0 -0
  149. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/mixin.py +0 -0
  150. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
  151. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
  152. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
  153. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
  154. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
  155. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
  156. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
  157. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
  158. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
  159. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
  160. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
  161. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
  162. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
  163. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/py.typed +0 -0
  164. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
  165. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/sgml.py +0 -0
  166. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/urls.py +0 -0
  167. {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/util.py +0 -0
  168. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/__init__.py +0 -0
  169. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/enclosure_dedupe.py +0 -0
  170. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/entry_dedupe.py +0 -0
  171. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/mark_as_read.py +0 -0
  172. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/readtime.py +0 -0
  173. {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/ua_fallback.py +0 -0
  174. {reader-3.17 → reader-3.19.dev0}/src/reader/py.typed +0 -0
  175. {reader-3.17 → reader-3.19.dev0}/src/reader/utils.py +0 -0
  176. {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/dependency_links.txt +0 -0
  177. {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/top_level.txt +0 -0
  178. {reader-3.17 → reader-3.19.dev0}/tests/data/10.json +0 -0
  179. {reader-3.17 → reader-3.19.dev0}/tests/data/10.json.py +0 -0
  180. {reader-3.17 → reader-3.19.dev0}/tests/data/custom +0 -0
  181. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.atom +0 -0
  182. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.atom.py +0 -0
  183. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.json +0 -0
  184. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.json.py +0 -0
  185. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.rss +0 -0
  186. {reader-3.17 → reader-3.19.dev0}/tests/data/empty.rss.py +0 -0
  187. {reader-3.17 → reader-3.19.dev0}/tests/data/full.atom +0 -0
  188. {reader-3.17 → reader-3.19.dev0}/tests/data/full.json +0 -0
  189. {reader-3.17 → reader-3.19.dev0}/tests/data/full.rss +0 -0
  190. {reader-3.17 → reader-3.19.dev0}/tests/data/invalid.json +0 -0
  191. {reader-3.17 → reader-3.19.dev0}/tests/data/invalid.json.py +0 -0
  192. {reader-3.17 → reader-3.19.dev0}/tests/data/relative.atom +0 -0
  193. {reader-3.17 → reader-3.19.dev0}/tests/data/relative.atom.py +0 -0
  194. {reader-3.17 → reader-3.19.dev0}/tests/data/relative.rss +0 -0
  195. {reader-3.17 → reader-3.19.dev0}/tests/data/relative.rss.py +0 -0
  196. {reader-3.17 → reader-3.19.dev0}/tests/data/sqlite_releases.html +0 -0
  197. {reader-3.17 → reader-3.19.dev0}/tests/data/unknown.json +0 -0
  198. {reader-3.17 → reader-3.19.dev0}/tests/data/unknown.json.py +0 -0
  199. {reader-3.17 → reader-3.19.dev0}/tests/fakeparser.py +0 -0
  200. {reader-3.17 → reader-3.19.dev0}/tests/reader_methods.py +0 -0
  201. {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/__init__.py +0 -0
  202. {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/good.py +0 -0
  203. {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/init_error.py +0 -0
  204. {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/missing_dependency.py +0 -0
  205. {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/missing_entry_point.py +0 -0
  206. {reader-3.17 → reader-3.19.dev0}/tests/test__types.py +0 -0
  207. {reader-3.17 → reader-3.19.dev0}/tests/test__utils.py +0 -0
  208. {reader-3.17 → reader-3.19.dev0}/tests/test_app.py +0 -0
  209. {reader-3.17 → reader-3.19.dev0}/tests/test_app_wsgi.py +0 -0
  210. {reader-3.17 → reader-3.19.dev0}/tests/test_bench.py +0 -0
  211. {reader-3.17 → reader-3.19.dev0}/tests/test_changes.py +0 -0
  212. {reader-3.17 → reader-3.19.dev0}/tests/test_cli.py +0 -0
  213. {reader-3.17 → reader-3.19.dev0}/tests/test_config.py +0 -0
  214. {reader-3.17 → reader-3.19.dev0}/tests/test_exceptions.py +0 -0
  215. {reader-3.17 → reader-3.19.dev0}/tests/test_hash_utils.py +0 -0
  216. {reader-3.17 → reader-3.19.dev0}/tests/test_html_utils.py +0 -0
  217. {reader-3.17 → reader-3.19.dev0}/tests/test_lazy_imports.py +0 -0
  218. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_enclosure_dedupe.py +0 -0
  219. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_entry_dedupe.py +0 -0
  220. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_mark_as_read.py +0 -0
  221. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_preview_feed_list.py +0 -0
  222. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_readtime.py +0 -0
  223. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_sqlite_releases.py +0 -0
  224. {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_ua_fallback.py +0 -0
  225. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_context.py +0 -0
  226. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_counts.py +0 -0
  227. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_deprecations.py +0 -0
  228. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_filter.py +0 -0
  229. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_integration.py +0 -0
  230. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_plugins.py +0 -0
  231. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_private.py +0 -0
  232. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_search.py +0 -0
  233. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_sort.py +0 -0
  234. {reader-3.17 → reader-3.19.dev0}/tests/test_reader_utils.py +0 -0
  235. {reader-3.17 → reader-3.19.dev0}/tests/test_search.py +0 -0
  236. {reader-3.17 → reader-3.19.dev0}/tests/test_sql_utils.py +0 -0
  237. {reader-3.17 → reader-3.19.dev0}/tests/test_sqlite_utils.py +0 -0
  238. {reader-3.17 → reader-3.19.dev0}/tests/test_storage.py +0 -0
  239. {reader-3.17 → reader-3.19.dev0}/tests/test_tags.py +0 -0
  240. {reader-3.17 → reader-3.19.dev0}/tests/test_types.py +0 -0
@@ -6,6 +6,39 @@ Changelog
6
6
  :no-index:
7
7
 
8
8
 
9
+ Version 3.19
10
+ ------------
11
+
12
+ Unreleased
13
+
14
+ * Support Python 3.14.
15
+
16
+ * :mod:`~reader._plugins.enclosure_tags` plugin:
17
+ strip HTML tags from values used as MP3 tags
18
+ (for example, ``<b>`` tags used to highlight search result matches).
19
+
20
+ * Remove long-deprecated, empty ``search`` and ``readtime`` extras.
21
+
22
+
23
+ Version 3.18
24
+ ------------
25
+
26
+ Released 2025-05-04
27
+
28
+ * Drop Python 3.10 support. (:issue:`354`)
29
+
30
+ * Add the ``overwrite`` argument to :meth:`~Reader.add_entry`.
31
+ * Add :class:`FeedSort`, :class:`EntrySort`, and :class:`EntrySearchSort` enums.
32
+ (:issue:`354`)
33
+
34
+ * Fix bug causing :meth:`.Reader.update_feeds`
35
+ to not honor ``updates_enabled=True`` when ``scheduled=True``.
36
+ (:issue:`365`)
37
+
38
+ * In the :mod:`~reader._plugins.cli_status` plugin,
39
+ overwrite the entry so it doesn't appear briefly as unread.
40
+
41
+
9
42
  Version 3.17
10
43
  ------------
11
44
 
@@ -1,13 +1,13 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: reader
3
- Version: 3.17
3
+ Version: 3.19.dev0
4
4
  Summary: A Python feed reader library.
5
5
  Author: lemon24
6
6
  License: BSD-3-Clause
7
7
  Project-URL: Documentation, https://reader.readthedocs.io/
8
- Project-URL: Changes, https://reader.readthedocs.io/en/latest/changelog.html
9
- Project-URL: Source Code, https://github.com/lemon24/reader
10
- Project-URL: Issue tracker, https://github.com/lemon24/reader/issues
8
+ Project-URL: Repository, https://github.com/lemon24/reader
9
+ Project-URL: Issues, https://github.com/lemon24/reader/issues
10
+ Project-URL: Changelog, https://reader.readthedocs.io/en/latest/changelog.html
11
11
  Keywords: atom,cdf,feed,rdf,rss,json feed,web feed,podcast,feed reader,feed aggregator
12
12
  Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Environment :: Console
@@ -19,10 +19,10 @@ Classifier: Operating System :: OS Independent
19
19
  Classifier: Programming Language :: Python
20
20
  Classifier: Programming Language :: Python :: 3
21
21
  Classifier: Programming Language :: Python :: 3 :: Only
22
- Classifier: Programming Language :: Python :: 3.10
23
22
  Classifier: Programming Language :: Python :: 3.11
24
23
  Classifier: Programming Language :: Python :: 3.12
25
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: Python :: 3.14
26
26
  Classifier: Programming Language :: Python :: Implementation :: CPython
27
27
  Classifier: Programming Language :: Python :: Implementation :: PyPy
28
28
  Classifier: Topic :: Internet
@@ -32,7 +32,7 @@ Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
32
32
  Classifier: Topic :: Software Development :: Libraries
33
33
  Classifier: Topic :: Utilities
34
34
  Classifier: Typing :: Typed
35
- Requires-Python: >=3.10
35
+ Requires-Python: >=3.11
36
36
  Description-Content-Type: text/x-rst
37
37
  License-File: LICENSE
38
38
  Requires-Dist: typing-extensions>=4
@@ -41,14 +41,14 @@ Requires-Dist: requests>=2.18
41
41
  Requires-Dist: werkzeug>2
42
42
  Requires-Dist: iso8601>=1
43
43
  Requires-Dist: beautifulsoup4>=4.5
44
- Provides-Extra: search
45
- Provides-Extra: readtime
44
+ Provides-Extra: all
45
+ Requires-Dist: reader[app,cli,unstable-plugins]; extra == "all"
46
46
  Provides-Extra: cli
47
47
  Requires-Dist: click>=7; extra == "cli"
48
48
  Requires-Dist: PyYAML; extra == "cli"
49
49
  Provides-Extra: app
50
50
  Requires-Dist: flask>=0.10; extra == "app"
51
- Requires-Dist: humanize!=4.7.*,>=4; extra == "app"
51
+ Requires-Dist: humanize>=4; extra == "app"
52
52
  Requires-Dist: PyYAML; extra == "app"
53
53
  Requires-Dist: WTForms; extra == "app"
54
54
  Requires-Dist: jinja2-fragments; extra == "app"
@@ -60,36 +60,7 @@ Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
60
60
  Requires-Dist: blinker>=1.4; extra == "unstable-plugins"
61
61
  Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
62
62
  Requires-Dist: tabulate; extra == "unstable-plugins"
63
- Provides-Extra: tests
64
- Requires-Dist: pytest>=4; extra == "tests"
65
- Requires-Dist: pytest-randomly; extra == "tests"
66
- Requires-Dist: pytest-subtests; extra == "tests"
67
- Requires-Dist: pytest-rerunfailures; extra == "tests"
68
- Requires-Dist: coverage; extra == "tests"
69
- Requires-Dist: pytest-cov; extra == "tests"
70
- Requires-Dist: requests-mock; extra == "tests"
71
- Requires-Dist: mechanicalsoup; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
72
- Requires-Dist: requests-wsgi-adapter; extra == "tests"
73
- Requires-Dist: lxml; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
74
- Requires-Dist: html5lib; extra == "tests"
75
- Requires-Dist: numpy; (implementation_name != "pypy" and os_name == "posix" and python_version <= "3.12") and extra == "tests"
76
- Requires-Dist: mypy; implementation_name != "pypy" and extra == "tests"
77
- Requires-Dist: types-requests; extra == "tests"
78
- Requires-Dist: types-beautifulsoup4; extra == "tests"
79
- Provides-Extra: docs
80
- Requires-Dist: sphinx; extra == "docs"
81
- Requires-Dist: sphinx-rtd-theme>=1.3.0rc1; extra == "docs"
82
- Requires-Dist: click>=7; extra == "docs"
83
- Requires-Dist: sphinx-click; extra == "docs"
84
- Requires-Dist: sphinx-hoverxref; extra == "docs"
85
- Requires-Dist: sphinxcontrib-log-cabinet; extra == "docs"
86
- Requires-Dist: setuptools; extra == "docs"
87
- Provides-Extra: dev
88
- Requires-Dist: reader[app,cli,docs,tests,unstable-plugins]; extra == "dev"
89
- Requires-Dist: tox; extra == "dev"
90
- Requires-Dist: pre-commit; extra == "dev"
91
- Requires-Dist: build; extra == "dev"
92
- Requires-Dist: twine; extra == "dev"
63
+ Dynamic: license-file
93
64
 
94
65
  .. begin-intro
95
66
 
@@ -171,6 +171,23 @@ The class hierarchy for :mod:`reader` exceptions is:
171
171
 
172
172
 
173
173
 
174
+ Enumerations
175
+ ------------
176
+
177
+ .. autoclass:: reader.FeedSort(value)
178
+ :show-inheritance:
179
+ :members:
180
+
181
+ .. autoclass:: reader.EntrySort(value)
182
+ :show-inheritance:
183
+ :members:
184
+
185
+ .. autoclass:: reader.EntrySearchSort(value)
186
+ :show-inheritance:
187
+ :members:
188
+
189
+
190
+
174
191
  .. _type aliases:
175
192
 
176
193
  Type aliases
@@ -33,7 +33,6 @@ extensions = [
33
33
  'sphinx.ext.intersphinx',
34
34
  'sphinx.ext.extlinks',
35
35
  'sphinx_click.ext',
36
- 'hoverxref.extension',
37
36
  'sphinxcontrib.log_cabinet',
38
37
  ]
39
38
 
@@ -112,19 +111,6 @@ extlinks = {
112
111
  }
113
112
 
114
113
 
115
- hoverxref_auto_ref = True
116
- hoverxref_domains = ["py"]
117
- hoverxref_role_types = {
118
- 'ref': 'tooltip',
119
- 'mod': 'tooltip',
120
- 'class': 'tooltip',
121
- 'meth': 'tooltip',
122
- 'attr': 'tooltip',
123
- 'exc': 'tooltip',
124
- 'func': 'tooltip',
125
- 'data': 'tooltip',
126
- }
127
-
128
114
  pygments_style = 'friendly'
129
115
 
130
116
  html_theme = 'sphinx_rtd_theme'
@@ -109,11 +109,13 @@ Use the following command to update *reader*
109
109
  pip install --upgrade reader
110
110
 
111
111
 
112
+ .. _install-pre-release:
113
+
112
114
  Living on the edge
113
115
  ~~~~~~~~~~~~~~~~~~
114
116
 
115
117
  If you want to use the latest *reader* code before it’s released,
116
- install or update from the master branch:
118
+ install or update from the ``master`` branch:
117
119
 
118
120
  .. code-block:: bash
119
121
 
@@ -1,7 +1,3 @@
1
- [build-system]
2
- requires = ["setuptools", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
1
  [project]
6
2
  name = "reader"
7
3
  authors = [{name = "lemon24"}]
@@ -23,10 +19,10 @@ classifiers = [
23
19
  "Programming Language :: Python",
24
20
  "Programming Language :: Python :: 3",
25
21
  "Programming Language :: Python :: 3 :: Only",
26
- "Programming Language :: Python :: 3.10",
27
22
  "Programming Language :: Python :: 3.11",
28
23
  "Programming Language :: Python :: 3.12",
29
24
  "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
30
26
  "Programming Language :: Python :: Implementation :: CPython",
31
27
  "Programming Language :: Python :: Implementation :: PyPy",
32
28
  "Topic :: Internet",
@@ -37,7 +33,7 @@ classifiers = [
37
33
  "Topic :: Utilities",
38
34
  "Typing :: Typed",
39
35
  ]
40
- requires-python = ">=3.10"
36
+ requires-python = ">=3.11"
41
37
  dependencies = [
42
38
  "typing-extensions>=4",
43
39
  "feedparser>=6",
@@ -53,19 +49,16 @@ dynamic = ["version"]
53
49
 
54
50
  [project.urls]
55
51
  Documentation = "https://reader.readthedocs.io/"
56
- Changes = "https://reader.readthedocs.io/en/latest/changelog.html"
57
- "Source Code" = "https://github.com/lemon24/reader"
58
- "Issue tracker" = "https://github.com/lemon24/reader/issues"
52
+ Repository = "https://github.com/lemon24/reader"
53
+ Issues = "https://github.com/lemon24/reader/issues"
54
+ Changelog = "https://reader.readthedocs.io/en/latest/changelog.html"
59
55
 
60
56
  [project.optional-dependencies]
61
57
 
62
- # STABLE
63
-
64
- search = [] # empty since 2.4, kept to avoid breaking dependents
65
- readtime = [] # empty since 3.1, kept to avoid breaking dependents
66
-
67
58
  # UNSTABLE
68
59
 
60
+ all = ["reader[cli,app,unstable-plugins]"]
61
+
69
62
  cli = [
70
63
  "click>=7",
71
64
  # for config
@@ -73,8 +66,7 @@ cli = [
73
66
  ]
74
67
  app = [
75
68
  "flask>=0.10",
76
- # https://github.com/python-humanize/humanize/issues/122
77
- "humanize>=4,!=4.7.*",
69
+ "humanize>=4",
78
70
  # for config
79
71
  "PyYAML",
80
72
  # for v2
@@ -82,8 +74,6 @@ app = [
82
74
  "jinja2-fragments",
83
75
  ]
84
76
 
85
- # UNSTABLE PLUGINS
86
-
87
77
  # mushed together for convenience
88
78
  unstable-plugins = [
89
79
  # enclosure-tags
@@ -99,16 +89,14 @@ unstable-plugins = [
99
89
  "tabulate",
100
90
  ]
101
91
 
102
- # DEVELOPMENT
92
+ [dependency-groups]
103
93
 
104
- # run tests under one interpreter
105
94
  tests = [
106
95
  "pytest>=4",
107
96
  "pytest-randomly",
108
97
  "pytest-subtests",
109
98
  "pytest-rerunfailures",
110
99
  "coverage",
111
- "pytest-cov",
112
100
  "requests-mock",
113
101
  # mechanicalsoup hard-depends on lxml (see below)
114
102
  'mechanicalsoup; (implementation_name != "pypy" and python_version <= "3.12")',
@@ -120,35 +108,38 @@ tests = [
120
108
  "html5lib",
121
109
  # for bench.py
122
110
  'numpy; (implementation_name != "pypy" and os_name == "posix" and python_version <= "3.12")',
123
- # mypy does not work on pypy (yet).
124
- 'mypy; implementation_name != "pypy"',
111
+ ]
112
+
113
+ typing = [
114
+ 'mypy',
125
115
  "types-requests",
126
116
  "types-beautifulsoup4",
127
117
  ]
128
118
 
129
- # build docs
130
119
  docs = [
131
120
  "sphinx",
132
- # listing 1.3.0rc1 explicitly until 1.3 is released
133
- # https://github.com/readthedocs/sphinx_rtd_theme/pull/1464#issuecomment-1664799982
134
- "sphinx-rtd-theme>=1.3.0rc1",
121
+ "sphinx-rtd-theme",
135
122
  "click>=7",
136
123
  "sphinx-click",
137
- "sphinx-hoverxref",
138
124
  "sphinxcontrib-log-cabinet",
139
125
  # for read_configuration used in conf.py
140
126
  "setuptools",
141
127
  ]
142
128
 
143
- # things needed to develop / test locally / make releases
144
129
  dev = [
145
- "reader[cli,app,unstable-plugins,tests,docs]",
130
+ {include-group = "tests"},
131
+ {include-group = "typing"},
132
+ {include-group = "docs"},
146
133
  "tox",
147
134
  "pre-commit",
148
135
  "build",
149
136
  "twine",
150
137
  ]
151
138
 
139
+ [build-system]
140
+ requires = ["setuptools", "wheel"]
141
+ build-backend = "setuptools.build_meta"
142
+
152
143
  [tool.setuptools.dynamic]
153
144
  version = {attr = "reader.__version__"}
154
145
 
@@ -171,9 +162,16 @@ source = ["reader", "tests"]
171
162
  omit = [
172
163
  "src/reader/_vendor/*",
173
164
  ]
165
+ # TODO: remove when https://github.com/nedbat/coveragepy/issues/1987 is solved
166
+ core = "ctrace"
174
167
  [tool.coverage.paths]
175
168
  source = ["src", "*/site-packages"]
176
169
 
170
+ [tool.mypy]
171
+ files = ["src"]
172
+ show_error_codes = true
173
+ pretty = true
174
+ strict = true
177
175
  [[tool.mypy.overrides]]
178
176
  module = [
179
177
  "reader.__main__",
@@ -189,7 +187,7 @@ ignore_errors = true
189
187
 
190
188
  [tool.isort]
191
189
  profile = "black"
192
- py_version = 310
190
+ py_version = 311
193
191
  src_paths = ["src", "tests"]
194
192
  extend_skip = ["examples", "src/reader/_vendor"]
195
193
  skip_gitignore = true
@@ -0,0 +1,125 @@
1
+ #!/bin/bash
2
+ #
3
+ # usage: ./run.sh command [argument ...]
4
+ #
5
+ # Executable documentation for the development workflow.
6
+ #
7
+ # See https://death.andgravity.com/run-sh for how this works.
8
+
9
+
10
+ # preamble
11
+
12
+ set -o nounset
13
+ set -o pipefail
14
+ set -o errexit
15
+
16
+ PROJECT_ROOT=${0%/*}
17
+ if [[ $0 != $PROJECT_ROOT && $PROJECT_ROOT != "" ]]; then
18
+ cd "$PROJECT_ROOT"
19
+ fi
20
+ readonly PROJECT_ROOT=$( pwd )
21
+ readonly SCRIPT="$PROJECT_ROOT/$( basename "$0" )"
22
+
23
+
24
+ # main development workflow
25
+
26
+ function install {
27
+ pip install -e '.[all]' --group dev --upgrade --upgrade-strategy eager
28
+ pre-commit install --install-hooks
29
+ }
30
+
31
+ function test {
32
+ pytest --runslow "$@"
33
+ }
34
+
35
+ function test-all {
36
+ tox run-parallel "$@"
37
+ }
38
+
39
+ function coverage {
40
+ unset -f coverage
41
+ coverage run -m pytest --runslow "$@"
42
+ coverage html
43
+ coverage-report
44
+ }
45
+
46
+ function typing {
47
+ mypy "$@"
48
+ }
49
+
50
+ function docs {
51
+ sphinx-build -E -W docs docs/_build/html "$@"
52
+ }
53
+
54
+
55
+ # "watch" versions of the main commands
56
+
57
+ function test-dev {
58
+ watch pytest "$@"
59
+ }
60
+
61
+ function typing-dev {
62
+ watch typing "$@"
63
+ }
64
+
65
+ function docs-dev {
66
+ rm -r docs/_build/html
67
+ watch sphinx-build -W docs docs/_build/html "$@"
68
+ }
69
+
70
+ function serve-dev {
71
+ export READER_DB=db.sqlite
72
+ flask -A reader._app.wsgi --debug run "$@"
73
+ }
74
+
75
+
76
+ # low level commands
77
+
78
+ function coverage-report {
79
+ # --fail-under only for the library, not the CLI or the web app
80
+ unset -f coverage
81
+ coverage report \
82
+ --omit "$(
83
+ echo "
84
+ */reader/_vendor/*
85
+ */reader/__main__.py
86
+ */reader/_cli*
87
+ */reader/_config*
88
+ */reader/_app/*
89
+ */reader/_plugins/*
90
+ tests/*
91
+ " | xargs echo | sed 's/ /,/g'
92
+ )" \
93
+ --skip-covered \
94
+ --show-missing \
95
+ --fail-under $( on-pypy && echo 99 || echo 100 )
96
+ }
97
+
98
+
99
+ # utilities
100
+
101
+ function on-pypy {
102
+ [[ $( python -c 'import sys; print(sys.implementation.name)' ) == pypy ]]
103
+ }
104
+
105
+ function watch {
106
+ entr-project-files -cdr "$SCRIPT" "$@"
107
+ }
108
+
109
+ function entr-project-files {
110
+ set +o errexit
111
+ while true; do
112
+ ls-project-files | entr "$@"
113
+ if [[ $? -eq 0 ]]; then
114
+ break
115
+ fi
116
+ done
117
+ }
118
+
119
+ function ls-project-files {
120
+ git ls-files "$@"
121
+ git ls-files --exclude-standard --others "$@"
122
+ }
123
+
124
+
125
+ "$@"
@@ -37,7 +37,7 @@ Print the titles of the unread entries::
37
37
 
38
38
  """
39
39
 
40
- __version__ = '3.17'
40
+ __version__ = '3.19.dev0'
41
41
 
42
42
  # isort: off
43
43
 
@@ -58,6 +58,9 @@ from .types import (
58
58
  FeedCounts as FeedCounts,
59
59
  EntryCounts as EntryCounts,
60
60
  EntrySearchCounts as EntrySearchCounts,
61
+ FeedSort as FeedSort,
62
+ EntrySort as EntrySort,
63
+ EntrySearchSort as EntrySearchSort,
61
64
  UpdateResult as UpdateResult,
62
65
  UpdatedFeed as UpdatedFeed,
63
66
  EntryUpdateStatus as EntryUpdateStatus,
@@ -239,13 +239,9 @@ class NotModified(RetrieveError):
239
239
  _default_message = "not modified"
240
240
 
241
241
 
242
- @dataclass(frozen=True)
243
- class RetrieveResult(_namedtuple_compat, Generic[F, T, E]):
242
+ class RetrieveResult(NamedTuple, Generic[F, T, E]):
244
243
  """The result of retrieving a feed, regardless of the outcome."""
245
244
 
246
- # should be a NamedTuple, but the typing one became generic only in 3.11,
247
- # and we don't want to depend on typing_extensions at runtime
248
-
249
245
  #: The feed (a :class:`FeedArgument`, usually a :class:`FeedForUpdate`).
250
246
  feed: F
251
247
 
@@ -339,8 +335,7 @@ class FeedForUpdateRetrieverType(RetrieverType[T_co], Protocol): # pragma: no c
339
335
  """
340
336
 
341
337
 
342
- @dataclass(frozen=True)
343
- class ParseResult(_namedtuple_compat, Generic[F, E]):
338
+ class ParseResult(NamedTuple, Generic[F, E]):
344
339
  """The result of retrieving and parsing a feed, regardless of the outcome."""
345
340
 
346
341
  #: The feed (a :class:`FeedArgument`, usually a :class:`.FeedForUpdate`).
@@ -259,8 +259,7 @@ class Parser:
259
259
  Takes one argument and does not raise exceptions.
260
260
 
261
261
  """
262
- feed = result.feed
263
- context = result.value
262
+ feed, context = result
264
263
 
265
264
  http_info = None
266
265
  value: ParsedFeed | None | Exception
@@ -4,6 +4,7 @@ from collections.abc import Sequence
4
4
  from dataclasses import dataclass
5
5
  from dataclasses import field
6
6
  from typing import Any
7
+ from typing import Self
7
8
  from typing import TYPE_CHECKING
8
9
  from typing import TypeVar
9
10
 
@@ -14,8 +15,6 @@ from . import TimeoutType
14
15
 
15
16
 
16
17
  if TYPE_CHECKING: # pragma: no cover
17
- from typing_extensions import Self
18
-
19
18
  from . import Headers
20
19
  from . import RequestHook
21
20
  from . import ResponseHook
@@ -73,7 +73,6 @@ def save_output(reader, now, config, command_path, output):
73
73
 
74
74
  try:
75
75
  old_content = reader.get_entry((feed_url, entry_id)).content[0].value
76
- reader.delete_entry((feed_url, entry_id))
77
76
  except EntryNotFoundError:
78
77
  old_content = ''
79
78
 
@@ -91,7 +90,8 @@ def save_output(reader, now, config, command_path, output):
91
90
  title=title,
92
91
  updated=now,
93
92
  content=[dict(type='text/plain', value=''.join(parts))],
94
- )
93
+ ),
94
+ overwrite=True,
95
95
  )
96
96
  reader.mark_entry_as_read((feed_url, entry_id))
97
97
 
@@ -38,6 +38,7 @@ from flask import request
38
38
  from flask import Response
39
39
  from flask import stream_with_context
40
40
  from flask import url_for
41
+ from jinja2.filters import do_striptags as striptags
41
42
 
42
43
 
43
44
  blueprint = Blueprint('enclosure_tags', __name__)
@@ -146,12 +147,13 @@ def enclosure_tags_filter(enclosure, entry, feed_tags):
146
147
 
147
148
  args = {'url': enclosure.href, 'filename': filename}
148
149
  if entry.title:
149
- args['title'] = entry.title
150
+ args['title'] = striptags(entry.title)
150
151
  if album := (entry.feed.user_title or entry.feed.title):
152
+ album = striptags(album)
151
153
  args['album'] = album
152
154
  args['artist'] = album
153
155
  elif artist := (entry.author or entry.feed.author):
154
- args['artist'] = artist
156
+ args['artist'] = striptags(artist)
155
157
 
156
158
  for tag in feed_tags:
157
159
  if 'podcast' in tag.lower():
@@ -41,7 +41,7 @@ if debug: # pragma: no cover
41
41
  stmt = data.pop('stmt', None)
42
42
  print('STORAGE_DEBUG', json.dumps(data), file=sys.stderr)
43
43
  if stmt:
44
- print(stmt)
44
+ print(stmt, file=sys.stderr)
45
45
 
46
46
 
47
47
  wrap_exceptions = partial(_sqlite_utils.wrap_exceptions, StorageError)
@@ -55,7 +55,7 @@ class EntriesMixin(StorageBase):
55
55
  def get_entries(
56
56
  self,
57
57
  filter: EntryFilter = EntryFilter(), # noqa: B008
58
- sort: EntrySort = 'recent',
58
+ sort: EntrySort = EntrySort.RECENT,
59
59
  limit: int | None = None,
60
60
  starting_after: tuple[str, str] | None = None,
61
61
  ) -> Iterable[Entry]:
@@ -64,7 +64,7 @@ class EntriesMixin(StorageBase):
64
64
  partial(get_entries_query, filter, sort),
65
65
  row_factory=entry_factory,
66
66
  )
67
- if sort != 'random':
67
+ if sort != EntrySort.RANDOM:
68
68
  last = self.get_entry_last(sort, starting_after) if starting_after else None
69
69
  return paginated_query(limit, last)
70
70
  else:
@@ -571,7 +571,7 @@ RECENT_SORT_KEY = SortKey(
571
571
  desc=True,
572
572
  )
573
573
 
574
- ENTRY_SORT_KEYS = {'recent': RECENT_SORT_KEY}
574
+ ENTRY_SORT_KEYS = {EntrySort.RECENT: RECENT_SORT_KEY}
575
575
 
576
576
 
577
577
  def entries_recent_sort(
@@ -597,9 +597,9 @@ def entries_random_sort(query: Query) -> None:
597
597
  query.ORDER_BY("random()")
598
598
 
599
599
 
600
- ENTRIES_SORT: dict[str, Callable[[Query], None]] = {
601
- 'recent': entries_recent_sort,
602
- 'random': entries_random_sort,
600
+ ENTRIES_SORT: dict[EntrySort, Callable[[Query], None]] = {
601
+ EntrySort.RECENT: entries_recent_sort,
602
+ EntrySort.RANDOM: entries_random_sort,
603
603
  }
604
604
 
605
605