webutil

Common utilities and handler code for Python web apps.
- Install with
pip install webutil - Supports Python 3.9+
- Documentation
webutil is dedicated to the public domain. You may also use it under the CC0 public domain dedication.
Contents
flask_util: Flask decorators and handlers for caching, exception handling, regular expression URL routing, domain-wide redirects, rate limiting, headers, and serving XRD and JRD templates.logs: Flask request handler that collects full trace logs from Google Cloud Logging, formats them nicely, and serves themmodels: minor utility Model classes for the Google Cloud Datastore ndb librarytestutil: misc utilities and helpers for unittest, requests, and urllibutil: wide variety of utilities for data structures, web code, etc.webmention: Webmention endpoint discovery and sending
Changelog
3.0 - 2026-10-14
Breaking changes:
util:- Remove
if_changed. pretty_link: only linkhttpandhttpsURLs. For other URLs, return just the link text.
- Remove
Non-breaking changes:
flask_util:- Add
bool_paramfor getting boolean query params/form arguments. - Add
csp_reporthandler for loggingContent-Security-Policyviolation reports. MODERN_HEADERS: tightenContent-Security-Policysignificantly.
- Add
models:- Fix missing import in
Cache.get/Cache.put.
- Fix missing import in
testutil:- Add
assert_html_equals, which compares HTML strings and ignores insignificant whitespace and attribute order. requests_response: back the returned response with aurllib3.HTTPResponseinstead of a bareBytesIO, so thatresp.raw.stream()works for code that streams responses.
- Add
util:requests_*: addcachekwarg, an opt-in Flask-request-local cache of GET/HEAD responses and exceptions, keyed on method, URL, andAcceptheader.encode: fixencodingkwarg, it was ignored for nested values and always used UTF-8.is_connection_failure: makeprawcoreimport optional.linkify,tokenize_links: fix duplicated trailing punctuation after a link, eghttp://foo.com/a)..becamehttp://foo.com/a)......clean_url: fix query params with escaped delimiters, eg?a=b%26clost the%26c. The query string was unescaped before it was parsed.maybe_iso8601_to_rfc3339: return non-string inputs unchanged instead of raisingAttributeError.pretty_link: HTML-escape the URL inhrefand theattrsvalues.to_utc_timestamp: fix timezone aware datetimes, they were read as wall clock time and their UTC offset was ignored.trim_nulls: addkeep_empty_values_inkwarg.
2.0 - 2026-06-29
appengine_info:- Add Cloud Run support.
flask_util:- Add
block, abefore_requesthandler that blocks requests by client IP CIDR and/orUser-Agent.
- Add
models:- Add new
WriteOnce,WriteOnceBlobPropertyndb property classes. (Moved here from arroba.) - Add support for
$ENCRYPTED_PROPERTY_KEYenvironment variable.
- Add new
testutil:- Add new
@head_returns_200decorator. - Drop
moxfromTestCase. - Add new
unittest.mockandrequestshelpers toTestCase.
- Add new
util:requests_*: add newlog_databoolean kwarg.
1.0 - 2026-05-27
Initial PyPI release. Moved out of oauth-dropins, where it's been maintained for the last 10+ years, into its own dedicated package, pywebutil.
Release instructions
Here's how to package, test, and ship a new release.
- Pull from remote to make sure we're at head.
git checkout main git pull
- Run the unit tests.
source .venv/bin/activate.csh gcloud emulators firestore start --host-port=:8089 --database-mode=datastore-mode < /dev/null >& /dev/null & python -m unittest discover python -m unittest webutil/tests/hypothesis/*.py
- Bump the version number in
pyproject.tomlanddocs/conf.py.git grepthe old version number to make sure it only appears in the changelog. Change the current changelog entry inREADME.mdfor this new version from unreleased to the current date. - Build the docs. If you added any new modules, add them to the appropriate file(s) in
docs/source/. Then run./docs/build.sh. -
setenv ver X.Y git commit -am "release v$ver"
- Upload to test.pypi.org for testing.
uv build twine upload -r pypitest dist/pywebutil-$ver.tar.gz dist/pywebutil-$ver-py3-none-any.whl
- Install from test.pypi.org.
cd /tmp python3 -m venv .venv source .venv/bin/activate.csh pip3 install -i https://test.pypi.org/simple --extra-index-url https://pypi.org/simple pywebutil
- Smoke test that the code trivially loads and runs.
python # run test code belowTest code to paste into the interpreter:from webutil import util util.__file__ util.UrlCanonicalizer()('http://asdf.com') # should print 'https://asdf.com/' exit()
- Tag the release in git. In the tag message editor, delete the generated comments at bottom, leave the first line blank (to omit the release "title" in github), put
### Notable changeson the second line, then copy and paste this version's changelog contents below it.git tag -a v$ver --cleanup=verbatim git push git push --tags
- Click here to draft a new release on GitHub. Enter
vX.Yin the Tag version box. Leave Release title empty. Copy### Notable changesand the changelog contents into the description text box. - Upload to pypi.org!
twine upload dist/pywebutil-$ver-* dist/pywebutil-$ver.*
Metadata
Release files for pywebutil 3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pywebutil-3.0.tar.gz | 66.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pywebutil-3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 128.5 kB
Release files / pywebutil-3.0.tar.gz
| Download URL | pywebutil-3.0.tar.gz |
|---|---|
| Size | 66.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
73994d2e01695a8b5b9dfd86c46bc1d42669cc57048d13cff47cdacb98046bb6
|
|
BLAKE2b-256 checksum How to use checksums |
05184dc898e68f9c09aab0cd73ba038b74db04a9da6a27bb8a0a3c9d9d4dc8cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / pywebutil-3.0-py3-none-any.whl
| Download URL | pywebutil-3.0-py3-none-any.whl |
|---|---|
| Size | 62.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9ad7586538928ae6f5b1e960d2c4e3c4b1b989f34dd352a83f2d00c2b477410a
|
|
BLAKE2b-256 checksum How to use checksums |
88fab4a58b2da3ea8b4cbcc79a679d45c0fe13156674fb10f6ab3c34a7db0972
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|