httpr 0.2.3.dev163__tar.gz → 0.2.6__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.
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/workflows/CI.yml +21 -41
- {httpr-0.2.3.dev163 → httpr-0.2.6}/Cargo.lock +1 -1
- {httpr-0.2.3.dev163 → httpr-0.2.6}/Cargo.toml +1 -1
- httpr-0.2.6/PKG-INFO +418 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/README.md +13 -13
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/index.md +2 -2
- {httpr-0.2.3.dev163 → httpr-0.2.6}/pyproject.toml +2 -1
- httpr-0.2.3.dev163/PKG-INFO +0 -54
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/actions/set-version/action.yml +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/copilot-instructions.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/workflows/CI.yml.backup +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/workflows/copilot-setup-steps.yml +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/workflows/mkdocs.yml +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.github/workflows/set_version.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.gitignore +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/.pre-commit-config.yaml +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/CLAUDE.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/LICENSE +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark/README.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark/benchmark.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark/benchmark_cbor.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark/generate_image.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark/server.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/benchmark.jpg +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/advanced/cookies.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/advanced/index.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/advanced/proxy.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/advanced/ssl-tls.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/api/async-client.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/api/client.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/api/functions.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/api/index.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/api/response.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/quickstart.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/tutorial/async.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/tutorial/authentication.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/tutorial/index.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/tutorial/making-requests.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/tutorial/response-handling.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/writings/index.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/docs/writings/posts/2025-02-24-python-http-clients-suck.md +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/httpr/__init__.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/httpr/httpr.pyi +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/httpr/py.typed +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/httpr.code-workspace +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/mkdocs.yml +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/src/exceptions.rs +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/src/lib.rs +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/src/response.rs +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/src/traits.rs +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/src/utils.rs +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/cbor_test_server.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/conftest.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/httpx_conns.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_asyncclient.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_cbor.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_client.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_defs.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_docs.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_exceptions.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_ssl.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/tests/test_streaming.py +0 -0
- {httpr-0.2.3.dev163 → httpr-0.2.6}/uv.lock +0 -0
|
@@ -7,9 +7,6 @@ on:
|
|
|
7
7
|
tags:
|
|
8
8
|
- "*"
|
|
9
9
|
pull_request:
|
|
10
|
-
schedule:
|
|
11
|
-
# Run weekly on Sundays at midnight UTC
|
|
12
|
-
- cron: "0 0 * * 0"
|
|
13
10
|
workflow_dispatch:
|
|
14
11
|
|
|
15
12
|
permissions:
|
|
@@ -39,10 +36,10 @@ jobs:
|
|
|
39
36
|
- name: Rust clippy
|
|
40
37
|
run: cargo clippy -- -D warnings
|
|
41
38
|
|
|
42
|
-
# Fast test job - runs on PRs
|
|
39
|
+
# Fast test job - runs on PRs, main branch pushes, and tag pushes with Python version matrix
|
|
43
40
|
test:
|
|
44
41
|
runs-on: ubuntu-22.04
|
|
45
|
-
if: github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/main')
|
|
42
|
+
if: github.event_name == 'pull_request' || (github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')))
|
|
46
43
|
strategy:
|
|
47
44
|
matrix:
|
|
48
45
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
@@ -80,13 +77,11 @@ jobs:
|
|
|
80
77
|
uv sync --extra docs
|
|
81
78
|
uv run mkdocs build --strict
|
|
82
79
|
|
|
83
|
-
# Build jobs - run on tags
|
|
80
|
+
# Build jobs - run only on tags or manual dispatch
|
|
84
81
|
linux:
|
|
85
82
|
runs-on: ${{ matrix.platform.runner }}
|
|
86
|
-
# Wait for test job if it runs, but don't fail if it was skipped (schedule/tag/dispatch)
|
|
87
83
|
needs: [test]
|
|
88
|
-
|
|
89
|
-
if: ${{ always() && github.event_name != 'pull_request' && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
84
|
+
if: ${{ always() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
90
85
|
strategy:
|
|
91
86
|
matrix:
|
|
92
87
|
platform:
|
|
@@ -140,27 +135,13 @@ jobs:
|
|
|
140
135
|
set -e
|
|
141
136
|
uv sync --extra dev --find-links dist --reinstall
|
|
142
137
|
uv run pytest
|
|
143
|
-
-
|
|
144
|
-
|
|
145
|
-
uses: uraimo/run-on-arch-action@v2
|
|
146
|
-
with:
|
|
147
|
-
arch: ${{ matrix.platform.target }}
|
|
148
|
-
distro: ubuntu22.04
|
|
149
|
-
githubToken: ${{ github.token }}
|
|
150
|
-
install: |
|
|
151
|
-
apt-get update
|
|
152
|
-
apt-get install -y --no-install-recommends python3 python3-pip python3-dev build-essential libffi-dev libssl-dev pkg-config curl
|
|
153
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
154
|
-
run: |
|
|
155
|
-
set -e
|
|
156
|
-
export PATH="$HOME/.local/bin:$PATH"
|
|
157
|
-
uv sync --extra dev --find-links dist --reinstall
|
|
158
|
-
uv run pytest
|
|
138
|
+
# Skip pytest on armv7 - QEMU emulation is 20x+ slower than native.
|
|
139
|
+
# Tests already run on x86_64 and aarch64 which provides sufficient coverage.
|
|
159
140
|
|
|
160
141
|
musllinux:
|
|
161
142
|
runs-on: ${{ matrix.platform.runner }}
|
|
162
143
|
needs: [test]
|
|
163
|
-
if: ${{ always() && github.event_name
|
|
144
|
+
if: ${{ always() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
164
145
|
strategy:
|
|
165
146
|
matrix:
|
|
166
147
|
platform:
|
|
@@ -218,7 +199,7 @@ jobs:
|
|
|
218
199
|
windows:
|
|
219
200
|
runs-on: ${{ matrix.platform.runner }}
|
|
220
201
|
needs: [test]
|
|
221
|
-
if: ${{ always() && github.event_name
|
|
202
|
+
if: ${{ always() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
222
203
|
strategy:
|
|
223
204
|
matrix:
|
|
224
205
|
platform:
|
|
@@ -269,7 +250,7 @@ jobs:
|
|
|
269
250
|
macos:
|
|
270
251
|
runs-on: ${{ matrix.platform.runner }}
|
|
271
252
|
needs: [test]
|
|
272
|
-
if: ${{ always() && github.event_name
|
|
253
|
+
if: ${{ always() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
273
254
|
strategy:
|
|
274
255
|
matrix:
|
|
275
256
|
platform:
|
|
@@ -315,7 +296,7 @@ jobs:
|
|
|
315
296
|
sdist:
|
|
316
297
|
runs-on: ubuntu-latest
|
|
317
298
|
needs: [test]
|
|
318
|
-
if: ${{ always() && github.event_name
|
|
299
|
+
if: ${{ always() && (startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch') && (needs.test.result == 'success' || needs.test.result == 'skipped') }}
|
|
319
300
|
steps:
|
|
320
301
|
- uses: actions/checkout@v4
|
|
321
302
|
- uses: astral-sh/setup-uv@v7
|
|
@@ -341,8 +322,8 @@ jobs:
|
|
|
341
322
|
name: Release
|
|
342
323
|
environment: pypi
|
|
343
324
|
runs-on: ubuntu-latest
|
|
344
|
-
# Release on tag pushes
|
|
345
|
-
if: ${{ startsWith(github.ref, 'refs/tags/') ||
|
|
325
|
+
# Release only on tag pushes or manual dispatch
|
|
326
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
|
|
346
327
|
needs: [linux, musllinux, windows, macos, sdist]
|
|
347
328
|
permissions:
|
|
348
329
|
# Use to sign the release artifacts
|
|
@@ -358,8 +339,8 @@ jobs:
|
|
|
358
339
|
with:
|
|
359
340
|
subject-path: "wheels-*/*"
|
|
360
341
|
- name: Publish to PyPI
|
|
361
|
-
# Publish on tag pushes
|
|
362
|
-
if: ${{ startsWith(github.ref, 'refs/tags/') ||
|
|
342
|
+
# Publish on tag pushes or manual dispatch
|
|
343
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
|
|
363
344
|
uses: PyO3/maturin-action@v1
|
|
364
345
|
env:
|
|
365
346
|
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -372,6 +353,7 @@ jobs:
|
|
|
372
353
|
contents: write
|
|
373
354
|
runs-on: ubuntu-latest
|
|
374
355
|
needs: [linux]
|
|
356
|
+
if: ${{ startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' }}
|
|
375
357
|
steps:
|
|
376
358
|
- uses: actions/checkout@v4
|
|
377
359
|
with:
|
|
@@ -393,20 +375,18 @@ jobs:
|
|
|
393
375
|
- name: Run benchmark
|
|
394
376
|
run: uv run python benchmark/benchmark.py
|
|
395
377
|
- name: Generate and commit benchmark image
|
|
396
|
-
if: startsWith(github.ref, 'refs/tags/')
|
|
378
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
397
379
|
run: |
|
|
398
380
|
uv run python benchmark/generate_image.py
|
|
399
381
|
git config --global user.name 'github-actions[bot]'
|
|
400
382
|
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
|
383
|
+
# Checkout main branch to avoid detached HEAD issues
|
|
384
|
+
git fetch origin main
|
|
385
|
+
git checkout main
|
|
401
386
|
git add *.jpg
|
|
402
387
|
if ! git diff --quiet --cached; then
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
else
|
|
406
|
-
git commit -m "Update benchmark image for ${{ github.ref_name }}"
|
|
407
|
-
fi
|
|
408
|
-
# Push to main branch explicitly (handles detached HEAD state from tag checkout)
|
|
409
|
-
git push origin HEAD:main
|
|
388
|
+
git commit -m "Update benchmark image for ${{ github.ref_name }}"
|
|
389
|
+
git push origin main
|
|
410
390
|
else
|
|
411
391
|
echo "No changes to commit"
|
|
412
392
|
fi
|
httpr-0.2.6/PKG-INFO
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: httpr
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
13
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Dist: certifi ; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.1.1 ; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest-asyncio>=0.25.3 ; extra == 'dev'
|
|
18
|
+
Requires-Dist: pytest-httpbin>=2.1.0 ; extra == 'dev'
|
|
19
|
+
Requires-Dist: typing-extensions ; python_full_version < '3.12' and extra == 'dev'
|
|
20
|
+
Requires-Dist: mypy>=1.14.1 ; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.9.2 ; extra == 'dev'
|
|
22
|
+
Requires-Dist: maturin ; extra == 'dev'
|
|
23
|
+
Requires-Dist: trustme ; extra == 'dev'
|
|
24
|
+
Requires-Dist: cbor2 ; extra == 'dev'
|
|
25
|
+
Requires-Dist: mkdocs-material[imaging] ; extra == 'docs'
|
|
26
|
+
Requires-Dist: mkdocstrings[python]>=0.27.0 ; extra == 'docs'
|
|
27
|
+
Requires-Dist: mkdocs-gen-files ; extra == 'docs'
|
|
28
|
+
Requires-Dist: mkdocs-literate-nav ; extra == 'docs'
|
|
29
|
+
Requires-Dist: mkdocs-llmstxt ; extra == 'docs'
|
|
30
|
+
Requires-Dist: matplotlib ; extra == 'benchmark'
|
|
31
|
+
Requires-Dist: pandas ; extra == 'benchmark'
|
|
32
|
+
Requires-Dist: starlette ; extra == 'benchmark'
|
|
33
|
+
Requires-Dist: uvicorn ; extra == 'benchmark'
|
|
34
|
+
Requires-Dist: requests ; extra == 'benchmark'
|
|
35
|
+
Requires-Dist: httpx ; extra == 'benchmark'
|
|
36
|
+
Requires-Dist: tls-client ; extra == 'benchmark'
|
|
37
|
+
Requires-Dist: curl-cffi ; extra == 'benchmark'
|
|
38
|
+
Requires-Dist: pycurl ; extra == 'benchmark'
|
|
39
|
+
Requires-Dist: typing-extensions ; extra == 'benchmark'
|
|
40
|
+
Requires-Dist: aiohttp ; extra == 'benchmark'
|
|
41
|
+
Requires-Dist: cbor2 ; extra == 'benchmark'
|
|
42
|
+
Requires-Dist: jupyter ; extra == 'benchmark'
|
|
43
|
+
Requires-Dist: ipykernel ; extra == 'benchmark'
|
|
44
|
+
Requires-Dist: gunicorn ; extra == 'benchmark'
|
|
45
|
+
Requires-Dist: fastapi ; extra == 'benchmark'
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Provides-Extra: docs
|
|
48
|
+
Provides-Extra: benchmark
|
|
49
|
+
License-File: LICENSE
|
|
50
|
+
Summary: Fast HTTP client for Python
|
|
51
|
+
Keywords: python,request
|
|
52
|
+
Author: thomasht86
|
|
53
|
+
License: MIT License
|
|
54
|
+
Requires-Python: >=3.10
|
|
55
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
56
|
+
|
|
57
|
+
# httpr
|
|
58
|
+
|
|
59
|
+
**Blazing fast http-client** for Python in Rust 🦀 that can be used as drop-in replacement for `httpx` and `requests` in most cases.
|
|
60
|
+
|
|
61
|
+
- **Fast**: `httpr` is built on top of `reqwests`, which is a blazing fast http client in Rust. Check out the [benchmark](#benchmark).
|
|
62
|
+
- **Both async and sync**: `httpr` provides both a sync and async client.
|
|
63
|
+
- **Lightweight**: `httpr` is a lightweight http client with zero python-dependencies.
|
|
64
|
+
- **Async**: first-class async support.
|
|
65
|
+
- **Streaming**: supports streaming responses for efficient memory usage with large payloads.
|
|
66
|
+
- **http2**: `httpr` supports HTTP/2.
|
|
67
|
+
- **mTLS**: `httpr` supports mTLS.
|
|
68
|
+
|
|
69
|
+
## Not implemented yet
|
|
70
|
+
|
|
71
|
+
- **Fine-grained error handling**: Fine-grained error handling is not implemented yet.
|
|
72
|
+
|
|
73
|
+
## Documentation
|
|
74
|
+
|
|
75
|
+
📖 **Full documentation**: [thomasht86.github.io/httpr](https://thomasht86.github.io/httpr)
|
|
76
|
+
|
|
77
|
+
🤖 **LLM-friendly docs**: [llms.txt](https://thomasht86.github.io/httpr/llms.txt) | [llms-full.txt](https://thomasht86.github.io/httpr/llms-full.txt)
|
|
78
|
+
|
|
79
|
+
## Table of Contents
|
|
80
|
+
|
|
81
|
+
- [httpr](#httpr)
|
|
82
|
+
- [Not implemented yet](#not-implemented-yet)
|
|
83
|
+
- [Documentation](#documentation)
|
|
84
|
+
- [Table of Contents](#table-of-contents)
|
|
85
|
+
- [Installation](#installation)
|
|
86
|
+
- [Install with uv](#install-with-uv)
|
|
87
|
+
- [Install from PyPI](#install-from-pypi)
|
|
88
|
+
- [Benchmark](#benchmark)
|
|
89
|
+
- [Usage](#usage)
|
|
90
|
+
- [I. Client](#i-client)
|
|
91
|
+
- [Client methods](#client-methods)
|
|
92
|
+
- [Response object](#response-object)
|
|
93
|
+
- [Streaming responses](#streaming-responses)
|
|
94
|
+
- [Examples](#examples)
|
|
95
|
+
- [II. AsyncClient](#ii-asyncclient)
|
|
96
|
+
- [Precompiled wheels](#precompiled-wheels)
|
|
97
|
+
- [CI](#ci)
|
|
98
|
+
- [Acknowledgements](#acknowledgements)
|
|
99
|
+
|
|
100
|
+
## Installation
|
|
101
|
+
|
|
102
|
+
### Install with uv
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
uv add httpr
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
or
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
uv pip install httpr
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Install from PyPI
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
pip install -U httpr
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Benchmark
|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
### I. Client
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
class Client:
|
|
130
|
+
"""Initializes an HTTP client.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
auth (tuple[str, str| None] | None): Username and password for basic authentication. Default is None.
|
|
134
|
+
auth_bearer (str | None): Bearer token for authentication. Default is None.
|
|
135
|
+
params (dict[str, str] | None): Default query parameters to include in all requests. Default is None.
|
|
136
|
+
headers (dict[str, str] | None): Default headers to send with requests.
|
|
137
|
+
cookies (dict[str, str] | None): - Map of cookies to send with requests as the `Cookie` header.
|
|
138
|
+
timeout (float | None): HTTP request timeout in seconds. Default is 30.
|
|
139
|
+
cookie_store (bool | None): Enable a persistent cookie store. Received cookies will be preserved and included
|
|
140
|
+
in additional requests. Default is True.
|
|
141
|
+
referer (bool | None): Enable or disable automatic setting of the `Referer` header. Default is True.
|
|
142
|
+
proxy (str | None): Proxy URL for HTTP requests. Example: "socks5://127.0.0.1:9150". Default is None.
|
|
143
|
+
follow_redirects (bool | None): Whether to follow redirects. Default is True.
|
|
144
|
+
max_redirects (int | None): Maximum redirects to follow. Default 20. Applies if `follow_redirects` is True.
|
|
145
|
+
verify (bool | None): Verify SSL certificates. Default is True.
|
|
146
|
+
ca_cert_file (str | None): Path to CA certificate store. Default is None.
|
|
147
|
+
https_only` (bool | None): Restrict the Client to be used with HTTPS only requests. Default is `false`.
|
|
148
|
+
http2_only` (bool | None): If true - use only HTTP/2; if false - use only HTTP/1. Default is `false`.
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Client methods
|
|
154
|
+
|
|
155
|
+
The `Client` class provides a set of methods for making HTTP requests: `get`, `head`, `options`, `delete`, `post`, `put`, `patch`, each of which internally utilizes the `request()` method for execution. The parameters for these methods closely resemble those in `httpx`.
|
|
156
|
+
```python
|
|
157
|
+
def get(
|
|
158
|
+
url: str,
|
|
159
|
+
params: dict[str, str] | None = None,
|
|
160
|
+
headers: dict[str, str] | None = None,
|
|
161
|
+
cookies: dict[str, str] | None = None,
|
|
162
|
+
auth: tuple[str, str| None] | None = None,
|
|
163
|
+
auth_bearer: str | None = None,
|
|
164
|
+
timeout: float | None = 30,
|
|
165
|
+
):
|
|
166
|
+
"""Performs a GET request to the specified URL.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
url (str): The URL to which the request will be made.
|
|
170
|
+
params (dict[str, str] | None): A map of query parameters to append to the URL. Default is None.
|
|
171
|
+
headers (dict[str, str] | None): A map of HTTP headers to send with the request. Default is None.
|
|
172
|
+
cookies (dict[str, str] | None): - An optional map of cookies to send with requests as the `Cookie` header.
|
|
173
|
+
auth (tuple[str, str| None] | None): A tuple containing the username and an optional password
|
|
174
|
+
for basic authentication. Default is None.
|
|
175
|
+
auth_bearer (str | None): A string representing the bearer token for bearer token authentication. Default is None.
|
|
176
|
+
timeout (float | None): The timeout for the request in seconds. Default is 30.
|
|
177
|
+
|
|
178
|
+
"""
|
|
179
|
+
```
|
|
180
|
+
```python
|
|
181
|
+
def post(
|
|
182
|
+
url: str,
|
|
183
|
+
params: dict[str, str] | None = None,
|
|
184
|
+
headers: dict[str, str] | None = None,
|
|
185
|
+
cookies: dict[str, str] | None = None,
|
|
186
|
+
content: bytes | None = None,
|
|
187
|
+
data: dict[str, Any] | None = None,
|
|
188
|
+
json: Any | None = None,
|
|
189
|
+
files: dict[str, str] | None = None,
|
|
190
|
+
auth: tuple[str, str| None] | None = None,
|
|
191
|
+
auth_bearer: str | None = None,
|
|
192
|
+
timeout: float | None = 30,
|
|
193
|
+
):
|
|
194
|
+
"""Performs a POST request to the specified URL.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
url (str): The URL to which the request will be made.
|
|
198
|
+
params (dict[str, str] | None): A map of query parameters to append to the URL. Default is None.
|
|
199
|
+
headers (dict[str, str] | None): A map of HTTP headers to send with the request. Default is None.
|
|
200
|
+
cookies (dict[str, str] | None): - An optional map of cookies to send with requests as the `Cookie` header.
|
|
201
|
+
content (bytes | None): The content to send in the request body as bytes. Default is None.
|
|
202
|
+
data (dict[str, Any] | None): The form data to send in the request body. Default is None.
|
|
203
|
+
json (Any | None): A JSON serializable object to send in the request body. Default is None.
|
|
204
|
+
files (dict[str, str] | None): A map of file fields to file paths to be sent as multipart/form-data. Default is None.
|
|
205
|
+
auth (tuple[str, str| None] | None): A tuple containing the username and an optional password
|
|
206
|
+
for basic authentication. Default is None.
|
|
207
|
+
auth_bearer (str | None): A string representing the bearer token for bearer token authentication. Default is None.
|
|
208
|
+
timeout (float | None): The timeout for the request in seconds. Default is 30.
|
|
209
|
+
|
|
210
|
+
"""
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Response object
|
|
214
|
+
|
|
215
|
+
The `Client` class returns a `Response` object that contains the following attributes and methods:
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
resp.content
|
|
219
|
+
resp.cookies
|
|
220
|
+
resp.encoding
|
|
221
|
+
resp.headers
|
|
222
|
+
resp.json()
|
|
223
|
+
resp.status_code
|
|
224
|
+
resp.text
|
|
225
|
+
resp.text_markdown # html is converted to markdown text using html2text-rs
|
|
226
|
+
resp.text_plain # html is converted to plain text
|
|
227
|
+
resp.text_rich # html is converted to rich text
|
|
228
|
+
resp.url
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### Streaming responses
|
|
232
|
+
|
|
233
|
+
The `Client` class supports streaming responses for efficient memory usage when handling large payloads. Use the `stream()` context manager to iterate over response data without buffering the entire response in memory.
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# Stream bytes chunks
|
|
237
|
+
with client.stream("GET", "https://example.com/large-file") as response:
|
|
238
|
+
print(f"Status: {response.status_code}")
|
|
239
|
+
for chunk in response.iter_bytes():
|
|
240
|
+
process(chunk)
|
|
241
|
+
|
|
242
|
+
# Stream text chunks
|
|
243
|
+
with client.stream("GET", "https://example.com/text") as response:
|
|
244
|
+
for text in response.iter_text():
|
|
245
|
+
print(text, end="")
|
|
246
|
+
|
|
247
|
+
# Stream line by line (useful for Server-Sent Events)
|
|
248
|
+
with client.stream("GET", "https://example.com/events") as response:
|
|
249
|
+
for line in response.iter_lines():
|
|
250
|
+
print(line.strip())
|
|
251
|
+
|
|
252
|
+
# Read entire response (if needed after checking headers)
|
|
253
|
+
with client.stream("GET", url) as response:
|
|
254
|
+
if response.status_code == 200:
|
|
255
|
+
content = response.read()
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**StreamingResponse attributes:**
|
|
259
|
+
- `status_code` - HTTP status code
|
|
260
|
+
- `headers` - Response headers (case-insensitive)
|
|
261
|
+
- `cookies` - Response cookies
|
|
262
|
+
- `url` - Final URL after redirects
|
|
263
|
+
- `is_closed` - Whether the stream has been closed
|
|
264
|
+
- `is_consumed` - Whether the stream has been fully consumed
|
|
265
|
+
|
|
266
|
+
**StreamingResponse methods:**
|
|
267
|
+
- `iter_bytes()` - Iterate over response as bytes chunks
|
|
268
|
+
- `iter_text()` - Iterate over response as text chunks (decoded using response encoding)
|
|
269
|
+
- `iter_lines()` - Iterate over response line by line
|
|
270
|
+
- `read()` - Read entire remaining response body into memory
|
|
271
|
+
- `close()` - Close the stream and release resources
|
|
272
|
+
|
|
273
|
+
**Important notes:**
|
|
274
|
+
- Streaming must be used as a context manager (with statement)
|
|
275
|
+
- Headers, cookies, and status code are available immediately before reading the body
|
|
276
|
+
- The response body is only read when you iterate over it or call `read()`
|
|
277
|
+
- Once consumed, the stream cannot be read again
|
|
278
|
+
- Streaming is supported for all HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
|
|
279
|
+
|
|
280
|
+
#### Examples
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
import httpr
|
|
284
|
+
|
|
285
|
+
# Initialize the client
|
|
286
|
+
client = httpr.Client()
|
|
287
|
+
|
|
288
|
+
# GET request
|
|
289
|
+
resp = client.get("https://tls.peet.ws/api/all")
|
|
290
|
+
print(resp.json())
|
|
291
|
+
|
|
292
|
+
# GET request with passing params and setting timeout
|
|
293
|
+
params = {"param1": "value1", "param2": "value2"}
|
|
294
|
+
resp = client.post(url="https://httpbin.org/anything", params=params, timeout=10)
|
|
295
|
+
print(r.text)
|
|
296
|
+
|
|
297
|
+
# POST Binary Request Data
|
|
298
|
+
content = b"some_data"
|
|
299
|
+
resp = client.post(url="https://httpbin.org/anything", content=content)
|
|
300
|
+
print(r.text)
|
|
301
|
+
|
|
302
|
+
# POST Form Encoded Data
|
|
303
|
+
data = {"key1": "value1", "key2": "value2"}
|
|
304
|
+
resp = client.post(url="https://httpbin.org/anything", data=data)
|
|
305
|
+
print(r.text)
|
|
306
|
+
|
|
307
|
+
# POST JSON Encoded Data
|
|
308
|
+
json = {"key1": "value1", "key2": "value2"}
|
|
309
|
+
resp = client.post(url="https://httpbin.org/anything", json=json)
|
|
310
|
+
print(r.text)
|
|
311
|
+
|
|
312
|
+
# POST Multipart-Encoded Files
|
|
313
|
+
files = {'file1': '/home/root/file1.txt', 'file2': 'home/root/file2.txt'}
|
|
314
|
+
r = client.post("https://httpbin.org/post", files=files)
|
|
315
|
+
print(r.text)
|
|
316
|
+
|
|
317
|
+
# Authentication using user/password
|
|
318
|
+
auth = ("user", "password")
|
|
319
|
+
resp = client.post(url="https://httpbin.org/anything", auth=auth)
|
|
320
|
+
print(r.text)
|
|
321
|
+
|
|
322
|
+
# Authentication using auth bearer
|
|
323
|
+
auth_bearer = "bearerXXXXXXXXXXXXXXXXXXXX"
|
|
324
|
+
resp = client.post(url="https://httpbin.org/anything", auth_bearer=auth_bearer)
|
|
325
|
+
print(r.text)
|
|
326
|
+
|
|
327
|
+
# Using proxy or env var HTTPR_PROXY
|
|
328
|
+
resp = httpr.Client(proxy="http://127.0.0.1:8080").get("https://tls.peet.ws/api/all")
|
|
329
|
+
print(resp.json())
|
|
330
|
+
export HTTPR_PROXY="socks5://127.0.0.1:1080"
|
|
331
|
+
resp = httpr.Client().get("https://tls.peet.ws/api/all")
|
|
332
|
+
print(resp.json())
|
|
333
|
+
|
|
334
|
+
# Using custom CA certificate store: env var HTTPR_CA_BUNDLE
|
|
335
|
+
resp = httpr.Client(ca_cert_file="/cert/cacert.pem").get("https://tls.peet.ws/api/all")
|
|
336
|
+
print(resp.json())
|
|
337
|
+
resp = httpr.Client(ca_cert_file=certifi.where()).get("https://tls.peet.ws/api/all")
|
|
338
|
+
print(resp.json())
|
|
339
|
+
export HTTPR_CA_BUNDLE="/home/user/Downloads/cert.pem"
|
|
340
|
+
resp = httpr.Client().get("https://tls.peet.ws/api/all")
|
|
341
|
+
print(resp.json())
|
|
342
|
+
|
|
343
|
+
# You can also use convenience functions that use a default Client instance under the hood:
|
|
344
|
+
# httpr.get() | httpr.head() | httpr.options() | httpr.delete() | httpr.post() | httpr.patch() | httpr.put()
|
|
345
|
+
resp = httpr.get("https://httpbin.org/anything")
|
|
346
|
+
print(r.text)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### II. AsyncClient
|
|
350
|
+
|
|
351
|
+
`httpr.AsyncClient()` is an asynchronous wrapper around the `httpr.Client` class, offering the same functions, behavior, and input arguments.
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
import asyncio
|
|
355
|
+
import logging
|
|
356
|
+
|
|
357
|
+
import httpr
|
|
358
|
+
|
|
359
|
+
async def aget_text(url):
|
|
360
|
+
async with httpr.AsyncClient() as client:
|
|
361
|
+
resp = await client.get(url)
|
|
362
|
+
return resp.text
|
|
363
|
+
|
|
364
|
+
async def main():
|
|
365
|
+
urls = ["https://nytimes.com/", "https://cnn.com/", "https://abcnews.go.com/"]
|
|
366
|
+
tasks = [aget_text(u) for u in urls]
|
|
367
|
+
results = await asyncio.gather(*tasks)
|
|
368
|
+
|
|
369
|
+
if __name__ == "__main__":
|
|
370
|
+
logging.basicConfig(level=logging.INFO)
|
|
371
|
+
asyncio.run(main())
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
**Streaming with AsyncClient:**
|
|
375
|
+
|
|
376
|
+
The `AsyncClient` also supports streaming responses with the same API:
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
async with httpr.AsyncClient() as client:
|
|
380
|
+
async with client.stream("GET", "https://example.com/large-file") as response:
|
|
381
|
+
for chunk in response.iter_bytes():
|
|
382
|
+
process(chunk)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Note: While the context manager is async, the iteration over chunks (`iter_bytes()`, `iter_text()`, `iter_lines()`) is synchronous.
|
|
386
|
+
|
|
387
|
+
## Precompiled wheels
|
|
388
|
+
|
|
389
|
+
Provides precompiled wheels for the following platforms:
|
|
390
|
+
|
|
391
|
+
- 🐧 linux: `amd64`, `aarch64`, `armv7` (aarch64 and armv7 builds are `manylinux_2_34` compatible. `ubuntu>=22.04`, `debian>=12`)
|
|
392
|
+
- 🐧 musllinux: `amd64`, `aarch64`
|
|
393
|
+
- 🪟 windows: `amd64`
|
|
394
|
+
- 🍏 macos: `amd64`, `aarch64`.
|
|
395
|
+
|
|
396
|
+
## CI
|
|
397
|
+
|
|
398
|
+
| Job | PRs | Push to main | Tags (Release) | Manual |
|
|
399
|
+
|-----|:---:|:------------:|:--------------:|:------:|
|
|
400
|
+
| `lint` | ✓ | | | |
|
|
401
|
+
| `test` (Python 3.10-3.14) | ✓ | ✓ | ✓ | |
|
|
402
|
+
| `docs` (build) | ✓ | | | |
|
|
403
|
+
| `linux`, `musllinux`, `windows`, `macos`, `sdist` | | | ✓ | ✓ |
|
|
404
|
+
| `release` (PyPI publish) | | | ✓ | ✓ |
|
|
405
|
+
| `benchmark` | | | ✓ | ✓ |
|
|
406
|
+
|
|
407
|
+
- **PRs**: Run lint, tests across Python 3.10-3.14 matrix, and verify docs build
|
|
408
|
+
- **Push to main**: Run tests only
|
|
409
|
+
- **Tags**: Run tests, build wheels, publish stable release to PyPI, run benchmarks
|
|
410
|
+
- **Manual**: Full multi-platform wheel builds with release and benchmarks
|
|
411
|
+
|
|
412
|
+
## Acknowledgements
|
|
413
|
+
|
|
414
|
+
- [uv](https://docs.astral.sh/uv/): The package manager used, and for leading the way in the "Rust for python tools"-sphere.
|
|
415
|
+
- [primp](https://github.com/deedy5/primp): *A lot* of code is borrowed from primp, that wraps rust library `rquest` for python in a similar way. If primp supported mTLS, I would have used it instead.
|
|
416
|
+
- [reqwests](https://github.com/seanmonstar/reqwest): The rust library that powers httpr.
|
|
417
|
+
- [pyo3](https://github.com/PyO3/pyo3)
|
|
418
|
+
- [maturin](https://github.com/PyO3/maturin)
|
|
@@ -339,19 +339,19 @@ Provides precompiled wheels for the following platforms:
|
|
|
339
339
|
|
|
340
340
|
## CI
|
|
341
341
|
|
|
342
|
-
| Job | PRs | Push to main | Tags (Release) |
|
|
343
|
-
|
|
344
|
-
| `
|
|
345
|
-
| `
|
|
346
|
-
| `docs` (
|
|
347
|
-
| `linux`, `musllinux`, `windows`, `macos`, `sdist` | |
|
|
348
|
-
| `release` (PyPI publish) | |
|
|
349
|
-
| `benchmark` | |
|
|
350
|
-
|
|
351
|
-
- **PRs**: Run tests across Python 3.10-3.14 matrix and verify docs build
|
|
352
|
-
- **Push to main**: Run tests
|
|
353
|
-
- **Tags**:
|
|
354
|
-
- **
|
|
342
|
+
| Job | PRs | Push to main | Tags (Release) | Manual |
|
|
343
|
+
|-----|:---:|:------------:|:--------------:|:------:|
|
|
344
|
+
| `lint` | ✓ | | | |
|
|
345
|
+
| `test` (Python 3.10-3.14) | ✓ | ✓ | ✓ | |
|
|
346
|
+
| `docs` (build) | ✓ | | | |
|
|
347
|
+
| `linux`, `musllinux`, `windows`, `macos`, `sdist` | | | ✓ | ✓ |
|
|
348
|
+
| `release` (PyPI publish) | | | ✓ | ✓ |
|
|
349
|
+
| `benchmark` | | | ✓ | ✓ |
|
|
350
|
+
|
|
351
|
+
- **PRs**: Run lint, tests across Python 3.10-3.14 matrix, and verify docs build
|
|
352
|
+
- **Push to main**: Run tests only
|
|
353
|
+
- **Tags**: Run tests, build wheels, publish stable release to PyPI, run benchmarks
|
|
354
|
+
- **Manual**: Full multi-platform wheel builds with release and benchmarks
|
|
355
355
|
|
|
356
356
|
## Acknowledgements
|
|
357
357
|
|
|
@@ -149,8 +149,8 @@ print(response.cookies) # Response cookies
|
|
|
149
149
|
|
|
150
150
|
This documentation is available in LLM-optimized formats:
|
|
151
151
|
|
|
152
|
-
- **[llms.txt](llms.txt)** - Documentation index for LLMs
|
|
153
|
-
- **[llms-full.txt](llms-full.txt)** - Complete documentation in a single file
|
|
152
|
+
- **[llms.txt](https://thomasht86.github.io/httpr/llms.txt)** - Documentation index for LLMs
|
|
153
|
+
- **[llms-full.txt](https://thomasht86.github.io/httpr/llms-full.txt)** - Complete documentation in a single file
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
@@ -5,10 +5,11 @@ build-backend = "maturin"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "httpr"
|
|
7
7
|
description = "Fast HTTP client for Python"
|
|
8
|
+
readme = "README.md"
|
|
8
9
|
requires-python = ">=3.10"
|
|
9
10
|
keywords = [ "python", "request",]
|
|
10
11
|
classifiers = [ "Programming Language :: Rust", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries :: Python Modules",]
|
|
11
|
-
version = "0.2.
|
|
12
|
+
version = "0.2.6"
|
|
12
13
|
dependencies = []
|
|
13
14
|
[[project.authors]]
|
|
14
15
|
name = "thomasht86"
|
httpr-0.2.3.dev163/PKG-INFO
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: httpr
|
|
3
|
-
Version: 0.2.3.dev163
|
|
4
|
-
Classifier: Programming Language :: Rust
|
|
5
|
-
Classifier: Programming Language :: Python :: 3
|
|
6
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
7
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
12
|
-
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
13
|
-
Classifier: Topic :: Internet :: WWW/HTTP
|
|
14
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
-
Requires-Dist: certifi ; extra == 'dev'
|
|
16
|
-
Requires-Dist: pytest>=8.1.1 ; extra == 'dev'
|
|
17
|
-
Requires-Dist: pytest-asyncio>=0.25.3 ; extra == 'dev'
|
|
18
|
-
Requires-Dist: pytest-httpbin>=2.1.0 ; extra == 'dev'
|
|
19
|
-
Requires-Dist: typing-extensions ; python_full_version < '3.12' and extra == 'dev'
|
|
20
|
-
Requires-Dist: mypy>=1.14.1 ; extra == 'dev'
|
|
21
|
-
Requires-Dist: ruff>=0.9.2 ; extra == 'dev'
|
|
22
|
-
Requires-Dist: maturin ; extra == 'dev'
|
|
23
|
-
Requires-Dist: trustme ; extra == 'dev'
|
|
24
|
-
Requires-Dist: cbor2 ; extra == 'dev'
|
|
25
|
-
Requires-Dist: mkdocs-material[imaging] ; extra == 'docs'
|
|
26
|
-
Requires-Dist: mkdocstrings[python]>=0.27.0 ; extra == 'docs'
|
|
27
|
-
Requires-Dist: mkdocs-gen-files ; extra == 'docs'
|
|
28
|
-
Requires-Dist: mkdocs-literate-nav ; extra == 'docs'
|
|
29
|
-
Requires-Dist: mkdocs-llmstxt ; extra == 'docs'
|
|
30
|
-
Requires-Dist: matplotlib ; extra == 'benchmark'
|
|
31
|
-
Requires-Dist: pandas ; extra == 'benchmark'
|
|
32
|
-
Requires-Dist: starlette ; extra == 'benchmark'
|
|
33
|
-
Requires-Dist: uvicorn ; extra == 'benchmark'
|
|
34
|
-
Requires-Dist: requests ; extra == 'benchmark'
|
|
35
|
-
Requires-Dist: httpx ; extra == 'benchmark'
|
|
36
|
-
Requires-Dist: tls-client ; extra == 'benchmark'
|
|
37
|
-
Requires-Dist: curl-cffi ; extra == 'benchmark'
|
|
38
|
-
Requires-Dist: pycurl ; extra == 'benchmark'
|
|
39
|
-
Requires-Dist: typing-extensions ; extra == 'benchmark'
|
|
40
|
-
Requires-Dist: aiohttp ; extra == 'benchmark'
|
|
41
|
-
Requires-Dist: cbor2 ; extra == 'benchmark'
|
|
42
|
-
Requires-Dist: jupyter ; extra == 'benchmark'
|
|
43
|
-
Requires-Dist: ipykernel ; extra == 'benchmark'
|
|
44
|
-
Requires-Dist: gunicorn ; extra == 'benchmark'
|
|
45
|
-
Requires-Dist: fastapi ; extra == 'benchmark'
|
|
46
|
-
Provides-Extra: dev
|
|
47
|
-
Provides-Extra: docs
|
|
48
|
-
Provides-Extra: benchmark
|
|
49
|
-
License-File: LICENSE
|
|
50
|
-
Summary: Fast HTTP client for Python
|
|
51
|
-
Keywords: python,request
|
|
52
|
-
Author: thomasht86
|
|
53
|
-
License: MIT License
|
|
54
|
-
Requires-Python: >=3.10
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{httpr-0.2.3.dev163 → httpr-0.2.6}/docs/writings/posts/2025-02-24-python-http-clients-suck.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|