reader 3.17__tar.gz → 3.19__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}/CHANGES.rst +41 -0
  2. {reader-3.17/src/reader.egg-info → reader-3.19}/PKG-INFO +11 -40
  3. {reader-3.17 → reader-3.19}/docs/api.rst +17 -0
  4. {reader-3.17 → reader-3.19}/docs/conf.py +0 -14
  5. {reader-3.17 → reader-3.19}/docs/dev.rst +16 -10
  6. {reader-3.17 → reader-3.19}/docs/install.rst +3 -1
  7. {reader-3.17 → reader-3.19}/pyproject.toml +29 -31
  8. reader-3.19/run.sh +125 -0
  9. {reader-3.17 → reader-3.19}/scripts/release.py +9 -19
  10. {reader-3.17 → reader-3.19}/src/reader/__init__.py +4 -1
  11. {reader-3.17 → reader-3.19}/src/reader/_parser/__init__.py +2 -7
  12. {reader-3.17 → reader-3.19}/src/reader/_parser/_lazy.py +1 -2
  13. {reader-3.17 → reader-3.19}/src/reader/_parser/requests/_lazy.py +1 -2
  14. {reader-3.17 → reader-3.19}/src/reader/_plugins/cli_status.py +2 -2
  15. {reader-3.17 → reader-3.19}/src/reader/_plugins/enclosure_tags.py +4 -2
  16. {reader-3.17 → reader-3.19}/src/reader/_storage/_base.py +1 -1
  17. {reader-3.17 → reader-3.19}/src/reader/_storage/_entries.py +6 -6
  18. {reader-3.17 → reader-3.19}/src/reader/_storage/_feeds.py +6 -4
  19. {reader-3.17 → reader-3.19}/src/reader/_storage/_search.py +12 -11
  20. {reader-3.17 → reader-3.19}/src/reader/_storage/_sql_utils.py +2 -3
  21. {reader-3.17 → reader-3.19}/src/reader/_storage/_sqlite_utils.py +15 -4
  22. {reader-3.17 → reader-3.19}/src/reader/_types.py +3 -7
  23. {reader-3.17 → reader-3.19}/src/reader/_update.py +1 -2
  24. {reader-3.17 → reader-3.19}/src/reader/core.py +39 -87
  25. {reader-3.17 → reader-3.19}/src/reader/exceptions.py +15 -81
  26. {reader-3.17 → reader-3.19}/src/reader/types.py +74 -22
  27. {reader-3.17 → reader-3.19/src/reader.egg-info}/PKG-INFO +11 -40
  28. {reader-3.17 → reader-3.19}/src/reader.egg-info/SOURCES.txt +0 -6
  29. reader-3.19/src/reader.egg-info/requires.txt +27 -0
  30. {reader-3.17 → reader-3.19}/tests/conftest.py +1 -0
  31. {reader-3.17 → reader-3.19}/tests/data/full.atom.py +5 -11
  32. {reader-3.17 → reader-3.19}/tests/data/full.json.py +3 -3
  33. {reader-3.17 → reader-3.19}/tests/data/full.rss.py +3 -3
  34. {reader-3.17 → reader-3.19}/tests/test_parser.py +10 -29
  35. {reader-3.17 → reader-3.19}/tests/test_plugins_cli_status.py +2 -1
  36. {reader-3.17 → reader-3.19}/tests/test_reader.py +5 -0
  37. {reader-3.17 → reader-3.19}/tests/test_reader_hooks.py +14 -4
  38. {reader-3.17 → reader-3.19}/tests/test_reader_update.py +17 -0
  39. {reader-3.17 → reader-3.19}/tests/utils.py +33 -43
  40. reader-3.19/tox.ini +40 -0
  41. reader-3.17/docs/.DS_Store +0 -0
  42. reader-3.17/docs/Makefile +0 -20
  43. reader-3.17/docs/make.bat +0 -36
  44. reader-3.17/run.sh +0 -188
  45. reader-3.17/scripts/.coverage +0 -0
  46. reader-3.17/scripts/generate_import_all.py +0 -15
  47. reader-3.17/src/reader.egg-info/requires.txt +0 -67
  48. reader-3.17/tests/test_test_utils.py +0 -36
  49. reader-3.17/tox.ini +0 -40
  50. {reader-3.17 → reader-3.19}/LICENSE +0 -0
  51. {reader-3.17 → reader-3.19}/MANIFEST.in +0 -0
  52. {reader-3.17 → reader-3.19}/README.rst +0 -0
  53. {reader-3.17 → reader-3.19}/docs/app.rst +0 -0
  54. {reader-3.17 → reader-3.19}/docs/changelog.rst +0 -0
  55. {reader-3.17 → reader-3.19}/docs/cli.rst +0 -0
  56. {reader-3.17 → reader-3.19}/docs/config.rst +0 -0
  57. {reader-3.17 → reader-3.19}/docs/contributing.rst +0 -0
  58. {reader-3.17 → reader-3.19}/docs/dev-app.rst +0 -0
  59. {reader-3.17 → reader-3.19}/docs/guide.rst +0 -0
  60. {reader-3.17 → reader-3.19}/docs/images/redesign-01.png +0 -0
  61. {reader-3.17 → reader-3.19}/docs/index.rst +0 -0
  62. {reader-3.17 → reader-3.19}/docs/internal.rst +0 -0
  63. {reader-3.17 → reader-3.19}/docs/plugins.rst +0 -0
  64. {reader-3.17 → reader-3.19}/docs/screenshots/dillo.png +0 -0
  65. {reader-3.17 → reader-3.19}/docs/screenshots/entries-feed.png +0 -0
  66. {reader-3.17 → reader-3.19}/docs/screenshots/entries-v2-dark.png +0 -0
  67. {reader-3.17 → reader-3.19}/docs/screenshots/entries-v2-filters-light.png +0 -0
  68. {reader-3.17 → reader-3.19}/docs/screenshots/entries.png +0 -0
  69. {reader-3.17 → reader-3.19}/docs/screenshots/entry-one.png +0 -0
  70. {reader-3.17 → reader-3.19}/docs/screenshots/entry-two.png +0 -0
  71. {reader-3.17 → reader-3.19}/docs/screenshots/feeds.png +0 -0
  72. {reader-3.17 → reader-3.19}/docs/screenshots/lynx.png +0 -0
  73. {reader-3.17 → reader-3.19}/docs/screenshots/search.png +0 -0
  74. {reader-3.17 → reader-3.19}/docs/tutorial.rst +0 -0
  75. {reader-3.17 → reader-3.19}/docs/why.rst +0 -0
  76. {reader-3.17 → reader-3.19}/examples/config.yaml +0 -0
  77. {reader-3.17 → reader-3.19}/examples/custom_headers.py +0 -0
  78. {reader-3.17 → reader-3.19}/examples/feed_slugs.py +0 -0
  79. {reader-3.17 → reader-3.19}/examples/parser_only.py +0 -0
  80. {reader-3.17 → reader-3.19}/examples/podcast.py +0 -0
  81. {reader-3.17 → reader-3.19}/examples/terminal.py +0 -0
  82. {reader-3.17 → reader-3.19}/scripts/backup.sh +0 -0
  83. {reader-3.17 → reader-3.19}/scripts/bench.py +0 -0
  84. {reader-3.17 → reader-3.19}/scripts/debug_storage_stats.py +0 -0
  85. {reader-3.17 → reader-3.19}/scripts/jscontrols.html +0 -0
  86. {reader-3.17 → reader-3.19}/scripts/jscontrols.py +0 -0
  87. {reader-3.17 → reader-3.19}/scripts/lines.sh +0 -0
  88. {reader-3.17 → reader-3.19}/setup.cfg +0 -0
  89. {reader-3.17 → reader-3.19}/src/reader/__main__.py +0 -0
  90. {reader-3.17 → reader-3.19}/src/reader/_app/__init__.py +0 -0
  91. {reader-3.17 → reader-3.19}/src/reader/_app/api_thing.py +0 -0
  92. {reader-3.17 → reader-3.19}/src/reader/_app/cli.py +0 -0
  93. {reader-3.17 → reader-3.19}/src/reader/_app/static/controls.js +0 -0
  94. {reader-3.17 → reader-3.19}/src/reader/_app/static/style.css +0 -0
  95. {reader-3.17 → reader-3.19}/src/reader/_app/templates/add_entry.html +0 -0
  96. {reader-3.17 → reader-3.19}/src/reader/_app/templates/entries.html +0 -0
  97. {reader-3.17 → reader-3.19}/src/reader/_app/templates/entry.html +0 -0
  98. {reader-3.17 → reader-3.19}/src/reader/_app/templates/feeds.html +0 -0
  99. {reader-3.17 → reader-3.19}/src/reader/_app/templates/layout.html +0 -0
  100. {reader-3.17 → reader-3.19}/src/reader/_app/templates/macros.html +0 -0
  101. {reader-3.17 → reader-3.19}/src/reader/_app/templates/metadata.html +0 -0
  102. {reader-3.17 → reader-3.19}/src/reader/_app/templates/tags.html +0 -0
  103. {reader-3.17 → reader-3.19}/src/reader/_app/v2/__init__.py +0 -0
  104. {reader-3.17 → reader-3.19}/src/reader/_app/v2/forms.py +0 -0
  105. {reader-3.17 → reader-3.19}/src/reader/_app/v2/static/style.css +0 -0
  106. {reader-3.17 → reader-3.19}/src/reader/_app/v2/static/theme.js +0 -0
  107. {reader-3.17 → reader-3.19}/src/reader/_app/v2/templates/v2/entries.html +0 -0
  108. {reader-3.17 → reader-3.19}/src/reader/_app/v2/templates/v2/layout.html +0 -0
  109. {reader-3.17 → reader-3.19}/src/reader/_app/v2/templates/v2/macros.html +0 -0
  110. {reader-3.17 → reader-3.19}/src/reader/_app/wsgi.py +0 -0
  111. {reader-3.17 → reader-3.19}/src/reader/_cli.py +0 -0
  112. {reader-3.17 → reader-3.19}/src/reader/_config.py +0 -0
  113. {reader-3.17 → reader-3.19}/src/reader/_hash_utils.py +0 -0
  114. {reader-3.17 → reader-3.19}/src/reader/_parser/_http_utils.py +0 -0
  115. {reader-3.17 → reader-3.19}/src/reader/_parser/_url_utils.py +0 -0
  116. {reader-3.17 → reader-3.19}/src/reader/_parser/feedparser.py +0 -0
  117. {reader-3.17 → reader-3.19}/src/reader/_parser/file.py +0 -0
  118. {reader-3.17 → reader-3.19}/src/reader/_parser/http.py +0 -0
  119. {reader-3.17 → reader-3.19}/src/reader/_parser/jsonfeed.py +0 -0
  120. {reader-3.17 → reader-3.19}/src/reader/_parser/requests/__init__.py +0 -0
  121. {reader-3.17 → reader-3.19}/src/reader/_plugins/__init__.py +0 -0
  122. {reader-3.17 → reader-3.19}/src/reader/_plugins/preview_feed_list.py +0 -0
  123. {reader-3.17 → reader-3.19}/src/reader/_plugins/share.py +0 -0
  124. {reader-3.17 → reader-3.19}/src/reader/_plugins/sqlite_releases.py +0 -0
  125. {reader-3.17 → reader-3.19}/src/reader/_plugins/templates/preview_feed_list.html +0 -0
  126. {reader-3.17 → reader-3.19}/src/reader/_plugins/timer.py +0 -0
  127. {reader-3.17 → reader-3.19}/src/reader/_storage/__init__.py +0 -0
  128. {reader-3.17 → reader-3.19}/src/reader/_storage/_changes.py +0 -0
  129. {reader-3.17 → reader-3.19}/src/reader/_storage/_html_utils.py +0 -0
  130. {reader-3.17 → reader-3.19}/src/reader/_storage/_schema.py +0 -0
  131. {reader-3.17 → reader-3.19}/src/reader/_storage/_tags.py +0 -0
  132. {reader-3.17 → reader-3.19}/src/reader/_utils.py +0 -0
  133. {reader-3.17 → reader-3.19}/src/reader/_vendor/__init__.py +0 -0
  134. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/__init__.py +0 -0
  135. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/api.py +0 -0
  136. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
  137. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
  138. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
  139. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
  140. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
  141. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
  142. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
  143. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
  144. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
  145. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/encodings.py +0 -0
  146. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/exceptions.py +0 -0
  147. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/html.py +0 -0
  148. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/http.py +0 -0
  149. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/mixin.py +0 -0
  150. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
  151. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
  152. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
  153. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
  154. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
  155. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
  156. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
  157. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
  158. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
  159. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
  160. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
  161. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
  162. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
  163. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/py.typed +0 -0
  164. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
  165. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/sgml.py +0 -0
  166. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/urls.py +0 -0
  167. {reader-3.17 → reader-3.19}/src/reader/_vendor/feedparser/util.py +0 -0
  168. {reader-3.17 → reader-3.19}/src/reader/plugins/__init__.py +0 -0
  169. {reader-3.17 → reader-3.19}/src/reader/plugins/enclosure_dedupe.py +0 -0
  170. {reader-3.17 → reader-3.19}/src/reader/plugins/entry_dedupe.py +0 -0
  171. {reader-3.17 → reader-3.19}/src/reader/plugins/mark_as_read.py +0 -0
  172. {reader-3.17 → reader-3.19}/src/reader/plugins/readtime.py +0 -0
  173. {reader-3.17 → reader-3.19}/src/reader/plugins/ua_fallback.py +0 -0
  174. {reader-3.17 → reader-3.19}/src/reader/py.typed +0 -0
  175. {reader-3.17 → reader-3.19}/src/reader/utils.py +0 -0
  176. {reader-3.17 → reader-3.19}/src/reader.egg-info/dependency_links.txt +0 -0
  177. {reader-3.17 → reader-3.19}/src/reader.egg-info/top_level.txt +0 -0
  178. {reader-3.17 → reader-3.19}/tests/data/10.json +0 -0
  179. {reader-3.17 → reader-3.19}/tests/data/10.json.py +0 -0
  180. {reader-3.17 → reader-3.19}/tests/data/custom +0 -0
  181. {reader-3.17 → reader-3.19}/tests/data/empty.atom +0 -0
  182. {reader-3.17 → reader-3.19}/tests/data/empty.atom.py +0 -0
  183. {reader-3.17 → reader-3.19}/tests/data/empty.json +0 -0
  184. {reader-3.17 → reader-3.19}/tests/data/empty.json.py +0 -0
  185. {reader-3.17 → reader-3.19}/tests/data/empty.rss +0 -0
  186. {reader-3.17 → reader-3.19}/tests/data/empty.rss.py +0 -0
  187. {reader-3.17 → reader-3.19}/tests/data/full.atom +0 -0
  188. {reader-3.17 → reader-3.19}/tests/data/full.json +0 -0
  189. {reader-3.17 → reader-3.19}/tests/data/full.rss +0 -0
  190. {reader-3.17 → reader-3.19}/tests/data/invalid.json +0 -0
  191. {reader-3.17 → reader-3.19}/tests/data/invalid.json.py +0 -0
  192. {reader-3.17 → reader-3.19}/tests/data/relative.atom +0 -0
  193. {reader-3.17 → reader-3.19}/tests/data/relative.atom.py +0 -0
  194. {reader-3.17 → reader-3.19}/tests/data/relative.rss +0 -0
  195. {reader-3.17 → reader-3.19}/tests/data/relative.rss.py +0 -0
  196. {reader-3.17 → reader-3.19}/tests/data/sqlite_releases.html +0 -0
  197. {reader-3.17 → reader-3.19}/tests/data/unknown.json +0 -0
  198. {reader-3.17 → reader-3.19}/tests/data/unknown.json.py +0 -0
  199. {reader-3.17 → reader-3.19}/tests/fakeparser.py +0 -0
  200. {reader-3.17 → reader-3.19}/tests/reader_methods.py +0 -0
  201. {reader-3.17 → reader-3.19}/tests/reader_test_plugins/__init__.py +0 -0
  202. {reader-3.17 → reader-3.19}/tests/reader_test_plugins/good.py +0 -0
  203. {reader-3.17 → reader-3.19}/tests/reader_test_plugins/init_error.py +0 -0
  204. {reader-3.17 → reader-3.19}/tests/reader_test_plugins/missing_dependency.py +0 -0
  205. {reader-3.17 → reader-3.19}/tests/reader_test_plugins/missing_entry_point.py +0 -0
  206. {reader-3.17 → reader-3.19}/tests/test__types.py +0 -0
  207. {reader-3.17 → reader-3.19}/tests/test__utils.py +0 -0
  208. {reader-3.17 → reader-3.19}/tests/test_app.py +0 -0
  209. {reader-3.17 → reader-3.19}/tests/test_app_wsgi.py +0 -0
  210. {reader-3.17 → reader-3.19}/tests/test_bench.py +0 -0
  211. {reader-3.17 → reader-3.19}/tests/test_changes.py +0 -0
  212. {reader-3.17 → reader-3.19}/tests/test_cli.py +0 -0
  213. {reader-3.17 → reader-3.19}/tests/test_config.py +0 -0
  214. {reader-3.17 → reader-3.19}/tests/test_exceptions.py +0 -0
  215. {reader-3.17 → reader-3.19}/tests/test_hash_utils.py +0 -0
  216. {reader-3.17 → reader-3.19}/tests/test_html_utils.py +0 -0
  217. {reader-3.17 → reader-3.19}/tests/test_lazy_imports.py +0 -0
  218. {reader-3.17 → reader-3.19}/tests/test_plugins_enclosure_dedupe.py +0 -0
  219. {reader-3.17 → reader-3.19}/tests/test_plugins_entry_dedupe.py +0 -0
  220. {reader-3.17 → reader-3.19}/tests/test_plugins_mark_as_read.py +0 -0
  221. {reader-3.17 → reader-3.19}/tests/test_plugins_preview_feed_list.py +0 -0
  222. {reader-3.17 → reader-3.19}/tests/test_plugins_readtime.py +0 -0
  223. {reader-3.17 → reader-3.19}/tests/test_plugins_sqlite_releases.py +0 -0
  224. {reader-3.17 → reader-3.19}/tests/test_plugins_ua_fallback.py +0 -0
  225. {reader-3.17 → reader-3.19}/tests/test_reader_context.py +0 -0
  226. {reader-3.17 → reader-3.19}/tests/test_reader_counts.py +0 -0
  227. {reader-3.17 → reader-3.19}/tests/test_reader_deprecations.py +0 -0
  228. {reader-3.17 → reader-3.19}/tests/test_reader_filter.py +0 -0
  229. {reader-3.17 → reader-3.19}/tests/test_reader_integration.py +0 -0
  230. {reader-3.17 → reader-3.19}/tests/test_reader_plugins.py +0 -0
  231. {reader-3.17 → reader-3.19}/tests/test_reader_private.py +0 -0
  232. {reader-3.17 → reader-3.19}/tests/test_reader_search.py +0 -0
  233. {reader-3.17 → reader-3.19}/tests/test_reader_sort.py +0 -0
  234. {reader-3.17 → reader-3.19}/tests/test_reader_utils.py +0 -0
  235. {reader-3.17 → reader-3.19}/tests/test_search.py +0 -0
  236. {reader-3.17 → reader-3.19}/tests/test_sql_utils.py +0 -0
  237. {reader-3.17 → reader-3.19}/tests/test_sqlite_utils.py +0 -0
  238. {reader-3.17 → reader-3.19}/tests/test_storage.py +0 -0
  239. {reader-3.17 → reader-3.19}/tests/test_tags.py +0 -0
  240. {reader-3.17 → reader-3.19}/tests/test_types.py +0 -0
