mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-01 10:11:30 +08:00
Migrate docs build to MkDocs
This commit is contained in:
parent
58d803977d
commit
19a2efec63
72
.github/workflows/docs.yml
vendored
Normal file
72
.github/workflows/docs.yml
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
- 'requirements_dev.txt'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'mkdocs.yml'
|
||||
- 'requirements_dev.txt'
|
||||
- '.github/workflows/docs.yml'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements_dev.txt
|
||||
|
||||
- name: Build documentation
|
||||
run: mkdocs build
|
||||
|
||||
- name: Upload site artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: gunicorn-site
|
||||
path: site
|
||||
retention-days: 7
|
||||
|
||||
deploy:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements_dev.txt
|
||||
|
||||
- name: Build documentation
|
||||
run: mkdocs build
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: site
|
||||
publish_branch: gh-pages
|
||||
commit_message: "docs: deploy {sha}"
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -16,3 +16,5 @@ examples/frameworks/pylonstest/pylonstest.egg-info/
|
||||
MANIFEST
|
||||
nohup.out
|
||||
setuptools-*
|
||||
site/
|
||||
docs/site/
|
||||
|
||||
8
Makefile
8
Makefile
@ -9,9 +9,15 @@ test:
|
||||
coverage:
|
||||
venv/bin/python setup.py test --cov
|
||||
|
||||
docs:
|
||||
mkdocs build
|
||||
|
||||
docs-serve:
|
||||
mkdocs serve
|
||||
|
||||
clean:
|
||||
@rm -rf .Python MANIFEST build dist venv* *.egg-info *.egg
|
||||
@find . -type f -name "*.py[co]" -delete
|
||||
@find . -type d -name "__pycache__" -delete
|
||||
|
||||
.PHONY: build clean coverage test
|
||||
.PHONY: build clean coverage docs docs-serve test
|
||||
|
||||
8
benchmarks/baseline.json
Normal file
8
benchmarks/baseline.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"gthread": {
|
||||
"simple": {},
|
||||
"simple_high_concurrency": {},
|
||||
"slow_io": {},
|
||||
"large_response": {}
|
||||
}
|
||||
}
|
||||
40
benchmarks/quick_bench.sh
Executable file
40
benchmarks/quick_bench.sh
Executable file
@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
# Quick benchmark for gthread worker
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
echo "Starting gunicorn with gthread worker..."
|
||||
../.venv/bin/python -m gunicorn \
|
||||
--worker-class gthread \
|
||||
--workers 2 \
|
||||
--threads 4 \
|
||||
--worker-connections 1000 \
|
||||
--bind 127.0.0.1:8765 \
|
||||
--access-logfile /dev/null \
|
||||
--error-logfile /dev/null \
|
||||
--log-level warning \
|
||||
simple_app:application &
|
||||
|
||||
GUNICORN_PID=$!
|
||||
sleep 3
|
||||
|
||||
echo ""
|
||||
echo "=== Benchmark: Simple requests (10000 requests, 100 concurrent) ==="
|
||||
ab -n 10000 -c 100 -k http://127.0.0.1:8765/ 2>&1 | grep -E "(Requests per second|Time per request|Failed requests)"
|
||||
|
||||
echo ""
|
||||
echo "=== Benchmark: High concurrency (5000 requests, 500 concurrent) ==="
|
||||
ab -n 5000 -c 500 -k http://127.0.0.1:8765/ 2>&1 | grep -E "(Requests per second|Time per request|Failed requests)"
|
||||
|
||||
echo ""
|
||||
echo "=== Benchmark: Large response (1000 requests, 50 concurrent) ==="
|
||||
ab -n 1000 -c 50 -k http://127.0.0.1:8765/large 2>&1 | grep -E "(Requests per second|Time per request|Failed requests)"
|
||||
|
||||
echo ""
|
||||
echo "Stopping gunicorn..."
|
||||
kill $GUNICORN_PID 2>/dev/null || true
|
||||
wait $GUNICORN_PID 2>/dev/null || true
|
||||
|
||||
echo "Done!"
|
||||
238
benchmarks/run_benchmark.py
Executable file
238
benchmarks/run_benchmark.py
Executable file
@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Benchmark script for gunicorn gthread worker.
|
||||
|
||||
This script runs various benchmarks against gunicorn and reports performance metrics.
|
||||
Requires: gunicorn, requests (for warmup), and wrk or ab for load testing.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
BENCHMARK_DIR = Path(__file__).parent
|
||||
APP_MODULE = "simple_app:application"
|
||||
|
||||
|
||||
def check_dependencies():
|
||||
"""Check if required tools are available."""
|
||||
# Check for wrk (preferred) or ab
|
||||
for tool in ['wrk', 'ab']:
|
||||
try:
|
||||
subprocess.run([tool, '--version'], capture_output=True, check=False)
|
||||
return tool
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
print("Error: Neither 'wrk' nor 'ab' found. Install one of them.")
|
||||
print(" macOS: brew install wrk")
|
||||
print(" Linux: apt-get install wrk (or apache2-utils for ab)")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def start_gunicorn(worker_class, workers, threads, connections, bind, extra_args=None):
|
||||
"""Start gunicorn server and return the process."""
|
||||
cmd = [
|
||||
sys.executable, '-m', 'gunicorn',
|
||||
'--worker-class', worker_class,
|
||||
'--workers', str(workers),
|
||||
'--threads', str(threads),
|
||||
'--worker-connections', str(connections),
|
||||
'--bind', bind,
|
||||
'--access-logfile', '-',
|
||||
'--error-logfile', '-',
|
||||
'--log-level', 'warning',
|
||||
APP_MODULE,
|
||||
]
|
||||
if extra_args:
|
||||
cmd.extend(extra_args)
|
||||
|
||||
env = os.environ.copy()
|
||||
env['PYTHONPATH'] = str(BENCHMARK_DIR.parent)
|
||||
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=BENCHMARK_DIR,
|
||||
env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
|
||||
# Wait for server to be ready
|
||||
time.sleep(2)
|
||||
return proc
|
||||
|
||||
|
||||
def stop_gunicorn(proc):
|
||||
"""Stop the gunicorn server."""
|
||||
proc.send_signal(signal.SIGTERM)
|
||||
try:
|
||||
proc.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
proc.wait()
|
||||
|
||||
|
||||
def run_wrk_benchmark(url, duration, threads, connections):
|
||||
"""Run wrk benchmark and return results."""
|
||||
cmd = [
|
||||
'wrk',
|
||||
'-t', str(threads),
|
||||
'-c', str(connections),
|
||||
'-d', f'{duration}s',
|
||||
'--latency',
|
||||
url,
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
|
||||
return parse_wrk_output(result.stdout)
|
||||
|
||||
|
||||
def run_ab_benchmark(url, requests, concurrency):
|
||||
"""Run Apache Bench benchmark and return results."""
|
||||
cmd = [
|
||||
'ab',
|
||||
'-n', str(requests),
|
||||
'-c', str(concurrency),
|
||||
'-k', # keepalive
|
||||
url,
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
|
||||
return parse_ab_output(result.stdout)
|
||||
|
||||
|
||||
def parse_wrk_output(output):
|
||||
"""Parse wrk output to extract metrics."""
|
||||
metrics = {}
|
||||
for line in output.split('\n'):
|
||||
if 'Requests/sec' in line:
|
||||
metrics['requests_per_sec'] = float(line.split(':')[1].strip())
|
||||
elif 'Transfer/sec' in line:
|
||||
metrics['transfer_per_sec'] = line.split(':')[1].strip()
|
||||
elif 'Latency' in line and 'Distribution' not in line:
|
||||
parts = line.split()
|
||||
if len(parts) >= 2:
|
||||
metrics['latency_avg'] = parts[1]
|
||||
elif '50%' in line:
|
||||
metrics['latency_p50'] = line.split()[1]
|
||||
elif '99%' in line:
|
||||
metrics['latency_p99'] = line.split()[1]
|
||||
return metrics
|
||||
|
||||
|
||||
def parse_ab_output(output):
|
||||
"""Parse ab output to extract metrics."""
|
||||
metrics = {}
|
||||
for line in output.split('\n'):
|
||||
if 'Requests per second' in line:
|
||||
metrics['requests_per_sec'] = float(line.split(':')[1].split()[0])
|
||||
elif 'Time per request' in line and 'mean' in line:
|
||||
metrics['latency_avg'] = line.split(':')[1].strip()
|
||||
elif 'Transfer rate' in line:
|
||||
metrics['transfer_per_sec'] = line.split(':')[1].strip()
|
||||
return metrics
|
||||
|
||||
|
||||
def run_benchmark_suite(tool, bind_addr):
|
||||
"""Run a suite of benchmarks."""
|
||||
results = {}
|
||||
|
||||
# Test configurations
|
||||
configs = [
|
||||
{'name': 'simple', 'path': '/', 'connections': 100},
|
||||
{'name': 'simple_high_concurrency', 'path': '/', 'connections': 500},
|
||||
{'name': 'slow_io', 'path': '/slow', 'connections': 50},
|
||||
{'name': 'large_response', 'path': '/large', 'connections': 100},
|
||||
]
|
||||
|
||||
for config in configs:
|
||||
url = f'http://{bind_addr}{config["path"]}'
|
||||
print(f" Running {config['name']}...")
|
||||
|
||||
if tool == 'wrk':
|
||||
metrics = run_wrk_benchmark(
|
||||
url,
|
||||
duration=10,
|
||||
threads=4,
|
||||
connections=config['connections'],
|
||||
)
|
||||
else:
|
||||
metrics = run_ab_benchmark(
|
||||
url,
|
||||
requests=10000,
|
||||
concurrency=config['connections'],
|
||||
)
|
||||
|
||||
results[config['name']] = metrics
|
||||
print(f" Requests/sec: {metrics.get('requests_per_sec', 'N/A')}")
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Benchmark gunicorn gthread worker')
|
||||
parser.add_argument('--workers', type=int, default=2, help='Number of workers')
|
||||
parser.add_argument('--threads', type=int, default=4, help='Threads per worker')
|
||||
parser.add_argument('--connections', type=int, default=1000, help='Worker connections')
|
||||
parser.add_argument('--bind', default='127.0.0.1:8000', help='Bind address')
|
||||
parser.add_argument('--compare', action='store_true', help='Compare sync vs gthread')
|
||||
parser.add_argument('--output', help='Output JSON file for results')
|
||||
args = parser.parse_args()
|
||||
|
||||
tool = check_dependencies()
|
||||
print(f"Using benchmark tool: {tool}")
|
||||
|
||||
all_results = {}
|
||||
|
||||
if args.compare:
|
||||
# Compare sync and gthread workers
|
||||
for worker_class in ['sync', 'gthread']:
|
||||
print(f"\nBenchmarking {worker_class} worker...")
|
||||
proc = start_gunicorn(
|
||||
worker_class=worker_class,
|
||||
workers=args.workers,
|
||||
threads=args.threads,
|
||||
connections=args.connections,
|
||||
bind=args.bind,
|
||||
)
|
||||
try:
|
||||
all_results[worker_class] = run_benchmark_suite(tool, args.bind)
|
||||
finally:
|
||||
stop_gunicorn(proc)
|
||||
else:
|
||||
# Just benchmark gthread
|
||||
print("\nBenchmarking gthread worker...")
|
||||
proc = start_gunicorn(
|
||||
worker_class='gthread',
|
||||
workers=args.workers,
|
||||
threads=args.threads,
|
||||
connections=args.connections,
|
||||
bind=args.bind,
|
||||
)
|
||||
try:
|
||||
all_results['gthread'] = run_benchmark_suite(tool, args.bind)
|
||||
finally:
|
||||
stop_gunicorn(proc)
|
||||
|
||||
# Print summary
|
||||
print("\n" + "=" * 60)
|
||||
print("BENCHMARK SUMMARY")
|
||||
print("=" * 60)
|
||||
for worker, results in all_results.items():
|
||||
print(f"\n{worker.upper()} Worker:")
|
||||
for test, metrics in results.items():
|
||||
rps = metrics.get('requests_per_sec', 'N/A')
|
||||
print(f" {test}: {rps} req/s")
|
||||
|
||||
if args.output:
|
||||
with open(args.output, 'w') as f:
|
||||
json.dump(all_results, f, indent=2)
|
||||
print(f"\nResults saved to {args.output}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
18
benchmarks/simple_app.py
Normal file
18
benchmarks/simple_app.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Simple WSGI app for benchmarking
|
||||
|
||||
def application(environ, start_response):
|
||||
"""Basic hello world response."""
|
||||
path = environ.get('PATH_INFO', '/')
|
||||
|
||||
if path == '/large':
|
||||
body = b'X' * 65536 # 64KB
|
||||
else:
|
||||
body = b'Hello, World!'
|
||||
|
||||
status = '200 OK'
|
||||
headers = [
|
||||
('Content-Type', 'text/plain'),
|
||||
('Content-Length', str(len(body))),
|
||||
]
|
||||
start_response(status, headers)
|
||||
return [body]
|
||||
29
docs/README.rst
Normal file
29
docs/README.rst
Normal file
@ -0,0 +1,29 @@
|
||||
Generate Documentation
|
||||
======================
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Install the documentation dependencies with::
|
||||
|
||||
pip install -r requirements_dev.txt
|
||||
|
||||
This provides MkDocs with the Material theme and supporting plugins.
|
||||
|
||||
|
||||
Build static HTML
|
||||
-----------------
|
||||
::
|
||||
|
||||
mkdocs build
|
||||
|
||||
The rendered site is emitted into the ``site/`` directory.
|
||||
|
||||
|
||||
Preview locally
|
||||
---------------
|
||||
::
|
||||
|
||||
mkdocs serve
|
||||
|
||||
This serves the documentation at http://127.0.0.1:8000/ with live reload.
|
||||
190
docs/content/2010-news.md
Normal file
190
docs/content/2010-news.md
Normal file
@ -0,0 +1,190 @@
|
||||
<span id="news-2010"></span>
|
||||
# Changelog - 2010
|
||||
|
||||
## 0.12.0 / 2010-12-22
|
||||
|
||||
- Add support for logging configuration using a ini file.
|
||||
It uses the standard Python logging's module Configuration
|
||||
file format and allows anyone to use his custom file handler
|
||||
- Add IPV6 support
|
||||
- Add multidomain application example
|
||||
- Improve gunicorn_django command when importing settings module
|
||||
using DJANGO_SETTINGS_MODULE environment variable
|
||||
- Send appropriate error status on http parsing
|
||||
- Fix pidfile, set permissions so other user can read
|
||||
it and use it.
|
||||
- Fix temporary file leaking
|
||||
- Fix setpgrp issue, can now be launched via ubuntu upstart
|
||||
- Set the number of workers to zero on WINCH
|
||||
|
||||
## 0.11.2 / 2010-10-30
|
||||
|
||||
* Add SERVER_SOFTWARE to the os.environ
|
||||
* Add support for django settings environment variable
|
||||
* Add support for logging configuration in Paster ini-files
|
||||
* Improve arbiter notification in asynchronous workers
|
||||
* Display the right error when a worker can't be used
|
||||
* Fix Django support
|
||||
* Fix HUP with Paster applications
|
||||
* Fix readline in wsgi.input
|
||||
|
||||
## 0.11.1 / 2010-09-02
|
||||
|
||||
* Implement max-requests feature to prevent memory leaks.
|
||||
* Added 'worker_exit' server hook.
|
||||
* Reseed the random number generator after fork().
|
||||
* Improve Eventlet worker.
|
||||
* Fix Django command `run_gunicorn`.
|
||||
* Fix the default proc name internal setting.
|
||||
* Workaround to prevent Gevent worker to segfault on MacOSX.
|
||||
|
||||
## 0.11.0 / 2010-08-12
|
||||
|
||||
* Improve dramatically performances of Gevent and Eventlet workers
|
||||
* Optimize HTTP parsing
|
||||
* Drop Server and Date headers in start_response when provided.
|
||||
* Fix latency issue in async workers
|
||||
|
||||
## 0.10.1 / 2010-08-06
|
||||
|
||||
* Improve gevent's workers. Add "egg:gunicorn#gevent_wsgi" worker using
|
||||
`gevent.wsgi <http://www.gevent.org/gevent.wsgi.html>`_ and
|
||||
"egg:gunicorn#gevent_pywsgi" worker using `gevent.pywsgi
|
||||
<http://www.gevent.org/gevent.pywsgi.html>`_ .
|
||||
**"egg:gunicorn#gevent"** using our own HTTP parser is still here and
|
||||
is **recommended** for normal uses. Use the "gevent.wsgi" parser if you
|
||||
need really fast connections and don't need streaming, keepalive or ssl.
|
||||
* Add pre/post request hooks
|
||||
* Exit more quietly
|
||||
* Fix gevent dns issue
|
||||
|
||||
## 0.10.0 / 2010-07-08
|
||||
|
||||
* New HTTP parser.
|
||||
* New HUP behaviour. Re-reads the configuration and then reloads all
|
||||
worker processes without changing the master process id. Helpful for
|
||||
code reloading and monitoring applications like supervisord and runit.
|
||||
* Added a preload configuration parameter. By default, application code
|
||||
is now loaded after a worker forks. This couple with the new HUP
|
||||
handling can be used for dev servers to do hot code reloading. Using
|
||||
the preload flag can help a bit in small memory VM's.
|
||||
* Allow people to pass command line arguments to WSGI applications. See:
|
||||
`examples/alt_spec.py
|
||||
<http://github.com/benoitc/gunicorn/raw/master/examples/alt_spec.py>`_
|
||||
* Added an example gevent reloader configuration:
|
||||
`examples/example_gevent_reloader.py
|
||||
<http://github.com/benoitc/gunicorn/blob/master/examples/example_gevent_reloader.py>`_.
|
||||
* New gevent worker "egg:gunicorn#gevent2", working with gevent.wsgi.
|
||||
* Internal refactoring and various bug fixes.
|
||||
* New documentation website.
|
||||
|
||||
## 0.9.1 / 2010-05-26
|
||||
|
||||
* Support https via X-Forwarded-Protocol or X-Forwarded-Ssl headers
|
||||
* Fix configuration
|
||||
* Remove -d options which was used instead of -D for daemon.
|
||||
* Fix umask in unix socket
|
||||
|
||||
## 0.9.0 / 2010-05-24
|
||||
|
||||
* Added *when_ready* hook. Called just after the server is started
|
||||
* Added *preload* setting. Load application code before the worker processes
|
||||
are forked.
|
||||
* Refactored Config
|
||||
* Fix pidfile
|
||||
* Fix QUIT/HUP in async workers
|
||||
* Fix reexec
|
||||
* Documentation improvements
|
||||
|
||||
## 0.8.1 / 2010-04-29
|
||||
|
||||
* Fix builtins import in config
|
||||
* Fix installation with pip
|
||||
* Fix Tornado WSGI support
|
||||
* Delay application loading until after processing all configuration
|
||||
|
||||
## 0.8.0 / 2010-04-22
|
||||
|
||||
* Refactored Worker management for better async support. Now use the -k option
|
||||
to set the type of request processing to use
|
||||
* Added support for Tornado_
|
||||
|
||||
## 0.7.2 / 2010-04-15
|
||||
|
||||
* Added --spew option to help debugging (installs a system trace hook)
|
||||
* Some fixes in async arbiters
|
||||
* Fix a bug in start_response on error
|
||||
|
||||
## 0.7.1 / 2010-04-01
|
||||
|
||||
* Fix bug when responses have no body.
|
||||
|
||||
## 0.7.0 / 2010-03-26
|
||||
|
||||
* Added support for Eventlet_ and Gevent_ based workers.
|
||||
* Added Websockets_ support
|
||||
* Fix Chunked Encoding
|
||||
* Fix SIGWINCH on OpenBSD_
|
||||
* Fix `PEP 333`_ compliance for the write callable.
|
||||
|
||||
## 0.6.5 / 2010-03-11
|
||||
|
||||
* Fix pidfile handling
|
||||
* Fix Exception Error
|
||||
|
||||
## 0.6.4 / 2010-03-08
|
||||
|
||||
* Use cStringIO for performance when possible.
|
||||
* Fix worker freeze when a remote connection closes unexpectedly.
|
||||
|
||||
## 0.6.3 / 2010-03-07
|
||||
|
||||
* Make HTTP parsing faster.
|
||||
* Various bug fixes
|
||||
|
||||
## 0.6.2 / 2010-03-01
|
||||
|
||||
* Added support for chunked response.
|
||||
* Added proc_name option to the config file.
|
||||
* Improved the HTTP parser. It now uses buffers instead of strings to store
|
||||
temporary data.
|
||||
* Improved performance when sending responses.
|
||||
* Workers are now murdered by age (the oldest is killed first).
|
||||
|
||||
## 0.6.1 / 2010-02-24
|
||||
|
||||
* Added gunicorn config file support for Django admin command
|
||||
* Fix gunicorn config file. -c was broken.
|
||||
* Removed TTIN/TTOU from workers which blocked other signals.
|
||||
|
||||
## 0.6.0 / 2010-02-22
|
||||
|
||||
* Added setproctitle support
|
||||
* Change privilege switch behavior. We now work like NGINX, master keeps the
|
||||
permissions, new uid/gid permissions are only set for workers.
|
||||
|
||||
## 0.5.1 / 2010-02-22
|
||||
|
||||
* Fix umask
|
||||
* Added Debian packaging
|
||||
|
||||
## 0.5.0 / 2010-02-20
|
||||
|
||||
* Added `configuration file <configuration.html>`_ handler.
|
||||
* Added support for pre/post fork hooks
|
||||
* Added support for before_exec hook
|
||||
* Added support for unix sockets
|
||||
* Added launch of workers processes under different user/group
|
||||
* Added umask option
|
||||
* Added SCRIPT_NAME support
|
||||
* Better support of some exotic settings for Django projects
|
||||
* Better support of Paste-compatible applications
|
||||
* Some refactoring to make the code easier to hack
|
||||
* Allow multiple keys in request and response headers
|
||||
|
||||
.. _Tornado: http://www.tornadoweb.org/
|
||||
.. _`PEP 333`: https://www.python.org/dev/peps/pep-0333/
|
||||
.. _Eventlet: http://eventlet.net/
|
||||
.. _Gevent: http://www.gevent.org/
|
||||
.. _OpenBSD: https://www.openbsd.org/
|
||||
.. _Websockets: https://html.spec.whatwg.org/multipage/web-sockets.html
|
||||
66
docs/content/2011-news.md
Normal file
66
docs/content/2011-news.md
Normal file
@ -0,0 +1,66 @@
|
||||
<span id="news-2011"></span>
|
||||
# Changelog - 2011
|
||||
|
||||
## 0.13.4 / 2011-09-23
|
||||
|
||||
- fix util.closerange function used to prevent leaking fds on python 2.5
|
||||
(typo.md)
|
||||
|
||||
## 0.13.3 / 2011-09-19
|
||||
- refactor gevent worker
|
||||
- prevent leaking fds on reexec
|
||||
- fix inverted request_time computation
|
||||
|
||||
## 0.13.2 / 2011-09-17
|
||||
|
||||
- Add support for Tornado 2.0 in tornado worker
|
||||
- Improve access logs: allows customisation of the log format & add
|
||||
request time
|
||||
- Logger module is now pluggable
|
||||
- Improve graceful shutdown in Python versions >= 2.6
|
||||
- Fix post_request root arity for compatibility
|
||||
- Fix sendfile support
|
||||
- Fix Django reloading
|
||||
|
||||
## 0.13.1 / 2011-08-22
|
||||
|
||||
- Fix unix socket. log argument was missing.
|
||||
|
||||
## 0.13.0 / 2011-08-22
|
||||
|
||||
- Improve logging: allows file-reopening and add access log file
|
||||
compatible with the `apache combined log format <http://httpd.apache.org/docs/2.0/logs.html#combined>`_
|
||||
- Add the possibility to set custom SSL headers. X-Forwarded-Protocol
|
||||
and X-Forwarded-SSL are still the default
|
||||
- New `on_reload` hook to customize how gunicorn spawn new workers on
|
||||
SIGHUP
|
||||
- Handle projects with relative path in django_gunicorn command
|
||||
- Preserve path parameters in PATH_INFO
|
||||
- post_request hook now accepts the environ as argument.
|
||||
- When stopping the arbiter, close the listener asap.
|
||||
- Fix Django command `run_gunicorn` in settings reloading
|
||||
- Fix Tornado_ worker exiting
|
||||
- Fix the use of sendfile in wsgi.file_wrapper
|
||||
|
||||
|
||||
## 0.12.2 / 2011-05-18
|
||||
|
||||
- Add wsgi.file_wrapper optimised for FreeBSD, Linux & MacOSX (use
|
||||
sendfile if available)
|
||||
- Fix django run_gunicorn command. Make sure we reload the application
|
||||
code.
|
||||
- Fix django localisation
|
||||
- Compatible with gevent 0.14dev
|
||||
|
||||
## 0.12.1 / 2011-03-23
|
||||
|
||||
- Add "on_starting" hook. This hook can be used to set anything before
|
||||
the arbiter really start
|
||||
- Support bdist_rpm in setup
|
||||
- Improve content-length handling (pep 3333)
|
||||
- Improve Django support
|
||||
- Fix daemonizing (#142)
|
||||
- Fix ipv6 handling
|
||||
|
||||
|
||||
.. _Tornado: http://www.tornadoweb.org/
|
||||
117
docs/content/2012-news.md
Normal file
117
docs/content/2012-news.md
Normal file
@ -0,0 +1,117 @@
|
||||
<span id="news-2012"></span>
|
||||
# Changelog - 2012
|
||||
|
||||
## 0.17.0 / 2012-12-25
|
||||
|
||||
- allows gunicorn to bind to multiple address
|
||||
- add SSL support
|
||||
- add syslog support
|
||||
- add nworkers_changed hook
|
||||
- add response arg for post_request hook
|
||||
- parse command line with argparse (replace deprecated optparse)
|
||||
- fix PWD detection in arbiter
|
||||
- miscellaneous PEP8 fixes
|
||||
|
||||
## 0.16.1 / 2012-11-19
|
||||
|
||||
- Fix packaging
|
||||
|
||||
## 0.16.0 / 2012-11-19
|
||||
|
||||
- **Added support for Python 3.2 & 3.3**
|
||||
- Expose --pythonpath command to all gunicorn commands
|
||||
- Honor $PORT environment variable, useful for deployment on heroku
|
||||
- Removed support for Python 2.5
|
||||
- Make sure we reopen the logs on the console
|
||||
- Fix django settings module detection from path
|
||||
- Reverted timeout for client socket. Fix issue on blocking issues.
|
||||
- Fixed gevent worker
|
||||
|
||||
## 0.15.0 / 2012-10-18
|
||||
|
||||
- new documentation site on http://docs.gunicorn.org
|
||||
- new website on http://gunicorn.org
|
||||
- add `haproxy PROXY protocol <http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt>`_ support
|
||||
- add ForwardedAllowIPS option: allows to filter Front-end's IPs
|
||||
allowed to handle X-Forwarded-* headers.
|
||||
- add callable hooks for paster config
|
||||
- add x-forwarded-proto as secure scheme default (Heroku is using this)
|
||||
- allows gunicorn to load a pre-compiled application
|
||||
- support file reopening & reexec for all loggers
|
||||
- initialize the logging config file with defaults.
|
||||
- set timeout for client socket (slow client DoS).
|
||||
- NoMoreData, ChunkMissingTerminator, InvalidChunkSize are now
|
||||
IOError exceptions
|
||||
- fix graceful shutdown in gevent
|
||||
- fix limit request line check
|
||||
|
||||
## 0.14.6 / 2012-07-26
|
||||
|
||||
|
||||
- fix gevent & subproces
|
||||
- fix request line length check
|
||||
- fix keepalive = 0
|
||||
- fix tornado worker
|
||||
|
||||
## 0.14.5 / 2012-06-24
|
||||
|
||||
- fix logging during daemonisation
|
||||
|
||||
## 0.14.4 / 2012-06-24
|
||||
|
||||
- new --graceful-timeout option
|
||||
- fix multiple issues with request limit
|
||||
- more fixes in django settings resolutions
|
||||
- fix gevent.core import
|
||||
- fix keepalive=0 in eventlet worker
|
||||
- fix handle_error display with the unix worker
|
||||
- fix tornado.wsgi.WSGIApplication calling error
|
||||
|
||||
- **breaking change**: take the control on graceful reload back.
|
||||
graceful can't be overridden anymore using the on_reload function.
|
||||
|
||||
## 0.14.3 / 2012-05-15
|
||||
|
||||
- improvement: performance of http.body.Body.readline()
|
||||
- improvement: log HTTP errors in access log like Apache
|
||||
- improvement: display traceback when the worker fails to boot
|
||||
- improvement: makes gunicorn work with gevent 1.0
|
||||
- examples: websocket example now supports hybi13
|
||||
- fix: reopen log files after initialization
|
||||
- fix: websockets support
|
||||
- fix: django1.4 support
|
||||
- fix: only load the paster application 1 time
|
||||
|
||||
## 0.14.2 / 2012-03-16
|
||||
|
||||
- add validate_class validator: allows to use a class or a method to
|
||||
initialize the app during in-code configuration
|
||||
- add support for max_requests in tornado worker
|
||||
- add support for disabling x_forwarded_for_header in tornado worker
|
||||
- gevent_wsgi is now an alias of gevent_pywsgi
|
||||
- Fix gevent_pywsgi worker
|
||||
|
||||
## 0.14.1 / 2012-03-02
|
||||
|
||||
- fixing source archive, reducing its size
|
||||
|
||||
## 0.14.0 / 2012-02-27
|
||||
|
||||
- check if Request line is too large: You can now pass the parameter
|
||||
``--limit-request-line`` or set the ``limit_request_line`` in your
|
||||
configuration file to set the max size of the request line in bytes.
|
||||
- limit the number of headers fields and their size. Add
|
||||
``--limit-request-field`` and ``limit-request-field-size`` settings
|
||||
- add ``p`` variable to the log access format to log pidfile
|
||||
- add ``{HeaderName}o`` variable to the logo access format to log the
|
||||
response header HeaderName
|
||||
- request header is now logged with the variable ``{HeaderName}i`` in the
|
||||
access log file
|
||||
- improve error logging
|
||||
- support logging.configFile
|
||||
- support django 1.4 in both gunicorn_django & run_gunicorn command
|
||||
- improve reload in django run_gunicorn command (should just work now)
|
||||
- allows people to set the ``X-Forwarded-For`` header key and disable it by
|
||||
setting an empty string.
|
||||
- fix support of Tornado
|
||||
- many other fixes.
|
||||
83
docs/content/2013-news.md
Normal file
83
docs/content/2013-news.md
Normal file
@ -0,0 +1,83 @@
|
||||
<span id="news-2013"></span>
|
||||
# Changelog - 2013
|
||||
|
||||
## 18.0 / 2013-08-26
|
||||
|
||||
- new: add ``-e/--env`` command line argument to pass an environment variables to
|
||||
gunicorn
|
||||
- new: add ``--chdir`` command line argument to specified directory
|
||||
before apps loading. - new: add wsgi.file_wrapper support in async workers
|
||||
- new: add ``--paste`` command line argument to set the paster config file
|
||||
- deprecated: the command ``gunicorn_django`` is now deprecated. You should now
|
||||
run your application with the WSGI interface installed with your project (see
|
||||
https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/gunicorn/) for
|
||||
more infos.
|
||||
- deprecated: the command ``gunicorn_paste`` is deprecated. You now should use
|
||||
the new ``--paste`` argument to set the configuration file of your paster
|
||||
application.
|
||||
- fix: Removes unmatched leading quote from the beginning of the default access
|
||||
log format string
|
||||
- fix: null timeout
|
||||
- fix: gevent worker
|
||||
- fix: don't reload the paster app when using pserve
|
||||
- fix: after closing for error do not keep alive the connection
|
||||
- fix: responses 1xx, 204 and 304 should not force the connection to be closed
|
||||
|
||||
## 17.5 / 2013-07-03
|
||||
|
||||
- new: add signals documentation
|
||||
- new: add post_worker_init hook for workers
|
||||
- new: try to use gunicorn.conf.py in current folder as the default
|
||||
config file.
|
||||
- fix graceful timeout with the Eventlet worker
|
||||
- fix: don't raise an error when closing the socket if already closed
|
||||
- fix: fix --settings parameter for django application and try to find
|
||||
the django settings when using the ``gunicorn`` command.
|
||||
- fix: give the initial global_conf to paster application
|
||||
- fix: fix 'Expect: 100-continue' support on Python 3
|
||||
|
||||
### New versioning:
|
||||
|
||||
With this release, the versioning of Gunicorn is changing. Gunicorn is
|
||||
stable since a long time and there is no point to release a "1.0" now.
|
||||
It should have been done since a long time. 0.17 really meant it was the
|
||||
17th stable version. From the beginning we have only 2 kind of
|
||||
releases:
|
||||
|
||||
major release: releases with major changes or huge features added
|
||||
services releases: fixes and minor features added So from now we will
|
||||
apply the following versioning ``<major>.<service>``. For example ``17.5`` is a
|
||||
service release.
|
||||
|
||||
## 0.17.4 / 2013-04-24
|
||||
|
||||
- fix unix socket address parsing
|
||||
|
||||
## 0.17.3 / 2013-04-23
|
||||
|
||||
- add systemd sockets support
|
||||
- add ``python -m gunicorn.app.wsgiapp`` support
|
||||
- improve logger class inheritance
|
||||
- exit when the config file isn't found
|
||||
- add the -R option to enable stdio inheritance in daemon mode
|
||||
- don't close file descriptors > 3 in daemon mode
|
||||
- improve STDOUT/STDERR logging
|
||||
- fix pythonpath option
|
||||
- fix pidfile creation on Python 3
|
||||
- fix gevent worker exit
|
||||
- fix ipv6 detection when the platform isn't supporting it
|
||||
|
||||
## 0.17.2 / 2013-01-07
|
||||
|
||||
- optimize readline
|
||||
- make imports errors more visible when loading an app or a logging
|
||||
class
|
||||
- fix tornado worker: don't pass ssl options if there are none
|
||||
- fix PEP3333: accept only bytetrings in the response body
|
||||
- fix support on CYGWIN platforms
|
||||
|
||||
## 0.17.1 / 2013-01-05
|
||||
|
||||
- add syslog facility name setting
|
||||
- fix ``--version`` command line argument
|
||||
- fix wsgi url_scheme for https
|
||||
202
docs/content/2014-news.md
Normal file
202
docs/content/2014-news.md
Normal file
@ -0,0 +1,202 @@
|
||||
<span id="news-2014"></span>
|
||||
# Changelog - 2014
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes.
|
||||
|
||||
|
||||
## 19.1.1 / 2014-08-16
|
||||
|
||||
### Changes
|
||||
|
||||
### Core
|
||||
|
||||
- fix [Issue #835](https://github.com/benoitc/gunicorn/issues/835): display correct pid of already running instance
|
||||
- fix [PR #833](https://github.com/benoitc/gunicorn/pull/833): fix `PyTest` class in setup.py.
|
||||
|
||||
|
||||
### Logging
|
||||
|
||||
- fix [Issue #838](https://github.com/benoitc/gunicorn/issues/838): statsd logger, send statsd timing metrics in milliseconds
|
||||
- fix [Issue #839](https://github.com/benoitc/gunicorn/issues/839): statsd logger, allows for empty log message while pushing
|
||||
metrics and restore worker number in DEBUG logs
|
||||
- fix [Issue #850](https://github.com/benoitc/gunicorn/issues/850): add timezone to logging
|
||||
- fix [Issue #853](https://github.com/benoitc/gunicorn/issues/853): Respect logger_class setting unless statsd is on
|
||||
|
||||
### AioHttp worker
|
||||
|
||||
- fix [Issue #830](https://github.com/benoitc/gunicorn/issues/830) make sure gaiohttp worker is shipped with gunicorn.
|
||||
|
||||
## 19.1 / 2014-07-26
|
||||
|
||||
### Changes
|
||||
|
||||
### Core
|
||||
|
||||
- fix [Issue #785](https://github.com/benoitc/gunicorn/issues/785): handle binary type address given to a client socket address
|
||||
- fix graceful shutdown. make sure QUIT and TERMS signals are switched everywhere.
|
||||
- [Issue #799](https://github.com/benoitc/gunicorn/issues/799): fix support loading config from module
|
||||
- [Issue #805](https://github.com/benoitc/gunicorn/issues/805): fix check for file-like objects
|
||||
- fix [Issue #815](https://github.com/benoitc/gunicorn/issues/815): args validation in WSGIApplication.init
|
||||
- fix [Issue #787](https://github.com/benoitc/gunicorn/issues/787): check if we load a pyc file or not.
|
||||
|
||||
|
||||
### Tornado worker
|
||||
|
||||
- fix [Issue #771](https://github.com/benoitc/gunicorn/issues/771): support tornado 4.0
|
||||
- fix [Issue #783](https://github.com/benoitc/gunicorn/issues/783): x_headers error. The x-forwarded-headers option has been removed
|
||||
in `c4873681299212d6082cd9902740eef18c2f14f1
|
||||
<https://github.com/benoitc/gunicorn/commit/c4873681299212d6082cd9902740eef18c2f14f1>`_.
|
||||
The discussion is available on [PR #633](https://github.com/benoitc/gunicorn/pull/633).
|
||||
|
||||
|
||||
### AioHttp worker
|
||||
|
||||
- fix: fetch all body in input. fix [Issue #803](https://github.com/benoitc/gunicorn/issues/803)
|
||||
- fix: don't install the worker if python < 3.3
|
||||
- fix [Issue #822](https://github.com/benoitc/gunicorn/issues/822): Support UNIX sockets in gaiohttp worker
|
||||
|
||||
|
||||
### Async worker
|
||||
|
||||
- fix [Issue #790](https://github.com/benoitc/gunicorn/issues/790): StopIteration shouldn't be caught at this level.
|
||||
|
||||
|
||||
### Logging
|
||||
|
||||
- add statsd logging handler fix [Issue #748](https://github.com/benoitc/gunicorn/issues/748)
|
||||
|
||||
|
||||
### Paster
|
||||
|
||||
- fix [Issue #809](https://github.com/benoitc/gunicorn/issues/809): Set global logging configuration from a Paste config.
|
||||
|
||||
|
||||
### Extra
|
||||
|
||||
- fix RuntimeError in gunicorn.reloader ([Issue #807](https://github.com/benoitc/gunicorn/issues/807))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
- update faq: put a note on how `watch logs in the console
|
||||
<http://docs.gunicorn.org/en/latest/faq.html#why-i-don-t-see-any-logs-in-the-console>`_
|
||||
since many people asked for it.
|
||||
|
||||
|
||||
## 19.0 / 2014-06-12
|
||||
|
||||
Gunicorn 19.0 is a major release with new features and fixes. This
|
||||
version improve a lot the usage of Gunicorn with python 3 by adding `two
|
||||
new workers <http://docs.gunicorn.org/en/latest/design.html#asyncio-workers>`_
|
||||
to it: `gthread` a fully threaded async worker using futures and `gaiohttp` a
|
||||
worker using asyncio.
|
||||
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### Switch QUIT and TERM signals
|
||||
|
||||
With this change, when gunicorn receives a QUIT all the workers are
|
||||
killed immediately and exit and TERM is used for the graceful shutdown.
|
||||
|
||||
Note: the old behaviour was based on the NGINX but the new one is more
|
||||
correct according the following doc:
|
||||
|
||||
https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
|
||||
|
||||
also it is complying with the way the signals are sent by heroku:
|
||||
|
||||
https://devcenter.heroku.com/articles/python-faq#what-constraints-exist-when-developing-applications-on-heroku
|
||||
|
||||
### Deprecations
|
||||
|
||||
`run_gunicorn`, `gunicorn_django` and `gunicorn_paster` are now
|
||||
completely deprecated and will be removed in the next release. Use the
|
||||
`gunicorn` command instead.
|
||||
|
||||
|
||||
### Changes
|
||||
|
||||
### core
|
||||
|
||||
- add aiohttp worker named `gaiohttp` using asyncio. Full async worker
|
||||
on python 3.
|
||||
- fix HTTP-violating excess whitespace in write_error output
|
||||
- fix: try to log what happened in the worker after a timeout, add a
|
||||
`worker_abort` hook on SIGABRT signal.
|
||||
- fix: save listener socket name in workers so we can handle buffered
|
||||
keep-alive requests after the listener has closed.
|
||||
- add on_exit hook called just before exiting gunicorn.
|
||||
- add support for python 3.4
|
||||
- fix: do not swallow unexpected errors when reaping
|
||||
- fix: remove incompatible SSL option with python 2.6
|
||||
- add new async gthread worker and `--threads` options allows to set multiple
|
||||
threads to listen on connection
|
||||
- deprecate `gunicorn_django` and `gunicorn_paster`
|
||||
- switch QUIT and TERM signal
|
||||
- reap workers in SIGCHLD handler
|
||||
- add universal wheel support
|
||||
- use `email.utils.formatdate` in gunicorn.util.http_date
|
||||
- deprecate the `--debug` option
|
||||
- fix: log exceptions that occur after response start …
|
||||
- allows loading of applications from `.pyc` files (#693)
|
||||
- fix: issue #691, raw_env config file parsing
|
||||
- use a dynamic timeout to wait for the optimal time. (Reduce power
|
||||
usage)
|
||||
- fix python3 support when notifying the arbiter
|
||||
- add: honor $WEB_CONCURRENCY environment variable. Useful for heroku
|
||||
setups.
|
||||
- add: include tz offset in access log
|
||||
- add: include access logs in the syslog handler.
|
||||
- add --reload option for code reloading
|
||||
- add the capability to load `gunicorn.base.Application` without the loading of
|
||||
the arguments of the command line. It allows you to [embed gunicorn in your own application](custom.md).
|
||||
- improve: set wsgi.multithread to True for async workers
|
||||
- fix logging: make sure to redirect wsgi.errors when needed
|
||||
- add: syslog logging can now be done to a unix socket
|
||||
- fix logging: don't try to redirect stdout/stderr to the logfile.
|
||||
- fix logging: don't propagate log
|
||||
- improve logging: file option can be overridden by the gunicorn options
|
||||
`--error-logfile` and `--access-logfile` if they are given.
|
||||
- fix: don't override SERVER_* by the Host header
|
||||
- fix: handle_error
|
||||
- add more option to configure SSL
|
||||
- fix: sendfile with SSL
|
||||
- add: worker_int callback (to react on SIGTERM)
|
||||
- fix: don't depend on entry point for internal classes, now absolute
|
||||
modules path can be given.
|
||||
- fix: Error messages are now encoded in latin1
|
||||
- fix: request line length check
|
||||
- improvement: proxy_allow_ips: Allow proxy protocol if "*" specified
|
||||
- fix: run worker's `setup` method before setting num_workers
|
||||
- fix: FileWrapper inherit from `object` now
|
||||
- fix: Error messages are now encoded in latin1
|
||||
- fix: don't spam the console on SIGWINCH.
|
||||
- fix: logging -don't stringify T and D logging atoms (#621)
|
||||
- add support for the latest django version
|
||||
- deprecate `run_gunicorn` django option
|
||||
- fix: sys imported twice
|
||||
|
||||
|
||||
### gevent worker
|
||||
|
||||
- fix: make sure to stop all listeners
|
||||
- fix: monkey patching is now done in the worker
|
||||
- fix: "global name 'hub' is not defined"
|
||||
- fix: reinit `hub` on old versions of gevent
|
||||
- support gevent 1.0
|
||||
- fix: add subprocess in monkey patching
|
||||
- fix: add support for multiple listener
|
||||
|
||||
|
||||
### eventlet worker
|
||||
|
||||
- fix: merge duplicate EventletWorker.init_process method (fixes #657)
|
||||
- fix: missing errno import for eventlet sendfile patch
|
||||
- fix: add support for multiple listener
|
||||
|
||||
|
||||
### tornado worker
|
||||
|
||||
- add graceful stop support
|
||||
187
docs/content/2015-news.md
Normal file
187
docs/content/2015-news.md
Normal file
@ -0,0 +1,187 @@
|
||||
<span id="news-2015"></span>
|
||||
# Changelog - 2015
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes.
|
||||
|
||||
|
||||
## 19.4.3 / 2015/12/30
|
||||
|
||||
- fix: don't check if a file is writable using os.stat with SELINUX ([Issue #1171](https://github.com/benoitc/gunicorn/issues/1171))
|
||||
|
||||
## 19.4.2 / 2015/12/29
|
||||
|
||||
### Core
|
||||
|
||||
- improvement: handle HaltServer in manage_workers ([Issue #1095](https://github.com/benoitc/gunicorn/issues/1095))
|
||||
- fix: Do not rely on sendfile sending requested count ([Issue #1155](https://github.com/benoitc/gunicorn/issues/1155))
|
||||
- fix: claridy --no-sendfile default ([Issue #1156](https://github.com/benoitc/gunicorn/issues/1156))
|
||||
- fix: LoggingCatch sendfile failure from no file descriptor ([Issue #1160](https://github.com/benoitc/gunicorn/issues/1160))
|
||||
|
||||
### Logging
|
||||
|
||||
- fix: Always send access log to syslog if syslog is on
|
||||
- fix: check auth before trying to own a file ([Issue #1157](https://github.com/benoitc/gunicorn/issues/1157))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
- fix: Fix Slowloris broken link. ([Issue #1142](https://github.com/benoitc/gunicorn/issues/1142))
|
||||
- Tweak markup in faq.rst
|
||||
|
||||
### Testing
|
||||
|
||||
- fix: gaiohttp test ([Issue #1164](https://github.com/benoitc/gunicorn/issues/1164))
|
||||
|
||||
## 19.4.1 / 2015/11/25
|
||||
|
||||
- fix tornado worker ([Issue #1154](https://github.com/benoitc/gunicorn/issues/1154))
|
||||
|
||||
## 19.4.0 / 2015/11/20
|
||||
|
||||
### Core
|
||||
|
||||
- fix: make sure that a user is able to access to the logs after dropping a
|
||||
privilege ([Issue #1116](https://github.com/benoitc/gunicorn/issues/1116))
|
||||
- improvement: inherit the `Exception` class where it needs to be ([Issue #997](https://github.com/benoitc/gunicorn/issues/997))
|
||||
- fix: make sure headers are always encoded as latin1 RFC 2616 ([Issue #1102](https://github.com/benoitc/gunicorn/issues/1102))
|
||||
- improvement: reduce arbiter noise ([Issue #1078](https://github.com/benoitc/gunicorn/issues/1078))
|
||||
- fix: don't close the unix socket when the worker exit ([Issue #1088](https://github.com/benoitc/gunicorn/issues/1088))
|
||||
- improvement: Make last logged worker count an explicit instance var ([Issue #1078](https://github.com/benoitc/gunicorn/issues/1078))
|
||||
- improvement: prefix config file with its type ([Issue #836](https://github.com/benoitc/gunicorn/issues/836))
|
||||
- improvement: pidfile handing ([Issue #1042](https://github.com/benoitc/gunicorn/issues/1042))
|
||||
- fix: catch OSError as well as ValueError on race condition ([Issue #1052](https://github.com/benoitc/gunicorn/issues/1052))
|
||||
- improve support of ipv6 by backporting urlparse.urlsplit from Python 2.7 to
|
||||
Python 2.6.
|
||||
- fix: raise InvalidRequestLine when the line contains malicious data
|
||||
([Issue #1023](https://github.com/benoitc/gunicorn/issues/1023))
|
||||
- fix: fix argument to disable sendfile
|
||||
- fix: add gthread to the list of supported workers ([Issue #1011](https://github.com/benoitc/gunicorn/issues/1011))
|
||||
- improvement: retry socket binding up to five times upon EADDRNOTAVAIL
|
||||
([Issue #1004](https://github.com/benoitc/gunicorn/issues/1004))
|
||||
- **breaking change**: only honor headers that can be encoded in ascii to comply to
|
||||
the RFC 7230 (See [Issue #1151](https://github.com/benoitc/gunicorn/issues/1151)).
|
||||
|
||||
### Logging
|
||||
|
||||
- add new parameters to access log ([Issue #1132](https://github.com/benoitc/gunicorn/issues/1132))
|
||||
- fix: make sure that files handles are correctly reopened on HUP
|
||||
([Issue #627](https://github.com/benoitc/gunicorn/issues/627))
|
||||
- include request URL in error message ([Issue #1071](https://github.com/benoitc/gunicorn/issues/1071))
|
||||
- get username in access logs ([Issue #1069](https://github.com/benoitc/gunicorn/issues/1069))
|
||||
- fix statsd logging support on Python 3 ([Issue #1010](https://github.com/benoitc/gunicorn/issues/1010))
|
||||
|
||||
### Testing
|
||||
|
||||
- use last version of mock.
|
||||
- many fixes in Travis CI support
|
||||
- miscellaneous improvements in tests
|
||||
|
||||
### Thread worker
|
||||
|
||||
- fix: Fix self.nr usage in ThreadedWorker so that auto restart works as
|
||||
expected ([Issue #1031](https://github.com/benoitc/gunicorn/issues/1031))
|
||||
|
||||
### Gevent worker
|
||||
|
||||
- fix quit signal handling ([Issue #1128](https://github.com/benoitc/gunicorn/issues/1128))
|
||||
- add support for Python 3 ([Issue #1066](https://github.com/benoitc/gunicorn/issues/1066))
|
||||
- fix: make graceful shutdown thread-safe ([Issue #1032](https://github.com/benoitc/gunicorn/issues/1032))
|
||||
|
||||
### Tornado worker
|
||||
|
||||
- fix ssl options ([Issue #1146](https://github.com/benoitc/gunicorn/issues/1146), [Issue #1135](https://github.com/benoitc/gunicorn/issues/1135))
|
||||
- don't check timeout when stopping gracefully ([Issue #1106](https://github.com/benoitc/gunicorn/issues/1106))
|
||||
|
||||
### AIOHttp worker
|
||||
|
||||
- add SSL support ([Issue #1105](https://github.com/benoitc/gunicorn/issues/1105))
|
||||
|
||||
### Documentation
|
||||
|
||||
- fix link to proc name setting ([Issue #1144](https://github.com/benoitc/gunicorn/issues/1144))
|
||||
- fix worker class documentation ([Issue #1141](https://github.com/benoitc/gunicorn/issues/1141), [Issue #1104](https://github.com/benoitc/gunicorn/issues/1104))
|
||||
- clarify graceful timeout documentation ([Issue #1137](https://github.com/benoitc/gunicorn/issues/1137))
|
||||
- don't duplicate NGINX config files examples ([Issue #1050](https://github.com/benoitc/gunicorn/issues/1050), [Issue #1048](https://github.com/benoitc/gunicorn/issues/1048))
|
||||
- add `web.py` framework example ([Issue #1117](https://github.com/benoitc/gunicorn/issues/1117))
|
||||
- update Debian/Ubuntu installations instructions ([Issue #1112](https://github.com/benoitc/gunicorn/issues/1112))
|
||||
- clarify `pythonpath` setting description ([Issue #1080](https://github.com/benoitc/gunicorn/issues/1080))
|
||||
- tweak some example for python3
|
||||
- clarify `sendfile` documentation
|
||||
- miscellaneous typos in source code comments (thanks!)
|
||||
- clarify why REMOTE_ADD may not be the user's IP address ([Issue #1037](https://github.com/benoitc/gunicorn/issues/1037))
|
||||
|
||||
|
||||
### Misc
|
||||
|
||||
- fix: reloader should survive SyntaxError ([Issue #994](https://github.com/benoitc/gunicorn/issues/994))
|
||||
- fix: expose the reloader class to the worker.
|
||||
|
||||
|
||||
|
||||
## 19.3.0 / 2015/03/06
|
||||
|
||||
### Core
|
||||
|
||||
- fix: [Issue #978](https://github.com/benoitc/gunicorn/issues/978) make sure a listener is inheritable
|
||||
- add `check_config` class method to workers
|
||||
- fix: [Issue #983](https://github.com/benoitc/gunicorn/issues/983) fix select timeout in sync worker with multiple
|
||||
connections
|
||||
- allows workers to access to the reloader. close [Issue #984](https://github.com/benoitc/gunicorn/issues/984)
|
||||
- raise TypeError instead of AssertionError
|
||||
|
||||
### Logging
|
||||
|
||||
- make Logger.loglevel a class attribute
|
||||
|
||||
### Documentation
|
||||
|
||||
- fix: [Issue #988](https://github.com/benoitc/gunicorn/issues/988) fix syntax errors in examples/gunicorn_rc
|
||||
|
||||
|
||||
## 19.2.1 / 2015/02/4
|
||||
|
||||
### Logging
|
||||
|
||||
- expose loglevel in the Logger class
|
||||
|
||||
### AsyncIO worker (gaiohttp.md)
|
||||
|
||||
- fix [Issue #977](https://github.com/benoitc/gunicorn/issues/977) fix initial crash
|
||||
|
||||
### Documentation
|
||||
|
||||
- document security mailing-list in the contributing page.
|
||||
|
||||
## 19.2 / 2015/01/30
|
||||
|
||||
### Core
|
||||
|
||||
- optimize the sync workers when listening on a single interface
|
||||
- add `--sendfile` settings to enable/disable sendfile. fix [Issue #856](https://github.com/benoitc/gunicorn/issues/856) .
|
||||
- add the selectors module to the code base. [Issue #886](https://github.com/benoitc/gunicorn/issues/886)
|
||||
- add `--max-requests-jitter` setting to set the maximum jitter to add to the
|
||||
max-requests setting.
|
||||
- fix [Issue #899](https://github.com/benoitc/gunicorn/issues/899) propagate proxy_protocol_info to keep-alive requests
|
||||
- fix [Issue #863](https://github.com/benoitc/gunicorn/issues/863) worker timeout: dynamic timeout has been removed
|
||||
- fix: Avoid world writable file
|
||||
|
||||
### Logging
|
||||
|
||||
- fix [Issue #941](https://github.com/benoitc/gunicorn/issues/941) set logconfig default to paster more trivially
|
||||
- add statsd-prefix config setting: set the prefix to use when emitting statsd
|
||||
metrics
|
||||
- [Issue #832](https://github.com/benoitc/gunicorn/issues/832) log to console by default
|
||||
|
||||
### Thread Worker
|
||||
|
||||
- fix [Issue #908](https://github.com/benoitc/gunicorn/issues/908) make sure the worker can continue to accept requests
|
||||
|
||||
### Eventlet Worker
|
||||
|
||||
- fix [Issue #867](https://github.com/benoitc/gunicorn/issues/867) Fix eventlet shutdown to actively shut down the workers.
|
||||
|
||||
### Documentation
|
||||
|
||||
Many improvements and fixes have been done, see the detailed changelog for
|
||||
more information.
|
||||
79
docs/content/2016-news.md
Normal file
79
docs/content/2016-news.md
Normal file
@ -0,0 +1,79 @@
|
||||
<span id="news-2016"></span>
|
||||
# Changelog - 2016
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
## 19.6.0 / 2016/05/21
|
||||
|
||||
### Core & Logging
|
||||
|
||||
- improvement of the binary upgrade behaviour using USR2: remove file locking ([Issue #1270](https://github.com/benoitc/gunicorn/issues/1270))
|
||||
- add the ``--capture-output`` setting to capture stdout/stderr tot the log
|
||||
file ([Issue #1271](https://github.com/benoitc/gunicorn/issues/1271))
|
||||
- Allow disabling ``sendfile()`` via the ``SENDFILE`` environment variable
|
||||
([Issue #1252](https://github.com/benoitc/gunicorn/issues/1252))
|
||||
- fix reload under pycharm ([Issue #1129](https://github.com/benoitc/gunicorn/issues/1129))
|
||||
|
||||
### Workers
|
||||
|
||||
- fix: make sure to remove the signal from the worker pipe ([Issue #1269](https://github.com/benoitc/gunicorn/issues/1269))
|
||||
- fix: **gthread** worker, handle removed socket in the select loop
|
||||
([Issue #1258](https://github.com/benoitc/gunicorn/issues/1258))
|
||||
|
||||
## 19.5.0 / 2016/05/10
|
||||
|
||||
### Core
|
||||
|
||||
- fix: Ensure response to HEAD request won't have message body
|
||||
- fix: lock domain socket and remove on last arbiter exit ([Issue #1220](https://github.com/benoitc/gunicorn/issues/1220))
|
||||
- improvement: use EnvironmentError instead of socket.error ([Issue #939](https://github.com/benoitc/gunicorn/issues/939))
|
||||
- add: new ``FORWARDED_ALLOW_IPS`` environment variable ([Issue #1205](https://github.com/benoitc/gunicorn/issues/1205))
|
||||
- fix: infinite recursion when destroying sockets ([Issue #1219](https://github.com/benoitc/gunicorn/issues/1219))
|
||||
- fix: close sockets on shutdown ([Issue #922](https://github.com/benoitc/gunicorn/issues/922))
|
||||
- fix: clean up sys.exc_info calls to drop circular refs ([Issue #1228](https://github.com/benoitc/gunicorn/issues/1228))
|
||||
- fix: do post_worker_init after load_wsgi ([Issue #1248](https://github.com/benoitc/gunicorn/issues/1248))
|
||||
|
||||
### Workers
|
||||
|
||||
- fix access logging in gaiohttp worker ([Issue #1193](https://github.com/benoitc/gunicorn/issues/1193))
|
||||
- eventlet: handle QUIT in a new coroutine ([Issue #1217](https://github.com/benoitc/gunicorn/issues/1217))
|
||||
- gevent: remove obsolete exception clauses in run ([Issue #1218](https://github.com/benoitc/gunicorn/issues/1218))
|
||||
- tornado: fix extra "Server" response header ([Issue #1246](https://github.com/benoitc/gunicorn/issues/1246))
|
||||
- fix: unblock the wait loop under python 3.5 in sync worker ([Issue #1256](https://github.com/benoitc/gunicorn/issues/1256))
|
||||
|
||||
### Logging
|
||||
|
||||
- fix: log message for listener reloading ([Issue #1181](https://github.com/benoitc/gunicorn/issues/1181))
|
||||
- Let logging module handle traceback printing ([Issue #1201](https://github.com/benoitc/gunicorn/issues/1201))
|
||||
- improvement: Allow configuring logger_class with statsd_host ([Issue #1188](https://github.com/benoitc/gunicorn/issues/1188))
|
||||
- fix: traceback formatting ([Issue #1235](https://github.com/benoitc/gunicorn/issues/1235))
|
||||
- fix: print error logs on stderr and access logs on stdout ([Issue #1184](https://github.com/benoitc/gunicorn/issues/1184))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
- Simplify installation instructions in gunicorn.org ([Issue #1072](https://github.com/benoitc/gunicorn/issues/1072))
|
||||
- Fix URL and default worker type in example_config ([Issue #1209](https://github.com/benoitc/gunicorn/issues/1209))
|
||||
- update django doc url to 1.8 lts ([Issue #1213](https://github.com/benoitc/gunicorn/issues/1213))
|
||||
- fix: miscellaneous wording corrections ([Issue #1216](https://github.com/benoitc/gunicorn/issues/1216))
|
||||
- Add PSF License Agreement of selectors.py to NOTICE (:issue: `1226`)
|
||||
- document LOGGING overriding ([Issue #1051](https://github.com/benoitc/gunicorn/issues/1051))
|
||||
- put a note that error logs are only errors from Gunicorn ([Issue #1124](https://github.com/benoitc/gunicorn/issues/1124))
|
||||
- add a note about the requirements of the threads workers under python 2.x ([Issue #1200](https://github.com/benoitc/gunicorn/issues/1200))
|
||||
- add access_log_format to config example ([Issue #1251](https://github.com/benoitc/gunicorn/issues/1251))
|
||||
|
||||
### Tests
|
||||
|
||||
- Use more pytest.raises() in test_http.py
|
||||
|
||||
|
||||
## 19.4.5 / 2016/01/05
|
||||
|
||||
- fix: NameError fileno in gunicorn.http.wsgi ([Issue #1178](https://github.com/benoitc/gunicorn/issues/1178))
|
||||
|
||||
## 19.4.4 / 2016/01/04
|
||||
|
||||
- fix: check if a fileobject can be used with sendfile(2.md) ([Issue #1174](https://github.com/benoitc/gunicorn/issues/1174))
|
||||
- doc: be more descriptive in errorlog option ([Issue #1173](https://github.com/benoitc/gunicorn/issues/1173))
|
||||
42
docs/content/2017-news.md
Normal file
42
docs/content/2017-news.md
Normal file
@ -0,0 +1,42 @@
|
||||
<span id="news-2017"></span>
|
||||
# Changelog - 2017
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
## 19.7.1 / 2017/03/21
|
||||
|
||||
- fix: continue if SO_REUSEPORT seems to be available but fails ([Issue #1480](https://github.com/benoitc/gunicorn/issues/1480))
|
||||
- fix: support non-decimal values for the umask command line option ([Issue #1325](https://github.com/benoitc/gunicorn/issues/1325))
|
||||
|
||||
## 19.7.0 / 2017/03/01
|
||||
|
||||
- The previously deprecated ``gunicorn_django`` command has been removed.
|
||||
Use the [gunicorn-cmd](run.md#gunicorn) command-line interface instead.
|
||||
- The previously deprecated ``django_settings`` setting has been removed.
|
||||
Use the [raw-env](reference/settings.md#raw_env) setting instead.
|
||||
- The default value of [ssl-version](reference/settings.md#ssl_version) has been changed from
|
||||
``ssl.PROTOCOL_TLSv1`` to ``ssl.PROTOCOL_SSLv23``.
|
||||
- fix: initialize the group access list when initgroups is set ([Issue #1297](https://github.com/benoitc/gunicorn/issues/1297))
|
||||
- add environment variables to gunicorn access log format ([Issue #1291](https://github.com/benoitc/gunicorn/issues/1291))
|
||||
- add --paste-global-conf option ([Issue #1304](https://github.com/benoitc/gunicorn/issues/1304))
|
||||
- fix: print access logs to STDOUT ([Issue #1184](https://github.com/benoitc/gunicorn/issues/1184))
|
||||
- remove upper limit on max header size config ([Issue #1313](https://github.com/benoitc/gunicorn/issues/1313))
|
||||
- fix: print original exception on AppImportError ([Issue #1334](https://github.com/benoitc/gunicorn/issues/1334))
|
||||
- use SO_REUSEPORT if available ([Issue #1344](https://github.com/benoitc/gunicorn/issues/1344))
|
||||
- `fix leak <https://github.com/benoitc/gunicorn/commit/b4c41481e2d5ef127199a4601417a6819053c3fd>`_ of duplicate file descriptor for bound sockets.
|
||||
- add --reload-engine option, support inotify and other backends ([Issue #1368](https://github.com/benoitc/gunicorn/issues/1368), [Issue #1459](https://github.com/benoitc/gunicorn/issues/1459))
|
||||
- fix: reject request with invalid HTTP versions
|
||||
- add ``child_exit`` callback ([Issue #1394](https://github.com/benoitc/gunicorn/issues/1394))
|
||||
- add support for eventlets _AlreadyHandled object ([Issue #1406](https://github.com/benoitc/gunicorn/issues/1406))
|
||||
- format boot tracebacks properly with reloader ([Issue #1408](https://github.com/benoitc/gunicorn/issues/1408))
|
||||
- refactor socket activation and fd inheritance for better support of SystemD ([Issue #1310](https://github.com/benoitc/gunicorn/issues/1310))
|
||||
- fix: o fds are given by default in gunicorn ([Issue #1423](https://github.com/benoitc/gunicorn/issues/1423))
|
||||
- add ability to pass settings to GUNICORN_CMD_ARGS environment variable which helps in container world ([Issue #1385](https://github.com/benoitc/gunicorn/issues/1385))
|
||||
- fix: catch access denied to pid file ([Issue #1091](https://github.com/benoitc/gunicorn/issues/1091))
|
||||
- many additions and improvements to the documentation
|
||||
|
||||
### Breaking Change
|
||||
|
||||
- **Python 2.6.0** is the last supported version
|
||||
64
docs/content/2018-news.md
Normal file
64
docs/content/2018-news.md
Normal file
@ -0,0 +1,64 @@
|
||||
<span id="news-2018"></span>
|
||||
# Changelog - 2018
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
## 19.9.0 / 2018/07/03
|
||||
|
||||
- fix: address a regression that prevented syslog support from working
|
||||
([Issue #1668](https://github.com/benoitc/gunicorn/issues/1668), [PR #1773](https://github.com/benoitc/gunicorn/pull/1773))
|
||||
- fix: correctly set `REMOTE_ADDR` on versions of Python 3 affected by
|
||||
`Python Issue 30205 <https://bugs.python.org/issue30205>`_
|
||||
([Issue #1755](https://github.com/benoitc/gunicorn/issues/1755), [PR #1796](https://github.com/benoitc/gunicorn/pull/1796))
|
||||
- fix: show zero response length correctly in access log ([PR #1787](https://github.com/benoitc/gunicorn/pull/1787))
|
||||
- fix: prevent raising `AttributeError` when ``--reload`` is not passed
|
||||
in case of a `SyntaxError` raised from the WSGI application.
|
||||
([Issue #1805](https://github.com/benoitc/gunicorn/issues/1805), [PR #1806](https://github.com/benoitc/gunicorn/pull/1806))
|
||||
- The internal module ``gunicorn.workers.async`` was renamed to ``gunicorn.workers.base_async``
|
||||
since ``async`` is now a reserved word in Python 3.7.
|
||||
([PR #1527](https://github.com/benoitc/gunicorn/pull/1527))
|
||||
|
||||
## 19.8.1 / 2018/04/30
|
||||
|
||||
- fix: secure scheme headers when bound to a unix socket
|
||||
([Issue #1766](https://github.com/benoitc/gunicorn/issues/1766), [PR #1767](https://github.com/benoitc/gunicorn/pull/1767))
|
||||
|
||||
## 19.8.0 / 2018/04/28
|
||||
|
||||
- Eventlet 0.21.0 support ([Issue #1584](https://github.com/benoitc/gunicorn/issues/1584))
|
||||
- Tornado 5 support ([Issue #1728](https://github.com/benoitc/gunicorn/issues/1728), [PR #1752](https://github.com/benoitc/gunicorn/pull/1752))
|
||||
- support watching additional files with ``--reload-extra-file``
|
||||
([PR #1527](https://github.com/benoitc/gunicorn/pull/1527))
|
||||
- support configuring logging with a dictionary with ``--logging-config-dict``
|
||||
([Issue #1087](https://github.com/benoitc/gunicorn/issues/1087), [PR #1110](https://github.com/benoitc/gunicorn/pull/1110), [PR #1602](https://github.com/benoitc/gunicorn/pull/1602))
|
||||
- add support for the ``--config`` flag in the ``GUNICORN_CMD_ARGS`` environment
|
||||
variable ([Issue #1576](https://github.com/benoitc/gunicorn/issues/1576), [PR #1581](https://github.com/benoitc/gunicorn/pull/1581))
|
||||
- disable ``SO_REUSEPORT`` by default and add the ``--reuse-port`` setting
|
||||
([Issue #1553](https://github.com/benoitc/gunicorn/issues/1553), [Issue #1603](https://github.com/benoitc/gunicorn/issues/1603), [PR #1669](https://github.com/benoitc/gunicorn/pull/1669))
|
||||
- fix: installing `inotify` on MacOS no longer breaks the reloader
|
||||
([Issue #1540](https://github.com/benoitc/gunicorn/issues/1540), [PR #1541](https://github.com/benoitc/gunicorn/pull/1541))
|
||||
- fix: do not throw ``TypeError`` when ``SO_REUSEPORT`` is not available
|
||||
([Issue #1501](https://github.com/benoitc/gunicorn/issues/1501), [PR #1491](https://github.com/benoitc/gunicorn/pull/1491))
|
||||
- fix: properly decode HTTP paths containing certain non-ASCII characters
|
||||
([Issue #1577](https://github.com/benoitc/gunicorn/issues/1577), [PR #1578](https://github.com/benoitc/gunicorn/pull/1578))
|
||||
- fix: remove whitespace when logging header values under gevent ([PR #1607](https://github.com/benoitc/gunicorn/pull/1607))
|
||||
- fix: close unlinked temporary files ([Issue #1327](https://github.com/benoitc/gunicorn/issues/1327), [PR #1428](https://github.com/benoitc/gunicorn/pull/1428))
|
||||
- fix: parse ``--umask=0`` correctly ([Issue #1622](https://github.com/benoitc/gunicorn/issues/1622), [PR #1632](https://github.com/benoitc/gunicorn/pull/1632))
|
||||
- fix: allow loading applications using relative file paths
|
||||
([Issue #1349](https://github.com/benoitc/gunicorn/issues/1349), [PR #1481](https://github.com/benoitc/gunicorn/pull/1481))
|
||||
- fix: force blocking mode on the gevent sockets ([Issue #880](https://github.com/benoitc/gunicorn/issues/880), [PR #1616](https://github.com/benoitc/gunicorn/pull/1616))
|
||||
- fix: preserve leading `/` in request path ([Issue #1512](https://github.com/benoitc/gunicorn/issues/1512), [PR #1511](https://github.com/benoitc/gunicorn/pull/1511))
|
||||
- fix: forbid contradictory secure scheme headers
|
||||
- fix: handle malformed basic authentication headers in access log
|
||||
([Issue #1683](https://github.com/benoitc/gunicorn/issues/1683), [PR #1684](https://github.com/benoitc/gunicorn/pull/1684))
|
||||
- fix: defer handling of ``USR1`` signal to a new greenlet under gevent
|
||||
([Issue #1645](https://github.com/benoitc/gunicorn/issues/1645), [PR #1651](https://github.com/benoitc/gunicorn/pull/1651))
|
||||
- fix: the threaded worker would sometimes close the wrong keep-alive
|
||||
connection under Python 2 ([Issue #1698](https://github.com/benoitc/gunicorn/issues/1698), [PR #1699](https://github.com/benoitc/gunicorn/pull/1699))
|
||||
- fix: re-open log files on ``USR1`` signal using ``handler._open`` to
|
||||
support subclasses of ``FileHandler`` ([Issue #1739](https://github.com/benoitc/gunicorn/issues/1739), [PR #1742](https://github.com/benoitc/gunicorn/pull/1742))
|
||||
- deprecation: the ``gaiohttp`` worker is deprecated, see the
|
||||
[worker-class](reference/settings.md#worker_class) documentation for more information
|
||||
([Issue #1338](https://github.com/benoitc/gunicorn/issues/1338), [PR #1418](https://github.com/benoitc/gunicorn/pull/1418), [PR #1569](https://github.com/benoitc/gunicorn/pull/1569))
|
||||
112
docs/content/2019-news.md
Normal file
112
docs/content/2019-news.md
Normal file
@ -0,0 +1,112 @@
|
||||
<span id="news-2019"></span>
|
||||
# Changelog - 2019
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
## 20.0.4 / 2019/11/26
|
||||
|
||||
- fix binding a socket using the file descriptor
|
||||
- remove support for the `bdist_rpm` build
|
||||
|
||||
## 20.0.3 / 2019/11/24
|
||||
|
||||
- fixed load of a config file without a Python extension
|
||||
- fixed `socketfromfd.fromfd` when defaults are not set
|
||||
|
||||
!!! note
|
||||
```
|
||||
## 20.0.2 / 2019/11/23
|
||||
|
||||
- fix changelog
|
||||
|
||||
## 20.0.1 / 2019/11/23
|
||||
|
||||
- fixed the way the config module is loaded. `__file__` is now available
|
||||
- fixed `wsgi.input_terminated`. It is always true.
|
||||
- use the highest protocol version of openssl by default
|
||||
- only support Python >= 3.5
|
||||
- added `__repr__` method to `Config` instance
|
||||
- fixed support of AIX platform and musl libc in `socketfromfd.fromfd` function
|
||||
- fixed support of applications loaded from a factory function
|
||||
- fixed chunked encoding support to prevent any `request smuggling <https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn>`_
|
||||
- Capture os.sendfile before patching in gevent and eventlet workers.
|
||||
fix `RecursionError`.
|
||||
- removed locking in reloader when adding new files
|
||||
- load the WSGI application before the loader to pick up all files
|
||||
|
||||
{note}
|
||||
as documented in Flask and other places.
|
||||
```
|
||||
## 19.10.0 / 2019/11/23
|
||||
|
||||
- unblock select loop during reload of a sync worker
|
||||
- security fix: http desync attack
|
||||
- handle `wsgi.input_terminated`
|
||||
- added support for str and bytes in unix socket addresses
|
||||
- fixed `max_requests` setting
|
||||
- headers values are now encoded as LATN1, not ASCII
|
||||
- fixed `InotifyReloadeder`: handle `module.__file__` is None
|
||||
- fixed compatibility with tornado 6
|
||||
- fixed root logging
|
||||
- Prevent removalof unix sockets from `reuse_port`
|
||||
- Clear tornado ioloop before os.fork
|
||||
- Miscellaneous fixes and improvement for linting using Pylint
|
||||
|
||||
## 20.0 / 2019/10/30
|
||||
|
||||
- Fixed `fdopen` `RuntimeWarning` in Python 3.8
|
||||
- Added check and exception for str type on value in Response process_headers method.
|
||||
- Ensure WSGI header value is string before conducting regex search on it.
|
||||
- Added pypy3 to list of tested environments
|
||||
- Grouped `StopIteration` and `KeyboardInterrupt` exceptions with same body together in Arbiter.run()
|
||||
- Added `setproctitle` module to `extras_require` in setup.py
|
||||
- Avoid unnecessary chown of temporary files
|
||||
- Logging: Handle auth type case insensitively
|
||||
- Removed `util.import_module`
|
||||
- Removed fallback for `types.SimpleNamespace` in tests utils
|
||||
- Use `SourceFileLoader` instead instead of `execfile_`
|
||||
- Use `importlib` instead of `__import__` and eval`
|
||||
- Fixed eventlet patching
|
||||
- Added optional `datadog <https://www.datadoghq.com>`_ tags for statsd metrics
|
||||
- Header values now are encoded using latin-1, not ascii.
|
||||
- Rewritten `parse_address` util added test
|
||||
- Removed redundant super() arguments
|
||||
- Simplify `futures` import in gthread module
|
||||
- Fixed worker_connections` setting to also affects the Gthread worker type
|
||||
- Fixed setting max_requests
|
||||
- Bump minimum Eventlet and Gevent versions to 0.24 and 1.4
|
||||
- Use Python default SSL cipher list by default
|
||||
- handle `wsgi.input_terminated` extension
|
||||
- Simplify Paste Deployment documentation
|
||||
- Fix root logging: root and logger are same level.
|
||||
- Fixed typo in ssl_version documentation
|
||||
- Documented systemd deployment unit examples
|
||||
- Added systemd sd_notify support
|
||||
- Fixed typo in gthread.py
|
||||
- Added `tornado <https://www.tornadoweb.org/>`_ 5 and 6 support
|
||||
- Declare our setuptools dependency
|
||||
- Added support to `--bind` to open file descriptors
|
||||
- Document how to serve WSGI app modules from Gunicorn
|
||||
- Provide guidance on X-Forwarded-For access log in documentation
|
||||
- Add support for named constants in the `--ssl-version` flag
|
||||
- Clarify log format usage of header & environment in documentation
|
||||
- Fixed systemd documentation to properly setup gunicorn unix socket
|
||||
- Prevent removal unix socket for reuse_port
|
||||
- Fix `ResourceWarning` when reading a Python config module
|
||||
- Remove unnecessary call to dict keys method
|
||||
- Support str and bytes for UNIX socket addresses
|
||||
- fixed `InotifyReloadeder`: handle `module.__file__` is None
|
||||
- `/dev/shm` as a convenient alternative to making your own tmpfs mount in fchmod FAQ
|
||||
- fix examples to work on python3
|
||||
- Fix typo in `--max-requests` documentation
|
||||
- Clear tornado ioloop before os.fork
|
||||
- Miscellaneous fixes and improvement for linting using Pylint
|
||||
|
||||
### Breaking Change
|
||||
|
||||
- Removed gaiohttp worker
|
||||
- Drop support for Python 2.x
|
||||
- Drop support for EOL Python 3.2 and 3.3
|
||||
- Drop support for Paste Deploy server blocks
|
||||
7
docs/content/2020-news.md
Normal file
7
docs/content/2020-news.md
Normal file
@ -0,0 +1,7 @@
|
||||
<span id="news-2020"></span>
|
||||
# Changelog - 2020
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
51
docs/content/2021-news.md
Normal file
51
docs/content/2021-news.md
Normal file
@ -0,0 +1,51 @@
|
||||
<span id="news-2021"></span>
|
||||
# Changelog - 2021
|
||||
|
||||
!!! note
|
||||
Please see [news](news.md) for the latest changes
|
||||
|
||||
|
||||
## 20.1.0 - 2021-02-12
|
||||
|
||||
- document WEB_CONCURRENCY is set by, at least, Heroku
|
||||
- capture peername from accept: Avoid calls to getpeername by capturing the peer name returned by
|
||||
accept
|
||||
- log a warning when a worker was terminated due to a signal
|
||||
- fix tornado usage with latest versions of Django
|
||||
- add support for python -m gunicorn
|
||||
- fix systemd socket activation example
|
||||
- allows to set wsgi application in config file using `wsgi_app`
|
||||
- document `--timeout = 0`
|
||||
- always close a connection when the number of requests exceeds the max requests
|
||||
- Disable keepalive during graceful shutdown
|
||||
- kill tasks in the gthread workers during upgrade
|
||||
- fix latency in gevent worker when accepting new requests
|
||||
- fix file watcher: handle errors when new worker reboot and ensure the list of files is kept
|
||||
- document the default name and path of the configuration file
|
||||
- document how variable impact configuration
|
||||
- document the `$PORT` environment variable
|
||||
- added milliseconds option to request_time in access_log
|
||||
- added PIP requirements to be used for example
|
||||
- remove version from the Server header
|
||||
- fix sendfile: use `socket.sendfile` instead of `os.sendfile`
|
||||
- reloader: use absolute path to prevent empty to prevent0 `InotifyError` when a file
|
||||
is added to the working directory
|
||||
- Add --print-config option to print the resolved settings at startup.
|
||||
- remove the `--log-dict-config` CLI flag because it never had a working format
|
||||
(the `logconfig_dict` setting in configuration files continues to work)
|
||||
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- minimum version is Python 3.5
|
||||
- remove version from the Server header
|
||||
|
||||
** Documentation **
|
||||
|
||||
|
||||
|
||||
** Others **
|
||||
|
||||
- miscellaneous changes in the code base to be a better citizen with Python 3
|
||||
- remove dead code
|
||||
- fix documentation generation
|
||||
36
docs/content/2023-news.md
Normal file
36
docs/content/2023-news.md
Normal file
@ -0,0 +1,36 @@
|
||||
<span id="news-2023"></span>
|
||||
# Changelog - 2023
|
||||
|
||||
## 21.2.0 - 2023-07-19
|
||||
|
||||
- fix thread worker: revert change considering connection as idle .
|
||||
|
||||
!!! note
|
||||
This is fixing the bad file description error.
|
||||
|
||||
21.1.0 - 2023-07-18
|
||||
|
||||
|
||||
===================
|
||||
|
||||
- fix thread worker: fix socket removal from the queue
|
||||
|
||||
## 21.0.1 - 2023-07-17
|
||||
|
||||
- fix documentation build
|
||||
|
||||
## 21.0.0 - 2023-07-17
|
||||
|
||||
- support python 3.11
|
||||
- fix gevent and eventlet workers
|
||||
- fix threads support (gththread.md): improve performance and unblock requests
|
||||
- SSL: now use SSLContext object
|
||||
- HTTP parser: miscellaneous fixes
|
||||
- remove unnecessary setuid calls
|
||||
- fix testing
|
||||
- improve logging
|
||||
- miscellaneous fixes to core engine
|
||||
|
||||
*** RELEASE NOTE ***
|
||||
|
||||
We made this release major to start our new release cycle. More info will be provided on our discussion forum.
|
||||
58
docs/content/2024-news.md
Normal file
58
docs/content/2024-news.md
Normal file
@ -0,0 +1,58 @@
|
||||
<span id="news-2024"></span>
|
||||
# Changelog - 2024
|
||||
|
||||
## 23.0.0 - 2024-08-10
|
||||
|
||||
- minor docs fixes ([PR #3217](https://github.com/benoitc/gunicorn/pull/3217), [PR #3089](https://github.com/benoitc/gunicorn/pull/3089), [PR #3167](https://github.com/benoitc/gunicorn/pull/3167))
|
||||
- worker_class parameter accepts a class ([PR #3079](https://github.com/benoitc/gunicorn/pull/3079))
|
||||
- fix deadlock if request terminated during chunked parsing ([PR #2688](https://github.com/benoitc/gunicorn/pull/2688))
|
||||
- permit receiving Transfer-Encodings: compress, deflate, gzip ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261))
|
||||
- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261))
|
||||
- sdist generation now explicitly excludes sphinx build folder ([PR #3257](https://github.com/benoitc/gunicorn/pull/3257))
|
||||
- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` ([PR #2336](https://github.com/benoitc/gunicorn/pull/2336))
|
||||
- raise correct Exception when encounting invalid chunked requests ([PR #3258](https://github.com/benoitc/gunicorn/pull/3258))
|
||||
- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192))
|
||||
- include IPv6 loopback address ``[::1]`` in default for [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) and [proxy-allow-ips](reference/settings.md#proxy_allow_ips) ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192))
|
||||
|
||||
!!! note
|
||||
- The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release
|
||||
- Review your [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) setting if you are still not seeing the SCRIPT_NAME transmitted
|
||||
- Review your [forwarder-headers](reference/settings.md#forwarder_headers) setting if you are missing headers after upgrading from a version prior to 22.0.0
|
||||
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- refuse requests where the uri field is empty ([PR #3255](https://github.com/benoitc/gunicorn/pull/3255))
|
||||
- refuse requests with invalid CR/LR/NUL in heade field values ([PR #3253](https://github.com/benoitc/gunicorn/pull/3253))
|
||||
- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 ([PR #3260](https://github.com/benoitc/gunicorn/pull/3260))
|
||||
- If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies.
|
||||
|
||||
## 22.0.0 - 2024-04-17
|
||||
|
||||
- use `utime` to notify workers liveness
|
||||
- migrate setup to pyproject.toml
|
||||
- fix numerous security vulnerabilities in HTTP parser (closing some request smuggling vectors)
|
||||
- parsing additional requests is no longer attempted past unsupported request framing
|
||||
- on HTTP versions < 1.1 support for chunked transfer is refused (only used in exploits)
|
||||
- requests conflicting configured or passed SCRIPT_NAME now produce a verbose error
|
||||
- Trailer fields are no longer inspected for headers indicating secure scheme
|
||||
- support Python 3.12
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- minimum version is Python 3.7
|
||||
- the limitations on valid characters in the HTTP method have been bounded to Internet Standards
|
||||
- requests specifying unsupported transfer coding (order.md) are refused by default (rare.md)
|
||||
- HTTP methods are no longer casefolded by default (IANA method registry contains none affected)
|
||||
- HTTP methods containing the number sign (#) are no longer accepted by default (rare.md)
|
||||
- HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported)
|
||||
- HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted
|
||||
- HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software
|
||||
- HTTP headers with empty field name are refused by default (no legitimate use cases, used in exploits)
|
||||
- requests with both Transfer-Encoding and Content-Length are refused by default (such a message might indicate an attempt to perform request smuggling)
|
||||
- empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies)
|
||||
|
||||
|
||||
### Security
|
||||
|
||||
- fix CVE-2024-1135
|
||||
119
docs/content/assets/gunicorn.svg
Normal file
119
docs/content/assets/gunicorn.svg
Normal file
@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
width="740.18402"
|
||||
height="161.62476"
|
||||
id="svg4375">
|
||||
<defs
|
||||
id="defs4377">
|
||||
<linearGradient
|
||||
x1="-403.07309"
|
||||
y1="-40.681377"
|
||||
x2="-560.61346"
|
||||
y2="-32.881535"
|
||||
id="linearGradient4343"
|
||||
xlink:href="#linearGradient3354-9"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3354-9">
|
||||
<stop
|
||||
id="stop3356-9"
|
||||
style="stop-color:#959595;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3358-9"
|
||||
style="stop-color:#cccccc;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="-403.07309"
|
||||
y1="-40.681377"
|
||||
x2="-560.61346"
|
||||
y2="-32.881535"
|
||||
id="linearGradient3269"
|
||||
xlink:href="#linearGradient3354-9"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata4380">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(215.61577,-659.72777)"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(0.95410088,0,0,1.0481072,336.12082,766.65951)"
|
||||
id="text3109-8-2-3-2"
|
||||
style="font-size:118.26729584px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#4d4d4d;fill-opacity:1;stroke:none;font-family:Century Gothic;-inkscape-font-specification:Century Gothic Bold">
|
||||
<path
|
||||
d="m -192.30737,-56.190303 15.93837,0 0,30.259797 c -2e-5,5.890292 0.40421,9.990375 1.2127,12.300261 0.80844,2.271427 2.09814,4.042355 3.8691,5.3127882 1.8094,1.2704632 4.02306,1.9056873 6.64098,1.9056742 2.61786,1.31e-5 4.83152,-0.6159618 6.64099,-1.8479265 1.84788,-1.2704333 3.21458,-3.1183579 4.10009,-5.5437799 0.65442,-1.809405 0.98166,-5.678498 0.98171,-11.607288 l 0,-30.779526 15.82287,0 0,26.621691 c -6e-5,10.972089 -0.86628,18.479283 -2.59865,22.5216047 -2.11747,4.9278127 -5.23585,8.7199081 -9.35513,11.3762975 -4.11938,2.6178955 -9.35517,3.9268422 -15.70737,3.9268438 -6.89126,-1.6e-6 -12.47353,-1.5399388 -16.74684,-4.6198163 -4.23484,-3.07987137 -7.21847,-7.3724463 -8.95089,-12.8777377 -1.23196,-3.811329 -1.84793,-10.741046 -1.84793,-20.789173 l 0,-26.15971"
|
||||
id="path2910-3"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m -130.62894,-56.190303 15.70737,0 0,6.409995 c 3.58033,-3.002821 6.8142,-5.081736 9.70161,-6.236752 2.92585,-1.193388 5.909485,-1.790114 8.950903,-1.790178 6.236704,6.4e-5 11.530238,2.175225 15.880619,6.52549 3.657292,3.695907 5.485968,9.162684 5.486031,16.400348 l 0,41.5205983 -15.591879,0 0,-27.5456543 c -4.9e-5,-7.507166 -0.346534,-12.492713 -1.039459,-14.956655 -0.65452,-2.463857 -1.828723,-4.331031 -3.52261,-5.601527 -1.655476,-1.308899 -3.71514,-1.963372 -6.179015,-1.963422 -3.1954,5e-5 -5.94804,1.078006 -8.25791,3.233871 -2.27144,2.117461 -3.84987,5.062591 -4.73531,8.835399 -0.46201,1.963458 -0.693,6.217534 -0.69298,12.762242 l 0,25.2357463 -15.70737,0 0,-62.8295013"
|
||||
id="path2912-9"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m -58.382674,-82.061274 c 2.771873,8.9e-5 5.139526,1.001048 7.102968,3.002881 2.001897,2.002004 3.002856,4.427405 3.00288,7.276211 -2.4e-5,2.810463 -0.981734,5.216615 -2.945133,7.218462 -1.963441,1.963492 -4.311845,2.945202 -7.04522,2.945133 -2.810399,6.9e-5 -5.216551,-1.000891 -7.218462,-3.00288 -1.963427,-2.040346 -2.945137,-4.504245 -2.945133,-7.391706 -4e-6,-2.771809 0.981706,-5.139462 2.945133,-7.102968 1.963413,-1.963334 4.331066,-2.945044 7.102967,-2.945133 m -7.911435,25.870971 15.82287,0 0,62.8295013 -15.82287,0 0,-62.8295013"
|
||||
id="path2914-9"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m 22.756753,-43.485808 -13.1087298,7.218463 c -2.4639564,-2.579352 -4.9086068,-4.369529 -7.3339592,-5.370536 -2.38695243,-1.000911 -5.1973376,-1.501391 -8.4311656,-1.501441 -5.8902994,5e-5 -10.6641044,1.770978 -14.3214284,5.312789 -3.618878,3.503402 -5.428304,8.007718 -5.428283,13.512962 -2.1e-5,5.351313 1.751657,9.720885 5.25504,13.108729 3.503331,3.3878798 8.103892,5.0818107 13.8016994,5.0817979 7.04517317,1.28e-5 12.5312,-2.4061391 16.4580968,-7.2184629 L 22.06378,-4.8525946 C 15.326486,3.8865605 5.8173728,8.2561324 -6.4635876,8.256134 -17.512676,8.2561324 -26.174822,4.9837658 -32.450051,-1.5609755 c -6.23676,-6.544725 -9.355133,-14.2059125 -9.355128,-22.9835855 -5e-6,-6.082721 1.520683,-11.684243 4.562068,-16.804582 3.041367,-5.120243 7.276194,-9.143329 12.704495,-12.06927 5.466754,-2.925821 11.568754,-4.388761 18.3060194,-4.388825 6.23670517,6.4e-5 11.838228,1.251263 16.8045846,3.7536 4.96624,2.463961 9.027824,5.986567 12.184765,10.56783"
|
||||
id="path2916-7"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m 61.798097,-57.807238 c 5.928721,6.4e-5 11.491744,1.482254 16.689087,4.446573 5.235731,2.964439 9.316569,6.987525 12.242523,12.06927 2.925814,5.08184 4.388768,10.567867 4.388838,16.458095 -7e-5,5.92879 -1.482264,11.472564 -4.446588,16.6313386 C 87.746013,-3.0431569 83.742165,0.99917828 78.660426,3.9250563 73.57858,6.8124412 67.977058,8.2561324 61.855845,8.256134 52.847175,8.2561324 45.147489,5.0607627 38.756764,-1.3299847 32.404509,-7.7592146 29.228388,-15.555147 29.228393,-24.717804 c -5e-6,-9.817069 3.599598,-17.997985 10.79882,-24.542774 6.313727,-5.697712 13.570681,-8.546596 21.770884,-8.54666 m 0.230991,14.841159 c -4.889338,5e-5 -8.970172,1.71323 -12.242513,5.139546 -3.233893,3.387906 -4.850827,7.738229 -4.850807,13.050981 -2e-5,5.466808 1.597664,9.894128 4.79306,13.281972 3.233842,3.3878795 7.314676,5.0818105 12.242513,5.0817974 4.927761,1.31e-5 9.027844,-1.7131671 12.30026,-5.1395454 3.272317,-3.426342 4.908505,-7.834413 4.908555,-13.224224 -5e-5,-5.389749 -1.616989,-9.759321 -4.850807,-13.108729 -3.19542,-3.387817 -7.295502,-5.081748 -12.300261,-5.081798"
|
||||
id="path2918-0"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m 101.59025,-56.190303 13.51297,0 0,7.911436 c 1.46292,-3.118318 3.40709,-5.485972 5.83251,-7.102968 2.42538,-1.616872 5.08177,-2.425339 7.96919,-2.425403 2.04038,6.4e-5 4.17705,0.539042 6.40999,1.616935 l -4.90855,13.570711 c -1.84796,-0.923913 -3.36865,-1.385895 -4.56207,-1.385945 -2.42543,5e-5 -4.4851,1.501489 -6.179,4.504321 -1.65546,3.002923 -2.48318,8.893183 -2.48316,17.670797 l 0.0577,3.060628 0,25.4089893 -15.64963,0 0,-62.8295013"
|
||||
id="path2920-3"
|
||||
style="fill:#4d4d4d" />
|
||||
<path
|
||||
d="m 141.78656,-56.190303 15.70737,0 0,6.409995 c 3.58033,-3.002821 6.8142,-5.081736 9.70162,-6.236752 2.92584,-1.193388 5.90947,-1.790114 8.95089,-1.790178 6.2367,6.4e-5 11.53024,2.175225 15.88062,6.52549 3.65729,3.695907 5.48597,9.162684 5.48603,16.400348 l 0,41.5205983 -15.59188,0 0,-27.5456543 c -5e-5,-7.507166 -0.34653,-12.492713 -1.03946,-14.956655 -0.65452,-2.463857 -1.82872,-4.331031 -3.52261,-5.601527 -1.65547,-1.308899 -3.71514,-1.963372 -6.179,-1.963422 -3.19541,5e-5 -5.94805,1.078006 -8.25792,3.233871 -2.27144,2.117461 -3.84988,5.062591 -4.73532,8.835399 -0.462,1.963458 -0.69299,6.217534 -0.69297,12.762242 l 0,25.2357463 -15.70737,0 0,-62.8295013"
|
||||
id="path2922-9"
|
||||
style="fill:#4d4d4d" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.4868765,0,0,1.4868765,477.80324,740.33267)"
|
||||
id="g2886-8"
|
||||
style="fill:#4d4d4d;fill-opacity:1">
|
||||
<text
|
||||
x="-299.4765"
|
||||
y="15.69857"
|
||||
transform="scale(0.95410088,1.0481072)"
|
||||
id="text3109-8-2-3-7-6"
|
||||
xml:space="preserve"
|
||||
style="font-size:127.35551453px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#4d4d4d;fill-opacity:1;stroke:none;font-family:Palatino;-inkscape-font-specification:Palatino Bold"><tspan
|
||||
x="-299.4765"
|
||||
y="15.69857"
|
||||
id="tspan2884-5"
|
||||
style="font-size:127.35551453px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#4d4d4d;fill-opacity:1;font-family:Palatino;-inkscape-font-specification:Palatino Bold">g</tspan></text>
|
||||
</g>
|
||||
<path
|
||||
d="m -339.89735,-32.881535 a 120.17799,8.4974337 0 1 1 -240.35599,0 120.17799,8.4974337 0 1 1 240.35599,0 z"
|
||||
transform="matrix(1.1060606,0,0,1.1060606,426.17959,848.32285)"
|
||||
id="path3423-1"
|
||||
style="opacity:0.26353838;fill:url(#linearGradient3269);fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
d="m -100.65527,815.73848 c -2.57334,-0.81915 -2.58247,-1.18087 -0.21166,-8.37918 2.367628,-7.18862 1.282568,-13.86445 -3.10637,-19.11195 -5.96822,-7.13575 -8.84216,-13.22467 -9.75823,-20.67444 -0.78646,-6.3958 -1.03575,-6.90285 -3.6397,-7.40279 -1.74646,-0.33531 -4.15929,0.32877 -9.90965,2.72745 -8.36615,3.4898 -10.35876,5.02218 -12.33291,9.4843 -1.03707,2.34406 -1.16172,3.7482 -0.57348,6.45967 0.7183,3.31089 3.66212,8.64054 4.77653,8.64768 0.29081,0.002 1.89748,1.1023 3.57036,2.44541 2.77589,2.22869 2.96643,2.61592 2.18093,4.43265 -1.70673,3.94745 -5.76177,8.73342 -7.39962,8.73342 -0.91894,0 -4.67154,-2.62848 -8.80223,-6.16546 -8.11348,-6.94729 -8.45354,-7.64379 -9.29155,-19.03126 -0.99988,-13.58711 2.34128,-19.92818 17.22216,-32.68537 l 9.33328,-8.0013 0.5961,-4.8534 c 0.61452,-5.00328 -0.25183,-16.91684 -1.70841,-23.49298 -0.86051,-3.885 -3.7003,-7.58525 -6.39519,-8.33292 -2.93605,-0.8146 -4.65723,0.86613 -6.89082,6.72892 -2.40994,6.32567 -4.71315,8.53245 -8.90528,8.53245 -2.61108,0 -5.04774,-1.67029 -6.73027,-4.61349 -1.20562,-2.10894 -1.90545,-14.77861 -1.18473,-21.44783 0.34669,-3.20813 0.36656,-6.45629 0.0442,-7.21814 -0.52459,-1.23963 -5.04199,-3.92118 -15.69218,-9.31491 -1.93608,-0.98052 -4.19318,-2.30073 -5.01577,-2.93381 -0.82258,-0.63307 -2.95712,-1.79702 -4.74342,-2.58654 -4.0461,-1.78831 -14.59582,-7.95686 -13.60818,-7.95686 1.86847,0 9.78678,2.4371 14.00212,4.30958 2.57327,1.14308 5.0365,2.07831 5.47385,2.07831 0.43736,0 5.39838,1.59698 11.0245,3.54885 5.62613,1.95185 10.76835,3.54883 11.42716,3.54883 1.56481,0 1.81019,-1.35379 1.30876,-7.22052 -0.22777,-2.66503 -0.21772,-4.84552 0.0224,-4.84552 0.24005,0 1.27682,0.51453 2.3039,1.14339 3.13787,1.92125 9.88743,3.09794 17.82053,3.10678 7.58555,0.009 17.48687,1.51346 21.27112,3.23319 5.42864,2.46702 11.72565,10.17235 19.713658,24.12261 5.55341,9.69849 11.5205,13.80519 20.07216,13.81419 3.45705,0.004 12.6805,-1.42134 25.17062,-3.88871 10.29868,-2.03446 23.894192,-2.49173 29.171452,-0.98115 6.43791,1.8428 14.95039,6.76935 21.98861,12.72577 6.58741,5.57491 7.60197,6.81262 11.64852,14.21045 4.82928,8.82878 10.15926,21.37645 14.899,35.07479 0.67537,1.95185 2.10182,5.23512 3.1699,7.29614 2.84984,5.49914 2.70779,5.83455 -2.47093,5.83455 -5.62088,0 -8.25697,-0.88636 -11.94164,-4.01528 -3.534,-3.00098 -4.45715,-4.83696 -9.98855,-19.86556 -2.83329,-7.6979 -5.59135,-12.31728 -7.35421,-12.31728 -1.20786,0 -3.65266,8.24914 -3.65266,12.32476 0,2.89469 1.814,6.8052 6.50386,14.02068 7.61871,11.72159 11.62643,28.29168 10.02221,41.4373 l -0.69293,5.67814 -5.07747,0.21136 c -7.99385,0.33278 -7.91382,0.44389 -7.91382,-10.98681 0,-12.16922 -0.82877,-14.80464 -6.19901,-19.71247 -2.2306,-2.03853 -7.23508,-7.83031 -11.12107,-12.87062 -3.88602,-5.04032 -7.60749,-9.16422 -8.26995,-9.16422 -1.52225,0 -2.28133,4.14488 -2.36225,12.8988 -0.0532,5.76495 -0.28025,6.74074 -1.98112,8.5172 -4.611042,4.81598 -7.847772,13.58519 -9.843172,26.668 -0.44167,2.89579 -0.82033,3.43751 -2.6974,3.85899 -2.76002,0.61973 -10.40844,0.72118 -11.06755,0.14681 -0.56842,-0.49534 0.42766,-8.35904 2.68721,-21.21493 0.85765,-4.87965 1.79377,-11.42725 2.08028,-14.55022 0.51005,-5.55953 -0.62987,-15.97557 -1.97899,-18.08289 -0.56095,-0.8762 -3.4173,-1.06606 -16.77722,-1.11512 -8.85564,-0.0325 -18.56749,-0.32384 -21.58186,-0.64737 l -5.48072,-0.58825 0,2.43214 c 0,2.60447 0.66758,4.90008 5.1317,17.6466 1.57224,4.48928 3.85053,11.33318 5.06287,15.20868 l 2.20425,7.04637 -1.86007,5.72944 c -1.02305,3.15119 -2.54137,6.92717 -3.37407,8.39107 -1.46872,2.58204 -1.64095,2.65994 -5.76025,2.60558 -2.33545,-0.0308 -5.28634,-0.38711 -6.557538,-0.79175 z"
|
||||
id="path3046-2-3-0"
|
||||
style="fill:#499848;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
40
docs/content/community.md
Normal file
40
docs/content/community.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Community
|
||||
|
||||
Connect with the project through these channels.
|
||||
|
||||
## Project management & discussions
|
||||
|
||||
Project maintenance guidelines live on the
|
||||
[wiki](https://github.com/benoitc/gunicorn/wiki/Project-management).
|
||||
|
||||
GitHub is used for:
|
||||
|
||||
- [Bug reports](https://github.com/benoitc/gunicorn/issues) — search before
|
||||
opening a new issue.
|
||||
- [Discussions](https://github.com/benoitc/gunicorn/discussions) — Q&A and usage
|
||||
tips.
|
||||
- [Feature planning](https://github.com/benoitc/gunicorn/issues) — development
|
||||
and project management topics.
|
||||
|
||||
## IRC
|
||||
|
||||
Join the Gunicorn channel on [Libera Chat](https://libera.chat/) at
|
||||
[`#gunicorn`](https://web.libera.chat/?channels=#gunicorn).
|
||||
|
||||
## Issue tracking
|
||||
|
||||
File bugs, enhancements, and tasks in the
|
||||
[GitHub issue tracker](https://github.com/benoitc/gunicorn/issues).
|
||||
|
||||
## Security issues
|
||||
|
||||
Report security vulnerabilities privately to
|
||||
[`security@gunicorn.org`](mailto:security@gunicorn.org); only core developers
|
||||
subscribe to this list.
|
||||
|
||||
## Contributing
|
||||
|
||||
Start with the
|
||||
[contributing guide](https://github.com/benoitc/gunicorn/blob/master/CONTRIBUTING.md)
|
||||
for development workflow, code style, and review expectations. New contributors
|
||||
are welcome—open a draft pull request early to gather feedback.
|
||||
78
docs/content/configure.md
Normal file
78
docs/content/configure.md
Normal file
@ -0,0 +1,78 @@
|
||||
<span id="configuration"></span>
|
||||
# Configuration Overview
|
||||
|
||||
Gunicorn reads configuration from five places, in increasing order of priority:
|
||||
|
||||
1. Environment variables, for settings that support them.
|
||||
2. Framework-specific configuration (currently Paste Deploy only).
|
||||
3. A Python configuration file `gunicorn.conf.py` (default in the working directory).
|
||||
4. The `GUNICORN_CMD_ARGS` environment variable.
|
||||
5. Command-line arguments.
|
||||
|
||||
If a configuration file is provided both via `GUNICORN_CMD_ARGS` and the CLI,
|
||||
only the file specified on the command line is used.
|
||||
|
||||
!!! note
|
||||
Print the fully resolved configuration:
|
||||
|
||||
bash
|
||||
gunicorn --print-config APP_MODULE
|
||||
```
|
||||
|
||||
Validate configuration and exit:
|
||||
|
||||
```bash
|
||||
gunicorn --check-config APP_MODULE
|
||||
```
|
||||
|
||||
This is also a quick way to confirm that your application can start.
|
||||
```
|
||||
|
||||
## Command line
|
||||
|
||||
Options set on the command line override framework settings and values from the
|
||||
configuration file. Not every setting has a command-line flag; run
|
||||
|
||||
```bash
|
||||
gunicorn -h
|
||||
```
|
||||
|
||||
for the complete list. The CLI also exposes `--version`, which is not part of
|
||||
the main [settings reference](reference/settings.md).
|
||||
|
||||
<span id="configuration_file"></span>
|
||||
## Configuration file
|
||||
|
||||
Provide a Python file (for example `gunicorn.conf.py`). Gunicorn executes the
|
||||
file on every start or reload, so any valid Python is allowed:
|
||||
|
||||
```python
|
||||
import multiprocessing
|
||||
|
||||
bind = "127.0.0.1:8000"
|
||||
workers = multiprocessing.cpu_count() * 2 + 1
|
||||
```
|
||||
|
||||
Every configuration key is documented in the [settings reference](reference/settings.md).
|
||||
|
||||
## Framework settings
|
||||
|
||||
At present only Paste Deploy applications expose framework-specific settings.
|
||||
If you have ideas for Django or other frameworks, open an
|
||||
[issue](https://github.com/benoitc/gunicorn/issues).
|
||||
|
||||
### Paste applications
|
||||
|
||||
Reference Gunicorn as the server in your INI file:
|
||||
|
||||
```ini
|
||||
[server:main]
|
||||
use = egg:gunicorn#main
|
||||
host = 192.168.0.1
|
||||
port = 80
|
||||
workers = 2
|
||||
proc_name = brim
|
||||
```
|
||||
|
||||
Gunicorn merges any recognised parameters into the base configuration. Values
|
||||
from the configuration file and command line still override these defaults.
|
||||
62
docs/content/custom.md
Normal file
62
docs/content/custom.md
Normal file
@ -0,0 +1,62 @@
|
||||
<span id="custom"></span>
|
||||
# Custom Application
|
||||
|
||||
!!! info "Added in 19.0"
|
||||
Use Gunicorn as part of your own WSGI application by subclassing
|
||||
`gunicorn.app.base.BaseApplication`.
|
||||
|
||||
|
||||
|
||||
Example: create a tiny WSGI app and load it with a custom application:
|
||||
|
||||
```text
|
||||
--8<-- "examples/standalone_app.py"
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Using server hooks
|
||||
|
||||
Provide hooks through configuration, just like a standard Gunicorn deployment.
|
||||
For example, a `pre_fork` hook:
|
||||
|
||||
```python
|
||||
def pre_fork(server, worker):
|
||||
print(f"pre-fork server {server} worker {worker}", file=sys.stderr)
|
||||
|
||||
if __name__ == "__main__":
|
||||
options = {
|
||||
"bind": "127.0.0.1:8080",
|
||||
"workers": number_of_workers(),
|
||||
"pre_fork": pre_fork,
|
||||
}
|
||||
```
|
||||
|
||||
## Direct usage of existing WSGI apps
|
||||
|
||||
Run Gunicorn from Python to serve a WSGI application instance at runtime—useful
|
||||
for rolling deploys or packaging with PEX. Gunicorn exposes
|
||||
`gunicorn.app.wsgiapp`, which accepts any WSGI app (for example a Flask or
|
||||
Django instance). Assuming your package is `exampleapi` and the application is
|
||||
`app`:
|
||||
|
||||
```bash
|
||||
python -m gunicorn.app.wsgiapp exampleapi:app
|
||||
```
|
||||
|
||||
All CLI flags and configuration files still apply:
|
||||
|
||||
```bash
|
||||
# Custom parameters
|
||||
python -m gunicorn.app.wsgiapp exampleapi:app --bind=0.0.0.0:8081 --workers=4
|
||||
# Using a config file
|
||||
python -m gunicorn.app.wsgiapp exampleapi:app -c config.py
|
||||
```
|
||||
|
||||
For PEX builds use `-c gunicorn` at build time so the packaged app accepts the
|
||||
entry point at runtime:
|
||||
|
||||
```bash
|
||||
pex . -v -c gunicorn -o compiledapp.pex
|
||||
./compiledapp.pex exampleapi:app -c gunicorn_config.py
|
||||
```
|
||||
322
docs/content/deploy.md
Normal file
322
docs/content/deploy.md
Normal file
@ -0,0 +1,322 @@
|
||||
# Deploying Gunicorn
|
||||
|
||||
We strongly recommend running Gunicorn behind a proxy server.
|
||||
|
||||
## Nginx configuration
|
||||
|
||||
Although many HTTP proxies exist, we recommend [Nginx](https://nginx.org/).
|
||||
When using the default synchronous workers you must ensure the proxy buffers
|
||||
slow clients; otherwise Gunicorn becomes vulnerable to denial-of-service
|
||||
attacks. Use [Hey](https://github.com/rakyll/hey) to verify proxy behaviour.
|
||||
|
||||
An example configuration for fast clients with Nginx
|
||||
([source](https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf)):
|
||||
|
||||
```nginx title="nginx.conf"
|
||||
--8<-- "examples/nginx.conf"
|
||||
```
|
||||
|
||||
|
||||
|
||||
To support streaming requests/responses or patterns such as Comet, long
|
||||
polling, or WebSockets, disable proxy buffering and run Gunicorn with an async
|
||||
worker class:
|
||||
|
||||
```nginx
|
||||
location @proxy_to_app {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
|
||||
proxy_pass http://app_server;
|
||||
}
|
||||
```
|
||||
|
||||
To ignore aborted requests (for example, health checks that close connections
|
||||
prematurely) enable
|
||||
[`proxy_ignore_client_abort`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort):
|
||||
|
||||
```nginx
|
||||
proxy_ignore_client_abort on;
|
||||
```
|
||||
|
||||
!!! note
|
||||
The default value for `proxy_ignore_client_abort` is `off`. If it remains off
|
||||
Nginx logs will report error 499 and Gunicorn may log `Ignoring EPIPE` when the
|
||||
log level is `debug`.
|
||||
|
||||
|
||||
|
||||
Pass protocol information to Gunicorn so applications can generate correct
|
||||
URLs. Add this header to your `location` block:
|
||||
|
||||
```nginx
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
```
|
||||
|
||||
If Nginx runs on a different host, tell Gunicorn which proxies are trusted so it
|
||||
accepts the `X-Forwarded-*` headers:
|
||||
|
||||
```bash
|
||||
gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app
|
||||
```
|
||||
|
||||
When all traffic comes from trusted proxies (for example Heroku) you can set
|
||||
`--forwarded-allow-ips='*'`. This is **dangerous** if untrusted clients can
|
||||
reach Gunicorn directly, because forged headers could make your application
|
||||
serve secure content over plain HTTP.
|
||||
|
||||
Gunicorn 19 changed the handling of `REMOTE_ADDR` to conform to
|
||||
[RFC 3875](https://www.rfc-editor.org/rfc/rfc3875), meaning it now records the
|
||||
proxy IP rather than the upstream client. To log the real client address, set
|
||||
[`access_log_format`](reference/settings.md#access_log_format) to include `X-Forwarded-For`:
|
||||
|
||||
```text
|
||||
%({x-forwarded-for}i)s %(l.md)s %(u.md)s %(t.md)s "%(r.md)s" %(s.md)s %(b.md)s "%(f.md)s" "%(a.md)s"
|
||||
```
|
||||
|
||||
When binding Gunicorn to a UNIX socket `REMOTE_ADDR` will be empty.
|
||||
|
||||
## Using virtual environments
|
||||
|
||||
Install Gunicorn inside your project
|
||||
[virtual environment](https://pypi.python.org/pypi/virtualenv) to keep versions
|
||||
isolated:
|
||||
|
||||
```bash
|
||||
mkdir ~/venvs/
|
||||
virtualenv ~/venvs/webapp
|
||||
source ~/venvs/webapp/bin/activate
|
||||
pip install gunicorn
|
||||
deactivate
|
||||
```
|
||||
|
||||
Force installation into the active virtual environment with `--ignore-installed`:
|
||||
|
||||
```bash
|
||||
source ~/venvs/webapp/bin/activate
|
||||
pip install -I gunicorn
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
!!! note
|
||||
Do not enable Gunicorn's daemon mode when using process monitors. These
|
||||
supervisors expect to manage the direct child process.
|
||||
|
||||
|
||||
|
||||
### Gaffer
|
||||
|
||||
Use [Gaffer](https://gaffer.readthedocs.io/) with *gafferd* to manage Gunicorn:
|
||||
|
||||
```ini
|
||||
[process:gunicorn]
|
||||
cmd = gunicorn -w 3 test:app
|
||||
cwd = /path/to/project
|
||||
```
|
||||
|
||||
Create a `Procfile` if you prefer:
|
||||
|
||||
```procfile
|
||||
gunicorn = gunicorn -w 3 test:app
|
||||
```
|
||||
|
||||
Start Gunicorn via Gaffer:
|
||||
|
||||
```bash
|
||||
gaffer start
|
||||
```
|
||||
|
||||
Or load it into a running *gafferd* instance:
|
||||
|
||||
```bash
|
||||
gaffer load
|
||||
```
|
||||
|
||||
### runit
|
||||
|
||||
[runit](http://smarden.org/runit/) is a popular supervisor. A sample service
|
||||
script (see the
|
||||
[full example](https://github.com/benoitc/gunicorn/blob/master/examples/gunicorn_rc)):
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
|
||||
GUNICORN=/usr/local/bin/gunicorn
|
||||
ROOT=/path/to/project
|
||||
PID=/var/run/gunicorn.pid
|
||||
|
||||
APP=main:application
|
||||
|
||||
if [ -f $PID ]; then rm $PID; fi
|
||||
|
||||
cd $ROOT
|
||||
exec $GUNICORN -c $ROOT/gunicorn.conf.py --pid=$PID $APP
|
||||
```
|
||||
|
||||
Save as `/etc/sv/<app_name>/run`, make it executable, and symlink into
|
||||
`/etc/service/<app_name>`. runit will then supervise Gunicorn.
|
||||
|
||||
### Supervisor
|
||||
|
||||
[Supervisor](http://supervisord.org/) configuration example (adapted from
|
||||
[examples/supervisor.conf](https://github.com/benoitc/gunicorn/blob/master/examples/supervisor.conf)):
|
||||
|
||||
```ini
|
||||
[program:gunicorn]
|
||||
command=/path/to/gunicorn main:application -c /path/to/gunicorn.conf.py
|
||||
directory=/path/to/project
|
||||
user=nobody
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
```
|
||||
|
||||
### Upstart
|
||||
|
||||
Sample Upstart config (logs go to `/var/log/upstart/myapp.log`):
|
||||
|
||||
```upstart
|
||||
# /etc/init/myapp.conf
|
||||
|
||||
description "myapp"
|
||||
|
||||
start on (filesystem.md)
|
||||
stop on runlevel [016]
|
||||
|
||||
respawn
|
||||
setuid nobody
|
||||
setgid nogroup
|
||||
chdir /path/to/app/directory
|
||||
|
||||
exec /path/to/virtualenv/bin/gunicorn myapp:app
|
||||
```
|
||||
|
||||
### systemd
|
||||
|
||||
[systemd](https://www.freedesktop.org/wiki/Software/systemd/) can create a UNIX
|
||||
socket and launch Gunicorn on demand.
|
||||
|
||||
Service file:
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/gunicorn.service
|
||||
|
||||
[Unit]
|
||||
Description=gunicorn daemon
|
||||
Requires=gunicorn.socket
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
NotifyAccess=main
|
||||
User=someuser
|
||||
Group=someuser
|
||||
RuntimeDirectory=gunicorn
|
||||
WorkingDirectory=/home/someuser/applicationroot
|
||||
ExecStart=/usr/bin/gunicorn applicationname.wsgi
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
KillMode=mixed
|
||||
TimeoutStopSec=5
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
`Type=notify` lets Gunicorn report readiness to systemd. If the service should
|
||||
run under a transient user consider adding `DynamicUser=true`. Tighten
|
||||
permissions further with `ProtectSystem=strict` if the app permits.
|
||||
|
||||
Socket activation file:
|
||||
|
||||
```ini
|
||||
# /etc/systemd/system/gunicorn.socket
|
||||
|
||||
[Unit]
|
||||
Description=gunicorn socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/gunicorn.sock
|
||||
SocketUser=www-data
|
||||
SocketGroup=www-data
|
||||
SocketMode=0660
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
```
|
||||
|
||||
Enable and start the socket so it begins listening immediately and on reboot:
|
||||
|
||||
```bash
|
||||
systemctl enable --now gunicorn.socket
|
||||
```
|
||||
|
||||
Test connectivity from the nginx user (Debian defaults to `www-data`):
|
||||
|
||||
```bash
|
||||
sudo -u www-data curl --unix-socket /run/gunicorn.sock http
|
||||
```
|
||||
|
||||
!!! note
|
||||
Use `systemctl show --value -p MainPID gunicorn.service` to retrieve the main
|
||||
process ID or `systemctl kill -s HUP gunicorn.service` to send signals.
|
||||
|
||||
|
||||
|
||||
Configure Nginx to proxy to the new socket:
|
||||
|
||||
```nginx
|
||||
user www-data;
|
||||
...
|
||||
http {
|
||||
server {
|
||||
listen 8000;
|
||||
server_name 127.0.0.1;
|
||||
location / {
|
||||
proxy_pass http://unix:/run/gunicorn.sock;
|
||||
}
|
||||
}
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
!!! note
|
||||
Adjust `listen` and `server_name` for production (typically port 80 and your
|
||||
site's domain).
|
||||
|
||||
|
||||
|
||||
Ensure nginx starts automatically:
|
||||
|
||||
```bash
|
||||
systemctl enable nginx.service
|
||||
systemctl start nginx
|
||||
```
|
||||
|
||||
Browse to <http://127.0.0.1:8000/> to verify Gunicorn + Nginx + systemd.
|
||||
|
||||
## Logging
|
||||
|
||||
Configure logging through the CLI flags described in the
|
||||
[settings documentation](reference/settings.md#logging) or via a
|
||||
[logging configuration file](https://github.com/benoitc/gunicorn/blob/master/examples/logging.conf).
|
||||
Rotate logs with `logrotate` by sending `SIGUSR1`:
|
||||
|
||||
```bash
|
||||
kill -USR1 $(cat /var/run/gunicorn.pid)
|
||||
```
|
||||
|
||||
!!! note
|
||||
If you override the `LOGGING` dictionary, set `disable_existing_loggers` to
|
||||
`False` so Gunicorn's loggers remain active.
|
||||
|
||||
|
||||
|
||||
!!! warning
|
||||
Gunicorn's error log should capture Gunicorn-related messages only. Route your
|
||||
application logs separately.
|
||||
|
||||
|
||||
83
docs/content/design.md
Normal file
83
docs/content/design.md
Normal file
@ -0,0 +1,83 @@
|
||||
<span id="design"></span>
|
||||
# Design
|
||||
|
||||
A brief look at Gunicorn's architecture.
|
||||
|
||||
## Server model
|
||||
|
||||
Gunicorn uses a pre-fork worker model: a master process manages worker
|
||||
processes, while the workers handle requests and responses. The master never
|
||||
touches individual client sockets.
|
||||
|
||||
### Master
|
||||
|
||||
The master process listens for signals (TTIN, TTOU, CHLD, etc.) and adjusts the
|
||||
worker pool accordingly. `TTIN`/`TTOU` change the number of workers; `CHLD`
|
||||
indicates a worker exited and must be restarted.
|
||||
|
||||
### Sync workers
|
||||
|
||||
The default `sync` worker handles one request at a time. Errors affect only the
|
||||
current request. Because connections close after each response, persistent
|
||||
connections are not supported even if you set `Keep-Alive` headers manually.
|
||||
|
||||
### Async workers
|
||||
|
||||
Async workers are powered by [greenlets](https://github.com/python-greenlet/greenlet)
|
||||
through [Eventlet](http://eventlet.net/) or [Gevent](http://www.gevent.org/).
|
||||
Most apps work without modification, though full compatibility may require
|
||||
patches (for example installing [`psycogreen`](https://github.com/psycopg/psycogreen/)
|
||||
when using [Psycopg](http://initd.org/psycopg/)). Some apps that depend on the
|
||||
original blocking behaviour may not be compatible.
|
||||
|
||||
### Gthread workers
|
||||
|
||||
`gthread` is a threaded worker. The main loop accepts connections and places
|
||||
them in a thread pool. Keep-alive connections return to the pool to await
|
||||
further events; idle connections close after the keepalive timeout.
|
||||
|
||||
### Tornado workers
|
||||
|
||||
A Tornado worker class exists for Tornado-based applications. While it can
|
||||
serve WSGI apps, this configuration is not recommended.
|
||||
|
||||
<span id="asyncio-workers"></span>
|
||||
### AsyncIO workers
|
||||
|
||||
Use third-party workers to pair Gunicorn with asyncio frameworks (see the
|
||||
[aiohttp deployment guide](https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn)
|
||||
or the [Flask aiohttp example](https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py)).
|
||||
|
||||
## Choosing a worker type
|
||||
|
||||
Synchronous workers assume your app is CPU/network bound and avoids indefinite
|
||||
operations. Any outbound HTTP calls or other blocking behaviour benefit from an
|
||||
async worker. Because synchronous workers are vulnerable to slow clients,
|
||||
Gunicorn requires a buffering proxy in front of the default configuration. Tools
|
||||
like [Hey](https://github.com/rakyll/hey) can simulate slow responses to test
|
||||
this scenario.
|
||||
|
||||
Examples that need async workers:
|
||||
|
||||
- Long blocking calls (outbound web services)
|
||||
- Direct internet traffic (no buffering proxy)
|
||||
- Streaming request/response bodies
|
||||
- Long polling
|
||||
- WebSockets / Comet
|
||||
|
||||
## How many workers?
|
||||
|
||||
Do **not** scale workers to match client count. Gunicorn usually needs only 4–12
|
||||
workers to handle heavy traffic. Start with `(2 * num_cores) + 1` and adjust
|
||||
under load using `TTIN`/`TTOU`.
|
||||
|
||||
Too many workers waste resources and can reduce throughput.
|
||||
|
||||
## How many threads?
|
||||
|
||||
Since Gunicorn 19 you can set `--threads` (with the `gthread` worker) to process
|
||||
requests concurrently. Threads can extend request time beyond the worker
|
||||
timeout while still notifying the master. The optimal mix of threads and worker
|
||||
processes depends on the runtime (for example CPython vs. Jython). Threads share
|
||||
memory, lowering footprint, and still allow reloads because application code is
|
||||
loaded in worker processes.
|
||||
160
docs/content/faq.md
Normal file
160
docs/content/faq.md
Normal file
@ -0,0 +1,160 @@
|
||||
<span id="faq"></span>
|
||||
# FAQ
|
||||
|
||||
## WSGI bits
|
||||
|
||||
### How do I set `SCRIPT_NAME`?
|
||||
|
||||
By default `SCRIPT_NAME` is an empty string. Set it via an environment variable
|
||||
or HTTP header. Because the header contains an underscore it is only accepted
|
||||
from trusted forwarders listed in [`forwarded_allow_ips`](reference/settings.md#forwarded_allow_ips).
|
||||
|
||||
!!! note
|
||||
If your application should appear under a subfolder, `SCRIPT_NAME` typically
|
||||
starts with a single leading slash and no trailing slash.
|
||||
|
||||
|
||||
|
||||
## Server stuff
|
||||
|
||||
### How do I reload my application in Gunicorn?
|
||||
|
||||
Send `HUP` to the master process for a graceful reload:
|
||||
|
||||
```bash
|
||||
kill -HUP masterpid
|
||||
```
|
||||
|
||||
### How might I test a proxy configuration?
|
||||
|
||||
Use [Hey](https://github.com/rakyll/hey) to confirm that your proxy buffers
|
||||
responses correctly for synchronous workers:
|
||||
|
||||
```bash
|
||||
hey -n 10000 -c 100 http://127.0.0.1:5000/
|
||||
```
|
||||
|
||||
That benchmark issues 10,000 requests with a concurrency of 100.
|
||||
|
||||
### How can I name processes?
|
||||
|
||||
Install [setproctitle](https://pypi.python.org/pypi/setproctitle) to give
|
||||
Gunicorn processes meaningful names in tools such as `ps` and `top`. This helps
|
||||
when running multiple Gunicorn instances. See the
|
||||
[`proc_name`](reference/settings.md#proc_name) setting for details.
|
||||
|
||||
### Why is there no HTTP keep-alive?
|
||||
|
||||
The default sync workers target Nginx, which uses HTTP/1.0 for upstream
|
||||
connections. If you need to serve unbuffered internet traffic directly, pick an
|
||||
async worker instead.
|
||||
|
||||
## Worker processes
|
||||
|
||||
### How do I know which type of worker to use?
|
||||
|
||||
Read the [design guide](design.md) for guidance on worker types.
|
||||
|
||||
### What types of workers are available?
|
||||
|
||||
See the [`worker_class`](reference/settings.md#worker_class) configuration reference.
|
||||
|
||||
### How can I figure out the best number of worker processes?
|
||||
|
||||
Follow the recommendations for tuning the [`number of workers`](design.md#how-many-workers).
|
||||
|
||||
### How can I change the number of workers dynamically?
|
||||
|
||||
Send `TTIN` or `TTOU` to the master process:
|
||||
|
||||
```bash
|
||||
kill -TTIN $masterpid # increment workers
|
||||
kill -TTOU $masterpid # decrement workers
|
||||
```
|
||||
|
||||
### Does Gunicorn suffer from the thundering herd problem?
|
||||
|
||||
Potentially, when many sleeping handlers wake simultaneously but only one takes
|
||||
the request. There is ongoing work to mitigate this
|
||||
([issue #792](https://github.com/benoitc/gunicorn/issues/792)). Monitor load if
|
||||
you use large numbers of workers or threads.
|
||||
|
||||
### Why don't I see logs in the console?
|
||||
|
||||
Gunicorn 19.0 disabled console logging by default. Use `--log-file=-` to stream
|
||||
logs to stdout. Console logging returned in 19.2.
|
||||
|
||||
## Kernel parameters
|
||||
|
||||
High-concurrency deployments may need kernel tuning. These Linux-oriented tips
|
||||
apply to any network service.
|
||||
|
||||
### How can I increase the maximum number of file descriptors?
|
||||
|
||||
Raise the per-process limit (remember sockets count as files). Running `sudo
|
||||
ulimit` is ineffective—switch to root, adjust the limit, then launch Gunicorn.
|
||||
Consider managing limits via systemd service units or init scripts.
|
||||
|
||||
### How can I increase the maximum socket backlog?
|
||||
|
||||
Increase the queue of pending connections:
|
||||
|
||||
```bash
|
||||
sudo sysctl -w net.core.somaxconn="2048"
|
||||
```
|
||||
|
||||
### How can I disable the use of `sendfile()`?
|
||||
|
||||
Pass `--no-sendfile` or set the `SENDFILE=0` environment variable.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Django reports `ImproperlyConfigured`
|
||||
|
||||
Asynchronous workers may break `django.core.urlresolvers.reverse`. Use
|
||||
`reverse_lazy` instead.
|
||||
|
||||
### How do I avoid blocking in `os.fchmod`?
|
||||
|
||||
Gunicorn's heartbeat touches temporary files. On disk-backed filesystems (for
|
||||
example `/tmp` on some distributions) `os.fchmod` can block if I/O stalls or the
|
||||
filesystem fills up. Mount a `tmpfs` and point `--worker-tmp-dir` to it.
|
||||
|
||||
Check whether `/tmp` is RAM-backed:
|
||||
|
||||
```bash
|
||||
df /tmp
|
||||
```
|
||||
|
||||
If not, create a new `tmpfs` mount:
|
||||
|
||||
```bash
|
||||
sudo cp /etc/fstab /etc/fstab.orig
|
||||
sudo mkdir /mem
|
||||
echo 'tmpfs /mem tmpfs defaults,size=64m,mode=1777,noatime,comment=for-gunicorn 0 0' | sudo tee -a /etc/fstab
|
||||
sudo mount /mem
|
||||
```
|
||||
|
||||
Verify the result:
|
||||
|
||||
```bash
|
||||
df /mem
|
||||
```
|
||||
|
||||
Then start Gunicorn with `--worker-tmp-dir /mem`.
|
||||
|
||||
### Why are workers silently killed?
|
||||
|
||||
If a worker vanishes without logs, check for `SIGKILL`. Reverse proxies may show
|
||||
`502` responses while Gunicorn logs only new worker startups (for example,
|
||||
`[INFO] Booting worker`). A common culprit is the OOM killer in cgroups-limited
|
||||
environments.
|
||||
|
||||
Inspect kernel logs:
|
||||
|
||||
```bash
|
||||
dmesg | grep gunicorn
|
||||
```
|
||||
|
||||
If you see messages similar to `Memory cgroup out of memory ... Killed process
|
||||
(gunicorn.md)`, raise memory limits or adjust OOM behaviour.
|
||||
68
docs/content/index.md
Normal file
68
docs/content/index.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Gunicorn
|
||||
|
||||
<div class="hero">
|
||||
<div class="hero__inner">
|
||||
<div class="hero__copy">
|
||||
<img class="hero__logo" src="assets/gunicorn.svg" alt="Gunicorn mascot" />
|
||||
<h1>Production-ready Python web services</h1>
|
||||
<p>Gunicorn is a dependable WSGI HTTP server for UNIX that keeps Python applications running fast and resilient in production. Built on a pre-fork worker model and trusted in countless deployments, it pairs clean configuration with flexible worker strategies so you can meet any traffic pattern.</p>
|
||||
<div class="hero__cta">
|
||||
<a class="md-button md-button--primary" href="install/">Install Gunicorn</a>
|
||||
<a class="md-button" href="https://github.com/benoitc/gunicorn">View on GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero__code">
|
||||
<pre><code class="language-console">$ pip install gunicorn
|
||||
$ gunicorn example:app --workers 3</code></pre>
|
||||
<div class="hero__version">Latest release: <span>{{ release }}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. Install Gunicorn into your application environment.
|
||||
2. Point Gunicorn at your WSGI app: `gunicorn myproject.wsgi`.
|
||||
3. Tune worker type, concurrency, and hooks using the rich [settings](reference/settings.md).
|
||||
|
||||
Need a longer walkthrough? Jump into the [install guide](install.md).
|
||||
|
||||
## Why teams choose Gunicorn
|
||||
|
||||
<section class="feature-grid">
|
||||
<article class="feature-card">
|
||||
<h3>Works with your framework</h3>
|
||||
<p>Django, Flask, FastAPI, Pyramid, you name it—Gunicorn speaks WSGI so your stack just runs.</p>
|
||||
<a href="run/">Running Gunicorn →</a>
|
||||
</article>
|
||||
<article class="feature-card">
|
||||
<h3>Flexible workers</h3>
|
||||
<p>Sync, async, gevent, eventlet—choose the concurrency model that fits.</p>
|
||||
<a href="reference/settings/#worker_class">Worker classes →</a>
|
||||
</article>
|
||||
<article class="feature-card">
|
||||
<h3>Battle-tested hooks</h3>
|
||||
<p>Lifecycle hooks let you instrument, reload, and extend Gunicorn to match your deployment requirements.</p>
|
||||
<a href="custom/">Server hooks →</a>
|
||||
</article>
|
||||
<article class="feature-card">
|
||||
<h3>Containers to bare metal</h3>
|
||||
<p>Deploy with systemd, Kubernetes, Heroku, or Docker—the configuration stays predictable everywhere.</p>
|
||||
<a href="deploy/">Deployment patterns →</a>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
## Documentation map
|
||||
|
||||
- [Install](install.md): Set up Gunicorn in a clean environment.
|
||||
- [Run](run.md): CLI usage and integration with frameworks.
|
||||
- [Configure](configure.md): Combine CLI flags and config files effectively.
|
||||
- [Settings reference](reference/settings.md): Generated from the Gunicorn source of truth.
|
||||
- [Signals](signals.md): Manage worker lifecycle in production.
|
||||
- [Instrumentation](instrumentation.md): Monitor metrics and logs.
|
||||
|
||||
## Community & support
|
||||
|
||||
- Report bugs or request features on [GitHub Issues](https://github.com/benoitc/gunicorn/issues).
|
||||
- Discuss strategies with maintainers in `#gunicorn` on [Libera Chat](https://libera.chat/).
|
||||
- Contributions are welcome—see the [contributing guide](community.md#contributing) and say hi to the maintainers.
|
||||
142
docs/content/install.md
Normal file
142
docs/content/install.md
Normal file
@ -0,0 +1,142 @@
|
||||
# Installation
|
||||
|
||||
!!! note
|
||||
Gunicorn requires **Python 3.12 or newer**.
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
pip install gunicorn
|
||||
```
|
||||
|
||||
## From source
|
||||
|
||||
Install Gunicorn from GitHub if you want the latest development version:
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/benoitc/gunicorn.git
|
||||
```
|
||||
|
||||
Stay current by upgrading in place:
|
||||
|
||||
```bash
|
||||
pip install -U git+https://github.com/benoitc/gunicorn.git
|
||||
```
|
||||
|
||||
## Async workers
|
||||
|
||||
Install Eventlet or Gevent if your application benefits from cooperative I/O.
|
||||
Both rely on `greenlet`, so make sure the Python headers are available (for
|
||||
example, install the `python-dev` package on Ubuntu).
|
||||
|
||||
```bash
|
||||
pip install greenlet # Required for both
|
||||
pip install eventlet # For eventlet workers
|
||||
pip install gunicorn[eventlet] # Or, using extra
|
||||
pip install gevent # For gevent workers
|
||||
pip install gunicorn[gevent] # Or, using extra
|
||||
```
|
||||
|
||||
!!! note
|
||||
Gevent also needs `libevent` 1.4.x or 2.0.4+. Install it from your package
|
||||
manager or build it manually if the packaged version is too old.
|
||||
|
||||
|
||||
|
||||
## Extra packages
|
||||
|
||||
Some Gunicorn options require additional dependencies. Install them via
|
||||
extras to pull everything in with one command.
|
||||
|
||||
Most extras enable alternative worker types—see the
|
||||
[design docs](design.md) for when each worker makes sense.
|
||||
|
||||
- `gunicorn[eventlet]` — Eventlet-based greenlet workers
|
||||
- `gunicorn[gevent]` — Gevent-based greenlet workers
|
||||
- `gunicorn[gthread]` — Threaded workers
|
||||
- `gunicorn[tornado]` — Tornado-based workers (not recommended)
|
||||
|
||||
If you run more than one Gunicorn instance, the
|
||||
[`proc_name`](reference/settings.md#proc_name) setting helps distinguish them in tools such
|
||||
as `ps` and `top`.
|
||||
|
||||
- `gunicorn[setproctitle]` — Enables setting the process name
|
||||
|
||||
You can combine multiple extras, for example:
|
||||
|
||||
```bash
|
||||
pip install gunicorn[gevent,setproctitle]
|
||||
```
|
||||
|
||||
## Debian GNU/Linux
|
||||
|
||||
On Debian systems prefer the distribution packages unless you need per-project
|
||||
virtual environments:
|
||||
|
||||
- Zero-effort installation: automatically starts multiple instances based on
|
||||
configs in `/etc/gunicorn.d`.
|
||||
- Sensible log locations (`/var/log/gunicorn`) with `logrotate` support.
|
||||
- Improved security: run each instance with a dedicated UNIX user/group.
|
||||
- Safe upgrades: minimal downtime, reversible changes, and easy package purge.
|
||||
|
||||
### stable ("buster")
|
||||
|
||||
The Debian [stable](https://www.debian.org/releases/stable/) release ships
|
||||
Gunicorn 19.9.0 (December 2020):
|
||||
|
||||
```bash
|
||||
sudo apt-get install gunicorn3
|
||||
```
|
||||
|
||||
Install Gunicorn 20.0.4 from [Debian Backports](https://backports.debian.org/)
|
||||
by adding this line to `/etc/apt/sources.list`:
|
||||
|
||||
```text
|
||||
deb http://ftp.debian.org/debian buster-backports main
|
||||
```
|
||||
|
||||
Refresh package metadata and install:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get -t buster-backports install gunicorn
|
||||
```
|
||||
|
||||
### oldstable ("stretch")
|
||||
|
||||
Stretch provides Gunicorn 19.6.0 (December 2020). Install the Python 3 version:
|
||||
|
||||
```bash
|
||||
sudo apt-get install gunicorn3
|
||||
```
|
||||
|
||||
To upgrade to 19.7.1 from backports, add:
|
||||
|
||||
```text
|
||||
deb http://ftp.debian.org/debian stretch-backports main
|
||||
```
|
||||
|
||||
Then update and install:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get -t stretch-backports install gunicorn3
|
||||
```
|
||||
|
||||
### testing ("bullseye") and unstable ("sid")
|
||||
|
||||
Both distributions include Gunicorn 20.0.4. Install it in the usual way:
|
||||
|
||||
```bash
|
||||
sudo apt-get install gunicorn
|
||||
```
|
||||
|
||||
## Ubuntu
|
||||
|
||||
Ubuntu 20.04 LTS (Focal Fossa) and newer include Gunicorn 20.0.4. Keep it
|
||||
current through the package manager:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install gunicorn
|
||||
```
|
||||
32
docs/content/instrumentation.md
Normal file
32
docs/content/instrumentation.md
Normal file
@ -0,0 +1,32 @@
|
||||
<span id="instrumentation"></span>
|
||||
# Instrumentation
|
||||
|
||||
!!! info "Added in 19.1"
|
||||
Gunicorn exposes optional instrumentation for the arbiter and workers using the
|
||||
statsD protocol over UDP. The `gunicorn.instrument.statsd` module turns
|
||||
Gunicorn into a statsD client.
|
||||
|
||||
|
||||
|
||||
UDP keeps Gunicorn isolated from slow statsD consumers, so metrics collection
|
||||
does not impact request handling.
|
||||
|
||||
Tell Gunicorn where the statsD server is located:
|
||||
|
||||
```bash
|
||||
gunicorn --statsd-host=localhost:8125 --statsd-prefix=service.app ...
|
||||
```
|
||||
|
||||
The `Statsd` logger subclasses `gunicorn.glogging.Logger` and tracks:
|
||||
|
||||
- `gunicorn.requests` — request rate per second
|
||||
- `gunicorn.request.duration` — request duration histogram (milliseconds.md)
|
||||
- `gunicorn.workers` — number of workers managed by the arbiter (gauge.md)
|
||||
- `gunicorn.log.critical` — rate of critical log messages
|
||||
- `gunicorn.log.error` — rate of error log messages
|
||||
- `gunicorn.log.warning` — rate of warning log messages
|
||||
- `gunicorn.log.exception` — rate of exceptional log messages
|
||||
|
||||
See the [`statsd_host`](reference/settings.md#statsd_host) setting for additional options.
|
||||
|
||||
[statsD](https://github.com/etsy/statsd)
|
||||
75
docs/content/news.md
Normal file
75
docs/content/news.md
Normal file
@ -0,0 +1,75 @@
|
||||
<span id="news"></span>
|
||||
# Changelog
|
||||
|
||||
## 23.0.0 - 2024-08-10
|
||||
|
||||
- minor docs fixes ([PR #3217](https://github.com/benoitc/gunicorn/pull/3217), [PR #3089](https://github.com/benoitc/gunicorn/pull/3089), [PR #3167](https://github.com/benoitc/gunicorn/pull/3167))
|
||||
- worker_class parameter accepts a class ([PR #3079](https://github.com/benoitc/gunicorn/pull/3079))
|
||||
- fix deadlock if request terminated during chunked parsing ([PR #2688](https://github.com/benoitc/gunicorn/pull/2688))
|
||||
- permit receiving Transfer-Encodings: compress, deflate, gzip ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261))
|
||||
- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261))
|
||||
- sdist generation now explicitly excludes sphinx build folder ([PR #3257](https://github.com/benoitc/gunicorn/pull/3257))
|
||||
- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` ([PR #2336](https://github.com/benoitc/gunicorn/pull/2336))
|
||||
- raise correct Exception when encounting invalid chunked requests ([PR #3258](https://github.com/benoitc/gunicorn/pull/3258))
|
||||
- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192))
|
||||
- include IPv6 loopback address ``[::1]`` in default for [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) and [proxy-allow-ips](reference/settings.md#proxy_allow_ips) ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192))
|
||||
|
||||
!!! note
|
||||
- The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release
|
||||
- Review your [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) setting if you are still not seeing the SCRIPT_NAME transmitted
|
||||
- Review your [forwarder-headers](reference/settings.md#forwarder_headers) setting if you are missing headers after upgrading from a version prior to 22.0.0
|
||||
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- refuse requests where the uri field is empty ([PR #3255](https://github.com/benoitc/gunicorn/pull/3255))
|
||||
- refuse requests with invalid CR/LR/NUL in heade field values ([PR #3253](https://github.com/benoitc/gunicorn/pull/3253))
|
||||
- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 ([PR #3260](https://github.com/benoitc/gunicorn/pull/3260))
|
||||
- If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies.
|
||||
|
||||
## 22.0.0 - 2024-04-17
|
||||
|
||||
- use `utime` to notify workers liveness
|
||||
- migrate setup to pyproject.toml
|
||||
- fix numerous security vulnerabilities in HTTP parser (closing some request smuggling vectors)
|
||||
- parsing additional requests is no longer attempted past unsupported request framing
|
||||
- on HTTP versions < 1.1 support for chunked transfer is refused (only used in exploits)
|
||||
- requests conflicting configured or passed SCRIPT_NAME now produce a verbose error
|
||||
- Trailer fields are no longer inspected for headers indicating secure scheme
|
||||
- support Python 3.12
|
||||
|
||||
### Breaking changes
|
||||
|
||||
- minimum version is Python 3.7
|
||||
- the limitations on valid characters in the HTTP method have been bounded to Internet Standards
|
||||
- requests specifying unsupported transfer coding (order.md) are refused by default (rare.md)
|
||||
- HTTP methods are no longer casefolded by default (IANA method registry contains none affected)
|
||||
- HTTP methods containing the number sign (#) are no longer accepted by default (rare.md)
|
||||
- HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported)
|
||||
- HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted
|
||||
- HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software
|
||||
- HTTP headers with empty field name are refused by default (no legitimate use cases, used in exploits)
|
||||
- requests with both Transfer-Encoding and Content-Length are refused by default (such a message might indicate an attempt to perform request smuggling)
|
||||
- empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies)
|
||||
|
||||
|
||||
### Security
|
||||
|
||||
- fix CVE-2024-1135
|
||||
|
||||
## History
|
||||
|
||||
- [2024](2024-news.md)
|
||||
- [2023](2023-news.md)
|
||||
- [2021](2021-news.md)
|
||||
- [2020](2020-news.md)
|
||||
- [2019](2019-news.md)
|
||||
- [2018](2018-news.md)
|
||||
- [2017](2017-news.md)
|
||||
- [2016](2016-news.md)
|
||||
- [2015](2015-news.md)
|
||||
- [2014](2014-news.md)
|
||||
- [2013](2013-news.md)
|
||||
- [2012](2012-news.md)
|
||||
- [2011](2011-news.md)
|
||||
- [2010](2010-news.md)
|
||||
1605
docs/content/reference/settings.md
Normal file
1605
docs/content/reference/settings.md
Normal file
File diff suppressed because it is too large
Load Diff
154
docs/content/run.md
Normal file
154
docs/content/run.md
Normal file
@ -0,0 +1,154 @@
|
||||
# Running Gunicorn
|
||||
|
||||
You can run Gunicorn directly from the command line or integrate it with
|
||||
popular frameworks like Django, Pyramid, or TurboGears. For deployment
|
||||
patterns see the [deployment guide](deploy.md).
|
||||
|
||||
## Commands
|
||||
|
||||
After installation you have access to the `gunicorn` executable.
|
||||
|
||||
<span id="gunicorn-cmd"></span>
|
||||
### `gunicorn`
|
||||
|
||||
Basic usage:
|
||||
|
||||
```bash
|
||||
gunicorn [OPTIONS] [WSGI_APP]
|
||||
```
|
||||
|
||||
`WSGI_APP` follows the pattern `MODULE_NAME:VARIABLE_NAME`. The module can be a
|
||||
full dotted path. The variable refers to a WSGI callable defined in that
|
||||
module.
|
||||
|
||||
!!! info "Changed in 20.1.0"
|
||||
`WSGI_APP` can be omitted when defined in a [configuration file](configure.md).
|
||||
|
||||
|
||||
|
||||
Example test application:
|
||||
|
||||
```python
|
||||
def app(environ, start_response):
|
||||
"""Simplest possible application object"""
|
||||
data = b"Hello, World!\n"
|
||||
status = "200 OK"
|
||||
response_headers = [
|
||||
("Content-type", "text/plain"),
|
||||
("Content-Length", str(len(data.md)))
|
||||
]
|
||||
start_response(status, response_headers)
|
||||
return iter([data])
|
||||
```
|
||||
|
||||
Run it with:
|
||||
|
||||
```bash
|
||||
gunicorn --workers=2 test:app
|
||||
```
|
||||
|
||||
You can also expose a factory function that returns the application:
|
||||
|
||||
```python
|
||||
def create_app():
|
||||
app = FrameworkApp()
|
||||
...
|
||||
return app
|
||||
```
|
||||
|
||||
```bash
|
||||
gunicorn --workers=2 'test:create_app()'
|
||||
```
|
||||
|
||||
Passing positional and keyword arguments is supported but prefer
|
||||
configuration files or environment variables for anything beyond quick tests.
|
||||
|
||||
#### Commonly used arguments
|
||||
|
||||
- `-c CONFIG`, `--config CONFIG` — configuration file (`PATH`, `file:PATH`, or
|
||||
`python:MODULE_NAME`).
|
||||
- `-b BIND`, `--bind BIND` — socket to bind (host, host:port, `fd://FD`,
|
||||
or `unix:PATH`).
|
||||
- `-w WORKERS`, `--workers WORKERS` — number of worker processes, typically
|
||||
two to four per CPU core. See the [FAQ](faq.md) for tuning tips.
|
||||
- `-k WORKERCLASS`, `--worker-class WORKERCLASS` — worker type (`sync`,
|
||||
`eventlet`, `gevent`, `tornado`, `gthread`). Read the
|
||||
[settings entry](reference/settings.md#worker_class) before switching classes.
|
||||
- `-n APP_NAME`, `--name APP_NAME` — set the process name (requires
|
||||
[`setproctitle`](https://pypi.python.org/pypi/setproctitle)).
|
||||
|
||||
You can pass any setting via the environment variable
|
||||
`GUNICORN_CMD_ARGS`. See the [configuration guide](configure.md) and
|
||||
[settings reference](reference/settings.md) for details.
|
||||
|
||||
## Integration
|
||||
|
||||
Gunicorn integrates cleanly with Django and Paste Deploy applications.
|
||||
|
||||
### Django
|
||||
|
||||
Gunicorn looks for a WSGI callable named `application`. A typical invocation is:
|
||||
|
||||
```bash
|
||||
gunicorn myproject.wsgi
|
||||
```
|
||||
|
||||
!!! note
|
||||
Ensure your project is on `PYTHONPATH`. The easiest way is to run this command
|
||||
from the directory containing `manage.py`.
|
||||
|
||||
|
||||
|
||||
Set environment variables with `--env` and add your project to `PYTHONPATH`
|
||||
if needed:
|
||||
|
||||
```bash
|
||||
gunicorn --env DJANGO_SETTINGS_MODULE=myproject.settings myproject.wsgi
|
||||
```
|
||||
|
||||
See [`raw_env`](reference/settings.md#raw_env) and [`pythonpath`](reference/settings.md#pythonpath) for
|
||||
more options.
|
||||
|
||||
### Paste Deployment
|
||||
|
||||
Frameworks such as Pyramid and TurboGears often rely on Paste Deployment
|
||||
configuration. You can use Gunicorn in two ways.
|
||||
|
||||
#### As a Paste server runner
|
||||
|
||||
Let your framework command (for example `pserve` or `gearbox`) load Gunicorn by
|
||||
configuring it as the server:
|
||||
|
||||
```ini
|
||||
[server:main]
|
||||
use = egg:gunicorn#main
|
||||
host = 127.0.0.1
|
||||
port = 8080
|
||||
workers = 3
|
||||
```
|
||||
|
||||
This approach is quick to set up but Gunicorn cannot control how the
|
||||
application loads. Options like [`reload`](reference/settings.md#reload) will be ignored and
|
||||
hot upgrades are unavailable. Features such as daemon mode may conflict with
|
||||
what your framework already provides. Prefer running those features through the
|
||||
framework (for example `pserve --reload`). Advanced configuration is still
|
||||
possible by pointing the `config` key at a Gunicorn configuration file.
|
||||
|
||||
#### Using Gunicorn's Paste support
|
||||
|
||||
Use the [`paste`](reference/settings.md#paste) option to load a Paste configuration directly
|
||||
with the Gunicorn CLI. This unlocks Gunicorn's reloader and hot code upgrades,
|
||||
while still letting Paste define the application object.
|
||||
|
||||
```bash
|
||||
gunicorn --paste development.ini -b :8080 --chdir /path/to/project
|
||||
```
|
||||
|
||||
Select a different application section by appending the name:
|
||||
|
||||
```bash
|
||||
gunicorn --paste development.ini#admin -b :8080 --chdir /path/to/project
|
||||
```
|
||||
|
||||
In both modes Gunicorn will honor any Paste `loggers` configuration unless you
|
||||
override it with Gunicorn-specific [logging settings](reference/settings.md#logging).
|
||||
97
docs/content/signals.md
Normal file
97
docs/content/signals.md
Normal file
@ -0,0 +1,97 @@
|
||||
<span id="signals"></span>
|
||||
# Signal Handling
|
||||
|
||||
A quick reference to the signals handled by Gunicorn. This includes the signals
|
||||
used internally to coordinate with worker processes.
|
||||
|
||||
## Master process
|
||||
|
||||
- `QUIT`, `INT` — quick shutdown.
|
||||
- `TERM` — graceful shutdown; waits for workers to finish requests up to
|
||||
[`graceful_timeout`](reference/settings.md#graceful_timeout).
|
||||
- `HUP` — reload configuration, spawn new workers, and gracefully stop old
|
||||
ones. If the app is not preloaded (see [`preload_app`](reference/settings.md#preload_app))
|
||||
the application code is reloaded too.
|
||||
- `TTIN` — increase worker count by one.
|
||||
- `TTOU` — decrease worker count by one.
|
||||
- `USR1` — reopen log files.
|
||||
- `USR2` — perform a binary upgrade. Send `TERM` to the old master afterwards
|
||||
to stop it. This also reloads preloaded applications (see
|
||||
[binary upgrades](#binary-upgrade)).
|
||||
- `WINCH` — gracefully stop workers when Gunicorn runs as a daemon.
|
||||
|
||||
## Worker process
|
||||
|
||||
Workers rarely need direct signalling—if the master stays alive it will respawn
|
||||
workers automatically.
|
||||
|
||||
- `QUIT`, `INT` — quick shutdown.
|
||||
- `TERM` — graceful shutdown.
|
||||
- `USR1` — reopen log files.
|
||||
|
||||
## Reload the configuration
|
||||
|
||||
Use `HUP` to reload Gunicorn on the fly:
|
||||
|
||||
```text
|
||||
2013-06-29 06:26:55 [20682] [INFO] Handling signal: hup
|
||||
2013-06-29 06:26:55 [20682] [INFO] Hang up: Master
|
||||
2013-06-29 06:26:55 [20703] [INFO] Booting worker with pid: 20703
|
||||
2013-06-29 06:26:55 [20702] [INFO] Booting worker with pid: 20702
|
||||
2013-06-29 06:26:55 [20688] [INFO] Worker exiting (pid: 20688)
|
||||
2013-06-29 06:26:55 [20687] [INFO] Worker exiting (pid: 20687)
|
||||
2013-06-29 06:26:55 [20689] [INFO] Worker exiting (pid: 20689)
|
||||
2013-06-29 06:26:55 [20704] [INFO] Booting worker with pid: 20704
|
||||
```
|
||||
|
||||
Gunicorn reloads its settings, starts new workers, and gracefully shuts down the
|
||||
previous ones. If the app is not preloaded it reloads the application module as
|
||||
well.
|
||||
|
||||
<span id="binary-upgrade"></span>
|
||||
## Upgrading to a new binary on the fly
|
||||
|
||||
!!! info "Changed in 19.6.0"
|
||||
PID files now follow the pattern `<name>.pid.2` instead of `<name>.pid.oldbin`.
|
||||
|
||||
|
||||
|
||||
You can replace the Gunicorn binary without downtime. Incoming requests remain
|
||||
served and preloaded applications reload.
|
||||
|
||||
1. Replace the old binary and send `USR2` to the master. Gunicorn starts a new
|
||||
master whose PID file ends with `.2` and spawns new workers.
|
||||
|
||||
```text
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
20844 benoitc 20 0 54808 11m 3352 S 0.0 0.1 0:00.36 gunicorn: master [test:app]
|
||||
20849 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app]
|
||||
20850 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app]
|
||||
20851 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app]
|
||||
20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.35 gunicorn: master [test:app]
|
||||
20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app]
|
||||
20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.00 gunicorn: worker [test:app]
|
||||
20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app]
|
||||
```
|
||||
|
||||
2. Send `WINCH` to the old master to gracefully stop its workers.
|
||||
|
||||
You can still roll back while the old master keeps its listen sockets:
|
||||
|
||||
1. Send `HUP` to the old master to restart its workers without reloading the
|
||||
config file.
|
||||
2. Send `TERM` to the new master to shut down its workers gracefully.
|
||||
3. Send `QUIT` to the new master to force it to exit.
|
||||
|
||||
If the new workers linger, send `KILL` after the new master quits.
|
||||
|
||||
To complete the upgrade, send `TERM` to the old master so only the new server
|
||||
continues running:
|
||||
|
||||
```text
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.45 gunicorn: master [test:app]
|
||||
20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app]
|
||||
20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app]
|
||||
20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app]
|
||||
```
|
||||
192
docs/content/styles/overrides.css
Normal file
192
docs/content/styles/overrides.css
Normal file
@ -0,0 +1,192 @@
|
||||
:root {
|
||||
--gunicorn-green: #1d692d;
|
||||
--gunicorn-green-dark: #14501f;
|
||||
--gunicorn-green-light: #2a8729;
|
||||
--gunicorn-cream: #f6f6f1;
|
||||
--md-primary-fg-color: var(--gunicorn-green-light);
|
||||
--md-primary-fg-color--light: #3da843;
|
||||
--md-primary-fg-color--dark: var(--gunicorn-green-dark);
|
||||
--md-accent-fg-color: var(--gunicorn-green);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--gunicorn-cream: #1d1f1d;
|
||||
--md-primary-fg-color: var(--gunicorn-green);
|
||||
--md-primary-fg-color--light: #3da843;
|
||||
--md-primary-fg-color--dark: var(--gunicorn-green-dark);
|
||||
--md-accent-fg-color: var(--gunicorn-green-light);
|
||||
}
|
||||
|
||||
.md-header__button.md-logo svg {
|
||||
height: 1.8rem;
|
||||
}
|
||||
|
||||
.md-typeset .hero {
|
||||
margin: 2rem 0 3rem;
|
||||
padding: 3.5rem;
|
||||
background: linear-gradient(135deg, rgba(29, 105, 45, 0.96), rgba(42, 135, 41, 0.85));
|
||||
color: #fff;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .hero {
|
||||
background: linear-gradient(135deg, rgba(20, 80, 31, 0.95), rgba(29, 105, 45, 0.88));
|
||||
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.md-typeset .hero__inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 2.5rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.md-typeset .hero__copy {
|
||||
flex: 1 1 320px;
|
||||
max-width: 520px;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.md-typeset .hero__copy h1 {
|
||||
margin: 0 0 1rem;
|
||||
font-size: 2.6rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.md-typeset .hero__cta {
|
||||
margin-top: 1.75rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.md-typeset .hero__code {
|
||||
flex: 1 1 260px;
|
||||
max-width: 420px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 14px;
|
||||
padding: 1.5rem;
|
||||
backdrop-filter: blur(4px);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .hero__code {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.md-typeset .hero__code pre {
|
||||
margin: 0 0 1rem;
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
color: #e8f5ea;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .hero__code pre {
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.md-typeset .hero__version {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.md-typeset .feature-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1.6rem;
|
||||
margin: 2.5rem 0 3rem;
|
||||
}
|
||||
|
||||
.md-typeset .feature-card {
|
||||
background: var(--gunicorn-cream);
|
||||
border-radius: 14px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .feature-card {
|
||||
background: rgba(45, 48, 45, 0.9);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
box-shadow: 0 18px 36px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
.md-typeset .feature-card h3 {
|
||||
margin-top: 0;
|
||||
font-size: 1.3rem;
|
||||
color: var(--gunicorn-green-dark);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .feature-card h3 {
|
||||
color: var(--gunicorn-cream);
|
||||
}
|
||||
|
||||
.md-typeset .feature-card a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-weight: 600;
|
||||
color: var(--gunicorn-green);
|
||||
}
|
||||
|
||||
.md-typeset .feature-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 18px 36px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.md-typeset .feature-card:hover a::after {
|
||||
content: '\\2192';
|
||||
opacity: 1;
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.md-typeset .feature-card a::after {
|
||||
content: '\\2192';
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.md-typeset .hero {
|
||||
padding: 2.25rem;
|
||||
}
|
||||
|
||||
.md-typeset .hero__copy h1 {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.md-typeset .hero {
|
||||
margin-top: 1.5rem;
|
||||
padding: 1.75rem;
|
||||
}
|
||||
|
||||
.md-typeset .hero__cta {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.md-typeset .hero__code {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.md-footer-meta__inner {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.md-typeset .hero__logo {
|
||||
height: 64px;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .hero__logo {
|
||||
filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.35));
|
||||
}
|
||||
11
docs/macros.py
Normal file
11
docs/macros.py
Normal file
@ -0,0 +1,11 @@
|
||||
from importlib import import_module
|
||||
|
||||
def define_env(env):
|
||||
"""Register template variables for MkDocs macros."""
|
||||
gunicorn = import_module("gunicorn")
|
||||
env.variables.update(
|
||||
release=gunicorn.__version__,
|
||||
version=gunicorn.__version__,
|
||||
github_repo="https://github.com/benoitc/gunicorn",
|
||||
pypi_url=f"https://pypi.org/project/gunicorn/{gunicorn.__version__}/",
|
||||
)
|
||||
35
docs/modernization-plan.md
Normal file
35
docs/modernization-plan.md
Normal file
@ -0,0 +1,35 @@
|
||||
# Website Modernization Plan
|
||||
|
||||
## Goals
|
||||
- Serve a single, canonical domain backed by a static MkDocs build.
|
||||
- Keep the documentation authoring experience entirely in Markdown.
|
||||
- Modernize the marketing home page with a refreshed visual identity.
|
||||
- Preserve the generated settings reference sourced from Python code.
|
||||
|
||||
## Architecture Overview
|
||||
- **Static site generator:** MkDocs with the Material theme.
|
||||
- **Content layout:** Markdown files in `docs/content/`, grouped by guides, reference, and news archives.
|
||||
- **Styling:** Lightweight CSS overrides in `docs/content/styles/overrides.css` for hero, feature cards, and color palette.
|
||||
- **Dynamic data:** `docs/macros.py` exposes the Gunicorn version, while `scripts/build_settings_doc.py` renders the settings reference into Markdown during every build.
|
||||
- **Assets:** SVG mascot and hero art live under `docs/content/assets/` so both the homepage and docs share the same branding.
|
||||
|
||||
## Completed Work
|
||||
- Removed Sphinx configuration, themes, and the legacy static snapshot under `docs/site/`.
|
||||
- Converted the entire content library (guides, FAQ, design notes, yearly news) from MyST/RST to MkDocs-friendly Markdown.
|
||||
- Rebuilt the homepage using Material’s layout primitives with responsive hero, CTAs, and feature cards.
|
||||
- Added CSS overrides that mirror Gunicorn’s brand colors and support light/dark modes.
|
||||
- Replaced the Sphinx extension with a standalone Markdown generator for the settings reference.
|
||||
- Introduced an automated MkDocs workflow (`.github/workflows/docs.yml`) that builds on every push and deploys to `gh-pages` from the `main` branch.
|
||||
|
||||
## Remaining Enhancements
|
||||
1. **Visual polish:** produce updated screenshots/asciicasts for quickstart and deployment examples; add Open Graph imagery.
|
||||
2. **Content review:** prune outdated news entries, tighten FAQs, and add framework-specific quickstarts (FastAPI, Flask, Django).
|
||||
3. **Accessibility & internationalization:** run axe audits, ensure color contrast, and consider adding minimal localization support.
|
||||
4. **Performance extras:** enable MkDocs search index minification and gzip the GitHub Pages output (served automatically once deployed).
|
||||
5. **Contributor docs:** extend `CONTRIBUTING.md` with MkDocs authoring tips, link to preview artifacts, and describe the `mkdocs serve` workflow.
|
||||
|
||||
## Deployment Checklist
|
||||
- [x] Update DNS to point away from ReadTheDocs once `gh-pages` is published.
|
||||
- [x] Verify `site_url` in `mkdocs.yml` for canonical URLs and sitemap generation.
|
||||
- [x] Ensure `CNAME` (if required) is checked into `gh-pages` during deployment.
|
||||
- [ ] Announce the migration to end-users and update links in READMEs and PyPI metadata.
|
||||
94
mkdocs.yml
Normal file
94
mkdocs.yml
Normal file
@ -0,0 +1,94 @@
|
||||
site_name: Gunicorn
|
||||
site_url: https://gunicorn.org
|
||||
repo_url: https://github.com/benoitc/gunicorn
|
||||
repo_name: benoitc/gunicorn
|
||||
docs_dir: docs/content
|
||||
use_directory_urls: true
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Guides:
|
||||
- Install: install.md
|
||||
- Run: run.md
|
||||
- Configure: configure.md
|
||||
- Deploy: deploy.md
|
||||
- Signals: signals.md
|
||||
- Instrumentation: instrumentation.md
|
||||
- Custom: custom.md
|
||||
- Community: community.md
|
||||
- FAQ: faq.md
|
||||
- Design: design.md
|
||||
- Reference:
|
||||
- Settings: reference/settings.md
|
||||
- News:
|
||||
- Latest: news.md
|
||||
- '2024': 2024-news.md
|
||||
- '2023': 2023-news.md
|
||||
- '2021': 2021-news.md
|
||||
- '2020': 2020-news.md
|
||||
- '2019': 2019-news.md
|
||||
- '2018': 2018-news.md
|
||||
- '2017': 2017-news.md
|
||||
- '2016': 2016-news.md
|
||||
- '2015': 2015-news.md
|
||||
- '2014': 2014-news.md
|
||||
- '2013': 2013-news.md
|
||||
- '2012': 2012-news.md
|
||||
- '2011': 2011-news.md
|
||||
- '2010': 2010-news.md
|
||||
|
||||
theme:
|
||||
name: material
|
||||
language: en
|
||||
logo: assets/gunicorn.svg
|
||||
favicon: assets/gunicorn.svg
|
||||
features:
|
||||
- content.code.copy
|
||||
- navigation.instant
|
||||
- navigation.tracking
|
||||
- navigation.sections
|
||||
- navigation.tabs
|
||||
- navigation.top
|
||||
- search.highlight
|
||||
- search.suggest
|
||||
- toc.follow
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- macros
|
||||
- gen-files:
|
||||
scripts:
|
||||
- scripts/build_settings_doc.py
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- attr_list
|
||||
- def_list
|
||||
- footnotes
|
||||
- md_in_html
|
||||
- tables
|
||||
- toc:
|
||||
permalink: true
|
||||
- pymdownx.details
|
||||
- pymdownx.highlight
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.magiclink
|
||||
- pymdownx.superfences
|
||||
- pymdownx.snippets:
|
||||
base_path:
|
||||
- .
|
||||
check_paths: true
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
|
||||
extra_css:
|
||||
- styles/overrides.css
|
||||
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/benoitc/gunicorn
|
||||
- icon: fontawesome/brands/python
|
||||
link: https://pypi.org/project/gunicorn/
|
||||
@ -5,5 +5,8 @@
|
||||
# otherwise, oldest known-working version is 61.2
|
||||
setuptools>=68.0
|
||||
|
||||
sphinx
|
||||
sphinx_rtd_theme
|
||||
mkdocs>=1.6
|
||||
mkdocs-material>=9.5
|
||||
mkdocs-gen-files>=0.5
|
||||
mkdocs-macros-plugin>=1.0
|
||||
pymdown-extensions>=10.0
|
||||
|
||||
254
scripts/build_settings_doc.py
Normal file
254
scripts/build_settings_doc.py
Normal file
@ -0,0 +1,254 @@
|
||||
"""Generate the Markdown settings reference for MkDocs."""
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
import re
|
||||
|
||||
import gunicorn.config as guncfg
|
||||
|
||||
HEAD = """\
|
||||
> **Generated file** — update `gunicorn/config.py` instead.
|
||||
|
||||
# Settings
|
||||
|
||||
This reference is built directly from `gunicorn.config.KNOWN_SETTINGS` and is
|
||||
regenerated during every documentation build.
|
||||
|
||||
!!! note
|
||||
Settings can be provided through the `GUNICORN_CMD_ARGS` environment
|
||||
variable. For example:
|
||||
|
||||
```console
|
||||
$ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app
|
||||
```
|
||||
|
||||
_Added in 19.7._
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def _format_default(setting: guncfg.Setting) -> tuple[str, bool]:
|
||||
if hasattr(setting, "default_doc"):
|
||||
text = textwrap.dedent(setting.default_doc).strip("\n")
|
||||
return text, True
|
||||
default = setting.default
|
||||
if callable(default):
|
||||
source = textwrap.dedent(inspect.getsource(default)).strip("\n")
|
||||
return f"```python\n{source}\n```", True
|
||||
if default == "":
|
||||
return "`''`", False
|
||||
return f"`{default!r}`", False
|
||||
|
||||
|
||||
def _format_cli(setting: guncfg.Setting) -> str | None:
|
||||
if not setting.cli:
|
||||
return None
|
||||
if setting.meta:
|
||||
variants = [f"`{opt} {setting.meta}`" for opt in setting.cli]
|
||||
else:
|
||||
variants = [f"`{opt}`" for opt in setting.cli]
|
||||
return ", ".join(variants)
|
||||
|
||||
|
||||
REF_MAP = {
|
||||
"forwarded-allow-ips": ("reference/settings.md", "forwarded_allow_ips"),
|
||||
"forwarder-headers": ("reference/settings.md", "forwarder_headers"),
|
||||
"proxy-allow-ips": ("reference/settings.md", "proxy_allow_ips"),
|
||||
"worker-class": ("reference/settings.md", "worker_class"),
|
||||
"reload": ("reference/settings.md", "reload"),
|
||||
"raw-env": ("reference/settings.md", "raw_env"),
|
||||
"check-config": ("reference/settings.md", "check_config"),
|
||||
"errorlog": ("reference/settings.md", "errorlog"),
|
||||
"logconfig": ("reference/settings.md", "logconfig"),
|
||||
"logconfig-json": ("reference/settings.md", "logconfig_json"),
|
||||
"ssl-context": ("reference/settings.md", "ssl_context"),
|
||||
"ssl-version": ("reference/settings.md", "ssl_version"),
|
||||
"blocking-os-fchmod": ("reference/settings.md", "blocking_os_fchmod"),
|
||||
"configuration_file": ("../configure.md", "configuration-file"),
|
||||
}
|
||||
|
||||
REF_PATTERN = re.compile(r":ref:`([^`]+)`")
|
||||
|
||||
|
||||
def _convert_refs(text: str) -> str:
|
||||
def repl(match: re.Match[str]) -> str:
|
||||
raw = match.group(1)
|
||||
if "<" in raw and raw.endswith(">"):
|
||||
label, target = raw.split("<", 1)
|
||||
target = target[:-1]
|
||||
label = label.replace("\n", " ").strip()
|
||||
else:
|
||||
label, target = None, raw.strip()
|
||||
info = REF_MAP.get(target)
|
||||
if not info:
|
||||
return (label or target).replace("\n", " ").strip()
|
||||
path, anchor = info
|
||||
if path.endswith(".md"):
|
||||
if path == "reference/settings.md" and anchor:
|
||||
href = f"#{anchor}"
|
||||
else:
|
||||
href = path + (f"#{anchor}" if anchor else "")
|
||||
else:
|
||||
href = path + (f"#{anchor}" if anchor else "")
|
||||
text = (label or target).replace("\n", " ").strip()
|
||||
return f"[{text}]({href})"
|
||||
|
||||
return REF_PATTERN.sub(repl, text)
|
||||
|
||||
|
||||
def _consume_indented(lines: List[str], start: int) -> tuple[str, int]:
|
||||
body: List[str] = []
|
||||
i = start
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
if line.startswith(" ") or not line.strip():
|
||||
body.append(line)
|
||||
i += 1
|
||||
else:
|
||||
break
|
||||
text = textwrap.dedent("\n".join(body)).strip("\n")
|
||||
return text, i
|
||||
|
||||
|
||||
def _convert_desc(desc: str) -> str:
|
||||
raw_lines = textwrap.dedent(desc).splitlines()
|
||||
output: List[str] = []
|
||||
i = 0
|
||||
while i < len(raw_lines):
|
||||
line = raw_lines[i]
|
||||
stripped = line.strip()
|
||||
if stripped.startswith(".. note::"):
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
output.append("!!! note")
|
||||
if body:
|
||||
for body_line in body.splitlines():
|
||||
output.append(f" {body_line}" if body_line else "")
|
||||
output.append("")
|
||||
continue
|
||||
if stripped.startswith(".. warning::"):
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
output.append("!!! warning")
|
||||
if body:
|
||||
for body_line in body.splitlines():
|
||||
output.append(f" {body_line}" if body_line else "")
|
||||
output.append("")
|
||||
continue
|
||||
if stripped.startswith(".. deprecated::"):
|
||||
version = stripped.split("::", 1)[1].strip()
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
title = f"Deprecated in {version}" if version else "Deprecated"
|
||||
output.append(f"!!! danger \"{title}\"")
|
||||
if body:
|
||||
for body_line in body.splitlines():
|
||||
output.append(f" {body_line}" if body_line else "")
|
||||
output.append("")
|
||||
continue
|
||||
if stripped.startswith(".. versionadded::"):
|
||||
version = stripped.split("::", 1)[1].strip()
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
title = f"Added in {version}" if version else "Added"
|
||||
output.append(f"!!! info \"{title}\"")
|
||||
if body:
|
||||
for body_line in body.splitlines():
|
||||
output.append(f" {body_line}" if body_line else "")
|
||||
output.append("")
|
||||
continue
|
||||
if stripped.startswith(".. versionchanged::"):
|
||||
version = stripped.split("::", 1)[1].strip()
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
title = f"Changed in {version}" if version else "Changed"
|
||||
output.append(f"!!! info \"{title}\"")
|
||||
if body:
|
||||
for body_line in body.splitlines():
|
||||
output.append(f" {body_line}" if body_line else "")
|
||||
output.append("")
|
||||
continue
|
||||
if stripped.startswith(".. code::") or stripped.startswith(".. code-block::"):
|
||||
language = stripped.split("::", 1)[1].strip()
|
||||
body, i = _consume_indented(raw_lines, i + 1)
|
||||
fence = language or "text"
|
||||
output.append(f"```{fence}")
|
||||
if body:
|
||||
output.append(body)
|
||||
output.append("```")
|
||||
output.append("")
|
||||
continue
|
||||
|
||||
output.append(line)
|
||||
i += 1
|
||||
|
||||
text = "\n".join(output)
|
||||
text = _convert_refs(text)
|
||||
# Collapse excessive blank lines
|
||||
text = re.sub(r"\n{3,}", "\n\n", text)
|
||||
return text.strip("\n")
|
||||
|
||||
|
||||
def _format_setting(setting: guncfg.Setting) -> str:
|
||||
lines: list[str] = [f"## `{setting.name}`", ""]
|
||||
|
||||
cli = _format_cli(setting)
|
||||
if cli:
|
||||
lines.extend((f"**Command line:** {cli}", ""))
|
||||
|
||||
default_text, is_block = _format_default(setting)
|
||||
if is_block:
|
||||
lines.append("**Default:**")
|
||||
lines.append("")
|
||||
lines.append(default_text)
|
||||
else:
|
||||
lines.append(f"**Default:** {default_text}")
|
||||
lines.append("")
|
||||
|
||||
desc = _convert_desc(setting.desc)
|
||||
if desc:
|
||||
lines.append(desc)
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def render_settings() -> str:
|
||||
sections: list[str] = [HEAD, '<span id="blocking_os_fchmod"></span>', ""]
|
||||
known_settings = sorted(guncfg.KNOWN_SETTINGS, key=lambda s: s.section)
|
||||
current_section: str | None = None
|
||||
|
||||
for setting in known_settings:
|
||||
if setting.section != current_section:
|
||||
current_section = setting.section
|
||||
sections.append(f"# {current_section}\n")
|
||||
sections.append(_format_setting(setting))
|
||||
|
||||
return "\n".join(sections).strip() + "\n"
|
||||
|
||||
|
||||
def _write_output(markdown: str) -> None:
|
||||
try:
|
||||
import mkdocs_gen_files # type: ignore
|
||||
except ImportError:
|
||||
mkdocs_gen_files = None
|
||||
|
||||
if mkdocs_gen_files is not None:
|
||||
try:
|
||||
with mkdocs_gen_files.open("reference/settings.md", "w") as fh:
|
||||
fh.write(markdown)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
output = Path(__file__).resolve().parents[1] / "docs" / "content" / "reference" / "settings.md"
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(markdown, encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
markdown = render_settings()
|
||||
_write_output(markdown)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
643
uv.lock
generated
Normal file
643
uv.lock
generated
Normal file
@ -0,0 +1,643 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[[package]]
|
||||
name = "backports-asyncio-runner"
|
||||
version = "1.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893, upload-time = "2025-07-02T02:27:15.685Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cffi"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.13.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/9a/3742e58fd04b233df95c012ee9f3dfe04708a5e1d32613bd2d47d4e1be0d/coverage-7.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1fa280b3ad78eea5be86f94f461c04943d942697e0dac889fa18fff8f5f9147", size = 218633, upload-time = "2025-12-28T15:40:10.165Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/45/7e6bdc94d89cd7c8017ce735cf50478ddfe765d4fbf0c24d71d30ea33d7a/coverage-7.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c3d8c679607220979434f494b139dfb00131ebf70bb406553d69c1ff01a5c33d", size = 219147, upload-time = "2025-12-28T15:40:12.069Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/38/0d6a258625fd7f10773fe94097dc16937a5f0e3e0cdf3adef67d3ac6baef/coverage-7.13.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:339dc63b3eba969067b00f41f15ad161bf2946613156fb131266d8debc8e44d0", size = 245894, upload-time = "2025-12-28T15:40:13.556Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/58/409d15ea487986994cbd4d06376e9860e9b157cfbfd402b1236770ab8dd2/coverage-7.13.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db622b999ffe49cb891f2fff3b340cdc2f9797d01a0a202a0973ba2562501d90", size = 247721, upload-time = "2025-12-28T15:40:15.37Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/bf/6e8056a83fd7a96c93341f1ffe10df636dd89f26d5e7b9ca511ce3bcf0df/coverage-7.13.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1443ba9acbb593fa7c1c29e011d7c9761545fe35e7652e85ce7f51a16f7e08d", size = 249585, upload-time = "2025-12-28T15:40:17.226Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/15/e1daff723f9f5959acb63cbe35b11203a9df77ee4b95b45fffd38b318390/coverage-7.13.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c832ec92c4499ac463186af72f9ed4d8daec15499b16f0a879b0d1c8e5cf4a3b", size = 246597, upload-time = "2025-12-28T15:40:19.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/74/a6/1efd31c5433743a6ddbc9d37ac30c196bb07c7eab3d74fbb99b924c93174/coverage-7.13.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:562ec27dfa3f311e0db1ba243ec6e5f6ab96b1edfcfc6cf86f28038bc4961ce6", size = 247626, upload-time = "2025-12-28T15:40:20.846Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/9f/1609267dd3e749f57fdd66ca6752567d1c13b58a20a809dc409b263d0b5f/coverage-7.13.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4de84e71173d4dada2897e5a0e1b7877e5eefbfe0d6a44edee6ce31d9b8ec09e", size = 245629, upload-time = "2025-12-28T15:40:22.397Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/f6/6815a220d5ec2466383d7cc36131b9fa6ecbe95c50ec52a631ba733f306a/coverage-7.13.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a5a68357f686f8c4d527a2dc04f52e669c2fc1cbde38f6f7eb6a0e58cbd17cae", size = 245901, upload-time = "2025-12-28T15:40:23.836Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/58/40576554cd12e0872faf6d2c0eb3bc85f71d78427946ddd19ad65201e2c0/coverage-7.13.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:77cc258aeb29a3417062758975521eae60af6f79e930d6993555eeac6a8eac29", size = 246505, upload-time = "2025-12-28T15:40:25.421Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/77/9233a90253fba576b0eee81707b5781d0e21d97478e5377b226c5b096c0f/coverage-7.13.1-cp310-cp310-win32.whl", hash = "sha256:bb4f8c3c9a9f34423dba193f241f617b08ffc63e27f67159f60ae6baf2dcfe0f", size = 221257, upload-time = "2025-12-28T15:40:27.217Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/43/e842ff30c1a0a623ec80db89befb84a3a7aad7bfe44a6ea77d5a3e61fedd/coverage-7.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:c8e2706ceb622bc63bac98ebb10ef5da80ed70fbd8a7999a5076de3afaef0fb1", size = 222191, upload-time = "2025-12-28T15:40:28.916Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/9b/77baf488516e9ced25fc215a6f75d803493fc3f6a1a1227ac35697910c2a/coverage-7.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a55d509a1dc5a5b708b5dad3b5334e07a16ad4c2185e27b40e4dba796ab7f88", size = 218755, upload-time = "2025-12-28T15:40:30.812Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/cd/7ab01154e6eb79ee2fab76bf4d89e94c6648116557307ee4ebbb85e5c1bf/coverage-7.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4d010d080c4888371033baab27e47c9df7d6fb28d0b7b7adf85a4a49be9298b3", size = 219257, upload-time = "2025-12-28T15:40:32.333Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/d5/b11ef7863ffbbdb509da0023fad1e9eda1c0eaea61a6d2ea5b17d4ac706e/coverage-7.13.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d938b4a840fb1523b9dfbbb454f652967f18e197569c32266d4d13f37244c3d9", size = 249657, upload-time = "2025-12-28T15:40:34.1Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/7c/347280982982383621d29b8c544cf497ae07ac41e44b1ca4903024131f55/coverage-7.13.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bf100a3288f9bb7f919b87eb84f87101e197535b9bd0e2c2b5b3179633324fee", size = 251581, upload-time = "2025-12-28T15:40:36.131Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/f6/ebcfed11036ade4c0d75fa4453a6282bdd225bc073862766eec184a4c643/coverage-7.13.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef6688db9bf91ba111ae734ba6ef1a063304a881749726e0d3575f5c10a9facf", size = 253691, upload-time = "2025-12-28T15:40:37.626Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/92/af8f5582787f5d1a8b130b2dcba785fa5e9a7a8e121a0bb2220a6fdbdb8a/coverage-7.13.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b609fc9cdbd1f02e51f67f51e5aee60a841ef58a68d00d5ee2c0faf357481a3", size = 249799, upload-time = "2025-12-28T15:40:39.47Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/24/aa/0e39a2a3b16eebf7f193863323edbff38b6daba711abaaf807d4290cf61a/coverage-7.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c43257717611ff5e9a1d79dce8e47566235ebda63328718d9b65dd640bc832ef", size = 251389, upload-time = "2025-12-28T15:40:40.954Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/46/7f0c13111154dc5b978900c0ccee2e2ca239b910890e674a77f1363d483e/coverage-7.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e09fbecc007f7b6afdfb3b07ce5bd9f8494b6856dd4f577d26c66c391b829851", size = 249450, upload-time = "2025-12-28T15:40:42.489Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/ca/e80da6769e8b669ec3695598c58eef7ad98b0e26e66333996aee6316db23/coverage-7.13.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:a03a4f3a19a189919c7055098790285cc5c5b0b3976f8d227aea39dbf9f8bfdb", size = 249170, upload-time = "2025-12-28T15:40:44.279Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/18/9e29baabdec1a8644157f572541079b4658199cfd372a578f84228e860de/coverage-7.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3820778ea1387c2b6a818caec01c63adc5b3750211af6447e8dcfb9b6f08dbba", size = 250081, upload-time = "2025-12-28T15:40:45.748Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/f8/c3021625a71c3b2f516464d322e41636aea381018319050a8114105872ee/coverage-7.13.1-cp311-cp311-win32.whl", hash = "sha256:ff10896fa55167371960c5908150b434b71c876dfab97b69478f22c8b445ea19", size = 221281, upload-time = "2025-12-28T15:40:47.232Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/56/c216625f453df6e0559ed666d246fcbaaa93f3aa99eaa5080cea1229aa3d/coverage-7.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:a998cc0aeeea4c6d5622a3754da5a493055d2d95186bad877b0a34ea6e6dbe0a", size = 222215, upload-time = "2025-12-28T15:40:49.19Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/9a/be342e76f6e531cae6406dc46af0d350586f24d9b67fdfa6daee02df71af/coverage-7.13.1-cp311-cp311-win_arm64.whl", hash = "sha256:fea07c1a39a22614acb762e3fbbb4011f65eedafcb2948feeef641ac78b4ee5c", size = 220886, upload-time = "2025-12-28T15:40:51.067Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/8a/87af46cccdfa78f53db747b09f5f9a21d5fc38d796834adac09b30a8ce74/coverage-7.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6f34591000f06e62085b1865c9bc5f7858df748834662a51edadfd2c3bfe0dd3", size = 218927, upload-time = "2025-12-28T15:40:52.814Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/a8/6e22fdc67242a4a5a153f9438d05944553121c8f4ba70cb072af4c41362e/coverage-7.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b67e47c5595b9224599016e333f5ec25392597a89d5744658f837d204e16c63e", size = 219288, upload-time = "2025-12-28T15:40:54.262Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/0a/853a76e03b0f7c4375e2ca025df45c918beb367f3e20a0a8e91967f6e96c/coverage-7.13.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e7b8bd70c48ffb28461ebe092c2345536fb18bbbf19d287c8913699735f505c", size = 250786, upload-time = "2025-12-28T15:40:56.059Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/b4/694159c15c52b9f7ec7adf49d50e5f8ee71d3e9ef38adb4445d13dd56c20/coverage-7.13.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c223d078112e90dc0e5c4e35b98b9584164bea9fbbd221c0b21c5241f6d51b62", size = 253543, upload-time = "2025-12-28T15:40:57.585Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/b2/7f1f0437a5c855f87e17cf5d0dc35920b6440ff2b58b1ba9788c059c26c8/coverage-7.13.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:794f7c05af0763b1bbd1b9e6eff0e52ad068be3b12cd96c87de037b01390c968", size = 254635, upload-time = "2025-12-28T15:40:59.443Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/d1/73c3fdb8d7d3bddd9473c9c6a2e0682f09fc3dfbcb9c3f36412a7368bcab/coverage-7.13.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0642eae483cc8c2902e4af7298bf886d605e80f26382124cddc3967c2a3df09e", size = 251202, upload-time = "2025-12-28T15:41:01.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/3c/f0edf75dcc152f145d5598329e864bbbe04ab78660fe3e8e395f9fff010f/coverage-7.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f5e772ed5fef25b3de9f2008fe67b92d46831bd2bc5bdc5dd6bfd06b83b316f", size = 252566, upload-time = "2025-12-28T15:41:03.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/17/b3/e64206d3c5f7dcbceafd14941345a754d3dbc78a823a6ed526e23b9cdaab/coverage-7.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45980ea19277dc0a579e432aef6a504fe098ef3a9032ead15e446eb0f1191aee", size = 250711, upload-time = "2025-12-28T15:41:06.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/ad/28a3eb970a8ef5b479ee7f0c484a19c34e277479a5b70269dc652b730733/coverage-7.13.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e4f18eca6028ffa62adbd185a8f1e1dd242f2e68164dba5c2b74a5204850b4cf", size = 250278, upload-time = "2025-12-28T15:41:08.285Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/e3/c8f0f1a93133e3e1291ca76cbb63565bd4b5c5df63b141f539d747fff348/coverage-7.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8dca5590fec7a89ed6826fce625595279e586ead52e9e958d3237821fbc750c", size = 252154, upload-time = "2025-12-28T15:41:09.969Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/bf/9939c5d6859c380e405b19e736321f1c7d402728792f4c752ad1adcce005/coverage-7.13.1-cp312-cp312-win32.whl", hash = "sha256:ff86d4e85188bba72cfb876df3e11fa243439882c55957184af44a35bd5880b7", size = 221487, upload-time = "2025-12-28T15:41:11.468Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/dc/7282856a407c621c2aad74021680a01b23010bb8ebf427cf5eacda2e876f/coverage-7.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:16cc1da46c04fb0fb128b4dc430b78fa2aba8a6c0c9f8eb391fd5103409a6ac6", size = 222299, upload-time = "2025-12-28T15:41:13.386Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/79/176a11203412c350b3e9578620013af35bcdb79b651eb976f4a4b32044fa/coverage-7.13.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d9bc218650022a768f3775dd7fdac1886437325d8d295d923ebcfef4892ad5c", size = 220941, upload-time = "2025-12-28T15:41:14.975Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/8e/ba0e597560c6563fc0adb902fda6526df5d4aa73bb10adf0574d03bd2206/coverage-7.13.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:97ab3647280d458a1f9adb85244e81587505a43c0c7cff851f5116cd2814b894", size = 218996, upload-time = "2025-12-28T15:42:04.978Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/8e/764c6e116f4221dc7aa26c4061181ff92edb9c799adae6433d18eeba7a14/coverage-7.13.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8f572d989142e0908e6acf57ad1b9b86989ff057c006d13b76c146ec6a20216a", size = 219326, upload-time = "2025-12-28T15:42:06.691Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/a6/6130dc6d8da28cdcbb0f2bf8865aeca9b157622f7c0031e48c6cf9a0e591/coverage-7.13.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d72140ccf8a147e94274024ff6fd8fb7811354cf7ef88b1f0a988ebaa5bc774f", size = 250374, upload-time = "2025-12-28T15:42:08.786Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/2b/783ded568f7cd6b677762f780ad338bf4b4750205860c17c25f7c708995e/coverage-7.13.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d3c9f051b028810f5a87c88e5d6e9af3c0ff32ef62763bf15d29f740453ca909", size = 252882, upload-time = "2025-12-28T15:42:10.515Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/b2/9808766d082e6a4d59eb0cc881a57fc1600eb2c5882813eefff8254f71b5/coverage-7.13.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f398ba4df52d30b1763f62eed9de5620dcde96e6f491f4c62686736b155aa6e4", size = 254218, upload-time = "2025-12-28T15:42:12.208Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/ea/52a985bb447c871cb4d2e376e401116520991b597c85afdde1ea9ef54f2c/coverage-7.13.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:132718176cc723026d201e347f800cd1a9e4b62ccd3f82476950834dad501c75", size = 250391, upload-time = "2025-12-28T15:42:14.21Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/1d/125b36cc12310718873cfc8209ecfbc1008f14f4f5fa0662aa608e579353/coverage-7.13.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e549d642426e3579b3f4b92d0431543b012dcb6e825c91619d4e93b7363c3f9", size = 252239, upload-time = "2025-12-28T15:42:16.292Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6a/16/10c1c164950cade470107f9f14bbac8485f8fb8515f515fca53d337e4a7f/coverage-7.13.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:90480b2134999301eea795b3a9dbf606c6fbab1b489150c501da84a959442465", size = 250196, upload-time = "2025-12-28T15:42:18.54Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/c6/cd860fac08780c6fd659732f6ced1b40b79c35977c1356344e44d72ba6c4/coverage-7.13.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e825dbb7f84dfa24663dd75835e7257f8882629fc11f03ecf77d84a75134b864", size = 250008, upload-time = "2025-12-28T15:42:20.365Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/3a/a8c58d3d38f82a5711e1e0a67268362af48e1a03df27c03072ac30feefcf/coverage-7.13.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:623dcc6d7a7ba450bbdbeedbaa0c42b329bdae16491af2282f12a7e809be7eb9", size = 251671, upload-time = "2025-12-28T15:42:22.114Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/bc/fd4c1da651d037a1e3d53e8cb3f8182f4b53271ffa9a95a2e211bacc0349/coverage-7.13.1-cp314-cp314-win32.whl", hash = "sha256:6e73ebb44dca5f708dc871fe0b90cf4cff1a13f9956f747cc87b535a840386f5", size = 221777, upload-time = "2025-12-28T15:42:23.919Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/50/71acabdc8948464c17e90b5ffd92358579bd0910732c2a1c9537d7536aa6/coverage-7.13.1-cp314-cp314-win_amd64.whl", hash = "sha256:be753b225d159feb397bd0bf91ae86f689bad0da09d3b301478cd39b878ab31a", size = 222592, upload-time = "2025-12-28T15:42:25.619Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/c8/a6fb943081bb0cc926499c7907731a6dc9efc2cbdc76d738c0ab752f1a32/coverage-7.13.1-cp314-cp314-win_arm64.whl", hash = "sha256:228b90f613b25ba0019361e4ab81520b343b622fc657daf7e501c4ed6a2366c0", size = 221169, upload-time = "2025-12-28T15:42:27.629Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/61/d5b7a0a0e0e40d62e59bc8c7aa1afbd86280d82728ba97f0673b746b78e2/coverage-7.13.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:60cfb538fe9ef86e5b2ab0ca8fc8d62524777f6c611dcaf76dc16fbe9b8e698a", size = 219730, upload-time = "2025-12-28T15:42:29.306Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a3/2c/8881326445fd071bb49514d1ce97d18a46a980712b51fee84f9ab42845b4/coverage-7.13.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:57dfc8048c72ba48a8c45e188d811e5efd7e49b387effc8fb17e97936dde5bf6", size = 220001, upload-time = "2025-12-28T15:42:31.319Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/d7/50de63af51dfa3a7f91cc37ad8fcc1e244b734232fbc8b9ab0f3c834a5cd/coverage-7.13.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3f2f725aa3e909b3c5fdb8192490bdd8e1495e85906af74fe6e34a2a77ba0673", size = 261370, upload-time = "2025-12-28T15:42:32.992Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/2c/d31722f0ec918fd7453b2758312729f645978d212b410cd0f7c2aed88a94/coverage-7.13.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ee68b21909686eeb21dfcba2c3b81fee70dcf38b140dcd5aa70680995fa3aa5", size = 263485, upload-time = "2025-12-28T15:42:34.759Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/7a/2c114fa5c5fc08ba0777e4aec4c97e0b4a1afcb69c75f1f54cff78b073ab/coverage-7.13.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:724b1b270cb13ea2e6503476e34541a0b1f62280bc997eab443f87790202033d", size = 265890, upload-time = "2025-12-28T15:42:36.517Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/d9/f0794aa1c74ceabc780fe17f6c338456bbc4e96bd950f2e969f48ac6fb20/coverage-7.13.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:916abf1ac5cf7eb16bc540a5bf75c71c43a676f5c52fcb9fe75a2bd75fb944e8", size = 260445, upload-time = "2025-12-28T15:42:38.646Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/23/184b22a00d9bb97488863ced9454068c79e413cb23f472da6cbddc6cfc52/coverage-7.13.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:776483fd35b58d8afe3acbd9988d5de592ab6da2d2a865edfdbc9fdb43e7c486", size = 263357, upload-time = "2025-12-28T15:42:40.788Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/bd/58af54c0c9199ea4190284f389005779d7daf7bf3ce40dcd2d2b2f96da69/coverage-7.13.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b6f3b96617e9852703f5b633ea01315ca45c77e879584f283c44127f0f1ec564", size = 260959, upload-time = "2025-12-28T15:42:42.808Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/2a/6839294e8f78a4891bf1df79d69c536880ba2f970d0ff09e7513d6e352e9/coverage-7.13.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:bd63e7b74661fed317212fab774e2a648bc4bb09b35f25474f8e3325d2945cd7", size = 259792, upload-time = "2025-12-28T15:42:44.818Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/c3/528674d4623283310ad676c5af7414b9850ab6d55c2300e8aa4b945ec554/coverage-7.13.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:933082f161bbb3e9f90d00990dc956120f608cdbcaeea15c4d897f56ef4fe416", size = 262123, upload-time = "2025-12-28T15:42:47.108Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/c5/8c0515692fb4c73ac379d8dc09b18eaf0214ecb76ea6e62467ba7a1556ff/coverage-7.13.1-cp314-cp314t-win32.whl", hash = "sha256:18be793c4c87de2965e1c0f060f03d9e5aff66cfeae8e1dbe6e5b88056ec153f", size = 222562, upload-time = "2025-12-28T15:42:49.144Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/0e/c0a0c4678cb30dac735811db529b321d7e1c9120b79bd728d4f4d6b010e9/coverage-7.13.1-cp314-cp314t-win_amd64.whl", hash = "sha256:0e42e0ec0cd3e0d851cb3c91f770c9301f48647cb2877cb78f74bdaa07639a79", size = 223670, upload-time = "2025-12-28T15:42:51.218Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/5f/b177aa0011f354abf03a8f30a85032686d290fdeed4222b27d36b4372a50/coverage-7.13.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eaecf47ef10c72ece9a2a92118257da87e460e113b83cc0d2905cbbe931792b4", size = 221707, upload-time = "2025-12-28T15:42:53.034Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
toml = [
|
||||
{ name = "tomli", marker = "python_full_version <= '3.11'" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eventlet"
|
||||
version = "0.40.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "dnspython" },
|
||||
{ name = "greenlet" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/d8/f72d8583db7c559445e0e9500a9b9787332370c16980802204a403634585/eventlet-0.40.4.tar.gz", hash = "sha256:69bef712b1be18b4930df6f0c495d2a882bf7b63aa111e7b6eeff461cfcaf26f", size = 565920, upload-time = "2025-11-26T13:57:31.126Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/22/6d/8e1fa901f6a8307f90e7bd932064e27a0062a4a7a16af38966a9c3293c52/eventlet-0.40.4-py3-none-any.whl", hash = "sha256:6326c6d0bf55810bece151f7a5750207c610f389ba110ffd1541ed6e5215485b", size = 364588, upload-time = "2025-11-26T13:57:29.09Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gevent"
|
||||
version = "25.9.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" },
|
||||
{ name = "greenlet", marker = "platform_python_implementation == 'CPython'" },
|
||||
{ name = "zope-event" },
|
||||
{ name = "zope-interface" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9e/48/b3ef2673ffb940f980966694e40d6d32560f3ffa284ecaeb5ea3a90a6d3f/gevent-25.9.1.tar.gz", hash = "sha256:adf9cd552de44a4e6754c51ff2e78d9193b7fa6eab123db9578a210e657235dd", size = 5059025, upload-time = "2025-09-17T16:15:34.528Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/c7/2c60fc4e5c9144f2b91e23af8d87c626870ad3183cfd09d2b3ba6d699178/gevent-25.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:856b990be5590e44c3a3dc6c8d48a40eaccbb42e99d2b791d11d1e7711a4297e", size = 1831980, upload-time = "2025-09-17T15:41:22.597Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/ae/49bf0a01f95a1c92c001d7b3f482a2301626b8a0617f448c4cd14ca9b5d4/gevent-25.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:fe1599d0b30e6093eb3213551751b24feeb43db79f07e89d98dd2f3330c9063e", size = 1918777, upload-time = "2025-09-17T15:48:57.223Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/3f/266d2eb9f5d75c184a55a39e886b53a4ea7f42ff31f195220a363f0e3f9e/gevent-25.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:f0d8b64057b4bf1529b9ef9bd2259495747fba93d1f836c77bfeaacfec373fd0", size = 1869235, upload-time = "2025-09-17T15:49:18.255Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/24/c0c7c7db70ca74c7b1918388ebda7c8c2a3c3bff0bbfbaa9280ed04b3340/gevent-25.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b56cbc820e3136ba52cd690bdf77e47a4c239964d5f80dc657c1068e0fe9521c", size = 2177334, upload-time = "2025-09-17T15:15:10.073Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/1e/de96bd033c03955f54c455b51a5127b1d540afcfc97838d1801fafce6d2e/gevent-25.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c5fa9ce5122c085983e33e0dc058f81f5264cebe746de5c401654ab96dddfca8", size = 1847708, upload-time = "2025-09-17T15:52:38.475Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/26/8b/6851e9cd3e4f322fa15c1d196cbf1a8a123da69788b078227dd13dd4208f/gevent-25.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:03c74fec58eda4b4edc043311fca8ba4f8744ad1632eb0a41d5ec25413581975", size = 2234274, upload-time = "2025-09-17T15:24:07.797Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/d8/b1178b70538c91493bec283018b47c16eab4bac9ddf5a3d4b7dd905dab60/gevent-25.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a8ae9f895e8651d10b0a8328a61c9c53da11ea51b666388aa99b0ce90f9fdc27", size = 1695326, upload-time = "2025-09-17T20:10:25.455Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/86/03f8db0704fed41b0fa830425845f1eb4e20c92efa3f18751ee17809e9c6/gevent-25.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5aff9e8342dc954adb9c9c524db56c2f3557999463445ba3d9cbe3dada7b7", size = 1792418, upload-time = "2025-09-17T15:41:24.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/35/f6b3a31f0849a62cfa2c64574bcc68a781d5499c3195e296e892a121a3cf/gevent-25.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1cdf6db28f050ee103441caa8b0448ace545364f775059d5e2de089da975c457", size = 1875700, upload-time = "2025-09-17T15:48:59.652Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/1e/75055950aa9b48f553e061afa9e3728061b5ccecca358cef19166e4ab74a/gevent-25.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:812debe235a8295be3b2a63b136c2474241fa5c58af55e6a0f8cfc29d4936235", size = 1831365, upload-time = "2025-09-17T15:49:19.426Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/e8/5c1f6968e5547e501cfa03dcb0239dff55e44c3660a37ec534e32a0c008f/gevent-25.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b28b61ff9216a3d73fe8f35669eefcafa957f143ac534faf77e8a19eb9e6883a", size = 2122087, upload-time = "2025-09-17T15:15:12.329Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/2c/ebc5d38a7542af9fb7657bfe10932a558bb98c8a94e4748e827d3823fced/gevent-25.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5e4b6278b37373306fc6b1e5f0f1cf56339a1377f67c35972775143d8d7776ff", size = 1808776, upload-time = "2025-09-17T15:52:40.16Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/26/e1d7d6c8ffbf76fe1fbb4e77bdb7f47d419206adc391ec40a8ace6ebbbf0/gevent-25.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d99f0cb2ce43c2e8305bf75bee61a8bde06619d21b9d0316ea190fc7a0620a56", size = 2179141, upload-time = "2025-09-17T15:24:09.895Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/6c/bb21fd9c095506aeeaa616579a356aa50935165cc0f1e250e1e0575620a7/gevent-25.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:72152517ecf548e2f838c61b4be76637d99279dbaa7e01b3924df040aa996586", size = 1677941, upload-time = "2025-09-17T19:59:50.185Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/49/e55930ba5259629eb28ac7ee1abbca971996a9165f902f0249b561602f24/gevent-25.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:46b188248c84ffdec18a686fcac5dbb32365d76912e14fda350db5dc0bfd4f86", size = 2955991, upload-time = "2025-09-17T14:52:30.568Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/88/63dc9e903980e1da1e16541ec5c70f2b224ec0a8e34088cb42794f1c7f52/gevent-25.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f2b54ea3ca6f0c763281cd3f96010ac7e98c2e267feb1221b5a26e2ca0b9a692", size = 1808503, upload-time = "2025-09-17T15:41:25.59Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/8d/7236c3a8f6ef7e94c22e658397009596fa90f24c7d19da11ad7ab3a9248e/gevent-25.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a834804ac00ed8a92a69d3826342c677be651b1c3cd66cc35df8bc711057aa2", size = 1890001, upload-time = "2025-09-17T15:49:01.227Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/63/0d7f38c4a2085ecce26b50492fc6161aa67250d381e26d6a7322c309b00f/gevent-25.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:323a27192ec4da6b22a9e51c3d9d896ff20bc53fdc9e45e56eaab76d1c39dd74", size = 1855335, upload-time = "2025-09-17T15:49:20.582Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/18/da5211dfc54c7a57e7432fd9a6ffeae1ce36fe5a313fa782b1c96529ea3d/gevent-25.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6ea78b39a2c51d47ff0f130f4c755a9a4bbb2dd9721149420ad4712743911a51", size = 2109046, upload-time = "2025-09-17T15:15:13.817Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/5a/7bb5ec8e43a2c6444853c4a9f955f3e72f479d7c24ea86c95fb264a2de65/gevent-25.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dc45cd3e1cc07514a419960af932a62eb8515552ed004e56755e4bf20bad30c5", size = 1827099, upload-time = "2025-09-17T15:52:41.384Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/d4/b63a0a60635470d7d986ef19897e893c15326dd69e8fb342c76a4f07fe9e/gevent-25.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34e01e50c71eaf67e92c186ee0196a039d6e4f4b35670396baed4a2d8f1b347f", size = 2172623, upload-time = "2025-09-17T15:24:12.03Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/98/caf06d5d22a7c129c1fb2fc1477306902a2c8ddfd399cd26bbbd4caf2141/gevent-25.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acd6bcd5feabf22c7c5174bd3b9535ee9f088d2bbce789f740ad8d6554b18f3", size = 1682837, upload-time = "2025-09-17T19:48:47.318Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/77/b97f086388f87f8ad3e01364f845004aef0123d4430241c7c9b1f9bde742/gevent-25.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:4f84591d13845ee31c13f44bdf6bd6c3dbf385b5af98b2f25ec328213775f2ed", size = 2973739, upload-time = "2025-09-17T14:53:30.279Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/2e/9d5f204ead343e5b27bbb2fedaec7cd0009d50696b2266f590ae845d0331/gevent-25.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9cdbb24c276a2d0110ad5c978e49daf620b153719ac8a548ce1250a7eb1b9245", size = 1809165, upload-time = "2025-09-17T15:41:27.193Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/3e/791d1bf1eb47748606d5f2c2aa66571f474d63e0176228b1f1fd7b77ab37/gevent-25.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:88b6c07169468af631dcf0fdd3658f9246d6822cc51461d43f7c44f28b0abb82", size = 1890638, upload-time = "2025-09-17T15:49:02.45Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/5c/9ad0229b2b4d81249ca41e4f91dd8057deaa0da6d4fbe40bf13cdc5f7a47/gevent-25.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b7bb0e29a7b3e6ca9bed2394aa820244069982c36dc30b70eb1004dd67851a48", size = 1857118, upload-time = "2025-09-17T15:49:22.125Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/2a/3010ed6c44179a3a5c5c152e6de43a30ff8bc2c8de3115ad8733533a018f/gevent-25.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2951bb070c0ee37b632ac9134e4fdaad70d2e660c931bb792983a0837fe5b7d7", size = 2111598, upload-time = "2025-09-17T15:15:15.226Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/75/6bbe57c19a7aa4527cc0f9afcdf5a5f2aed2603b08aadbccb5bf7f607ff4/gevent-25.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4e17c2d57e9a42e25f2a73d297b22b60b2470a74be5a515b36c984e1a246d47", size = 1829059, upload-time = "2025-09-17T15:52:42.596Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/6e/19a9bee9092be45679cb69e4dd2e0bf5f897b7140b4b39c57cc123d24829/gevent-25.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d94936f8f8b23d9de2251798fcb603b84f083fdf0d7f427183c1828fb64f117", size = 2173529, upload-time = "2025-09-17T15:24:13.897Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/4f/50de9afd879440e25737e63f5ba6ee764b75a3abe17376496ab57f432546/gevent-25.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:eb51c5f9537b07da673258b4832f6635014fee31690c3f0944d34741b69f92fa", size = 1681518, upload-time = "2025-09-17T19:39:47.488Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/1a/948f8167b2cdce573cf01cec07afc64d0456dc134b07900b26ac7018b37e/gevent-25.9.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1a3fe4ea1c312dbf6b375b416925036fe79a40054e6bf6248ee46526ea628be1", size = 2982934, upload-time = "2025-09-17T14:54:11.302Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/ec/726b146d1d3aad82e03d2e1e1507048ab6072f906e83f97f40667866e582/gevent-25.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0adb937f13e5fb90cca2edf66d8d7e99d62a299687400ce2edee3f3504009356", size = 1813982, upload-time = "2025-09-17T15:41:28.506Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/5d/5f83f17162301662bd1ce702f8a736a8a8cac7b7a35e1d8b9866938d1f9d/gevent-25.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:427f869a2050a4202d93cf7fd6ab5cffb06d3e9113c10c967b6e2a0d45237cb8", size = 1894902, upload-time = "2025-09-17T15:49:03.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/cd/cf5e74e353f60dab357829069ffc300a7bb414c761f52cf8c0c6e9728b8d/gevent-25.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c049880175e8c93124188f9d926af0a62826a3b81aa6d3074928345f8238279e", size = 1861792, upload-time = "2025-09-17T15:49:23.279Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/65/b9a4526d4a4edce26fe4b3b993914ec9dc64baabad625a3101e51adb17f3/gevent-25.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b5a67a0974ad9f24721034d1e008856111e0535f1541499f72a733a73d658d1c", size = 2113215, upload-time = "2025-09-17T15:15:16.34Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/be/7d35731dfaf8370795b606e515d964a0967e129db76ea7873f552045dd39/gevent-25.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1d0f5d8d73f97e24ea8d24d8be0f51e0cf7c54b8021c1fddb580bf239474690f", size = 1833449, upload-time = "2025-09-17T15:52:43.75Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/58/7bc52544ea5e63af88c4a26c90776feb42551b7555a1c89c20069c168a3f/gevent-25.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddd3ff26e5c4240d3fbf5516c2d9d5f2a998ef87cfb73e1429cfaeaaec860fa6", size = 2176034, upload-time = "2025-09-17T15:24:15.676Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/69/a7c4ba2ffbc7c7dbf6d8b4f5d0f0a421f7815d229f4909854266c445a3d4/gevent-25.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:bb63c0d6cb9950cc94036a4995b9cc4667b8915366613449236970f4394f94d7", size = 1703019, upload-time = "2025-09-17T19:30:55.272Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "greenlet"
|
||||
version = "3.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/cb/48e964c452ca2b92175a9b2dca037a553036cb053ba69e284650ce755f13/greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e", size = 274908, upload-time = "2025-12-04T14:23:26.435Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/da/38d7bff4d0277b594ec557f479d65272a893f1f2a716cad91efeb8680953/greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62", size = 577113, upload-time = "2025-12-04T14:50:05.493Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/f2/89c5eb0faddc3ff014f1c04467d67dee0d1d334ab81fadbf3744847f8a8a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32", size = 590338, upload-time = "2025-12-04T14:57:41.136Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/80/d7/db0a5085035d05134f8c089643da2b44cc9b80647c39e93129c5ef170d8f/greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45", size = 601098, upload-time = "2025-12-04T15:07:11.898Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/a6/e959a127b630a58e23529972dbc868c107f9d583b5a9f878fb858c46bc1a/greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948", size = 590206, upload-time = "2025-12-04T14:26:01.254Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/60/29035719feb91798693023608447283b266b12efc576ed013dd9442364bb/greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794", size = 1550668, upload-time = "2025-12-04T15:04:22.439Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/5f/783a23754b691bfa86bd72c3033aa107490deac9b2ef190837b860996c9f/greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5", size = 1615483, upload-time = "2025-12-04T14:27:28.083Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/d5/c339b3b4bc8198b7caa4f2bd9fd685ac9f29795816d8db112da3d04175bb/greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71", size = 301164, upload-time = "2025-12-04T14:42:51.577Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f8/0a/a3871375c7b9727edaeeea994bfff7c63ff7804c9829c19309ba2e058807/greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb", size = 276379, upload-time = "2025-12-04T14:23:30.498Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/43/ab/7ebfe34dce8b87be0d11dae91acbf76f7b8246bf9d6b319c741f99fa59c6/greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3", size = 597294, upload-time = "2025-12-04T14:50:06.847Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/39/f1c8da50024feecd0793dbd5e08f526809b8ab5609224a2da40aad3a7641/greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655", size = 607742, upload-time = "2025-12-04T14:57:42.349Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/77/cb/43692bcd5f7a0da6ec0ec6d58ee7cddb606d055ce94a62ac9b1aa481e969/greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7", size = 622297, upload-time = "2025-12-04T15:07:13.552Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/75/b0/6bde0b1011a60782108c01de5913c588cf51a839174538d266de15e4bf4d/greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b", size = 609885, upload-time = "2025-12-04T14:26:02.368Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/0e/49b46ac39f931f59f987b7cd9f34bfec8ef81d2a1e6e00682f55be5de9f4/greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53", size = 1567424, upload-time = "2025-12-04T15:04:23.757Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/f5/49a9ac2dff7f10091935def9165c90236d8f175afb27cbed38fb1d61ab6b/greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614", size = 1636017, upload-time = "2025-12-04T14:27:29.688Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/2f/28592176381b9ab2cafa12829ba7b472d177f3acc35d8fbcf3673d966fff/greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739", size = 275140, upload-time = "2025-12-04T14:23:01.282Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/80/fbe937bf81e9fca98c981fe499e59a3f45df2a04da0baa5c2be0dca0d329/greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808", size = 599219, upload-time = "2025-12-04T14:50:08.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/ff/7c985128f0514271b8268476af89aee6866df5eec04ac17dcfbc676213df/greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54", size = 610211, upload-time = "2025-12-04T14:57:43.968Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/07/c47a82d881319ec18a4510bb30463ed6891f2ad2c1901ed5ec23d3de351f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492", size = 624311, upload-time = "2025-12-04T15:07:14.697Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/8e/424b8c6e78bd9837d14ff7df01a9829fc883ba2ab4ea787d4f848435f23f/greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527", size = 612833, upload-time = "2025-12-04T14:26:03.669Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/ba/56699ff9b7c76ca12f1cdc27a886d0f81f2189c3455ff9f65246780f713d/greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39", size = 1567256, upload-time = "2025-12-04T15:04:25.276Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/37/f31136132967982d698c71a281a8901daf1a8fbab935dce7c0cf15f942cc/greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8", size = 1636483, upload-time = "2025-12-04T14:27:30.804Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/71/ba21c3fb8c5dce83b8c01f458a42e99ffdb1963aeec08fff5a18588d8fd7/greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38", size = 301833, upload-time = "2025-12-04T14:32:23.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d7/7c/f0a6d0ede2c7bf092d00bc83ad5bafb7e6ec9b4aab2fbdfa6f134dc73327/greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f", size = 275671, upload-time = "2025-12-04T14:23:05.267Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/44/06/dac639ae1a50f5969d82d2e3dd9767d30d6dbdbab0e1a54010c8fe90263c/greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365", size = 646360, upload-time = "2025-12-04T14:50:10.026Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/94/0fb76fe6c5369fba9bf98529ada6f4c3a1adf19e406a47332245ef0eb357/greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3", size = 658160, upload-time = "2025-12-04T14:57:45.41Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/79/d2c70cae6e823fac36c3bbc9077962105052b7ef81db2f01ec3b9bf17e2b/greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45", size = 671388, upload-time = "2025-12-04T15:07:15.789Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/14/bab308fc2c1b5228c3224ec2bf928ce2e4d21d8046c161e44a2012b5203e/greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955", size = 660166, upload-time = "2025-12-04T14:26:05.099Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/d2/91465d39164eaa0085177f61983d80ffe746c5a1860f009811d498e7259c/greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55", size = 1615193, upload-time = "2025-12-04T15:04:27.041Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/1b/83d110a37044b92423084d52d5d5a3b3a73cafb51b547e6d7366ff62eff1/greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc", size = 1683653, upload-time = "2025-12-04T14:27:32.366Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/9a/9030e6f9aa8fd7808e9c31ba4c38f87c4f8ec324ee67431d181fe396d705/greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170", size = 305387, upload-time = "2025-12-04T14:26:51.063Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/66/bd6317bc5932accf351fc19f177ffba53712a202f9df10587da8df257c7e/greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931", size = 282638, upload-time = "2025-12-04T14:25:20.941Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/cf/cc81cb030b40e738d6e69502ccbd0dd1bced0588e958f9e757945de24404/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388", size = 651145, upload-time = "2025-12-04T14:50:11.039Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/ea/1020037b5ecfe95ca7df8d8549959baceb8186031da83d5ecceff8b08cd2/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3", size = 654236, upload-time = "2025-12-04T14:57:47.007Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/cc/1e4bae2e45ca2fa55299f4e85854606a78ecc37fead20d69322f96000504/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221", size = 662506, upload-time = "2025-12-04T15:07:16.906Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/b9/f8025d71a6085c441a7eaff0fd928bbb275a6633773667023d19179fe815/greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b", size = 653783, upload-time = "2025-12-04T14:26:06.225Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/c7/876a8c7a7485d5d6b5c6821201d542ef28be645aa024cfe1145b35c120c1/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd", size = 1614857, upload-time = "2025-12-04T15:04:28.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/dc/041be1dff9f23dac5f48a43323cd0789cb798342011c19a248d9c9335536/greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9", size = 1676034, upload-time = "2025-12-04T14:27:33.531Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
eventlet = [
|
||||
{ name = "eventlet" },
|
||||
]
|
||||
gevent = [
|
||||
{ name = "gevent" },
|
||||
]
|
||||
setproctitle = [
|
||||
{ name = "setproctitle" },
|
||||
]
|
||||
testing = [
|
||||
{ name = "coverage" },
|
||||
{ name = "eventlet" },
|
||||
{ name = "gevent" },
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-asyncio" },
|
||||
{ name = "pytest-cov" },
|
||||
]
|
||||
tornado = [
|
||||
{ name = "tornado" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "coverage", marker = "extra == 'testing'" },
|
||||
{ name = "eventlet", marker = "extra == 'eventlet'", specifier = ">=0.40.3" },
|
||||
{ name = "eventlet", marker = "extra == 'testing'", specifier = ">=0.40.3" },
|
||||
{ name = "gevent", marker = "extra == 'gevent'", specifier = ">=23.9.0" },
|
||||
{ name = "gevent", marker = "extra == 'testing'", specifier = ">=23.9.0" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pytest", marker = "extra == 'testing'" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'testing'" },
|
||||
{ name = "pytest-cov", marker = "extra == 'testing'" },
|
||||
{ name = "setproctitle", marker = "extra == 'setproctitle'" },
|
||||
{ name = "tornado", marker = "extra == 'tornado'", specifier = ">=6.5.0" },
|
||||
]
|
||||
provides-extras = ["gevent", "eventlet", "tornado", "gthread", "setproctitle", "testing"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-asyncio"
|
||||
version = "1.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" },
|
||||
{ name = "pytest" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "7.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "coverage", extra = ["toml"] },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "setproctitle"
|
||||
version = "1.3.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8d/48/49393a96a2eef1ab418b17475fb92b8fcfad83d099e678751b05472e69de/setproctitle-1.3.7.tar.gz", hash = "sha256:bc2bc917691c1537d5b9bca1468437176809c7e11e5694ca79a9ca12345dcb9e", size = 27002, upload-time = "2025-09-05T12:51:25.278Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/48/fb401ec8c4953d519d05c87feca816ad668b8258448ff60579ac7a1c1386/setproctitle-1.3.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf555b6299f10a6eb44e4f96d2f5a3884c70ce25dc5c8796aaa2f7b40e72cb1b", size = 18079, upload-time = "2025-09-05T12:49:07.732Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/a3/c2b0333c2716fb3b4c9a973dd113366ac51b4f8d56b500f4f8f704b4817a/setproctitle-1.3.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:690b4776f9c15aaf1023bb07d7c5b797681a17af98a4a69e76a1d504e41108b7", size = 13099, upload-time = "2025-09-05T12:49:09.222Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/f8/17bda581c517678260e6541b600eeb67745f53596dc077174141ba2f6702/setproctitle-1.3.7-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:00afa6fc507967d8c9d592a887cdc6c1f5742ceac6a4354d111ca0214847732c", size = 31793, upload-time = "2025-09-05T12:49:10.297Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/d1/76a33ae80d4e788ecab9eb9b53db03e81cfc95367ec7e3fbf4989962fedd/setproctitle-1.3.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9e02667f6b9fc1238ba753c0f4b0a37ae184ce8f3bbbc38e115d99646b3f4cd3", size = 32779, upload-time = "2025-09-05T12:49:12.157Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/27/1a07c38121967061564f5e0884414a5ab11a783260450172d4fc68c15621/setproctitle-1.3.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:83fcd271567d133eb9532d3b067c8a75be175b2b3b271e2812921a05303a693f", size = 34578, upload-time = "2025-09-05T12:49:13.393Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d8/d4/725e6353935962d8bb12cbf7e7abba1d0d738c7f6935f90239d8e1ccf913/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13fe37951dda1a45c35d77d06e3da5d90e4f875c4918a7312b3b4556cfa7ff64", size = 32030, upload-time = "2025-09-05T12:49:15.362Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/67/24/e4677ae8e1cb0d549ab558b12db10c175a889be0974c589c428fece5433e/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a05509cfb2059e5d2ddff701d38e474169e9ce2a298cf1b6fd5f3a213a553fe5", size = 33363, upload-time = "2025-09-05T12:49:16.829Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/d4/69ce66e4373a48fdbb37489f3ded476bb393e27f514968c3a69a67343ae0/setproctitle-1.3.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6da835e76ae18574859224a75db6e15c4c2aaa66d300a57efeaa4c97ca4c7381", size = 31508, upload-time = "2025-09-05T12:49:18.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/5a/42c1ed0e9665d068146a68326529b5686a1881c8b9197c2664db4baf6aeb/setproctitle-1.3.7-cp310-cp310-win32.whl", hash = "sha256:9e803d1b1e20240a93bac0bc1025363f7f80cb7eab67dfe21efc0686cc59ad7c", size = 12558, upload-time = "2025-09-05T12:49:19.742Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/fe/dd206cc19a25561921456f6cb12b405635319299b6f366e0bebe872abc18/setproctitle-1.3.7-cp310-cp310-win_amd64.whl", hash = "sha256:a97200acc6b64ec4cada52c2ecaf1fba1ef9429ce9c542f8a7db5bcaa9dcbd95", size = 13245, upload-time = "2025-09-05T12:49:21.023Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/cd/1b7ba5cad635510720ce19d7122154df96a2387d2a74217be552887c93e5/setproctitle-1.3.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a600eeb4145fb0ee6c287cb82a2884bd4ec5bbb076921e287039dcc7b7cc6dd0", size = 18085, upload-time = "2025-09-05T12:49:22.183Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/1a/b2da0a620490aae355f9d72072ac13e901a9fec809a6a24fc6493a8f3c35/setproctitle-1.3.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97a090fed480471bb175689859532709e28c085087e344bca45cf318034f70c4", size = 13097, upload-time = "2025-09-05T12:49:23.322Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/2e/bd03ff02432a181c1787f6fc2a678f53b7dacdd5ded69c318fe1619556e8/setproctitle-1.3.7-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1607b963e7b53e24ec8a2cb4e0ab3ae591d7c6bf0a160feef0551da63452b37f", size = 32191, upload-time = "2025-09-05T12:49:24.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/78/1e62fc0937a8549f2220445ed2175daacee9b6764c7963b16148119b016d/setproctitle-1.3.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a20fb1a3974e2dab857870cf874b325b8705605cb7e7e8bcbb915bca896f52a9", size = 33203, upload-time = "2025-09-05T12:49:25.871Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/3c/65edc65db3fa3df400cf13b05e9d41a3c77517b4839ce873aa6b4043184f/setproctitle-1.3.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8d961bba676e07d77665204f36cffaa260f526e7b32d07ab3df6a2c1dfb44ba", size = 34963, upload-time = "2025-09-05T12:49:27.044Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/32/89157e3de997973e306e44152522385f428e16f92f3cf113461489e1e2ee/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:db0fd964fbd3a9f8999b502f65bd2e20883fdb5b1fae3a424e66db9a793ed307", size = 32398, upload-time = "2025-09-05T12:49:28.909Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/18/77a765a339ddf046844cb4513353d8e9dcd8183da9cdba6e078713e6b0b2/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:db116850fcf7cca19492030f8d3b4b6e231278e8fe097a043957d22ce1bdf3ee", size = 33657, upload-time = "2025-09-05T12:49:30.323Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/63/f0b6205c64d74d2a24a58644a38ec77bdbaa6afc13747e75973bf8904932/setproctitle-1.3.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316664d8b24a5c91ee244460bdaf7a74a707adaa9e14fbe0dc0a53168bb9aba1", size = 31836, upload-time = "2025-09-05T12:49:32.309Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/51/e1277f9ba302f1a250bbd3eedbbee747a244b3cc682eb58fb9733968f6d8/setproctitle-1.3.7-cp311-cp311-win32.whl", hash = "sha256:b74774ca471c86c09b9d5037c8451fff06bb82cd320d26ae5a01c758088c0d5d", size = 12556, upload-time = "2025-09-05T12:49:33.529Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/7b/822a23f17e9003dfdee92cd72758441ca2a3680388da813a371b716fb07f/setproctitle-1.3.7-cp311-cp311-win_amd64.whl", hash = "sha256:acb9097213a8dd3410ed9f0dc147840e45ca9797785272928d4be3f0e69e3be4", size = 13243, upload-time = "2025-09-05T12:49:34.553Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/f0/2dc88e842077719d7384d86cc47403e5102810492b33680e7dadcee64cd8/setproctitle-1.3.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2dc99aec591ab6126e636b11035a70991bc1ab7a261da428491a40b84376654e", size = 18049, upload-time = "2025-09-05T12:49:36.241Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/b4/50940504466689cda65680c9e9a1e518e5750c10490639fa687489ac7013/setproctitle-1.3.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdd8aa571b7aa39840fdbea620e308a19691ff595c3a10231e9ee830339dd798", size = 13079, upload-time = "2025-09-05T12:49:38.088Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/99/71630546b9395b095f4082be41165d1078204d1696c2d9baade3de3202d0/setproctitle-1.3.7-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2906b6c7959cdb75f46159bf0acd8cc9906cf1361c9e1ded0d065fe8f9039629", size = 32932, upload-time = "2025-09-05T12:49:39.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/22/cee06af4ffcfb0e8aba047bd44f5262e644199ae7527ae2c1f672b86495c/setproctitle-1.3.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6915964a6dda07920a1159321dcd6d94fc7fc526f815ca08a8063aeca3c204f1", size = 33736, upload-time = "2025-09-05T12:49:40.565Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/00/a5949a8bb06ef5e7df214fc393bb2fb6aedf0479b17214e57750dfdd0f24/setproctitle-1.3.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cff72899861c765bd4021d1ff1c68d60edc129711a2fdba77f9cb69ef726a8b6", size = 35605, upload-time = "2025-09-05T12:49:42.362Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/3a/50caca532a9343828e3bf5778c7a84d6c737a249b1796d50dd680290594d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b7cb05bd446687ff816a3aaaf831047fc4c364feff7ada94a66024f1367b448c", size = 33143, upload-time = "2025-09-05T12:49:43.515Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/14/b843a251296ce55e2e17c017d6b9f11ce0d3d070e9265de4ecad948b913d/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3a57b9a00de8cae7e2a1f7b9f0c2ac7b69372159e16a7708aa2f38f9e5cc987a", size = 34434, upload-time = "2025-09-05T12:49:45.31Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/b7/06145c238c0a6d2c4bc881f8be230bb9f36d2bf51aff7bddcb796d5eed67/setproctitle-1.3.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d8828b356114f6b308b04afe398ed93803d7fca4a955dd3abe84430e28d33739", size = 32795, upload-time = "2025-09-05T12:49:46.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/dc/ef76a81fac9bf27b84ed23df19c1f67391a753eed6e3c2254ebcb5133f56/setproctitle-1.3.7-cp312-cp312-win32.whl", hash = "sha256:b0304f905efc845829ac2bc791ddebb976db2885f6171f4a3de678d7ee3f7c9f", size = 12552, upload-time = "2025-09-05T12:49:47.635Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/5b/a9fe517912cd6e28cf43a212b80cb679ff179a91b623138a99796d7d18a0/setproctitle-1.3.7-cp312-cp312-win_amd64.whl", hash = "sha256:9888ceb4faea3116cf02a920ff00bfbc8cc899743e4b4ac914b03625bdc3c300", size = 13247, upload-time = "2025-09-05T12:49:49.16Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/2f/fcedcade3b307a391b6e17c774c6261a7166aed641aee00ed2aad96c63ce/setproctitle-1.3.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3736b2a423146b5e62230502e47e08e68282ff3b69bcfe08a322bee73407922", size = 18047, upload-time = "2025-09-05T12:49:50.271Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/ae/afc141ca9631350d0a80b8f287aac79a76f26b6af28fd8bf92dae70dc2c5/setproctitle-1.3.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3384e682b158d569e85a51cfbde2afd1ab57ecf93ea6651fe198d0ba451196ee", size = 13073, upload-time = "2025-09-05T12:49:51.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/87/ed/0a4f00315bc02510395b95eec3d4aa77c07192ee79f0baae77ea7b9603d8/setproctitle-1.3.7-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0564a936ea687cd24dffcea35903e2a20962aa6ac20e61dd3a207652401492dd", size = 33284, upload-time = "2025-09-05T12:49:52.741Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/e4/adf3c4c0a2173cb7920dc9df710bcc67e9bcdbf377e243b7a962dc31a51a/setproctitle-1.3.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5d1cb3f81531f0eb40e13246b679a1bdb58762b170303463cb06ecc296f26d0", size = 34104, upload-time = "2025-09-05T12:49:54.416Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/4f/6daf66394152756664257180439d37047aa9a1cfaa5e4f5ed35e93d1dc06/setproctitle-1.3.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a7d159e7345f343b44330cbba9194169b8590cb13dae940da47aa36a72aa9929", size = 35982, upload-time = "2025-09-05T12:49:56.295Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1b/62/f2c0595403cf915db031f346b0e3b2c0096050e90e0be658a64f44f4278a/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0b5074649797fd07c72ca1f6bff0406f4a42e1194faac03ecaab765ce605866f", size = 33150, upload-time = "2025-09-05T12:49:58.025Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/29/10dd41cde849fb2f9b626c846b7ea30c99c81a18a5037a45cc4ba33c19a7/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:61e96febced3f61b766115381d97a21a6265a0f29188a791f6df7ed777aef698", size = 34463, upload-time = "2025-09-05T12:49:59.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/3c/cedd8eccfaf15fb73a2c20525b68c9477518917c9437737fa0fda91e378f/setproctitle-1.3.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:047138279f9463f06b858e579cc79580fbf7a04554d24e6bddf8fe5dddbe3d4c", size = 32848, upload-time = "2025-09-05T12:50:01.107Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/3e/0a0e27d1c9926fecccfd1f91796c244416c70bf6bca448d988638faea81d/setproctitle-1.3.7-cp313-cp313-win32.whl", hash = "sha256:7f47accafac7fe6535ba8ba9efd59df9d84a6214565108d0ebb1199119c9cbbd", size = 12544, upload-time = "2025-09-05T12:50:15.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/36/1b/6bf4cb7acbbd5c846ede1c3f4d6b4ee52744d402e43546826da065ff2ab7/setproctitle-1.3.7-cp313-cp313-win_amd64.whl", hash = "sha256:fe5ca35aeec6dc50cabab9bf2d12fbc9067eede7ff4fe92b8f5b99d92e21263f", size = 13235, upload-time = "2025-09-05T12:50:16.89Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/a4/d588d3497d4714750e3eaf269e9e8985449203d82b16b933c39bd3fc52a1/setproctitle-1.3.7-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:10e92915c4b3086b1586933a36faf4f92f903c5554f3c34102d18c7d3f5378e9", size = 18058, upload-time = "2025-09-05T12:50:02.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/77/7637f7682322a7244e07c373881c7e982567e2cb1dd2f31bd31481e45500/setproctitle-1.3.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:de879e9c2eab637f34b1a14c4da1e030c12658cdc69ee1b3e5be81b380163ce5", size = 13072, upload-time = "2025-09-05T12:50:03.601Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/09/f366eca0973cfbac1470068d1313fa3fe3de4a594683385204ec7f1c4101/setproctitle-1.3.7-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c18246d88e227a5b16248687514f95642505000442165f4b7db354d39d0e4c29", size = 34490, upload-time = "2025-09-05T12:50:04.948Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/36/611fc2ed149fdea17c3677e1d0df30d8186eef9562acc248682b91312706/setproctitle-1.3.7-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7081f193dab22df2c36f9fc6d113f3793f83c27891af8fe30c64d89d9a37e152", size = 35267, upload-time = "2025-09-05T12:50:06.015Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/a4/64e77d0671446bd5a5554387b69e1efd915274686844bea733714c828813/setproctitle-1.3.7-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cc9b901ce129350637426a89cfd650066a4adc6899e47822e2478a74023ff7c", size = 37376, upload-time = "2025-09-05T12:50:07.484Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/bc/ad9c664fe524fb4a4b2d3663661a5c63453ce851736171e454fa2cdec35c/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80e177eff2d1ec172188d0d7fd9694f8e43d3aab76a6f5f929bee7bf7894e98b", size = 33963, upload-time = "2025-09-05T12:50:09.056Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/01/a36de7caf2d90c4c28678da1466b47495cbbad43badb4e982d8db8167ed4/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:23e520776c445478a67ee71b2a3c1ffdafbe1f9f677239e03d7e2cc635954e18", size = 35550, upload-time = "2025-09-05T12:50:10.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/68/17e8aea0ed5ebc17fbf03ed2562bfab277c280e3625850c38d92a7b5fcd9/setproctitle-1.3.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5fa1953126a3b9bd47049d58c51b9dac72e78ed120459bd3aceb1bacee72357c", size = 33727, upload-time = "2025-09-05T12:50:12.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/33/90a3bf43fe3a2242b4618aa799c672270250b5780667898f30663fd94993/setproctitle-1.3.7-cp313-cp313t-win32.whl", hash = "sha256:4a5e212bf438a4dbeece763f4962ad472c6008ff6702e230b4f16a037e2f6f29", size = 12549, upload-time = "2025-09-05T12:50:13.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/0e/50d1f07f3032e1f23d814ad6462bc0a138f369967c72494286b8a5228e40/setproctitle-1.3.7-cp313-cp313t-win_amd64.whl", hash = "sha256:cf2727b733e90b4f874bac53e3092aa0413fe1ea6d4f153f01207e6ce65034d9", size = 13243, upload-time = "2025-09-05T12:50:14.146Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/c7/43ac3a98414f91d1b86a276bc2f799ad0b4b010e08497a95750d5bc42803/setproctitle-1.3.7-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:80c36c6a87ff72eabf621d0c79b66f3bdd0ecc79e873c1e9f0651ee8bf215c63", size = 18052, upload-time = "2025-09-05T12:50:17.928Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cd/2c/dc258600a25e1a1f04948073826bebc55e18dbd99dc65a576277a82146fa/setproctitle-1.3.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b53602371a52b91c80aaf578b5ada29d311d12b8a69c0c17fbc35b76a1fd4f2e", size = 13071, upload-time = "2025-09-05T12:50:19.061Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/26/8e3bb082992f19823d831f3d62a89409deb6092e72fc6940962983ffc94f/setproctitle-1.3.7-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fcb966a6c57cf07cc9448321a08f3be6b11b7635be502669bc1d8745115d7e7f", size = 33180, upload-time = "2025-09-05T12:50:20.395Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/af/ae692a20276d1159dd0cf77b0bcf92cbb954b965655eb4a69672099bb214/setproctitle-1.3.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46178672599b940368d769474fe13ecef1b587d58bb438ea72b9987f74c56ea5", size = 34043, upload-time = "2025-09-05T12:50:22.454Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/b2/6a092076324dd4dac1a6d38482bedebbff5cf34ef29f58585ec76e47bc9d/setproctitle-1.3.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7f9e9e3ff135cbcc3edd2f4cf29b139f4aca040d931573102742db70ff428c17", size = 35892, upload-time = "2025-09-05T12:50:23.937Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/1a/8836b9f28cee32859ac36c3df85aa03e1ff4598d23ea17ca2e96b5845a8f/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:14c7eba8d90c93b0e79c01f0bd92a37b61983c27d6d7d5a3b5defd599113d60e", size = 32898, upload-time = "2025-09-05T12:50:25.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/22/8fabdc24baf42defb599714799d8445fe3ae987ec425a26ec8e80ea38f8e/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9e64e98077fb30b6cf98073d6c439cd91deb8ebbf8fc62d9dbf52bd38b0c6ac0", size = 34308, upload-time = "2025-09-05T12:50:26.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/15/1b/b9bee9de6c8cdcb3b3a6cb0b3e773afdb86bbbc1665a3bfa424a4294fda2/setproctitle-1.3.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b91387cc0f02a00ac95dcd93f066242d3cca10ff9e6153de7ee07069c6f0f7c8", size = 32536, upload-time = "2025-09-05T12:50:28.5Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/37/0c/75e5f2685a5e3eda0b39a8b158d6d8895d6daf3ba86dec9e3ba021510272/setproctitle-1.3.7-cp314-cp314-win32.whl", hash = "sha256:52b054a61c99d1b72fba58b7f5486e04b20fefc6961cd76722b424c187f362ed", size = 12731, upload-time = "2025-09-05T12:50:43.955Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/ae/acddbce90d1361e1786e1fb421bc25baeb0c22ef244ee5d0176511769ec8/setproctitle-1.3.7-cp314-cp314-win_amd64.whl", hash = "sha256:5818e4080ac04da1851b3ec71e8a0f64e3748bf9849045180566d8b736702416", size = 13464, upload-time = "2025-09-05T12:50:45.057Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/01/6d/20886c8ff2e6d85e3cabadab6aab9bb90acaf1a5cfcb04d633f8d61b2626/setproctitle-1.3.7-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6fc87caf9e323ac426910306c3e5d3205cd9f8dcac06d233fcafe9337f0928a3", size = 18062, upload-time = "2025-09-05T12:50:29.78Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/60/26dfc5f198715f1343b95c2f7a1c16ae9ffa45bd89ffd45a60ed258d24ea/setproctitle-1.3.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6134c63853d87a4897ba7d5cc0e16abfa687f6c66fc09f262bb70d67718f2309", size = 13075, upload-time = "2025-09-05T12:50:31.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/9c/980b01f50d51345dd513047e3ba9e96468134b9181319093e61db1c47188/setproctitle-1.3.7-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1403d2abfd32790b6369916e2313dffbe87d6b11dca5bbd898981bcde48e7a2b", size = 34744, upload-time = "2025-09-05T12:50:32.777Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/b4/82cd0c86e6d1c4538e1a7eb908c7517721513b801dff4ba3f98ef816a240/setproctitle-1.3.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e7c5bfe4228ea22373e3025965d1a4116097e555ee3436044f5c954a5e63ac45", size = 35589, upload-time = "2025-09-05T12:50:34.13Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/4f/9f6b2a7417fd45673037554021c888b31247f7594ff4bd2239918c5cd6d0/setproctitle-1.3.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:585edf25e54e21a94ccb0fe81ad32b9196b69ebc4fc25f81da81fb8a50cca9e4", size = 37698, upload-time = "2025-09-05T12:50:35.524Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/92/927b7d4744aac214d149c892cb5fa6dc6f49cfa040cb2b0a844acd63dcaf/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:96c38cdeef9036eb2724c2210e8d0b93224e709af68c435d46a4733a3675fee1", size = 34201, upload-time = "2025-09-05T12:50:36.697Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/0c/fd4901db5ba4b9d9013e62f61d9c18d52290497f956745cd3e91b0d80f90/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:45e3ef48350abb49cf937d0a8ba15e42cee1e5ae13ca41a77c66d1abc27a5070", size = 35801, upload-time = "2025-09-05T12:50:38.314Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/e3/54b496ac724e60e61cc3447f02690105901ca6d90da0377dffe49ff99fc7/setproctitle-1.3.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1fae595d032b30dab4d659bece20debd202229fce12b55abab978b7f30783d73", size = 33958, upload-time = "2025-09-05T12:50:39.841Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/a8/c84bb045ebf8c6fdc7f7532319e86f8380d14bbd3084e6348df56bdfe6fd/setproctitle-1.3.7-cp314-cp314t-win32.whl", hash = "sha256:02432f26f5d1329ab22279ff863c83589894977063f59e6c4b4845804a08f8c2", size = 12745, upload-time = "2025-09-05T12:50:41.377Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/b6/3a5a4f9952972791a9114ac01dfc123f0df79903577a3e0a7a404a695586/setproctitle-1.3.7-cp314-cp314t-win_amd64.whl", hash = "sha256:cbc388e3d86da1f766d8fc2e12682e446064c01cea9f88a88647cfe7c011de6a", size = 13469, upload-time = "2025-09-05T12:50:42.67Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/8a/aff5506ce89bc3168cb492b18ba45573158d528184e8a9759a05a09088a9/setproctitle-1.3.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:eb440c5644a448e6203935ed60466ec8d0df7278cd22dc6cf782d07911bcbea6", size = 12654, upload-time = "2025-09-05T12:51:17.141Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/89/5b6f2faedd6ced3d3c085a5efbd91380fb1f61f4c12bc42acad37932f4e9/setproctitle-1.3.7-pp310-pypy310_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:502b902a0e4c69031b87870ff4986c290ebbb12d6038a70639f09c331b18efb2", size = 14284, upload-time = "2025-09-05T12:51:18.393Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/c0/4312fed3ca393a29589603fd48f17937b4ed0638b923bac75a728382e730/setproctitle-1.3.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f6f268caeabb37ccd824d749e7ce0ec6337c4ed954adba33ec0d90cc46b0ab78", size = 13282, upload-time = "2025-09-05T12:51:19.703Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/5b/5e1c117ac84e3cefcf8d7a7f6b2461795a87e20869da065a5c087149060b/setproctitle-1.3.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1cac6a4b0252b8811d60b6d8d0f157c0fdfed379ac89c25a914e6346cf355a1", size = 12587, upload-time = "2025-09-05T12:51:21.195Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/02/b9eadc226195dcfa90eed37afe56b5dd6fa2f0e5220ab8b7867b8862b926/setproctitle-1.3.7-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f1704c9e041f2b1dc38f5be4552e141e1432fba3dd52c72eeffd5bc2db04dc65", size = 14286, upload-time = "2025-09-05T12:51:22.61Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/26/1be1d2a53c2a91ec48fa2ff4a409b395f836798adf194d99de9c059419ea/setproctitle-1.3.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b08b61976ffa548bd5349ce54404bf6b2d51bd74d4f1b241ed1b0f25bce09c3a", size = 13282, upload-time = "2025-09-05T12:51:24.094Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "2.4.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/d9/3dc2289e1f3b32eb19b9785b6a006b28ee99acb37d1d47f78d4c10e28bf8/tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867", size = 153663, upload-time = "2026-01-11T11:21:45.27Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/32/ef9f6845e6b9ca392cd3f64f9ec185cc6f09f0a2df3db08cbe8809d1d435/tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9", size = 148469, upload-time = "2026-01-11T11:21:46.873Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/c2/506e44cce89a8b1b1e047d64bd495c22c9f71f21e05f380f1a950dd9c217/tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95", size = 236039, upload-time = "2026-01-11T11:21:48.503Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/40/e1b65986dbc861b7e986e8ec394598187fa8aee85b1650b01dd925ca0be8/tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76", size = 243007, upload-time = "2026-01-11T11:21:49.456Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/6f/6e39ce66b58a5b7ae572a0f4352ff40c71e8573633deda43f6a379d56b3e/tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d", size = 240875, upload-time = "2026-01-11T11:21:50.755Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/ad/cb089cb190487caa80204d503c7fd0f4d443f90b95cf4ef5cf5aa0f439b0/tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576", size = 246271, upload-time = "2026-01-11T11:21:51.81Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/63/69125220e47fd7a3a27fd0de0c6398c89432fec41bc739823bcc66506af6/tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a", size = 96770, upload-time = "2026-01-11T11:21:52.647Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/0d/a22bb6c83f83386b0008425a6cd1fa1c14b5f3dd4bad05e98cf3dbbf4a64/tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa", size = 107626, upload-time = "2026-01-11T11:21:53.459Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/6d/77be674a3485e75cacbf2ddba2b146911477bd887dda9d8c9dfb2f15e871/tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614", size = 94842, upload-time = "2026-01-11T11:21:54.831Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/43/7389a1869f2f26dba52404e1ef13b4784b6b37dac93bac53457e3ff24ca3/tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1", size = 154894, upload-time = "2026-01-11T11:21:56.07Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/05/2f9bf110b5294132b2edf13fe6ca6ae456204f3d749f623307cbb7a946f2/tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8", size = 149053, upload-time = "2026-01-11T11:21:57.467Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/41/1eda3ca1abc6f6154a8db4d714a4d35c4ad90adc0bcf700657291593fbf3/tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a", size = 243481, upload-time = "2026-01-11T11:21:58.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/6d/02ff5ab6c8868b41e7d4b987ce2b5f6a51d3335a70aa144edd999e055a01/tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1", size = 251720, upload-time = "2026-01-11T11:22:00.178Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/57/0405c59a909c45d5b6f146107c6d997825aa87568b042042f7a9c0afed34/tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b", size = 247014, upload-time = "2026-01-11T11:22:01.238Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/0e/2e37568edd944b4165735687cbaf2fe3648129e440c26d02223672ee0630/tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51", size = 251820, upload-time = "2026-01-11T11:22:02.727Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5a/1c/ee3b707fdac82aeeb92d1a113f803cf6d0f37bdca0849cb489553e1f417a/tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729", size = 97712, upload-time = "2026-01-11T11:22:03.777Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/69/13/c07a9177d0b3bab7913299b9278845fc6eaaca14a02667c6be0b0a2270c8/tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da", size = 108296, upload-time = "2026-01-11T11:22:04.86Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/18/27/e267a60bbeeee343bcc279bb9e8fbed0cbe224bc7b2a3dc2975f22809a09/tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3", size = 94553, upload-time = "2026-01-11T11:22:05.854Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/91/7f65f9809f2936e1f4ce6268ae1903074563603b2a2bd969ebbda802744f/tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0", size = 154915, upload-time = "2026-01-11T11:22:06.703Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/aa/64dd73a5a849c2e8f216b755599c511badde80e91e9bc2271baa7b2cdbb1/tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e", size = 149038, upload-time = "2026-01-11T11:22:07.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/8a/6d38870bd3d52c8d1505ce054469a73f73a0fe62c0eaf5dddf61447e32fa/tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4", size = 242245, upload-time = "2026-01-11T11:22:08.344Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/59/bb/8002fadefb64ab2669e5b977df3f5e444febea60e717e755b38bb7c41029/tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e", size = 250335, upload-time = "2026-01-11T11:22:09.951Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/3d/4cdb6f791682b2ea916af2de96121b3cb1284d7c203d97d92d6003e91c8d/tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c", size = 245962, upload-time = "2026-01-11T11:22:11.27Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/4a/5f25789f9a460bd858ba9756ff52d0830d825b458e13f754952dd15fb7bb/tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f", size = 250396, upload-time = "2026-01-11T11:22:12.325Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/2f/b73a36fea58dfa08e8b3a268750e6853a6aac2a349241a905ebd86f3047a/tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86", size = 97530, upload-time = "2026-01-11T11:22:13.865Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3b/af/ca18c134b5d75de7e8dc551c5234eaba2e8e951f6b30139599b53de9c187/tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87", size = 108227, upload-time = "2026-01-11T11:22:15.224Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/c3/b386b832f209fee8073c8138ec50f27b4460db2fdae9ffe022df89a57f9b/tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132", size = 94748, upload-time = "2026-01-11T11:22:16.009Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/c4/84047a97eb1004418bc10bdbcfebda209fca6338002eba2dc27cc6d13563/tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6", size = 154725, upload-time = "2026-01-11T11:22:17.269Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/5d/d39038e646060b9d76274078cddf146ced86dc2b9e8bbf737ad5983609a0/tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc", size = 148901, upload-time = "2026-01-11T11:22:18.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/73/e5/383be1724cb30f4ce44983d249645684a48c435e1cd4f8b5cded8a816d3c/tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66", size = 243375, upload-time = "2026-01-11T11:22:19.154Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/f0/bea80c17971c8d16d3cc109dc3585b0f2ce1036b5f4a8a183789023574f2/tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d", size = 250639, upload-time = "2026-01-11T11:22:20.168Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/8f/2853c36abbb7608e3f945d8a74e32ed3a74ee3a1f468f1ffc7d1cb3abba6/tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702", size = 246897, upload-time = "2026-01-11T11:22:21.544Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/f0/6c05e3196ed5337b9fe7ea003e95fd3819a840b7a0f2bf5a408ef1dad8ed/tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8", size = 254697, upload-time = "2026-01-11T11:22:23.058Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/f5/2922ef29c9f2951883525def7429967fc4d8208494e5ab524234f06b688b/tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776", size = 98567, upload-time = "2026-01-11T11:22:24.033Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/31/22b52e2e06dd2a5fdbc3ee73226d763b184ff21fc24e20316a44ccc4d96b/tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475", size = 108556, upload-time = "2026-01-11T11:22:25.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/48/3d/5058dff3255a3d01b705413f64f4306a141a8fd7a251e5a495e3f192a998/tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2", size = 96014, upload-time = "2026-01-11T11:22:26.138Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/4e/75dab8586e268424202d3a1997ef6014919c941b50642a1682df43204c22/tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9", size = 163339, upload-time = "2026-01-11T11:22:27.143Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/e3/b904d9ab1016829a776d97f163f183a48be6a4deb87304d1e0116a349519/tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0", size = 159490, upload-time = "2026-01-11T11:22:28.399Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/5a/fc3622c8b1ad823e8ea98a35e3c632ee316d48f66f80f9708ceb4f2a0322/tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df", size = 269398, upload-time = "2026-01-11T11:22:29.345Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/33/62bd6152c8bdd4c305ad9faca48f51d3acb2df1f8791b1477d46ff86e7f8/tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d", size = 276515, upload-time = "2026-01-11T11:22:30.327Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4b/ff/ae53619499f5235ee4211e62a8d7982ba9e439a0fb4f2f351a93d67c1dd2/tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f", size = 273806, upload-time = "2026-01-11T11:22:32.56Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/47/71/cbca7787fa68d4d0a9f7072821980b39fbb1b6faeb5f5cf02f4a5559fa28/tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b", size = 281340, upload-time = "2026-01-11T11:22:33.505Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/00/d595c120963ad42474cf6ee7771ad0d0e8a49d0f01e29576ee9195d9ecdf/tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087", size = 108106, upload-time = "2026-01-11T11:22:34.451Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/de/69/9aa0c6a505c2f80e519b43764f8b4ba93b5a0bbd2d9a9de6e2b24271b9a5/tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd", size = 120504, upload-time = "2026-01-11T11:22:35.764Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/9f/f1668c281c58cfae01482f7114a4b88d345e4c140386241a1a24dcc9e7bc/tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4", size = 99561, upload-time = "2026-01-11T11:22:36.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.5.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zope-event"
|
||||
version = "6.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/33/d3eeac228fc14de76615612ee208be2d8a5b5b0fada36bf9b62d6b40600c/zope_event-6.1.tar.gz", hash = "sha256:6052a3e0cb8565d3d4ef1a3a7809336ac519bc4fe38398cb8d466db09adef4f0", size = 18739, upload-time = "2025-11-07T08:05:49.934Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/b0/956902e5e1302f8c5d124e219c6bf214e2649f92ad5fce85b05c039a04c9/zope_event-6.1-py3-none-any.whl", hash = "sha256:0ca78b6391b694272b23ec1335c0294cc471065ed10f7f606858fc54566c25a0", size = 6414, upload-time = "2025-11-07T08:05:48.874Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zope-interface"
|
||||
version = "8.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/86/a4/77daa5ba398996d16bb43fc721599d27d03eae68fe3c799de1963c72e228/zope_interface-8.2.tar.gz", hash = "sha256:afb20c371a601d261b4f6edb53c3c418c249db1a9717b0baafc9a9bb39ba1224", size = 254019, upload-time = "2026-01-09T07:51:07.253Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/fa/6d9eb3a33998a3019d7eb4fa1802d01d6602fad90e0aea443e6e0fe8e49a/zope_interface-8.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:788c293f3165964ec6527b2d861072c68eef53425213f36d3893ebee89a89623", size = 207541, upload-time = "2026-01-09T08:04:55.378Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/19/8c/ad23c96fdee84cb1f768f6695dac187cc26e9038e01c69713ba0f7dc46ab/zope_interface-8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9a4e785097e741a1c953b3970ce28f2823bd63c00adc5d276f2981dd66c96c15", size = 208075, upload-time = "2026-01-09T08:04:57.118Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dd/35/1bfd5fec31a307f0cf4065ee74ade63858ded3e2a71e248f1508118fcc95/zope_interface-8.2-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:16c69da19a06566664ddd4785f37cad5693a51d48df1515d264c20d005d322e2", size = 249528, upload-time = "2026-01-09T08:04:59.074Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c6/3a/5d50b5fdb0f8226a2edff6adb7efdd3762ec95dff827dbab1761cb9a9e85/zope_interface-8.2-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c31acfa3d7cde48bec45701b0e1f4698daffc378f559bfb296837d8c834732f6", size = 254646, upload-time = "2026-01-09T08:05:00.964Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2f/2a/ee7d675e151578eaf77828b8faac2b7ed9a69fead350bf5cf0e4afe7c73d/zope_interface-8.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0723507127f8269b8f3f22663168f717e9c9742107d1b6c9f419df561b71aa6d", size = 255083, upload-time = "2026-01-09T08:05:02.857Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/07/99e2342f976c3700e142eddc01524e375a9e9078869a6885d9c72f3a3659/zope_interface-8.2-cp310-cp310-win_amd64.whl", hash = "sha256:3bf73a910bb27344def2d301a03329c559a79b308e1e584686b74171d736be4e", size = 211924, upload-time = "2026-01-09T08:05:04.702Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/97/9c2aa8caae79915ed64eb114e18816f178984c917aa9adf2a18345e4f2e5/zope_interface-8.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c65ade7ea85516e428651048489f5e689e695c79188761de8c622594d1e13322", size = 208081, upload-time = "2026-01-09T08:05:06.623Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/86/4e2fcb01a8f6780ac84923748e450af0805531f47c0956b83065c99ab543/zope_interface-8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1ef4b43659e1348f35f38e7d1a6bbc1682efde239761f335ffc7e31e798b65b", size = 208522, upload-time = "2026-01-09T08:05:07.986Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/eb/08e277da32ddcd4014922854096cf6dcb7081fad415892c2da1bedefbf02/zope_interface-8.2-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:dfc4f44e8de2ff4eba20af4f0a3ca42d3c43ab24a08e49ccd8558b7a4185b466", size = 255198, upload-time = "2026-01-09T08:05:09.532Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/a1/b32484f3281a5dc83bc713ad61eca52c543735cdf204543172087a074a74/zope_interface-8.2-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8f094bfb49179ec5dc9981cb769af1275702bd64720ef94874d9e34da1390d4c", size = 259970, upload-time = "2026-01-09T08:05:11.477Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/81/bca0e8ae1e487d4093a8a7cfed2118aa2d4758c8cfd66e59d2af09d71f1c/zope_interface-8.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d2bb8e7364e18f083bf6744ccf30433b2a5f236c39c95df8514e3c13007098ce", size = 261153, upload-time = "2026-01-09T08:05:13.402Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/40/1e/e3ff2a708011e56b10b271b038d4cb650a8ad5b7d24352fe2edf6d6b187a/zope_interface-8.2-cp311-cp311-win_amd64.whl", hash = "sha256:6f4b4dfcfdfaa9177a600bb31cebf711fdb8c8e9ed84f14c61c420c6aa398489", size = 212330, upload-time = "2026-01-09T08:05:15.267Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/a0/1e1fabbd2e9c53ef92b69df6d14f4adc94ec25583b1380336905dc37e9a0/zope_interface-8.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:624b6787fc7c3e45fa401984f6add2c736b70a7506518c3b537ffaacc4b29d4c", size = 208785, upload-time = "2026-01-09T08:05:17.348Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c3/2a/88d098a06975c722a192ef1fb7d623d1b57c6a6997cf01a7aabb45ab1970/zope_interface-8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc9ded9e97a0ed17731d479596ed1071e53b18e6fdb2fc33af1e43f5fd2d3aaa", size = 208976, upload-time = "2026-01-09T08:05:18.792Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e8/757398549fdfd2f8c89f32c82ae4d2f0537ae2a5d2f21f4a2f711f5a059f/zope_interface-8.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:532367553e4420c80c0fc0cabcc2c74080d495573706f66723edee6eae53361d", size = 259411, upload-time = "2026-01-09T08:05:20.567Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/91/af/502601f0395ce84dff622f63cab47488657a04d0065547df42bee3a680ff/zope_interface-8.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2bf9cf275468bafa3c72688aad8cfcbe3d28ee792baf0b228a1b2d93bd1d541a", size = 264859, upload-time = "2026-01-09T08:05:22.234Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/89/0c/d2f765b9b4814a368a7c1b0ac23b68823c6789a732112668072fe596945d/zope_interface-8.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0009d2d3c02ea783045d7804da4fd016245e5c5de31a86cebba66dd6914d59a2", size = 264398, upload-time = "2026-01-09T08:05:23.853Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/81/2f171fbc4222066957e6b9220c4fb9146792540102c37e6d94e5d14aad97/zope_interface-8.2-cp312-cp312-win_amd64.whl", hash = "sha256:845d14e580220ae4544bd4d7eb800f0b6034fe5585fc2536806e0a26c2ee6640", size = 212444, upload-time = "2026-01-09T08:05:25.148Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/47/45188fb101fa060b20e6090e500682398ab415e516a0c228fbb22bc7def2/zope_interface-8.2-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:6068322004a0158c80dfd4708dfb103a899635408c67c3b10e9acec4dbacefec", size = 209170, upload-time = "2026-01-09T08:05:26.616Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/03/f6b9336c03c2b48403c4eb73a1ec961d94dc2fb5354c583dfb5fa05fd41f/zope_interface-8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2499de92e8275d0dd68f84425b3e19e9268cd1fa8507997900fa4175f157733c", size = 209229, upload-time = "2026-01-09T08:05:28.521Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/b1/65fe1dca708569f302ade02e6cdca309eab6752bc9f80105514f5b708651/zope_interface-8.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f777e68c76208503609c83ca021a6864902b646530a1a39abb9ed310d1100664", size = 259393, upload-time = "2026-01-09T08:05:29.897Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/a5/97b49cfceb6ed53d3dcfb3f3ebf24d83b5553194f0337fbbb3a9fec6cf78/zope_interface-8.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b05a919fdb0ed6ea942e5a7800e09a8b6cdae6f98fee1bef1c9d1a3fc43aaa0", size = 264863, upload-time = "2026-01-09T08:05:31.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/02/0b7a77292810efe3a0586a505b077ebafd5114e10c6e6e659f0c8e387e1f/zope_interface-8.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ccc62b5712dd7bd64cfba3ee63089fb11e840f5914b990033beeae3b2180b6cb", size = 264369, upload-time = "2026-01-09T08:05:32.941Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/1d/0d1ff3846302ed1b5bbf659316d8084b30106770a5f346b7ff4e9f540f80/zope_interface-8.2-cp313-cp313-win_amd64.whl", hash = "sha256:34f877d1d3bb7565c494ed93828fa6417641ca26faf6e8f044e0d0d500807028", size = 212447, upload-time = "2026-01-09T08:05:35.064Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/da/3c89de3917751446728b8898b4d53318bc2f8f6bf8196e150a063c59905e/zope_interface-8.2-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:46c7e4e8cbc698398a67e56ca985d19cb92365b4aafbeb6a712e8c101090f4cb", size = 209223, upload-time = "2026-01-09T08:05:36.449Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/7f/62d00ec53f0a6e5df0c984781e6f3999ed265129c4c3413df8128d1e0207/zope_interface-8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a87fc7517f825a97ff4a4ca4c8a950593c59e0f8e7bfe1b6f898a38d5ba9f9cf", size = 209366, upload-time = "2026-01-09T08:05:38.197Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/a2/f241986315174be8e00aabecfc2153cf8029c1327cab8ed53a9d979d7e08/zope_interface-8.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:ccf52f7d44d669203c2096c1a0c2c15d52e36b2e7a9413df50f48392c7d4d080", size = 261037, upload-time = "2026-01-09T08:05:39.568Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/02/cc/b321c51d6936ede296a1b8860cf173bee2928357fe1fff7f97234899173f/zope_interface-8.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aae807efc7bd26302eb2fea05cd6de7d59269ed6ae23a6de1ee47add6de99b8c", size = 264219, upload-time = "2026-01-09T08:05:41.624Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/fb/5f5e7b40a2f4efd873fe173624795ca47eaa22e29051270c981361b45209/zope_interface-8.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:05a0e42d6d830f547e114de2e7cd15750dc6c0c78f8138e6c5035e51ddfff37c", size = 264390, upload-time = "2026-01-09T08:05:42.936Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/82/3f2bc594370bc3abd58e5f9085d263bf682a222f059ed46275cde0570810/zope_interface-8.2-cp314-cp314-win_amd64.whl", hash = "sha256:561ce42390bee90bae51cf1c012902a8033b2aaefbd0deed81e877562a116d48", size = 212585, upload-time = "2026-01-09T08:05:44.419Z" },
|
||||
]
|
||||
Loading…
x
Reference in New Issue
Block a user