rqx 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rqx-0.1.0/.github/dependabot.yml +40 -0
- rqx-0.1.0/.github/workflows/CI.yml +214 -0
- rqx-0.1.0/.gitignore +98 -0
- rqx-0.1.0/CONTRIBUTING.md +86 -0
- rqx-0.1.0/Cargo.lock +2650 -0
- rqx-0.1.0/Cargo.toml +36 -0
- rqx-0.1.0/LICENSE +21 -0
- rqx-0.1.0/PKG-INFO +121 -0
- rqx-0.1.0/README.md +92 -0
- rqx-0.1.0/benchmarks/README.md +17 -0
- rqx-0.1.0/benchmarks/analyze_b1.py +54 -0
- rqx-0.1.0/benchmarks/b10_tls_handshake.py +178 -0
- rqx-0.1.0/benchmarks/b1_aiohttp.py +64 -0
- rqx-0.1.0/benchmarks/b1_httpr.py +70 -0
- rqx-0.1.0/benchmarks/b1_httpx.py +65 -0
- rqx-0.1.0/benchmarks/b1_rqx.py +64 -0
- rqx-0.1.0/benchmarks/b2_latency.py +157 -0
- rqx-0.1.0/benchmarks/b3_connection_pool.py +94 -0
- rqx-0.1.0/benchmarks/b4_memory.py +93 -0
- rqx-0.1.0/benchmarks/b5_json_parsing.py +100 -0
- rqx-0.1.0/benchmarks/b6_retry_overhead.py +101 -0
- rqx-0.1.0/benchmarks/b7_network_latency.py +131 -0
- rqx-0.1.0/benchmarks/b8_concurrency_sweep.py +329 -0
- rqx-0.1.0/benchmarks/b9_payload_sweep.py +272 -0
- rqx-0.1.0/benchmarks/delay_server.py +29 -0
- rqx-0.1.0/benchmarks/docker-compose.yaml +10 -0
- rqx-0.1.0/benchmarks/infra/.gitignore +13 -0
- rqx-0.1.0/benchmarks/infra/Pulumi.yaml +3 -0
- rqx-0.1.0/benchmarks/infra/README.md +97 -0
- rqx-0.1.0/benchmarks/infra/index.ts +275 -0
- rqx-0.1.0/benchmarks/infra/package-lock.json +2668 -0
- rqx-0.1.0/benchmarks/infra/package.json +11 -0
- rqx-0.1.0/benchmarks/infra/scripts/bench.sh +128 -0
- rqx-0.1.0/benchmarks/infra/scripts/client-setup.sh +80 -0
- rqx-0.1.0/benchmarks/infra/scripts/run-benches.sh +63 -0
- rqx-0.1.0/benchmarks/infra/scripts/server-setup.sh +37 -0
- rqx-0.1.0/benchmarks/infra/tsconfig.json +16 -0
- rqx-0.1.0/benchmarks/nginx/generate_payloads.py +58 -0
- rqx-0.1.0/benchmarks/nginx/nginx-host.conf +86 -0
- rqx-0.1.0/benchmarks/nginx/nginx.conf +28 -0
- rqx-0.1.0/benchmarks/nginx/response.json +63 -0
- rqx-0.1.0/benchmarks/plot_launch.py +147 -0
- rqx-0.1.0/benchmarks/run_all.sh +104 -0
- rqx-0.1.0/benchmarks/run_b1.sh +43 -0
- rqx-0.1.0/docs/launch_latency.png +0 -0
- rqx-0.1.0/docs/launch_memory.png +0 -0
- rqx-0.1.0/docs/launch_report.md +113 -0
- rqx-0.1.0/docs/launch_throughput.png +0 -0
- rqx-0.1.0/docs/report.md +164 -0
- rqx-0.1.0/docs/reqx_project_spec.md +928 -0
- rqx-0.1.0/justfile +48 -0
- rqx-0.1.0/pyproject.toml +46 -0
- rqx-0.1.0/python/rqx/__init__.py +80 -0
- rqx-0.1.0/python/rqx/_api.py +318 -0
- rqx-0.1.0/python/rqx/_types.pyi +560 -0
- rqx-0.1.0/python/rqx/py.typed +0 -0
- rqx-0.1.0/src/client.rs +1208 -0
- rqx-0.1.0/src/exceptions.rs +89 -0
- rqx-0.1.0/src/headers.rs +158 -0
- rqx-0.1.0/src/lib.rs +83 -0
- rqx-0.1.0/src/py_json.rs +124 -0
- rqx-0.1.0/src/request.rs +143 -0
- rqx-0.1.0/src/response.rs +320 -0
- rqx-0.1.0/src/retry.rs +174 -0
- rqx-0.1.0/src/runtime.rs +4 -0
- rqx-0.1.0/src/stream.rs +402 -0
- rqx-0.1.0/src/timeout.rs +112 -0
- rqx-0.1.0/src/transport.rs +726 -0
- rqx-0.1.0/src/url.rs +59 -0
- rqx-0.1.0/tests/conftest.py +241 -0
- rqx-0.1.0/tests/ssl/client_extfile.txt +2 -0
- rqx-0.1.0/tests/ssl/extfile.txt +2 -0
- rqx-0.1.0/tests/ssl/generate_certs.sh +129 -0
- rqx-0.1.0/tests/test_api.py +131 -0
- rqx-0.1.0/tests/test_async.py +633 -0
- rqx-0.1.0/tests/test_base_url.py +140 -0
- rqx-0.1.0/tests/test_compression.py +26 -0
- rqx-0.1.0/tests/test_encoding.py +67 -0
- rqx-0.1.0/tests/test_exceptions.py +100 -0
- rqx-0.1.0/tests/test_headers.py +93 -0
- rqx-0.1.0/tests/test_mtls.py +323 -0
- rqx-0.1.0/tests/test_response_props.py +124 -0
- rqx-0.1.0/tests/test_retry_config.py +139 -0
- rqx-0.1.0/tests/test_stream_redirects.py +91 -0
- rqx-0.1.0/tests/test_sync.py +886 -0
- rqx-0.1.0/tests/test_timeout.py +212 -0
- rqx-0.1.0/uv.lock +1225 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Dependabot version updates.
|
|
2
|
+
# Docs: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
3
|
+
#
|
|
4
|
+
# Three ecosystems live in this repo:
|
|
5
|
+
# - pip: Python deps in pyproject.toml
|
|
6
|
+
# - cargo: Rust deps in Cargo.toml / Cargo.lock
|
|
7
|
+
# - github-actions: action versions pinned in .github/workflows/*.yml
|
|
8
|
+
#
|
|
9
|
+
# Minor + patch updates are grouped into a single PR per ecosystem per week to
|
|
10
|
+
# reduce churn. Major updates land as individual PRs so they can be reviewed
|
|
11
|
+
# in isolation. Bump `interval` to `monthly` if weekly proves too noisy.
|
|
12
|
+
|
|
13
|
+
version: 2
|
|
14
|
+
updates:
|
|
15
|
+
- package-ecosystem: "pip"
|
|
16
|
+
directory: "/"
|
|
17
|
+
schedule:
|
|
18
|
+
interval: "weekly"
|
|
19
|
+
open-pull-requests-limit: 5
|
|
20
|
+
groups:
|
|
21
|
+
python-minor-and-patch:
|
|
22
|
+
update-types:
|
|
23
|
+
- "minor"
|
|
24
|
+
- "patch"
|
|
25
|
+
|
|
26
|
+
- package-ecosystem: "cargo"
|
|
27
|
+
directory: "/"
|
|
28
|
+
schedule:
|
|
29
|
+
interval: "weekly"
|
|
30
|
+
open-pull-requests-limit: 5
|
|
31
|
+
groups:
|
|
32
|
+
rust-minor-and-patch:
|
|
33
|
+
update-types:
|
|
34
|
+
- "minor"
|
|
35
|
+
- "patch"
|
|
36
|
+
|
|
37
|
+
- package-ecosystem: "github-actions"
|
|
38
|
+
directory: "/"
|
|
39
|
+
schedule:
|
|
40
|
+
interval: "weekly"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# This file is autogenerated by maturin v1.12.6
|
|
2
|
+
# To update, run
|
|
3
|
+
#
|
|
4
|
+
# maturin generate-ci github
|
|
5
|
+
#
|
|
6
|
+
name: CI
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
tags:
|
|
13
|
+
- '*'
|
|
14
|
+
pull_request:
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
lint:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v6
|
|
25
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
26
|
+
with:
|
|
27
|
+
components: clippy
|
|
28
|
+
- run: cargo clippy -- -W clippy::all
|
|
29
|
+
|
|
30
|
+
test:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
services:
|
|
33
|
+
httpbin:
|
|
34
|
+
image: kennethreitz/httpbin
|
|
35
|
+
ports:
|
|
36
|
+
- 80:80
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v6
|
|
39
|
+
- uses: actions/setup-python@v6
|
|
40
|
+
with:
|
|
41
|
+
python-version: "3.11"
|
|
42
|
+
- uses: astral-sh/setup-uv@v3
|
|
43
|
+
with:
|
|
44
|
+
enable-cache: true
|
|
45
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
46
|
+
- run: uv sync --extra dev --frozen
|
|
47
|
+
- run: uv run maturin develop
|
|
48
|
+
- run: uv run pytest tests/ -n 8
|
|
49
|
+
|
|
50
|
+
linux:
|
|
51
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
52
|
+
strategy:
|
|
53
|
+
matrix:
|
|
54
|
+
platform:
|
|
55
|
+
- runner: ubuntu-22.04
|
|
56
|
+
target: x86_64
|
|
57
|
+
- runner: ubuntu-22.04
|
|
58
|
+
target: x86
|
|
59
|
+
- runner: ubuntu-22.04
|
|
60
|
+
target: aarch64
|
|
61
|
+
- runner: ubuntu-22.04
|
|
62
|
+
target: armv7
|
|
63
|
+
- runner: ubuntu-22.04
|
|
64
|
+
target: s390x
|
|
65
|
+
- runner: ubuntu-22.04
|
|
66
|
+
target: ppc64le
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
- uses: actions/setup-python@v6
|
|
70
|
+
with:
|
|
71
|
+
python-version: 3.x
|
|
72
|
+
- name: Build wheels
|
|
73
|
+
uses: PyO3/maturin-action@v1
|
|
74
|
+
with:
|
|
75
|
+
target: ${{ matrix.platform.target }}
|
|
76
|
+
args: --release --out dist --find-interpreter
|
|
77
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
78
|
+
manylinux: 2_28
|
|
79
|
+
- name: Upload wheels
|
|
80
|
+
uses: actions/upload-artifact@v6
|
|
81
|
+
with:
|
|
82
|
+
name: wheels-linux-${{ matrix.platform.target }}
|
|
83
|
+
path: dist
|
|
84
|
+
|
|
85
|
+
musllinux:
|
|
86
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
87
|
+
strategy:
|
|
88
|
+
matrix:
|
|
89
|
+
platform:
|
|
90
|
+
- runner: ubuntu-22.04
|
|
91
|
+
target: x86_64
|
|
92
|
+
- runner: ubuntu-22.04
|
|
93
|
+
target: x86
|
|
94
|
+
- runner: ubuntu-22.04
|
|
95
|
+
target: aarch64
|
|
96
|
+
- runner: ubuntu-22.04
|
|
97
|
+
target: armv7
|
|
98
|
+
steps:
|
|
99
|
+
- uses: actions/checkout@v6
|
|
100
|
+
- uses: actions/setup-python@v6
|
|
101
|
+
with:
|
|
102
|
+
python-version: 3.x
|
|
103
|
+
- name: Build wheels
|
|
104
|
+
uses: PyO3/maturin-action@v1
|
|
105
|
+
with:
|
|
106
|
+
target: ${{ matrix.platform.target }}
|
|
107
|
+
args: --release --out dist --find-interpreter
|
|
108
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
109
|
+
manylinux: musllinux_1_2
|
|
110
|
+
- name: Upload wheels
|
|
111
|
+
uses: actions/upload-artifact@v6
|
|
112
|
+
with:
|
|
113
|
+
name: wheels-musllinux-${{ matrix.platform.target }}
|
|
114
|
+
path: dist
|
|
115
|
+
|
|
116
|
+
windows:
|
|
117
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
118
|
+
strategy:
|
|
119
|
+
matrix:
|
|
120
|
+
platform:
|
|
121
|
+
- runner: windows-latest
|
|
122
|
+
target: x64
|
|
123
|
+
python_arch: x64
|
|
124
|
+
- runner: windows-latest
|
|
125
|
+
target: x86
|
|
126
|
+
python_arch: x86
|
|
127
|
+
- runner: windows-11-arm
|
|
128
|
+
target: aarch64
|
|
129
|
+
python_arch: arm64
|
|
130
|
+
steps:
|
|
131
|
+
- uses: actions/checkout@v6
|
|
132
|
+
- uses: actions/setup-python@v6
|
|
133
|
+
with:
|
|
134
|
+
python-version: 3.13
|
|
135
|
+
architecture: ${{ matrix.platform.python_arch }}
|
|
136
|
+
- name: Build wheels
|
|
137
|
+
uses: PyO3/maturin-action@v1
|
|
138
|
+
with:
|
|
139
|
+
target: ${{ matrix.platform.target }}
|
|
140
|
+
args: --release --out dist --find-interpreter
|
|
141
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
142
|
+
- name: Upload wheels
|
|
143
|
+
uses: actions/upload-artifact@v6
|
|
144
|
+
with:
|
|
145
|
+
name: wheels-windows-${{ matrix.platform.target }}
|
|
146
|
+
path: dist
|
|
147
|
+
|
|
148
|
+
macos:
|
|
149
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
150
|
+
strategy:
|
|
151
|
+
matrix:
|
|
152
|
+
platform:
|
|
153
|
+
- runner: macos-15-intel
|
|
154
|
+
target: x86_64
|
|
155
|
+
- runner: macos-latest
|
|
156
|
+
target: aarch64
|
|
157
|
+
steps:
|
|
158
|
+
- uses: actions/checkout@v6
|
|
159
|
+
- uses: actions/setup-python@v6
|
|
160
|
+
with:
|
|
161
|
+
python-version: 3.x
|
|
162
|
+
- name: Build wheels
|
|
163
|
+
uses: PyO3/maturin-action@v1
|
|
164
|
+
with:
|
|
165
|
+
target: ${{ matrix.platform.target }}
|
|
166
|
+
args: --release --out dist --find-interpreter
|
|
167
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
168
|
+
- name: Upload wheels
|
|
169
|
+
uses: actions/upload-artifact@v6
|
|
170
|
+
with:
|
|
171
|
+
name: wheels-macos-${{ matrix.platform.target }}
|
|
172
|
+
path: dist
|
|
173
|
+
|
|
174
|
+
sdist:
|
|
175
|
+
runs-on: ubuntu-latest
|
|
176
|
+
steps:
|
|
177
|
+
- uses: actions/checkout@v6
|
|
178
|
+
- name: Build sdist
|
|
179
|
+
uses: PyO3/maturin-action@v1
|
|
180
|
+
with:
|
|
181
|
+
command: sdist
|
|
182
|
+
args: --out dist
|
|
183
|
+
- name: Upload sdist
|
|
184
|
+
uses: actions/upload-artifact@v6
|
|
185
|
+
with:
|
|
186
|
+
name: wheels-sdist
|
|
187
|
+
path: dist
|
|
188
|
+
|
|
189
|
+
release:
|
|
190
|
+
name: Release
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
|
|
193
|
+
needs: [linux, musllinux, windows, macos, sdist]
|
|
194
|
+
permissions:
|
|
195
|
+
# Use to sign the release artifacts
|
|
196
|
+
id-token: write
|
|
197
|
+
# Used to upload release artifacts
|
|
198
|
+
contents: write
|
|
199
|
+
# Used to generate artifact attestation
|
|
200
|
+
attestations: write
|
|
201
|
+
steps:
|
|
202
|
+
- uses: actions/download-artifact@v7
|
|
203
|
+
- name: Generate artifact attestation
|
|
204
|
+
uses: actions/attest-build-provenance@v3
|
|
205
|
+
with:
|
|
206
|
+
subject-path: 'wheels-*/*'
|
|
207
|
+
- name: Merge wheel directories
|
|
208
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
209
|
+
run: mkdir -p dist && cp wheels-*/* dist/
|
|
210
|
+
- name: Publish to PyPI
|
|
211
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
|
212
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
213
|
+
with:
|
|
214
|
+
packages-dir: dist/
|
rqx-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/target
|
|
2
|
+
|
|
3
|
+
# Byte-compiled / optimized / DLL files
|
|
4
|
+
__pycache__/
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
|
|
8
|
+
# C extensions
|
|
9
|
+
*.so
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
.Python
|
|
13
|
+
.venv/
|
|
14
|
+
env/
|
|
15
|
+
bin/
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
include/
|
|
26
|
+
man/
|
|
27
|
+
venv/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
*.dSYM
|
|
32
|
+
|
|
33
|
+
# Installer logs
|
|
34
|
+
pip-log.txt
|
|
35
|
+
pip-delete-this-directory.txt
|
|
36
|
+
pip-selfcheck.json
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.coverage
|
|
42
|
+
.cache
|
|
43
|
+
nosetests.xml
|
|
44
|
+
coverage.xml
|
|
45
|
+
|
|
46
|
+
# Translations
|
|
47
|
+
*.mo
|
|
48
|
+
|
|
49
|
+
# Mr Developer
|
|
50
|
+
.mr.developer.cfg
|
|
51
|
+
.project
|
|
52
|
+
.pydevproject
|
|
53
|
+
|
|
54
|
+
# Rope
|
|
55
|
+
.ropeproject
|
|
56
|
+
|
|
57
|
+
# Django stuff:
|
|
58
|
+
*.log
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
.DS_Store
|
|
62
|
+
|
|
63
|
+
# Sphinx documentation
|
|
64
|
+
docs/_build/
|
|
65
|
+
|
|
66
|
+
# PyCharm
|
|
67
|
+
.idea/
|
|
68
|
+
|
|
69
|
+
# VSCode
|
|
70
|
+
.vscode/
|
|
71
|
+
|
|
72
|
+
# Pyenv
|
|
73
|
+
.python-version
|
|
74
|
+
|
|
75
|
+
# AI
|
|
76
|
+
.claude/
|
|
77
|
+
CLAUDE.md
|
|
78
|
+
|
|
79
|
+
# Benchmark stuff
|
|
80
|
+
benchmarks/nginx/certs/
|
|
81
|
+
benchmarks/nginx/*.json
|
|
82
|
+
docs/bench_results/
|
|
83
|
+
|
|
84
|
+
# Bench result output (commit canonical runs explicitly with `git add -f`;
|
|
85
|
+
# everything else stays local + S3).
|
|
86
|
+
benchmarks/results/
|
|
87
|
+
b1_results.jsonl
|
|
88
|
+
|
|
89
|
+
# Pulumi state / stack secrets
|
|
90
|
+
benchmarks/infra/node_modules/
|
|
91
|
+
benchmarks/infra/bin/
|
|
92
|
+
benchmarks/infra/.pulumi/
|
|
93
|
+
|
|
94
|
+
# certs stuf
|
|
95
|
+
*.pem
|
|
96
|
+
*.csr
|
|
97
|
+
*.srl
|
|
98
|
+
*.cert-gen.lock
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Finding ways to help
|
|
4
|
+
|
|
5
|
+
This project started as an experiment, with the goal of learning. It evolved quickly into a genuine contender for high-concurrency HTTP handling in Python.
|
|
6
|
+
|
|
7
|
+
The goal is to be maintain feature parity with [httpx](https://github.com/encode/httpx), but with the performance of async Rust. This basically creates 2 natural places for improvements: feature parity and performance, with correctness as table stakes.
|
|
8
|
+
|
|
9
|
+
There are several tags we use to make that simple: `httpx-feature-parity` and then your run-of-the-mill tags like `bug`, `enhancement`, etc.
|
|
10
|
+
|
|
11
|
+
## Use of AI
|
|
12
|
+
|
|
13
|
+
This project started out as learning project. I used AI to help me learn some of the basics but wrote the large majority by hand... double-edged sword. So as we advance, I encourage the use of AI for breadth and speed. It's obvious when someone is using AI to write the code for them, let's try to avoid that so that when an issue comes up, someone can speak to it without relying on their AI to go dig for them.
|
|
14
|
+
|
|
15
|
+
### Good use cases for AI
|
|
16
|
+
|
|
17
|
+
- Getting it to run and analyze the benchmarks after a change.
|
|
18
|
+
- Doing a breadth-first search for alternatives.
|
|
19
|
+
- Experimenting with a variety of things in parallel.
|
|
20
|
+
|
|
21
|
+
### Bad use cases for AI
|
|
22
|
+
|
|
23
|
+
- Writing tests that don't mean anything.
|
|
24
|
+
- Refactoring large chunks of code.
|
|
25
|
+
- Assessing benchmarks.
|
|
26
|
+
- Writing up bug reports that you haven't experienced first hand.
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
### Prerequisites
|
|
31
|
+
|
|
32
|
+
Rust is the only requirement for local dev, however would strongly encourage the use of `just`, `uv`, and `rustup` with `clippy`.
|
|
33
|
+
|
|
34
|
+
- [Rust toolchain](https://rustup.rs/) (with `clippy`)
|
|
35
|
+
- Python 3.9+
|
|
36
|
+
- [uv](https://github.com/astral-sh/uv) — venv + dependency management
|
|
37
|
+
- [just](https://github.com/casey/just) — task runner (every doc references it)
|
|
38
|
+
|
|
39
|
+
### First-time setup
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
just setup # uv venv + dev deps + maturin develop
|
|
43
|
+
just test # full test suite (parallel via xdist)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`just setup` chains `uv venv`, `uv pip install -e ".[dev]"`, `uv lock`, and `maturin develop`. Skip `just` and you can run those steps directly.
|
|
47
|
+
|
|
48
|
+
## Project layout
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
src/ Rust core — pyo3 classes, transport, retry, etc.
|
|
52
|
+
python/rqx/ Python wrapper — re-exports + module-level functions
|
|
53
|
+
python/rqx/_types.pyi Type stubs for the compiled extension
|
|
54
|
+
tests/ pytest suite (sync + async + MTLS + streaming)
|
|
55
|
+
benchmarks/ Performance scripts
|
|
56
|
+
docs/ Project spec, report, benchmark output
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Benchmarks
|
|
60
|
+
|
|
61
|
+
Performance regressions are easy to introduce in a Rust/Python FFI project — every GIL acquire, every allocation crossing the boundary matters. Before merging anything that touches the hot path, run the relevant bench.
|
|
62
|
+
|
|
63
|
+
- `benchmarks/b1_{rqx,httpr,httpx,aiohttp}.py` + `run_b1.sh` — throughput sweep, per-client subprocess to keep tokio runtimes and the httpr threadpool from cross-contaminating. `b2_latency.py` through `b10_tls_handshake.py` cover the other dimensions (latency, pool, memory, JSON, retry overhead, network latency, concurrency sweep, payload sweep, TLS handshake).
|
|
64
|
+
- `benchmarks/run_all.sh` — full sweep. Builds in release mode, starts the local delay server, restarts nginx between benches to drain TCP TIME_WAIT (otherwise tail outliers explode). Output lands under `/tmp/reqx_bench_<timestamp>/`.
|
|
65
|
+
- `benchmarks/docker-compose.yaml` — the nginx + delay-server stack the benches hit.
|
|
66
|
+
|
|
67
|
+
**Caveat:** all numbers in `docs/bench_results/` and `docs/report.md` are from a local nginx + a local delay-server on the same machine running the client. Loopback throughput and a real remote HTTP server stress different parts of the stack (kernel TCP, DNS, TLS resumption, real RTT). Validating these results against a real internet-facing server on dedicated hardware is still TODO — tracked in [#41](https://github.com/rodcochran/rqx/issues/41). Until that runs, treat the existing numbers as relative comparisons against httpx/aiohttp on identical infrastructure, not as absolute production claims.
|
|
68
|
+
|
|
69
|
+
If you change something performance-sensitive, please include a fresh local measurement in the PR description.
|
|
70
|
+
|
|
71
|
+
## Submitting changes
|
|
72
|
+
|
|
73
|
+
- Branch from `main`, one PR per logical change.
|
|
74
|
+
- PR description: short Summary, `Closes #N`, then a Testing section in prose describing what was verified. No checklist-style Test plan — say what was actually run and what it proved.
|
|
75
|
+
- Run `just test` locally before opening the PR. CI runs the same suite on Linux.
|
|
76
|
+
|
|
77
|
+
## Reporting bugs
|
|
78
|
+
|
|
79
|
+
Open an issue with:
|
|
80
|
+
|
|
81
|
+
- A minimal reproducible snippet (Python code + the `rqx` version)
|
|
82
|
+
- What you expected to happen
|
|
83
|
+
- What actually happened (status codes, stack trace, whatever's relevant)
|
|
84
|
+
- Environment (OS, Python version)
|
|
85
|
+
|
|
86
|
+
A small repro is worth ten paragraphs of context.
|