reader 3.18__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.
- {reader-3.18 → reader-3.19}/CHANGES.rst +22 -0
- {reader-3.18/src/reader.egg-info → reader-3.19}/PKG-INFO +8 -37
- {reader-3.18 → reader-3.19}/docs/conf.py +0 -14
- {reader-3.18 → reader-3.19}/docs/dev.rst +16 -10
- {reader-3.18 → reader-3.19}/docs/install.rst +3 -1
- {reader-3.18 → reader-3.19}/pyproject.toml +27 -28
- reader-3.19/run.sh +125 -0
- {reader-3.18 → reader-3.19}/scripts/release.py +9 -19
- {reader-3.18 → reader-3.19}/src/reader/__init__.py +1 -1
- {reader-3.18 → reader-3.19}/src/reader/_plugins/enclosure_tags.py +4 -2
- {reader-3.18 → reader-3.19}/src/reader/_storage/_sqlite_utils.py +4 -2
- {reader-3.18 → reader-3.19}/src/reader/types.py +1 -1
- {reader-3.18 → reader-3.19/src/reader.egg-info}/PKG-INFO +8 -37
- {reader-3.18 → reader-3.19}/src/reader.egg-info/SOURCES.txt +0 -6
- reader-3.19/src/reader.egg-info/requires.txt +27 -0
- {reader-3.18 → reader-3.19}/tests/conftest.py +1 -0
- {reader-3.18 → reader-3.19}/tests/test_parser.py +10 -29
- {reader-3.18 → reader-3.19}/tests/test_plugins_cli_status.py +1 -1
- {reader-3.18 → reader-3.19}/tests/utils.py +33 -43
- reader-3.19/tox.ini +40 -0
- reader-3.18/docs/.DS_Store +0 -0
- reader-3.18/docs/Makefile +0 -20
- reader-3.18/docs/make.bat +0 -36
- reader-3.18/run.sh +0 -188
- reader-3.18/scripts/.coverage +0 -0
- reader-3.18/scripts/generate_import_all.py +0 -15
- reader-3.18/src/reader.egg-info/requires.txt +0 -67
- reader-3.18/tests/test_test_utils.py +0 -36
- reader-3.18/tox.ini +0 -40
- {reader-3.18 → reader-3.19}/LICENSE +0 -0
- {reader-3.18 → reader-3.19}/MANIFEST.in +0 -0
- {reader-3.18 → reader-3.19}/README.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/api.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/app.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/changelog.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/cli.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/config.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/contributing.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/dev-app.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/guide.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/images/redesign-01.png +0 -0
- {reader-3.18 → reader-3.19}/docs/index.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/internal.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/plugins.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/dillo.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entries-feed.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entries-v2-dark.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entries-v2-filters-light.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entries.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entry-one.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/entry-two.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/feeds.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/lynx.png +0 -0
- {reader-3.18 → reader-3.19}/docs/screenshots/search.png +0 -0
- {reader-3.18 → reader-3.19}/docs/tutorial.rst +0 -0
- {reader-3.18 → reader-3.19}/docs/why.rst +0 -0
- {reader-3.18 → reader-3.19}/examples/config.yaml +0 -0
- {reader-3.18 → reader-3.19}/examples/custom_headers.py +0 -0
- {reader-3.18 → reader-3.19}/examples/feed_slugs.py +0 -0
- {reader-3.18 → reader-3.19}/examples/parser_only.py +0 -0
- {reader-3.18 → reader-3.19}/examples/podcast.py +0 -0
- {reader-3.18 → reader-3.19}/examples/terminal.py +0 -0
- {reader-3.18 → reader-3.19}/scripts/backup.sh +0 -0
- {reader-3.18 → reader-3.19}/scripts/bench.py +0 -0
- {reader-3.18 → reader-3.19}/scripts/debug_storage_stats.py +0 -0
- {reader-3.18 → reader-3.19}/scripts/jscontrols.html +0 -0
- {reader-3.18 → reader-3.19}/scripts/jscontrols.py +0 -0
- {reader-3.18 → reader-3.19}/scripts/lines.sh +0 -0
- {reader-3.18 → reader-3.19}/setup.cfg +0 -0
- {reader-3.18 → reader-3.19}/src/reader/__main__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/api_thing.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/cli.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/static/controls.js +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/static/style.css +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/add_entry.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/entries.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/entry.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/feeds.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/layout.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/macros.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/metadata.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/templates/tags.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/forms.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/static/style.css +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/static/theme.js +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/templates/v2/entries.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/templates/v2/layout.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/v2/templates/v2/macros.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_app/wsgi.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_cli.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_config.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_hash_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/_http_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/_lazy.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/_url_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/feedparser.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/file.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/http.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/jsonfeed.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/requests/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_parser/requests/_lazy.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/cli_status.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/preview_feed_list.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/share.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/sqlite_releases.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/templates/preview_feed_list.html +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_plugins/timer.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_base.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_changes.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_entries.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_feeds.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_html_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_schema.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_search.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_sql_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_storage/_tags.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_types.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_update.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/api.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/encodings.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/exceptions.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/html.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/http.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/mixin.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/py.typed +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/sgml.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/urls.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/_vendor/feedparser/util.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/core.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/exceptions.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/enclosure_dedupe.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/entry_dedupe.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/mark_as_read.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/readtime.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/plugins/ua_fallback.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader/py.typed +0 -0
- {reader-3.18 → reader-3.19}/src/reader/utils.py +0 -0
- {reader-3.18 → reader-3.19}/src/reader.egg-info/dependency_links.txt +0 -0
- {reader-3.18 → reader-3.19}/src/reader.egg-info/top_level.txt +0 -0
- {reader-3.18 → reader-3.19}/tests/data/10.json +0 -0
- {reader-3.18 → reader-3.19}/tests/data/10.json.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/custom +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.atom +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.atom.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.json +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.json.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.rss +0 -0
- {reader-3.18 → reader-3.19}/tests/data/empty.rss.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.atom +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.atom.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.json +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.json.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.rss +0 -0
- {reader-3.18 → reader-3.19}/tests/data/full.rss.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/invalid.json +0 -0
- {reader-3.18 → reader-3.19}/tests/data/invalid.json.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/relative.atom +0 -0
- {reader-3.18 → reader-3.19}/tests/data/relative.atom.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/relative.rss +0 -0
- {reader-3.18 → reader-3.19}/tests/data/relative.rss.py +0 -0
- {reader-3.18 → reader-3.19}/tests/data/sqlite_releases.html +0 -0
- {reader-3.18 → reader-3.19}/tests/data/unknown.json +0 -0
- {reader-3.18 → reader-3.19}/tests/data/unknown.json.py +0 -0
- {reader-3.18 → reader-3.19}/tests/fakeparser.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_methods.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_test_plugins/__init__.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_test_plugins/good.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_test_plugins/init_error.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_test_plugins/missing_dependency.py +0 -0
- {reader-3.18 → reader-3.19}/tests/reader_test_plugins/missing_entry_point.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test__types.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test__utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_app.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_app_wsgi.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_bench.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_changes.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_cli.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_config.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_exceptions.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_hash_utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_html_utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_lazy_imports.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_enclosure_dedupe.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_entry_dedupe.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_mark_as_read.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_preview_feed_list.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_readtime.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_sqlite_releases.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_plugins_ua_fallback.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_context.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_counts.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_deprecations.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_filter.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_hooks.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_integration.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_plugins.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_private.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_search.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_sort.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_update.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_reader_utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_search.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_sql_utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_sqlite_utils.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_storage.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_tags.py +0 -0
- {reader-3.18 → reader-3.19}/tests/test_types.py +0 -0
|
@@ -6,6 +6,28 @@ 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
|
+
|
|
9
31
|
Version 3.18
|
|
10
32
|
------------
|
|
11
33
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reader
|
|
3
|
-
Version: 3.
|
|
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:
|
|
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
|
|
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
27
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
28
|
Classifier: Topic :: Internet
|
|
@@ -40,14 +41,14 @@ Requires-Dist: requests>=2.18
|
|
|
40
41
|
Requires-Dist: werkzeug>2
|
|
41
42
|
Requires-Dist: iso8601>=1
|
|
42
43
|
Requires-Dist: beautifulsoup4>=4.5
|
|
43
|
-
Provides-Extra:
|
|
44
|
-
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: reader[app,cli,unstable-plugins]; extra == "all"
|
|
45
46
|
Provides-Extra: cli
|
|
46
47
|
Requires-Dist: click>=7; extra == "cli"
|
|
47
48
|
Requires-Dist: PyYAML; extra == "cli"
|
|
48
49
|
Provides-Extra: app
|
|
49
50
|
Requires-Dist: flask>=0.10; extra == "app"
|
|
50
|
-
Requires-Dist: humanize
|
|
51
|
+
Requires-Dist: humanize>=4; extra == "app"
|
|
51
52
|
Requires-Dist: PyYAML; extra == "app"
|
|
52
53
|
Requires-Dist: WTForms; extra == "app"
|
|
53
54
|
Requires-Dist: jinja2-fragments; extra == "app"
|
|
@@ -59,36 +60,6 @@ Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
|
|
|
59
60
|
Requires-Dist: blinker>=1.4; extra == "unstable-plugins"
|
|
60
61
|
Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
|
|
61
62
|
Requires-Dist: tabulate; extra == "unstable-plugins"
|
|
62
|
-
Provides-Extra: tests
|
|
63
|
-
Requires-Dist: pytest>=4; extra == "tests"
|
|
64
|
-
Requires-Dist: pytest-randomly; extra == "tests"
|
|
65
|
-
Requires-Dist: pytest-subtests; extra == "tests"
|
|
66
|
-
Requires-Dist: pytest-rerunfailures; extra == "tests"
|
|
67
|
-
Requires-Dist: coverage; extra == "tests"
|
|
68
|
-
Requires-Dist: pytest-cov; extra == "tests"
|
|
69
|
-
Requires-Dist: requests-mock; extra == "tests"
|
|
70
|
-
Requires-Dist: mechanicalsoup; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
|
|
71
|
-
Requires-Dist: requests-wsgi-adapter; extra == "tests"
|
|
72
|
-
Requires-Dist: lxml; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
|
|
73
|
-
Requires-Dist: html5lib; extra == "tests"
|
|
74
|
-
Requires-Dist: numpy; (implementation_name != "pypy" and os_name == "posix" and python_version <= "3.12") and extra == "tests"
|
|
75
|
-
Requires-Dist: mypy; implementation_name != "pypy" and extra == "tests"
|
|
76
|
-
Requires-Dist: types-requests; extra == "tests"
|
|
77
|
-
Requires-Dist: types-beautifulsoup4; extra == "tests"
|
|
78
|
-
Provides-Extra: docs
|
|
79
|
-
Requires-Dist: sphinx; extra == "docs"
|
|
80
|
-
Requires-Dist: sphinx-rtd-theme>=1.3.0rc1; extra == "docs"
|
|
81
|
-
Requires-Dist: click>=7; extra == "docs"
|
|
82
|
-
Requires-Dist: sphinx-click; extra == "docs"
|
|
83
|
-
Requires-Dist: sphinx-hoverxref; extra == "docs"
|
|
84
|
-
Requires-Dist: sphinxcontrib-log-cabinet; extra == "docs"
|
|
85
|
-
Requires-Dist: setuptools; extra == "docs"
|
|
86
|
-
Provides-Extra: dev
|
|
87
|
-
Requires-Dist: reader[app,cli,docs,tests,unstable-plugins]; extra == "dev"
|
|
88
|
-
Requires-Dist: tox; extra == "dev"
|
|
89
|
-
Requires-Dist: pre-commit; extra == "dev"
|
|
90
|
-
Requires-Dist: build; extra == "dev"
|
|
91
|
-
Requires-Dist: twine; extra == "dev"
|
|
92
63
|
Dynamic: license-file
|
|
93
64
|
|
|
94
65
|
.. begin-intro
|
|
@@ -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:`
|
|
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 /
|
|
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)
|
|
245
|
-
*
|
|
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"}]
|
|
@@ -26,6 +22,7 @@ classifiers = [
|
|
|
26
22
|
"Programming Language :: Python :: 3.11",
|
|
27
23
|
"Programming Language :: Python :: 3.12",
|
|
28
24
|
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
29
26
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
30
27
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
31
28
|
"Topic :: Internet",
|
|
@@ -52,19 +49,16 @@ dynamic = ["version"]
|
|
|
52
49
|
|
|
53
50
|
[project.urls]
|
|
54
51
|
Documentation = "https://reader.readthedocs.io/"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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"
|
|
58
55
|
|
|
59
56
|
[project.optional-dependencies]
|
|
60
57
|
|
|
61
|
-
# STABLE
|
|
62
|
-
|
|
63
|
-
search = [] # empty since 2.4, kept to avoid breaking dependents
|
|
64
|
-
readtime = [] # empty since 3.1, kept to avoid breaking dependents
|
|
65
|
-
|
|
66
58
|
# UNSTABLE
|
|
67
59
|
|
|
60
|
+
all = ["reader[cli,app,unstable-plugins]"]
|
|
61
|
+
|
|
68
62
|
cli = [
|
|
69
63
|
"click>=7",
|
|
70
64
|
# for config
|
|
@@ -72,8 +66,7 @@ cli = [
|
|
|
72
66
|
]
|
|
73
67
|
app = [
|
|
74
68
|
"flask>=0.10",
|
|
75
|
-
|
|
76
|
-
"humanize>=4,!=4.7.*",
|
|
69
|
+
"humanize>=4",
|
|
77
70
|
# for config
|
|
78
71
|
"PyYAML",
|
|
79
72
|
# for v2
|
|
@@ -81,8 +74,6 @@ app = [
|
|
|
81
74
|
"jinja2-fragments",
|
|
82
75
|
]
|
|
83
76
|
|
|
84
|
-
# UNSTABLE PLUGINS
|
|
85
|
-
|
|
86
77
|
# mushed together for convenience
|
|
87
78
|
unstable-plugins = [
|
|
88
79
|
# enclosure-tags
|
|
@@ -98,16 +89,14 @@ unstable-plugins = [
|
|
|
98
89
|
"tabulate",
|
|
99
90
|
]
|
|
100
91
|
|
|
101
|
-
|
|
92
|
+
[dependency-groups]
|
|
102
93
|
|
|
103
|
-
# run tests under one interpreter
|
|
104
94
|
tests = [
|
|
105
95
|
"pytest>=4",
|
|
106
96
|
"pytest-randomly",
|
|
107
97
|
"pytest-subtests",
|
|
108
98
|
"pytest-rerunfailures",
|
|
109
99
|
"coverage",
|
|
110
|
-
"pytest-cov",
|
|
111
100
|
"requests-mock",
|
|
112
101
|
# mechanicalsoup hard-depends on lxml (see below)
|
|
113
102
|
'mechanicalsoup; (implementation_name != "pypy" and python_version <= "3.12")',
|
|
@@ -119,35 +108,38 @@ tests = [
|
|
|
119
108
|
"html5lib",
|
|
120
109
|
# for bench.py
|
|
121
110
|
'numpy; (implementation_name != "pypy" and os_name == "posix" and python_version <= "3.12")',
|
|
122
|
-
|
|
123
|
-
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
typing = [
|
|
114
|
+
'mypy',
|
|
124
115
|
"types-requests",
|
|
125
116
|
"types-beautifulsoup4",
|
|
126
117
|
]
|
|
127
118
|
|
|
128
|
-
# build docs
|
|
129
119
|
docs = [
|
|
130
120
|
"sphinx",
|
|
131
|
-
|
|
132
|
-
# https://github.com/readthedocs/sphinx_rtd_theme/pull/1464#issuecomment-1664799982
|
|
133
|
-
"sphinx-rtd-theme>=1.3.0rc1",
|
|
121
|
+
"sphinx-rtd-theme",
|
|
134
122
|
"click>=7",
|
|
135
123
|
"sphinx-click",
|
|
136
|
-
"sphinx-hoverxref",
|
|
137
124
|
"sphinxcontrib-log-cabinet",
|
|
138
125
|
# for read_configuration used in conf.py
|
|
139
126
|
"setuptools",
|
|
140
127
|
]
|
|
141
128
|
|
|
142
|
-
# things needed to develop / test locally / make releases
|
|
143
129
|
dev = [
|
|
144
|
-
"
|
|
130
|
+
{include-group = "tests"},
|
|
131
|
+
{include-group = "typing"},
|
|
132
|
+
{include-group = "docs"},
|
|
145
133
|
"tox",
|
|
146
134
|
"pre-commit",
|
|
147
135
|
"build",
|
|
148
136
|
"twine",
|
|
149
137
|
]
|
|
150
138
|
|
|
139
|
+
[build-system]
|
|
140
|
+
requires = ["setuptools", "wheel"]
|
|
141
|
+
build-backend = "setuptools.build_meta"
|
|
142
|
+
|
|
151
143
|
[tool.setuptools.dynamic]
|
|
152
144
|
version = {attr = "reader.__version__"}
|
|
153
145
|
|
|
@@ -170,9 +162,16 @@ source = ["reader", "tests"]
|
|
|
170
162
|
omit = [
|
|
171
163
|
"src/reader/_vendor/*",
|
|
172
164
|
]
|
|
165
|
+
# TODO: remove when https://github.com/nedbat/coveragepy/issues/1987 is solved
|
|
166
|
+
core = "ctrace"
|
|
173
167
|
[tool.coverage.paths]
|
|
174
168
|
source = ["src", "*/site-packages"]
|
|
175
169
|
|
|
170
|
+
[tool.mypy]
|
|
171
|
+
files = ["src"]
|
|
172
|
+
show_error_codes = true
|
|
173
|
+
pretty = true
|
|
174
|
+
strict = true
|
|
176
175
|
[[tool.mypy.overrides]]
|
|
177
176
|
module = [
|
|
178
177
|
"reader.__main__",
|
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(
|
|
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()
|
|
@@ -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():
|
|
@@ -23,6 +23,7 @@ from dataclasses import dataclass
|
|
|
23
23
|
from datetime import datetime
|
|
24
24
|
from datetime import timezone
|
|
25
25
|
from typing import Any
|
|
26
|
+
from typing import cast
|
|
26
27
|
from typing import no_type_check
|
|
27
28
|
from typing import TypeVar
|
|
28
29
|
|
|
@@ -471,8 +472,9 @@ class LocalConnectionFactory:
|
|
|
471
472
|
if not self._local.is_creating_thread:
|
|
472
473
|
self._other_threads = True
|
|
473
474
|
|
|
474
|
-
|
|
475
|
-
|
|
475
|
+
# TODO: remove needless cast (needed after mypy 1.16.0 update)
|
|
476
|
+
db = cast(sqlite3.Connection, sqlite3.connect(self.path, **self.kwargs))
|
|
477
|
+
self._local.db = db
|
|
476
478
|
self._local.call_count = 0
|
|
477
479
|
|
|
478
480
|
try:
|
|
@@ -757,7 +757,7 @@ class EntrySort(enum.StrEnum):
|
|
|
757
757
|
#:
|
|
758
758
|
#: .. note::
|
|
759
759
|
#:
|
|
760
|
-
#:
|
|
760
|
+
#: The algorithm for "recent" is a heuristic and may change over time.
|
|
761
761
|
#:
|
|
762
762
|
#: .. versionchanged:: 3.1
|
|
763
763
|
#: Sort entries by added date most of the time,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reader
|
|
3
|
-
Version: 3.
|
|
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:
|
|
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
|
|
@@ -22,6 +22,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
27
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
28
|
Classifier: Topic :: Internet
|
|
@@ -40,14 +41,14 @@ Requires-Dist: requests>=2.18
|
|
|
40
41
|
Requires-Dist: werkzeug>2
|
|
41
42
|
Requires-Dist: iso8601>=1
|
|
42
43
|
Requires-Dist: beautifulsoup4>=4.5
|
|
43
|
-
Provides-Extra:
|
|
44
|
-
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: reader[app,cli,unstable-plugins]; extra == "all"
|
|
45
46
|
Provides-Extra: cli
|
|
46
47
|
Requires-Dist: click>=7; extra == "cli"
|
|
47
48
|
Requires-Dist: PyYAML; extra == "cli"
|
|
48
49
|
Provides-Extra: app
|
|
49
50
|
Requires-Dist: flask>=0.10; extra == "app"
|
|
50
|
-
Requires-Dist: humanize
|
|
51
|
+
Requires-Dist: humanize>=4; extra == "app"
|
|
51
52
|
Requires-Dist: PyYAML; extra == "app"
|
|
52
53
|
Requires-Dist: WTForms; extra == "app"
|
|
53
54
|
Requires-Dist: jinja2-fragments; extra == "app"
|
|
@@ -59,36 +60,6 @@ Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
|
|
|
59
60
|
Requires-Dist: blinker>=1.4; extra == "unstable-plugins"
|
|
60
61
|
Requires-Dist: beautifulsoup4; extra == "unstable-plugins"
|
|
61
62
|
Requires-Dist: tabulate; extra == "unstable-plugins"
|
|
62
|
-
Provides-Extra: tests
|
|
63
|
-
Requires-Dist: pytest>=4; extra == "tests"
|
|
64
|
-
Requires-Dist: pytest-randomly; extra == "tests"
|
|
65
|
-
Requires-Dist: pytest-subtests; extra == "tests"
|
|
66
|
-
Requires-Dist: pytest-rerunfailures; extra == "tests"
|
|
67
|
-
Requires-Dist: coverage; extra == "tests"
|
|
68
|
-
Requires-Dist: pytest-cov; extra == "tests"
|
|
69
|
-
Requires-Dist: requests-mock; extra == "tests"
|
|
70
|
-
Requires-Dist: mechanicalsoup; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
|
|
71
|
-
Requires-Dist: requests-wsgi-adapter; extra == "tests"
|
|
72
|
-
Requires-Dist: lxml; (implementation_name != "pypy" and python_version <= "3.12") and extra == "tests"
|
|
73
|
-
Requires-Dist: html5lib; extra == "tests"
|
|
74
|
-
Requires-Dist: numpy; (implementation_name != "pypy" and os_name == "posix" and python_version <= "3.12") and extra == "tests"
|
|
75
|
-
Requires-Dist: mypy; implementation_name != "pypy" and extra == "tests"
|
|
76
|
-
Requires-Dist: types-requests; extra == "tests"
|
|
77
|
-
Requires-Dist: types-beautifulsoup4; extra == "tests"
|
|
78
|
-
Provides-Extra: docs
|
|
79
|
-
Requires-Dist: sphinx; extra == "docs"
|
|
80
|
-
Requires-Dist: sphinx-rtd-theme>=1.3.0rc1; extra == "docs"
|
|
81
|
-
Requires-Dist: click>=7; extra == "docs"
|
|
82
|
-
Requires-Dist: sphinx-click; extra == "docs"
|
|
83
|
-
Requires-Dist: sphinx-hoverxref; extra == "docs"
|
|
84
|
-
Requires-Dist: sphinxcontrib-log-cabinet; extra == "docs"
|
|
85
|
-
Requires-Dist: setuptools; extra == "docs"
|
|
86
|
-
Provides-Extra: dev
|
|
87
|
-
Requires-Dist: reader[app,cli,docs,tests,unstable-plugins]; extra == "dev"
|
|
88
|
-
Requires-Dist: tox; extra == "dev"
|
|
89
|
-
Requires-Dist: pre-commit; extra == "dev"
|
|
90
|
-
Requires-Dist: build; extra == "dev"
|
|
91
|
-
Requires-Dist: twine; extra == "dev"
|
|
92
63
|
Dynamic: license-file
|
|
93
64
|
|
|
94
65
|
.. begin-intro
|