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.
- {reader-3.17 → reader-3.19.dev0}/CHANGES.rst +33 -0
- {reader-3.17/src/reader.egg-info → reader-3.19.dev0}/PKG-INFO +11 -40
- {reader-3.17 → reader-3.19.dev0}/docs/api.rst +17 -0
- {reader-3.17 → reader-3.19.dev0}/docs/conf.py +0 -14
- {reader-3.17 → reader-3.19.dev0}/docs/install.rst +3 -1
- {reader-3.17 → reader-3.19.dev0}/pyproject.toml +29 -31
- reader-3.19.dev0/run.sh +125 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/__init__.py +4 -1
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/__init__.py +2 -7
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_lazy.py +1 -2
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/requests/_lazy.py +1 -2
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/cli_status.py +2 -2
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/enclosure_tags.py +4 -2
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_base.py +1 -1
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_entries.py +6 -6
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_feeds.py +6 -4
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_search.py +12 -11
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_sql_utils.py +2 -3
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_sqlite_utils.py +15 -4
- {reader-3.17 → reader-3.19.dev0}/src/reader/_types.py +3 -7
- {reader-3.17 → reader-3.19.dev0}/src/reader/_update.py +1 -2
- {reader-3.17 → reader-3.19.dev0}/src/reader/core.py +39 -87
- {reader-3.17 → reader-3.19.dev0}/src/reader/exceptions.py +15 -81
- {reader-3.17 → reader-3.19.dev0}/src/reader/types.py +74 -22
- {reader-3.17 → reader-3.19.dev0/src/reader.egg-info}/PKG-INFO +11 -40
- {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/SOURCES.txt +0 -6
- reader-3.19.dev0/src/reader.egg-info/requires.txt +27 -0
- {reader-3.17 → reader-3.19.dev0}/tests/conftest.py +1 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.atom.py +5 -11
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.json.py +3 -3
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.rss.py +3 -3
- {reader-3.17 → reader-3.19.dev0}/tests/test_parser.py +10 -29
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_cli_status.py +2 -1
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader.py +5 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_hooks.py +14 -4
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_update.py +17 -0
- {reader-3.17 → reader-3.19.dev0}/tests/utils.py +33 -43
- reader-3.19.dev0/tox.ini +40 -0
- reader-3.17/docs/.DS_Store +0 -0
- reader-3.17/docs/Makefile +0 -20
- reader-3.17/docs/make.bat +0 -36
- reader-3.17/run.sh +0 -188
- reader-3.17/scripts/.coverage +0 -0
- reader-3.17/scripts/generate_import_all.py +0 -15
- reader-3.17/src/reader.egg-info/requires.txt +0 -67
- reader-3.17/tests/test_test_utils.py +0 -36
- reader-3.17/tox.ini +0 -40
- {reader-3.17 → reader-3.19.dev0}/LICENSE +0 -0
- {reader-3.17 → reader-3.19.dev0}/MANIFEST.in +0 -0
- {reader-3.17 → reader-3.19.dev0}/README.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/app.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/changelog.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/cli.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/config.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/contributing.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/dev-app.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/dev.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/guide.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/images/redesign-01.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/index.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/internal.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/plugins.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/dillo.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-feed.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-v2-dark.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries-v2-filters-light.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entries.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entry-one.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/entry-two.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/feeds.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/lynx.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/screenshots/search.png +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/tutorial.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/docs/why.rst +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/config.yaml +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/custom_headers.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/feed_slugs.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/parser_only.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/podcast.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/examples/terminal.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/backup.sh +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/bench.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/debug_storage_stats.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/jscontrols.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/jscontrols.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/lines.sh +0 -0
- {reader-3.17 → reader-3.19.dev0}/scripts/release.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/setup.cfg +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/__main__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/api_thing.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/cli.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/static/controls.js +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/static/style.css +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/add_entry.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/entries.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/entry.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/feeds.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/layout.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/macros.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/metadata.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/templates/tags.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/forms.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/static/style.css +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/static/theme.js +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/entries.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/layout.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/v2/templates/v2/macros.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_app/wsgi.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_cli.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_config.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_hash_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_http_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/_url_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/feedparser.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/file.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/http.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/jsonfeed.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_parser/requests/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/preview_feed_list.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/share.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/sqlite_releases.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/templates/preview_feed_list.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_plugins/timer.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_changes.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_html_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_schema.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_storage/_tags.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/api.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/encodings.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/exceptions.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/html.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/http.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/mixin.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/py.typed +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/sgml.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/urls.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/_vendor/feedparser/util.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/enclosure_dedupe.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/entry_dedupe.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/mark_as_read.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/readtime.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/plugins/ua_fallback.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/py.typed +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader/utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/dependency_links.txt +0 -0
- {reader-3.17 → reader-3.19.dev0}/src/reader.egg-info/top_level.txt +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/10.json +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/10.json.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/custom +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.atom +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.atom.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.json +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.json.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.rss +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/empty.rss.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.atom +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.json +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/full.rss +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/invalid.json +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/invalid.json.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/relative.atom +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/relative.atom.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/relative.rss +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/relative.rss.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/sqlite_releases.html +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/unknown.json +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/data/unknown.json.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/fakeparser.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_methods.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/__init__.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/good.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/init_error.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/missing_dependency.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/reader_test_plugins/missing_entry_point.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test__types.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test__utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_app.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_app_wsgi.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_bench.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_changes.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_cli.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_config.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_exceptions.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_hash_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_html_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_lazy_imports.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_enclosure_dedupe.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_entry_dedupe.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_mark_as_read.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_preview_feed_list.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_readtime.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_sqlite_releases.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_plugins_ua_fallback.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_context.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_counts.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_deprecations.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_filter.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_integration.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_plugins.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_private.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_search.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_sort.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_reader_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_search.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_sql_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_sqlite_utils.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_storage.py +0 -0
- {reader-3.17 → reader-3.19.dev0}/tests/test_tags.py +0 -0
- {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.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: reader
|
|
3
|
-
Version: 3.
|
|
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:
|
|
9
|
-
Project-URL:
|
|
10
|
-
Project-URL:
|
|
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.
|
|
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:
|
|
45
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
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 =
|
|
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.dev0/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
|
+
"$@"
|
|
@@ -37,7 +37,7 @@ Print the titles of the unread entries::
|
|
|
37
37
|
|
|
38
38
|
"""
|
|
39
39
|
|
|
40
|
-
__version__ = '3.
|
|
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
|
-
|
|
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
|
-
|
|
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`).
|
|
@@ -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 =
|
|
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 !=
|
|
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 = {
|
|
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[
|
|
601
|
-
|
|
602
|
-
|
|
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
|
|