Skip to main content

RedCum

Async HTTP client for Python with native libcurl performance, extended with:

  1. A synchronous API (RedCum.sync) — no async/await required.
  2. impersonate= support wired through to libcurl-impersonate, with an auto-detecting fetch script (fetch_impersonate.sh) so getting it built is one command, not a manual per-architecture hunt — see BUILDING_IMPERSONATE.md.
  3. Every libcurl failure raised as a specific, catchable Python exception — this was already true in upstream RedCum and is unchanged/preserved here.
  4. A fix for a real crash-on-shutdown bug found while testing this fork (see "What changed and why" below).

Everything upstream RedCum does (async Client, streaming, HTTP/1.1/2/3, cookies, connection pooling, CurlURL, ...) still works exactly as before — nothing was removed, only added to.

Quick start (sync API)

import RedCum.sync as curl

resp = curl.get("https://target.com", impersonate="chrome110")
resp2 = curl.get("https://target.com", impersonate="safari18_0_ios")

print(resp.status_code, resp.text[:200])

No client setup, no event loop, no await. Connections are still pooled under the hood (a background thread owns one persistent event loop + one RedCum.Client), so repeated calls to curl.get(...) aren't reconnecting from scratch each time.

impersonate requires RedCum to be built against libcurl-impersonate. ./publish.sh --build-only --auto-impersonate handles this end-to-end — auto-detects your architecture, downloads the matching library, and builds a working wheel — verified for real, not just documented (see BUILDING_IMPERSONATE.md, which walks through the exact process that was used to confirm this: downloaded the actual release archive, linked RedCum against it, and confirmed real HTTP requests with impersonate="chrome110" and impersonate="safari18_0_ios" both return 200. On a stock-libcurl build (what ships in this zip by default), passing impersonate= raises a clear RuntimeError explaining exactly what to do — it never silently ignores the argument or crashes.

import RedCum
print(RedCum.has_impersonate())  # False until built per BUILDING_IMPERSONATE.md

Session — for anything beyond one-off calls

import RedCum.sync as curl

with curl.Session(impersonate="chrome110", timeout=15) as s:
    for url in urls:
        r = s.get(url)
        print(r.status_code)

Use Session when you want:

  • Shared headers/cookies/timeout across many calls
  • A single impersonate profile applied to every request from that session
  • Deterministic cleanup (with ... : or explicit .close())
  • To make concurrent calls from multiple threads against one connection pool (a Session is thread-safe — see tests/test_sync_api.py::test_concurrent_calls_from_multiple_threads)

Every request parameter is still there

curl.get, .post, .put, .patch, .delete, .head, .options, and .request all accept the same arguments as RedCum.Client's async methods — params, json, data, files, headers, cookies, timeout, allow_redirects, proxy_url, auth, verify, cert, stream_callback, progress_callback, verbose — plus the new impersonate / impersonate_default_headers.

resp = curl.post(
    "https://api.internal.example.com/upload",
    files={"file": ("report.pdf", open("report.pdf", "rb"))},
    headers={"Authorization": "Bearer ..."},
    impersonate="chrome110",
    timeout=30,
)

Error handling — the whole point of "simple"

Every connection-level failure raises. DNS failure, TLS handshake failure, connection refused, timeout — you never get back a Response that silently has status_code == -1. This is different from upstream RedCum's default (where that's opt-in via raise_for_status=True); for a "simple" API the sync layer here always raises on curl-level failure, since a caller who didn't opt into error-handling complexity shouldn't have to check for a magic -1 sentinel.

import RedCum.sync as curl
import RedCum.exceptions as exc

try:
    curl.get("https://this-domain-does-not-exist.invalid")
except exc.CouldntResolveHostError as e:
    print("DNS lookup failed:", e)
except exc.CurlError as e:
    # catches every other libcurl failure: timeouts, TLS errors,
    # connection refused, too many redirects, etc.
    print(f"Request failed ({e.code}):", e)

HTTP 4xx/5xx status codes stay opt-in, same as requests/httpx:

resp = curl.get("https://api.example.com/missing")
print(resp.status_code)  # 404, no exception

# opt in per-call:
resp.raise_for_status()  # raises HTTPError now

# or opt in for a whole session:
with curl.Session(raise_for_status=True) as s:
    s.get("https://api.example.com/missing")  # raises HTTPError immediately

Every libcurl CURLcode has its own exception class (CouldntResolveHostError, OperationTimedoutError, SslConnectErrorError, PeerFailedVerificationError, ...) — see RedCum/exceptions/__init__.py. This was already the case in upstream RedCum; this fork doesn't touch that mapping, just makes sure the sync layer actually surfaces it instead of swallowing it.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

redcum-0.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (5.6 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

redcum-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (5.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

redcum-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (5.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

File details

Details for the file redcum-0.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for redcum-0.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 6503dfa06c18450d6630a31e72a2b7d08dddf3154ea7e12275cdb01f6345138a
MD5 5baa19362968c485bea80500f64231e4
BLAKE2b-256 f10b4125f193947b3d1d1c4045a07444b06930d97c1391c9a4f4dca5e3ed2575

See more details on using hashes here.

File details

Details for the file redcum-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for redcum-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 b54bc887f20ee5669401b579f50ea87d9603fab45ce4d521d14033269354f596
MD5 d0f52cbe53771ef0a19a37ed7c173fc1
BLAKE2b-256 c6d4a0418e291484bf3006dc17617989a93f9f8d188b2f268109af6603ba13f6

See more details on using hashes here.

File details

Details for the file redcum-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for redcum-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 1144cf40f6b74a996c355968330a8ba442643c62a315db56f1480b55f6335c7d
MD5 44cf7dd5a1f5eb636359187587a4b330
BLAKE2b-256 243657d19f94e482b364c7a0e23b9f77ec66db9ae3c726e1c59cca99170f4a2e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page