@@ -6,6 +6,47 @@ Changelog
6
6
  :no-index:
7
7
 
8
8
 
9
+ Version 3.19
10
+ ------------
11
+
12
+ Released 2025-10-01
13
+
14
+ * Support Python 3.14.
15
+ * Remove deprecated empty ``search`` and ``readtime`` extras.
16
+ * Remove undocumented development ``tests``, ``docs``, and ``dev`` extras.
17
+
18
+ * :mod:`~reader._plugins.enclosure_tags` plugin:
19
+ strip HTML tags from values used as MP3 tags
20
+ (for example, ``<b>`` tags used to highlight search result matches).
21
+
22
+ * Project infrastructure improvements.
23
+
24
+ * Clean up :doc:`contributing` documentation and :gh:`run.sh <run.sh>` script.
25
+ * Use GitHub Actions to publish releases to PyPI.
26
+ * Split type checking and testing jobs in the ``build`` GHA workflow.
27
+ * Make tox runs slightly faster.
28
+ * Use dependency groups instead of extras for development dependencies.
29
+
30
+
31
+ Version 3.18
32
+ ------------
33
+
34
+ Released 2025-05-04
35
+
36
+ * Drop Python 3.10 support. (:issue:`354`)
37
+
38
+ * Add the ``overwrite`` argument to :meth:`~Reader.add_entry`.
39
+ * Add :class:`FeedSort`, :class:`EntrySort`, and :class:`EntrySearchSort` enums.
40
+ (:issue:`354`)
41
+
42
+ * Fix bug causing :meth:`.Reader.update_feeds`
43
+ to not honor ``updates_enabled=True`` when ``scheduled=True``.
44
+ (:issue:`365`)
45
+
46
+ * In the :mod:`~reader._plugins.cli_status` plugin,
47
+ overwrite the entry so it doesn't appear briefly as unread.
48
+
49
+
9
50
  Version 3.17
