webchanges 3.31.4__tar.gz → 3.34.0__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.
- {webchanges-3.31.4/webchanges.egg-info → webchanges-3.34.0}/PKG-INFO +12 -71
- {webchanges-3.31.4 → webchanges-3.34.0}/README.rst +7 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/pyproject.toml +94 -126
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/__init__.py +2 -2
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/_vendored/headers.py +5 -5
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/cli.py +10 -7
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/command.py +81 -53
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/config.py +1 -2
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/differs.py +355 -185
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/filters.py +45 -34
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/handler.py +97 -103
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/jobs.py +410 -279
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/main.py +7 -1
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/reporters.py +118 -63
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/storage.py +124 -55
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/util.py +18 -8
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/worker.py +21 -12
- {webchanges-3.31.4 → webchanges-3.34.0/webchanges.egg-info}/PKG-INFO +12 -71
- {webchanges-3.31.4 → webchanges-3.34.0}/LICENSE.md +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/MANIFEST.in +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/requirements.txt +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/setup.cfg +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/__main__.py +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/_vendored/__init__.py +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/_vendored/packaging_version.py +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/mailer.py +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/py.typed +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges/storage_minidb.py +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges.egg-info/SOURCES.txt +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges.egg-info/dependency_links.txt +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges.egg-info/entry_points.txt +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges.egg-info/requires.txt +0 -0
- {webchanges-3.31.4 → webchanges-3.34.0}/webchanges.egg-info/top_level.txt +0 -0
|
@@ -1,75 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: webchanges
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.34.0
|
|
4
4
|
Summary: Web Changes Delivered. AI-Summarized. Totally Anonymous.
|
|
5
5
|
Author-email: Mike Borsetti <mike+webchanges@borsetti.com>
|
|
6
6
|
Maintainer-email: Mike Borsetti <mike+webchanges@borsetti.com>
|
|
7
|
-
License:
|
|
8
|
-
Licenses
|
|
9
|
-
========
|
|
10
|
-
|
|
11
|
-
The MIT License (MIT)
|
|
12
|
-
|
|
13
|
-
Copyright (c) 2020- Mike Borsetti <mike@borsetti.com>
|
|
14
|
-
|
|
15
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
16
|
-
this software and associated documentation files (the "Software"), to deal in
|
|
17
|
-
the Software without restriction, including without limitation the rights to
|
|
18
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
19
|
-
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
20
|
-
subject to the following conditions:
|
|
21
|
-
|
|
22
|
-
The above copyright notice and this permission notice shall be included in all
|
|
23
|
-
copies or substantial portions of the Software.
|
|
24
|
-
|
|
25
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
27
|
-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
28
|
-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
29
|
-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
30
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
31
|
-
|
|
32
|
-
--------------------------------------------------------------------------------
|
|
33
|
-
|
|
34
|
-
SOURCE CODE REDISTRIBUTION NOTICE
|
|
35
|
-
(urlwatch by Thomas Perl)
|
|
36
|
-
|
|
37
|
-
This software redistributes source code of release 2.21, dated 30 July 2020, of
|
|
38
|
-
urlwatch
|
|
39
|
-
https://github.com/thp/urlwatch/tree/346b25914b0418342ffe2fb0529bed702fddc01f,
|
|
40
|
-
which is subject to the following copyright notice and license (from
|
|
41
|
-
https://raw.githubusercontent.com/thp/urlwatch/346b25914b0418342ffe2fb0529bed702fddc01f/COPYING),
|
|
42
|
-
hereby retained and redistributed with the source code (of which this license
|
|
43
|
-
file is part of), in binary form, and in the documentation. The appearance of
|
|
44
|
-
the name of the author below does not constitute an endorsement or promotion of
|
|
45
|
-
this software by such author.
|
|
46
|
-
|
|
47
|
-
Copyright (c) 2008-2020 Thomas Perl <m@thp.io>
|
|
48
|
-
All rights reserved.
|
|
49
|
-
|
|
50
|
-
Redistribution and use in source and binary forms, with or without
|
|
51
|
-
modification, are permitted provided that the following conditions
|
|
52
|
-
are met:
|
|
53
|
-
|
|
54
|
-
1. Redistributions of source code must retain the above copyright
|
|
55
|
-
notice, this list of conditions and the following disclaimer.
|
|
56
|
-
2. Redistributions in binary form must reproduce the above copyright
|
|
57
|
-
notice, this list of conditions and the following disclaimer in the
|
|
58
|
-
documentation and/or other materials provided with the distribution.
|
|
59
|
-
3. The name of the author may not be used to endorse or promote products
|
|
60
|
-
derived from this software without specific prior written permission.
|
|
61
|
-
|
|
62
|
-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
|
|
63
|
-
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
64
|
-
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
65
|
-
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
66
|
-
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
67
|
-
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
68
|
-
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
69
|
-
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
70
|
-
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
71
|
-
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
72
|
-
|
|
7
|
+
License-Expression: MIT AND BSD-3-Clause
|
|
73
8
|
Project-URL: Documentation, https://webchanges.readthedocs.io/
|
|
74
9
|
Project-URL: Repository, https://github.com/mborsetti/webchanges/
|
|
75
10
|
Project-URL: Changelog, https://webchanges.readthedocs.io/en/stable/changelog.html
|
|
@@ -81,18 +16,17 @@ Classifier: Environment :: Console
|
|
|
81
16
|
Classifier: Intended Audience :: Developers
|
|
82
17
|
Classifier: Intended Audience :: End Users/Desktop
|
|
83
18
|
Classifier: Intended Audience :: System Administrators
|
|
84
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
85
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
86
19
|
Classifier: Natural Language :: English
|
|
87
20
|
Classifier: Operating System :: OS Independent
|
|
88
21
|
Classifier: Programming Language :: Python
|
|
89
22
|
Classifier: Programming Language :: Python :: 3
|
|
90
23
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
91
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
92
24
|
Classifier: Programming Language :: Python :: 3.11
|
|
93
25
|
Classifier: Programming Language :: Python :: 3.12
|
|
94
26
|
Classifier: Programming Language :: Python :: 3.13
|
|
95
27
|
Classifier: Programming Language :: Python :: 3.14
|
|
28
|
+
Classifier: Programming Language :: Python :: Free Threading
|
|
29
|
+
Classifier: Programming Language :: Python :: Free Threading :: 4 - Resilient
|
|
96
30
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
97
31
|
Classifier: Topic :: Internet
|
|
98
32
|
Classifier: Topic :: Internet :: WWW/HTTP
|
|
@@ -100,7 +34,7 @@ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
|
|
|
100
34
|
Classifier: Topic :: System :: Monitoring
|
|
101
35
|
Classifier: Topic :: Utilities
|
|
102
36
|
Classifier: Typing :: Typed
|
|
103
|
-
Requires-Python: >=3.
|
|
37
|
+
Requires-Python: >=3.11
|
|
104
38
|
Description-Content-Type: text/x-rst
|
|
105
39
|
License-File: LICENSE.md
|
|
106
40
|
Requires-Dist: colorama; sys_platform == "win32"
|
|
@@ -189,6 +123,8 @@ For the best experience, use the current version of `Python <https://www.python.
|
|
|
189
123
|
older Python versions for 3 years after they're replaced by a newer one; we just ask that you use the most up-to-date
|
|
190
124
|
bug and security fix release from that older version.
|
|
191
125
|
|
|
126
|
+
While **webchanges** supports free-threated Python, certain optional dependencies may not.
|
|
127
|
+
|
|
192
128
|
For Generative AI summaries (BETA), you need a free `API Key from Google Cloud AI Studio
|
|
193
129
|
<https://aistudio.google.com/app/apikey>`__ (see `here
|
|
194
130
|
<https://webchanges.readthedocs.io/en/stable/differs.html#ai-google>`__).
|
|
@@ -216,6 +152,11 @@ Running in Docker
|
|
|
216
152
|
implementation (no browser) `here <https://github.com/yubiuser/webchanges-docker>`__, and one with a browser
|
|
217
153
|
`here <https://github.com/jhedlund/webchanges-docker>`__.
|
|
218
154
|
|
|
155
|
+
As a GitHub Action
|
|
156
|
+
------------------
|
|
157
|
+
**webchanges** can easily run as a `GitHub Action <https://www.docker.com/>`__! You will find an implementation
|
|
158
|
+
`here <https://github.com/swimmwatch/webchanges-action>`__.
|
|
159
|
+
|
|
219
160
|
|
|
220
161
|
Documentation |readthedocs|
|
|
221
162
|
===========================
|
|
@@ -22,6 +22,8 @@ For the best experience, use the current version of `Python <https://www.python.
|
|
|
22
22
|
older Python versions for 3 years after they're replaced by a newer one; we just ask that you use the most up-to-date
|
|
23
23
|
bug and security fix release from that older version.
|
|
24
24
|
|
|
25
|
+
While **webchanges** supports free-threated Python, certain optional dependencies may not.
|
|
26
|
+
|
|
25
27
|
For Generative AI summaries (BETA), you need a free `API Key from Google Cloud AI Studio
|
|
26
28
|
<https://aistudio.google.com/app/apikey>`__ (see `here
|
|
27
29
|
<https://webchanges.readthedocs.io/en/stable/differs.html#ai-google>`__).
|
|
@@ -49,6 +51,11 @@ Running in Docker
|
|
|
49
51
|
implementation (no browser) `here <https://github.com/yubiuser/webchanges-docker>`__, and one with a browser
|
|
50
52
|
`here <https://github.com/jhedlund/webchanges-docker>`__.
|
|
51
53
|
|
|
54
|
+
As a GitHub Action
|
|
55
|
+
------------------
|
|
56
|
+
**webchanges** can easily run as a `GitHub Action <https://www.docker.com/>`__! You will find an implementation
|
|
57
|
+
`here <https://github.com/swimmwatch/webchanges-action>`__.
|
|
58
|
+
|
|
52
59
|
|
|
53
60
|
Documentation |readthedocs|
|
|
54
61
|
===========================
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
[build-system]
|
|
8
8
|
# Minimum requirements for the build system to execute.
|
|
9
|
-
requires = ['setuptools'] # PEP 508 specifications.
|
|
9
|
+
requires = ['argparse-manpage[setuptools]'] # PEP 508 specifications.
|
|
10
10
|
# Setuptools specification
|
|
11
|
-
build-backend =
|
|
11
|
+
build-backend = 'setuptools.build_meta'
|
|
12
12
|
|
|
13
13
|
[project]
|
|
14
14
|
# See https://packaging.python.org/en/latest/specifications/declaring-project-metadata/
|
|
@@ -16,8 +16,9 @@ dynamic = ['version', 'dependencies']
|
|
|
16
16
|
name = 'webchanges'
|
|
17
17
|
description = 'Web Changes Delivered. AI-Summarized. Totally Anonymous.'
|
|
18
18
|
readme = { file = 'README.rst', content-type = 'text/x-rst' }
|
|
19
|
-
requires-python = '>=3.
|
|
20
|
-
license =
|
|
19
|
+
requires-python = '>=3.11'
|
|
20
|
+
license = "MIT AND BSD-3-Clause"
|
|
21
|
+
license-files = ['LICENSE.md']
|
|
21
22
|
authors = [{ name = 'Mike Borsetti', email = 'mike+webchanges@borsetti.com' }]
|
|
22
23
|
maintainers = [
|
|
23
24
|
{ name = 'Mike Borsetti', email = 'mike+webchanges@borsetti.com' },
|
|
@@ -29,18 +30,17 @@ classifiers = [
|
|
|
29
30
|
'Intended Audience :: Developers',
|
|
30
31
|
'Intended Audience :: End Users/Desktop',
|
|
31
32
|
'Intended Audience :: System Administrators',
|
|
32
|
-
'License :: OSI Approved :: BSD License',
|
|
33
|
-
'License :: OSI Approved :: MIT License',
|
|
34
33
|
'Natural Language :: English',
|
|
35
34
|
'Operating System :: OS Independent',
|
|
36
35
|
'Programming Language :: Python',
|
|
37
36
|
'Programming Language :: Python :: 3',
|
|
38
37
|
'Programming Language :: Python :: 3 :: Only',
|
|
39
|
-
'Programming Language :: Python :: 3.10',
|
|
40
38
|
'Programming Language :: Python :: 3.11',
|
|
41
39
|
'Programming Language :: Python :: 3.12',
|
|
42
40
|
'Programming Language :: Python :: 3.13',
|
|
43
41
|
'Programming Language :: Python :: 3.14',
|
|
42
|
+
'Programming Language :: Python :: Free Threading',
|
|
43
|
+
'Programming Language :: Python :: Free Threading :: 4 - Resilient',
|
|
44
44
|
'Programming Language :: Python :: Implementation :: CPython',
|
|
45
45
|
'Topic :: Internet',
|
|
46
46
|
'Topic :: Internet :: WWW/HTTP',
|
|
@@ -88,6 +88,7 @@ xmpp = ['aioxmpp']
|
|
|
88
88
|
redis = ['redis']
|
|
89
89
|
requests = ['requests']
|
|
90
90
|
safe_password = ['keyring']
|
|
91
|
+
# all
|
|
91
92
|
all = [
|
|
92
93
|
'webchanges[use_browser,beautify,bs4,html5lib,ical2text,jq,ocr,pdf2text,pypdf_crypto,deepdiff_xml,imagediff,matrix,pushbullet,pushover,xmpp,redis,requests,safe_password]',
|
|
93
94
|
]
|
|
@@ -109,6 +110,10 @@ dependencies = { file = 'requirements.txt' }
|
|
|
109
110
|
[tool.setuptools.package-data]
|
|
110
111
|
'webchanges' = ['py.typed']
|
|
111
112
|
|
|
113
|
+
# -------------------------- manpages --------------------------
|
|
114
|
+
# https://github.com/praiskup/argparse-manpage/blob/main/README.md
|
|
115
|
+
[tool.build_manpages]
|
|
116
|
+
manpages = ['man/webchanges.1:function=get_parser:pyfile=get_parser']
|
|
112
117
|
|
|
113
118
|
# -------------------------- coverage --------------------------
|
|
114
119
|
[tool.coverage.run]
|
|
@@ -170,60 +175,6 @@ exclude_lines = [
|
|
|
170
175
|
# ignore_errors = true
|
|
171
176
|
|
|
172
177
|
|
|
173
|
-
# -------------------------- mypy --------------------------
|
|
174
|
-
[tool.mypy]
|
|
175
|
-
# Static Typing for Python
|
|
176
|
-
# Runs as part of pre-commit
|
|
177
|
-
# Config file documentation at https://mypy.readthedocs.io/en/stable/config_file.html
|
|
178
|
-
|
|
179
|
-
# Disables import discovery of namespace packages (see PEP 420)
|
|
180
|
-
namespace_packages = true
|
|
181
|
-
|
|
182
|
-
# Specifies the Python version used to parse and check the target program.
|
|
183
|
-
# python_version = 3.12
|
|
184
|
-
|
|
185
|
-
# Suppresses error messages about imports that cannot be resolved.
|
|
186
|
-
ignore_missing_imports = true
|
|
187
|
-
|
|
188
|
-
# Disallows calling functions without type annotations from functions with type annotations.
|
|
189
|
-
disallow_untyped_calls = false
|
|
190
|
-
|
|
191
|
-
# Disallows defining functions without type annotations or with incomplete type annotations.
|
|
192
|
-
disallow_untyped_defs = true
|
|
193
|
-
|
|
194
|
-
# Reports an error whenever a function with type annotations is decorated with a decorator without annotations.
|
|
195
|
-
disallow_untyped_decorators = true
|
|
196
|
-
|
|
197
|
-
# Warns about casting an expression to its inferred type.
|
|
198
|
-
warn_redundant_casts = true
|
|
199
|
-
|
|
200
|
-
# Warns about unneeded # type: ignore comments.
|
|
201
|
-
# May behave differently in GitHub Actions than it does on Windows.
|
|
202
|
-
# warn_unused_ignores = true
|
|
203
|
-
|
|
204
|
-
# Shows a warning when returning a value with type Any from a function declared with a non-Any return type.
|
|
205
|
-
warn_return_any = true
|
|
206
|
-
|
|
207
|
-
# Shows a warning when encountering any code inferred to be unreachable or redundant after performing type analysis.
|
|
208
|
-
warn_unreachable = false
|
|
209
|
-
|
|
210
|
-
# Enables additional checks that are technically correct but may be impractical in real code.
|
|
211
|
-
extra_checks = true
|
|
212
|
-
|
|
213
|
-
# Shows documentation link to corresponding error code.
|
|
214
|
-
show_error_code_links = true
|
|
215
|
-
|
|
216
|
-
# Use visually nicer output in error messages: use soft word wrap, show source code snippets, and show error location
|
|
217
|
-
# markers.
|
|
218
|
-
pretty = true
|
|
219
|
-
|
|
220
|
-
# Use an SQLite database to store the cache.
|
|
221
|
-
sqlite_cache = true
|
|
222
|
-
|
|
223
|
-
# Warns about per-module sections in the config file that do not match any files processed when invoking mypy.
|
|
224
|
-
warn_unused_configs = true
|
|
225
|
-
|
|
226
|
-
|
|
227
178
|
# -------------------------- rstcheck --------------------------
|
|
228
179
|
[tool.rstcheck]
|
|
229
180
|
# Checks syntax of reStructuredText and code blocks nested within it.
|
|
@@ -240,12 +191,15 @@ report_level = 'WARNING'
|
|
|
240
191
|
# Testing framework
|
|
241
192
|
# Config file documentation at https://docs.pytest.org/en/stable/reference/reference.html#ini-options-ref
|
|
242
193
|
|
|
243
|
-
log_auto_indent =
|
|
194
|
+
# log_auto_indent = 2
|
|
244
195
|
# Enable log display during test run (aka "live logging" https://docs.pytest.org/en/stable/logging.html#live-logs)
|
|
245
|
-
log_cli = true
|
|
246
|
-
minversion = '
|
|
196
|
+
# log_cli = true
|
|
197
|
+
minversion = '9.0.2'
|
|
247
198
|
testpaths = ['tests']
|
|
248
199
|
|
|
200
|
+
# pytest-playwright
|
|
201
|
+
# addopts = ['--browser', 'chromium', '--browser-channel', 'chrome']
|
|
202
|
+
|
|
249
203
|
# Adds pytest-cov functionality (see https://pytest-cov.readthedocs.io/en/latest/config.html)
|
|
250
204
|
# Note: --cov moved to .github/workflows/ci-cd.yaml and tox.ini due to interference with PyCharm breakpoints (see
|
|
251
205
|
# https://github.com/pytest-dev/pytest-cov/issues/131) and to enable running tox --parallel
|
|
@@ -258,10 +212,7 @@ testpaths = ['tests']
|
|
|
258
212
|
# Config file documentation at https://docs.astral.sh/ruff/configuration/ and https://docs.astral.sh/ruff/settings/
|
|
259
213
|
|
|
260
214
|
# File patterns to omit from formatting and linting, in addition to those specified by exclude.
|
|
261
|
-
extend-exclude = [
|
|
262
|
-
"webchanges/storage_minidb.py",
|
|
263
|
-
"webchanges/_vendored",
|
|
264
|
-
]
|
|
215
|
+
extend-exclude = ['webchanges/storage_minidb.py', 'webchanges/_vendored']
|
|
265
216
|
|
|
266
217
|
# By default, Ruff will discover files matching *.py, *.pyi, *.ipynb, or pyproject.toml.
|
|
267
218
|
# Include additional files
|
|
@@ -271,83 +222,90 @@ extend-exclude = [
|
|
|
271
222
|
line-length = 120
|
|
272
223
|
|
|
273
224
|
# Target Python version
|
|
274
|
-
# target-version =
|
|
225
|
+
# target-version = 'py311' # Commented out to infer from [project] requires-python
|
|
275
226
|
|
|
276
227
|
[tool.ruff.lint]
|
|
277
228
|
# By default, Ruff enables Flake8's F rules, along with a subset of the E rules
|
|
278
229
|
# Enable rules not enabled by default, and ignore specific rules.
|
|
279
230
|
select = [
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
#
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
#
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
#
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
#
|
|
313
|
-
#
|
|
314
|
-
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
#
|
|
231
|
+
'ANN', # flake8-annotations
|
|
232
|
+
'S', # flake8-bandit
|
|
233
|
+
'BLE', # flake8-blind-except
|
|
234
|
+
'B', # flake8-bugbear
|
|
235
|
+
'A', # flake8-builtin
|
|
236
|
+
'C4', # flake8-comprehensions
|
|
237
|
+
'DTZ', # flake8-datetimez
|
|
238
|
+
# 'EM', # flake8-errmsg # TODO
|
|
239
|
+
'FA', # flake8-future-annotations
|
|
240
|
+
'INT', # flake8-gettext
|
|
241
|
+
'ISC', # flake8-implicit-str-concat
|
|
242
|
+
'LOG', # flake8-logging
|
|
243
|
+
# 'G', # flake8-logging-format # Prefer f-string to lazy `%` formatting and OK with '+'
|
|
244
|
+
'PIE', # flake8-pie
|
|
245
|
+
'PYI', # flake8-pyi
|
|
246
|
+
'PT', # flake8-pytest-style
|
|
247
|
+
'Q', # flake8-quotes
|
|
248
|
+
'RSE', # flake8-raise
|
|
249
|
+
'RET', # flake8-return
|
|
250
|
+
'SIM', # flake8-simplify
|
|
251
|
+
'TID', # flake8-tidy-imports
|
|
252
|
+
'TD', # flake8-todos
|
|
253
|
+
'TC', # flake8-type-checking
|
|
254
|
+
# 'ARG', # flake8-unused-arguments # Code loses clarity
|
|
255
|
+
'PTH', # flake8-use-pathlib
|
|
256
|
+
'FLY', # flynt
|
|
257
|
+
'I', # isort
|
|
258
|
+
'C90', # mccabe
|
|
259
|
+
'N', # pep8-naming
|
|
260
|
+
'PERF', # Perflint
|
|
261
|
+
'E', # pycodestyle errors
|
|
262
|
+
'W', # pycodestyle warnings
|
|
263
|
+
# 'DOC', # pydoclint # TODO
|
|
264
|
+
# 'D', # pydocstyle # TODO
|
|
265
|
+
'F', # Pyflakes
|
|
266
|
+
# 'PL', # Pylint # TODO
|
|
267
|
+
'FURB', # refurb
|
|
268
|
+
'RUF', # Ruff-specific rules
|
|
269
|
+
# 'TRY', # tryceratops # TODO
|
|
319
270
|
]
|
|
320
271
|
|
|
321
272
|
ignore = [
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
273
|
+
'FLY002', # Consider f-string instead of string join
|
|
274
|
+
# 'G003', # Logging statement uses `+`'
|
|
275
|
+
# 'G004', # Logging statement uses f-string (Prefer f-string to lazy `%` formatting)
|
|
276
|
+
'PLC0415', # `import` should be at the top-level of a file
|
|
277
|
+
'PT011', # pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception
|
|
278
|
+
'PT030', # pytest.warns({warning}) is too broad, set the match parameter or use a more specific warning
|
|
279
|
+
'RUF012', # Mutable class attributes should be annotated with `typing.ClassVar`
|
|
280
|
+
'SIM105', # Use contextlib.suppress({exception}) instead of try-except-pass
|
|
281
|
+
'SIM115', # Use a context manager for opening files
|
|
282
|
+
'TD002', # Missing author in TODO
|
|
283
|
+
'TD003', # Missing issue link for this TODO
|
|
329
284
|
]
|
|
330
285
|
|
|
331
286
|
# Allow fix for all enabled rules (when `--fix`) is provided.
|
|
332
|
-
fixable = [
|
|
287
|
+
fixable = ['ALL']
|
|
333
288
|
unfixable = []
|
|
334
289
|
|
|
335
290
|
# Allow unused variables when underscore-prefixed.
|
|
336
|
-
dummy-variable-rgx =
|
|
291
|
+
dummy-variable-rgx = '^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$'
|
|
292
|
+
|
|
293
|
+
# List of allowed 'confusable' Unicode characters to ignore when enforcing RUF001, RUF002, and RUF003.
|
|
294
|
+
allowed-confusables = ['–', '‘', '’']
|
|
337
295
|
|
|
338
296
|
[tool.ruff.lint.flake8-annotations]
|
|
339
|
-
allow-star-arg-any = true
|
|
297
|
+
allow-star-arg-any = true # TODO
|
|
340
298
|
|
|
341
299
|
[tool.ruff.lint.flake8-quotes]
|
|
342
|
-
inline-quotes =
|
|
300
|
+
inline-quotes = 'single'
|
|
343
301
|
|
|
344
302
|
[tool.ruff.lint.mccabe]
|
|
345
303
|
# Flag errors (`C901`) whenever the complexity level exceeds below.
|
|
346
304
|
max-complexity = 30
|
|
347
305
|
|
|
348
306
|
[tool.ruff.lint.per-file-ignores]
|
|
349
|
-
|
|
350
|
-
|
|
307
|
+
'tests/*' = [
|
|
308
|
+
'S101', # Use of `assert` detected
|
|
351
309
|
]
|
|
352
310
|
|
|
353
311
|
[tool.ruff.lint.pydoclint]
|
|
@@ -355,7 +313,7 @@ max-complexity = 30
|
|
|
355
313
|
ignore-one-line-docstrings = true
|
|
356
314
|
|
|
357
315
|
[tool.ruff.lint.pydocstyle]
|
|
358
|
-
convention =
|
|
316
|
+
convention = 'google'
|
|
359
317
|
|
|
360
318
|
[tool.ruff.format]
|
|
361
319
|
# Enable the formatter, which is a drop-in replacement for Black.
|
|
@@ -365,16 +323,16 @@ convention = "google"
|
|
|
365
323
|
exclude = []
|
|
366
324
|
|
|
367
325
|
# Use single quotes for strings.
|
|
368
|
-
quote-style =
|
|
326
|
+
quote-style = 'single'
|
|
369
327
|
|
|
370
328
|
# Like Black, indent with spaces, rather than tabs.
|
|
371
|
-
indent-style =
|
|
329
|
+
indent-style = 'space'
|
|
372
330
|
|
|
373
331
|
# Like Black, respect magic trailing commas.
|
|
374
332
|
skip-magic-trailing-comma = false
|
|
375
333
|
|
|
376
334
|
# Like Black, automatically detect the appropriate line ending.
|
|
377
|
-
line-ending =
|
|
335
|
+
line-ending = 'auto'
|
|
378
336
|
|
|
379
337
|
# Enable auto-formatting of code examples in docstrings. Markdown,
|
|
380
338
|
# reStructuredText code/literal blocks and doctests are all supported.
|
|
@@ -388,4 +346,14 @@ docstring-code-format = true
|
|
|
388
346
|
#
|
|
389
347
|
# This only has an effect when the `docstring-code-format` setting is
|
|
390
348
|
# enabled.
|
|
391
|
-
docstring-code-line-length =
|
|
349
|
+
docstring-code-line-length = 'dynamic'
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
# -------------------------- ty --------------------------
|
|
353
|
+
# Config file documentation at https://docs.astral.sh/ty/reference/configuration/
|
|
354
|
+
|
|
355
|
+
[tool.ty.environment]
|
|
356
|
+
extra-paths = ['./webchanges']
|
|
357
|
+
|
|
358
|
+
[tool.ty.src]
|
|
359
|
+
exclude = ['./webchanges/storage_minidb.py']
|
|
@@ -12,7 +12,7 @@ supported services. Can check the output of local commands as well.
|
|
|
12
12
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
|
-
__min_python_version__ = (3,
|
|
15
|
+
__min_python_version__ = (3, 11) # minimum version of Python required to run; 3.11 supported until fall 2026
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
__project_name__ = str(__package__)
|
|
@@ -22,7 +22,7 @@ __project_name__ = str(__package__)
|
|
|
22
22
|
# * MINOR version when you add functionality in a backwards compatible manner, and
|
|
23
23
|
# * MICRO or PATCH version when you make backwards compatible bug fixes. We no longer use '0'
|
|
24
24
|
# If unsure on increments, use pkg_resources.parse_version to parse
|
|
25
|
-
__version__ = '3.
|
|
25
|
+
__version__ = '3.34.0'
|
|
26
26
|
__description__ = (
|
|
27
27
|
'Check web (or command output) for changes since last run and notify.\n\nAnonymously alerts you of web changes.'
|
|
28
28
|
)
|
|
@@ -50,7 +50,7 @@ def to_str(value: str | bytes, encoding: str = 'utf-8') -> str:
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def to_bytes_or_str(value: str, match_type_of: typing.AnyStr) -> typing.AnyStr:
|
|
53
|
-
return value if isinstance(match_type_of, str) else value.encode()
|
|
53
|
+
return value if isinstance(match_type_of, str) else value.encode() # ty:ignore[invalid-return-type]
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
# from https://github.com/encode/httpx/blob/master/httpx/_models.py
|
|
@@ -81,8 +81,8 @@ def _obfuscate_sensitive_headers(
|
|
|
81
81
|
items: typing.Iterable[tuple[typing.AnyStr, typing.AnyStr]],
|
|
82
82
|
) -> typing.Iterator[tuple[typing.AnyStr, typing.AnyStr]]:
|
|
83
83
|
for k, v in items:
|
|
84
|
-
if to_str(k.lower()) in SENSITIVE_HEADERS:
|
|
85
|
-
v = to_bytes_or_str('[secure]', match_type_of=v)
|
|
84
|
+
if to_str(k.lower()) in SENSITIVE_HEADERS: # ty:ignore[no-matching-overload, invalid-argument-type]
|
|
85
|
+
v = to_bytes_or_str('[secure]', match_type_of=v) # ty:ignore[invalid-argument-type]
|
|
86
86
|
yield k, v
|
|
87
87
|
|
|
88
88
|
|
|
@@ -102,8 +102,8 @@ class Headers(typing.MutableMapping[str, str]):
|
|
|
102
102
|
self._list = list(headers._list)
|
|
103
103
|
elif isinstance(headers, Mapping):
|
|
104
104
|
for k, v in headers.items():
|
|
105
|
-
bytes_key = _normalize_header_key(k, encoding)
|
|
106
|
-
bytes_value = _normalize_header_value(v, encoding)
|
|
105
|
+
bytes_key = _normalize_header_key(k, encoding) # ty:ignore[invalid-argument-type]
|
|
106
|
+
bytes_value = _normalize_header_value(v, encoding) # ty:ignore[invalid-argument-type]
|
|
107
107
|
self._list.append((bytes_key, bytes_key.lower(), bytes_value))
|
|
108
108
|
elif headers is not None:
|
|
109
109
|
for k, v in headers:
|
|
@@ -24,9 +24,14 @@ from webchanges import __copyright__, __docs_url__, __min_python_version__, __pr
|
|
|
24
24
|
from webchanges.config import CommandConfig
|
|
25
25
|
from webchanges.util import file_ownership_checks, get_new_version_number, import_module_from_source
|
|
26
26
|
|
|
27
|
-
#
|
|
28
|
-
|
|
27
|
+
# Restore the default system behavior for the SIGPIPE signal, which is ignored by Python by default.
|
|
28
|
+
# This prevents a BrokenPipeError when piping output to a command like `less` that may close the pipe before reading all
|
|
29
|
+
# of the output.
|
|
30
|
+
try:
|
|
29
31
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL) # type: ignore[attr-defined] # not defined in Windows
|
|
32
|
+
except AttributeError:
|
|
33
|
+
pass
|
|
34
|
+
|
|
30
35
|
|
|
31
36
|
logger = logging.getLogger(__name__)
|
|
32
37
|
|
|
@@ -376,7 +381,7 @@ def main() -> None: # pragma: no cover
|
|
|
376
381
|
python_version_warning()
|
|
377
382
|
|
|
378
383
|
# Path where the config, jobs and hooks files are located
|
|
379
|
-
if
|
|
384
|
+
if sys.platform != 'win32':
|
|
380
385
|
config_path = platformdirs.user_config_path(__project_name__) # typically ~/.config/{__project_name__}
|
|
381
386
|
else:
|
|
382
387
|
config_path = platformdirs.user_documents_path().joinpath(__project_name__)
|
|
@@ -471,10 +476,8 @@ def main() -> None: # pragma: no cover
|
|
|
471
476
|
config_storage.load()
|
|
472
477
|
|
|
473
478
|
# Setup database API
|
|
474
|
-
database_engine = (
|
|
475
|
-
|
|
476
|
-
) # "or 'sqlite3'" is not needed except for a mypy bug; same for the "or 4" below
|
|
477
|
-
max_snapshots = command_config.max_snapshots or config_storage.config.get('database', {}).get('max_snapshots') or 4
|
|
479
|
+
database_engine = command_config.database_engine or config_storage.config.get('database', {}).get('engine')
|
|
480
|
+
max_snapshots = command_config.max_snapshots or config_storage.config.get('database', {}).get('max_snapshots')
|
|
478
481
|
if database_engine == 'sqlite3':
|
|
479
482
|
ssdb_storage: SsdbStorage = SsdbSQLite3Storage(command_config.ssdb_file, max_snapshots) # storage.py
|
|
480
483
|
elif any(str(command_config.ssdb_file).startswith(prefix) for prefix in ('redis://', 'rediss://')):
|