-
Notifications
You must be signed in to change notification settings - Fork 1
Free threading #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Free threading #30
Conversation
This allows for Hypercorn to be used behind servers/proxies that add this header as well.
This removes warnings and ensures that pytest asyncio doesn't affect the trio tests.
Even when the server tasks error, for example with a "ssl.SSLError: [SSL: APPLICATION_DATA_AFTER_CLOSE_NOTIFY] application data after close notify". Thanks to @jonathanslenders for the report and suggested fix.
This allows an alternative format to the default ini format used by
``fileConfig``. This can also be used on the command line,
hypercorn --log-config json:file.json ...
for example.
This change makes the Keep-Alive timeout routines sensitive to the global termination switch, so that a connection in a Keep-Alive state will immediately close when termination is requested. It achieves this by making the termination flag on the context an event instead. We also fix a minor bug where the Keep-Alive timeout would never be reset after the first time it was created. More work is needed for HTTP/3, as the semantics of a connection in a GOAWAY state are different than what is currently exposed as "idle" from the UDP server's perspective.
This ensures that for HTTP/1 the returned headers match the casing as sent by the ASGI app.
This allows an ASGI application to send link header values to Hypercorn which Hypercorn will then send as an Early Hints response (103). Informational responses are ignored for HTTP/1 as it is likely clients will not correctly understand the meaning.
This will allow the CI to run on github rather than gitlab, allowing me to transfer.
This should, hopefully allow the docs to build and make it clearer to other users how to setup and install the docs requirements.
GitHub has a better pricing model and is more popular for OSS, hence the move.
RFC 7232 is clear that 204 and 304 bodies should be suppressed, but says nothing for 412.
This ensures that the connection is marked as not idle before a protocol upgrade takes place. This therefore ensures that on upgrading a slow response is not timed out.
Forgot to check.
This allows Hypercorn to serve a wsgi application via:
hypercorn module:app
With requests being run in threads via an asyncio executor or a trio
run_sync call.
The type of app will be determined automatically, however if it isn't
an additional prefix can be used to specify wsgi or asgi as:
hypercorn wsgi:module:app
hypercorn asgi:module:app
Note that this drops support for ASGI2 applications as it is unlikely
this is useful anymore.
The former is no longer supported.
Rather than the outdated access logger class.
Rather than using a single process with the reloader and restarting the entire program there is now a main process that checks for changes and restarts the process workers if so. This should resolve the various bugs trying to restart the entire program. A downside is that there is now always at least two processes and it is harder to use a reloader when using the API method to serve an app. Note the application must be loaded in the main process so that the observer knows what files to check for changes.
As it doesn't reload it is pointless to load it again.
This extends the new functionality to the programatic usage.
I no longer test 3.7 locally.
This occurs if the response is sent before the full request body has been received.
These files are not script-like (no `if __name__ == "__main__":` or interesting side effects) and have no shebang lines (`#!`), so there is no reason for the executable bit to be set in their filesystem permissions.
I wish to consider this solution, and also ensure any solution applies in the same manner for asyncio and UDP servers.
All of the imports are already conditionalized on the Python interpreter version; there is no need to install this backport package on current interpreters.
This should make it clearer what the trusted_hops argument should be. This is based on the Werkzeug docs.
This is necessary as the data is not known to be either websocket or http data as the server must accept or reject the connection and hence it is a bad request. In practice this is rare as the upgrade request is a GET request which rarely has body data and most websocket clients wait for acceptance.
This prevents Hypercorn calling aioquic's interface too many times, due to many tasks running concurrently, triggering exponential backoff and errors. Many thanks to @rthalley from whom's work this is based.
This adds support for the ASGI http-trailers extension which allows for trailing headers to be sent after a response. Many thanks to @jeffsawatzky from whom parts of this implementation are based.
This is required to use `NotRequired` when type hinting TypedDicts as required in d8de5f2.
Better to handle the timer every time. With thanks to @rthalley.
This allows ASGI apps to store state during startup that is then passed in every scope.
This was an ASGI specification condition that has now been relaxed.
The previous code was meant to ensure the response was not sent until the first byte was recevied. However, as the response_body has been set this should be enough and ensures that empty response bodies work.
The EndBody event should only be sent after the headers as this results in the stream being closed. It is acceptable to send no response and only trailing headers, in which case a default 200 status code response is sent with the headers.
This reverts commit a099217. As get OSError: [Errno 92] Protocol not available in Docker containers - needs further investigation.
This was a mistake in the recent QUIC work. Odd that mypy didn't pick this up.
This reverts commit 74d5b95. The issue wasn't Docker, but rather trying to set TCP properties on a UDP socket, hence the additional condition in this version.
This brings Hypercorn in line with what is required for Python 3.13 onwards.
A lifespan.startup.failure should crash the server, however if these became wrapped in an Exception group in the ASGI app the server wouldn't crash, now fixed.
This fixes a regression caused by bfb0877 whereby the cancellation error was caught. It should instead be re-raised.
The path shouldn't have been adjusted, rather the root_path should have been changed - this matches WSGI whereby the script_name is changed. In addition the changes should have been made in a copied scope to isolate them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces "Free threading" support to Hypercorn, implementing significant changes to modernize the codebase and add new functionality. The primary purpose is to add support for free-threading Python builds while updating Python compatibility and adding new features.
Key changes include:
- Python version update: Minimum Python version increased from 3.7 to 3.8, with support added for 3.11 and 3.12
- Free threading support: Added
worker_typeconfiguration option to choose between "process" and "thread" workers - Direct WSGI support: Added native WSGI application serving capabilities through new app wrapper system
Reviewed Changes
Copilot reviewed 80 out of 82 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tox.ini | Updated Python versions and dependencies for testing |
| tests/ | Updated test files to use new app wrappers, type annotations, and async fixtures |
| src/hypercorn/ | Core implementation changes for WSGI support, worker threading, and modernized async patterns |
| docs/ | Documentation updates for new features and configuration options |
| pyproject.toml | Updated Python version requirements and dependencies |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| # changes, but only when the reloader is being used. | ||
| load_application(config.application_path, config.wsgi_max_body_size) | ||
|
|
||
| active = True |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove trailing whitespace.
| active = True | |
| active = True |
| if args.max_requests is not sentinel: | ||
| config.max_requests = args.max_requests | ||
| if args.max_requests_jitter is not sentinel: | ||
| config.max_requests_jitter = args.max_requests |
Copilot
AI
Oct 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should assign args.max_requests_jitter instead of args.max_requests to config.max_requests_jitter.
| config.max_requests_jitter = args.max_requests | |
| config.max_requests_jitter = args.max_requests_jitter |
No description provided.