10
51
  ------------
11
52
 
@@ -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
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'
@@ -226,25 +226,31 @@ Making a release
226
226
 
227
227
  .. note::
228
228
 
229
- :gh:`scripts/release.py <scripts/release.py>` already does most of these.
229
+ The :gh:`release.py <scripts/release.py>` script together with
230
+ the :gh:`publish <.github/workflows/publish.yaml>` GitHub Actions workflow
231
+ already do most of these.
230
232
 
231
233
  Making a release (from ``x`` to ``y`` == ``x + 1``):
232
234
 
233
235
  * (release.py) bump version in ``src/reader/__init__.py`` to ``y``
234
236
  * (release.py) update changelog with release version and date
235
237
  * (release.py) make sure tests pass / docs build
236
- * (release.py) clean up dist/: ``rm -rf dist/``
237
- * (release.py) build tarball and wheel: ``python -m build``
238
238
  * (release.py) push to GitHub
239
- * (release.py prompts) wait for GitHub Actions / Codecov / Read the Docs builds to pass
240
- * upload to test PyPI and check: ``twine upload --repository-url https://test.pypi.org/legacy/ dist/*``
241
- * (release.py) upload to PyPI: ``twine upload dist/*``
239
+ * (release.py prompts) wait for GitHub Actions / Read the Docs builds to pass
242
240
  * (release.py) tag current commit with `<major>.<minor>` and `<major>.x`
243
- (e.g. when releasing `1.20`: `1.20` and `1.x`)
244
- * (release.py prompts) create release in GitHub
245
- * build docs from latest and enable ``y`` docs version (should happen automatically after the first time)
241
+ (e.g. when releasing `1.20`: `1.20` and `1.x`) and push tags to GitHub
242
+ * (release.py prompts) approve publish workflow
243
+ * (publish workflow) build and upload to PyPI
244
+ * alternatively, to make a manual release (should not be needed)
245
+
246
+ * clean up dist/: ``rm -rf dist/``
247
+ * build tarball and wheel: ``python -m build``
248
+ * upload to test PyPI and check: ``twine upload --repository-url https://test.pypi.org/legacy/ dist/*``
249
+ * upload to PyPI: ``twine upload dist/*``
250
+
251
+ * (publish workflow) create draft release in GitHub
252
+ * (release.py prompts) publish release in GitHub
246
253
  * (release.py) bump versions from ``y`` to ``(y + 1).dev0``, add ``(y + 1)`` changelog section
247
- * (release.py prompts) trigger Read the Docs build for `<major>.x` (doesn't happen automatically)
248
254
 
249
255
 
250
256
 
@@ -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
reader-3.19/run.sh ADDED
@@ -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
+ "$@"
@@ -34,11 +34,6 @@ def run_tox():
34
34
  run_no_venv('tox -p all', shell=True)
35
35
 
36
36
 
37
- def build():
38
- run('rm -rf dist/', shell=True)
39
- run('python -m build', shell=True)
40
-
41
-
42
37
  def path_sub(pattern, repl, path):
43
38
  with open(path) as f:
44
39
  text = f.read()
@@ -112,10 +107,6 @@ def check_unpushed():
112
107
  abort("unpushed changes\n\n{}\n", p.stdout.strip('\n'))
113
108
 
114
109
 
115
- def upload_to_pypi():
116
- run('twine upload dist/*', shell=True)
117
-
118
-
119
110
  def add_and_push_tags(tags):
120
111
  for tag in tags:
121
112
  run(['git', 'tag', '--force', tag])
@@ -150,10 +141,6 @@ def main(version, new_version, date, tox, changelog):
150
141
 
151
142
  confirm("Wait for GitHub Actions / Read the Docs builds to pass.")
152
143
 
153
- confirm("Upload to PyPI?")
154
- build()
155
- upload_to_pypi()
156
-
157
144
  tags = [version]
158
145
  version_x = version.partition('.')[0] + '.x'
159
146
  if new_version_is_final:
@@ -162,7 +149,15 @@ def main(version, new_version, date, tox, changelog):
162
149
  confirm(f"Add and push tags ({', '.join(tags)})?")
163
150
  add_and_push_tags(tags)
164
151
 
165
- confirm("Create release {} in GitHub (doesn't happen automatically).", version)
152
+ confirm(
153
+ "Approve publish workflow to upload to PyPI.\n {}\nDone?",
154
+ "https://github.com/lemon24/reader/actions/workflows/publish.yaml",
155
+ )
156
+ confirm(
157
+ "Publish draft release {} in GitHub.\n {}\nDone?",
158
+ version,
159
+ "https://github.com/lemon24/reader/releases",
160
+ )
166
161
 
167
162
  new_version_full = f"{new_version}.dev0"
168
163
  update_init_version(new_version_full)
@@ -173,11 +168,6 @@ def main(version, new_version, date, tox, changelog):
173
168
  confirm("Push version {}?", new_version_full)
174
169
  push()
175
170
 
176
- # TODO: I just enabled branch or tag creation/deletion for the RtD webhook in GitHub, this might not be needed next time.
177
- confirm(
178
- f"Trigger Read the Docs build for {version_x} (doesn't happen automatically)."
179
- )
180
-
181
171
 
182
172
  if __name__ == '__main__':
183
173
  main()
@@ -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'
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