Library / SDK
pycurl/pycurl avatar
pycurl/pycurl

PycURL: a thin Python binding over libcurl

PycURL - Python interface to libcurl

1,170 stars329 forksPythonLGPL-2.1

At a glance

What is it?
PycURL is a Python interface to libcurl that exposes most of the C library's surface, from multi and share interfaces to WebSockets, MIME forms and an asyncio wrapper, at the cost of a C extension you have to build. It suits someone who needs a libcurl capability that requests does not have, and it is not the choice for an ordinary HTTP call.
Who is it for?
Adopt PycURL when you need a libcurl capability that higher-level Python HTTP clients do not expose, such as the multi interface, share handles, WebSockets or byte-level socket control. Skip it for ordinary requests, because building a C extension against a system libcurl is a real cost that a pure Python client does not carry.
Can I use it commercially?
Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What a thin wrapper buys you

PycURL is a Python interface to libcurl, the multiprotocol file transfer library, and it works like the urllib module in that it can fetch objects identified by a URL. Beyond simple fetches, however, it exposes most of the functionality of libcurl. The speed claim is stated plainly, that libcurl is very fast and PycURL, being a thin wrapper above libcurl, is very fast as well, and it was benchmarked to be several times faster than requests. The feature list behind that is what matters in practice. It supports most of libcurl's callbacks. It has the multi and share interfaces. It has context managers, with `Curl` and `CurlMulti` supporting the `with` statement. It has first-class WebSocket support over `ws://` and `wss://`. It has MIME and multipart form wrappers, `pycurl.Mime` and `pycurl.MimePart`. And it has a URL parsing wrapper, `pycurl.CurlUrl`, around libcurl's URL API. The primary language is Python, the licence is LGPL-2.1 or MIT, and the last push was on 2026-10-08 with releases v7.48.0 on 2026-09-17 and v7.47.0 on 2026-07-01.

The I/O integration features, which are the unusual ones

Three of the capabilities go beyond making HTTP easier and are the ones that make PycURL worth the C extension. Sockets used for network operations permit integration of PycURL into the application's I/O loop, for example using Tornado. Built-in asyncio support comes via `pycurl.AsyncCurlMulti`, an asyncio wrapper around `CurlMulti` driven by libcurl's multi-socket API. And low-level socket I/O gives direct byte-level control, for example with `CONNECT_ONLY`. The asyncio point deserves emphasis because it changes which object you use. `AsyncCurlMulti` is a different type from `CurlMulti`, so an application that wants to await requests inside a running event loop has to reach for the async wrapper rather than driving the synchronous multi interface itself. The underlying reason PycURL can offer these is that libcurl exposes its own socket API, so the library does not need to own the connection, which is what makes it fit inside an existing loop.

Installing it, and the libcurl dependency

The requirements are Python 3.10 to 3.15 and libcurl 7.19.0 or better. Source and binary distributions are on PyPI, and binary wheels are available for 32 and 64 bit Windows versions, which is the one platform where a C extension is otherwise painful. The installation instructions live in `INSTALL.rst`, and there is a separate section for installing from a Git checkout, since a source build of the extension needs a libcurl development package present. That is the practical cost of this library, and it is why the wheel situation matters. The setup script in the repository probes the system for curl and its features, running the curl configuration with `--features` and parsing the output to decide which macros to define, including the SSL detection that has to match at link time and run time. The project metadata reflects a modern toolchain, with setuptools 77 or newer as the build requirement and a `pyproject.toml` that carries the project metadata with a dynamic version.

Running the test suite

PycURL ships an automated test suite, and the documented way to run it is a virtual environment and pytest:

code
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e . --group dev
python -m pytest tests/

The note attached to that is specific and useful, that the `--group` option requires pip 25.1 or newer under PEP 735, which is the dependency group specification, and the test group in the project file includes flaky and other tooling. The suite depends on pytest and flask, and also on vsftpd. Some tests use vsftpd configured to accept anonymous uploads, and they are not run by default, which is a sensible default because as configured vsftpd allows reads and writes to anything the user running the tests has access to. To run them you set `PYCURL_VSFTPD_PATH` explicitly, either to the name in the path or to a full path such as `/usr/local/libexec/vsftpd`. The suite can also be run through `make test`, and after modifying the C sources under `src/` you rebuild the extension in place with `python -m pip install -e .`.

The C sources, and the documentation is generated from them

The Makefile lists the C sources, and the naming shows the architecture. There is `easy.c` as the main interface, with `easycb.c` for callbacks, `easyinfo.c`, `easyopt.c` for options, `easyperform.c` and `easyws.c` for the WebSocket support, then `mime.c` for the MIME API, `module.c` for the module definition, `multi.c` and `share.c` for the multi and share interfaces, `url.c` for the URL API, `threadsupport.c`, and several portability files, `oscompat.c`, `pythoncompat.c` and `stringcompat.c`. The documentation is generated rather than written, which is the pattern worth noting. The `docstrings.c` and `docstrings.h` files are generated sources, and the rule in the Makefile is that they are rebuilt from the reStructuredText files under `doc/docstrings` by a Python call into the setup module, `setup.generate_docstrings()`. The documentation targets depend on the build target because Sphinx extracts the docstrings from the built extension module, so the built documentation lands in the `build/doc` subdirectory.

Dual licensing and the code ownership history

PycURL is dual licensed under the LGPL and an MIT/X derivative license based on the cURL license, with a full copy of the LGPL in the file COPYING-LGPL and a full copy of the MIT/X derivative in COPYING-MIT, and you can redistribute and or modify PycURL according to the terms of either license. The project metadata records the same choice as `LGPL-2.1-only OR MIT`. The copyright lines in the README carry three names with their periods, Kjetil Jacobsen and Markus F.X.J. Oberhumer for 2001 to 2008 and Oleg Pudeyev for 2013 to 2022, and the maintainer field in the project file is Oleg Pudeyev. The dual licence is the practical reason a project like this can be adopted in a commercial setting without the LGPL's copyleft reach, since the MIT/X option lets you treat it as permissively licensed.

Where PycURL is the wrong tool

The limitation is the one implied by the design. This is a C extension, so installing it means a build against a system libcurl on anything without a wheel, and that is a real operational cost for a container image that has to be reproducible. It is also a heavy dependency for what most Python programs need, since a request to a JSON endpoint does not require a multi interface, a share handle, WebSocket support or byte-level socket control. The protocol coverage is broad but the interface is not Pythonic, with options set through named setters rather than keyword arguments, so the code reads more like a C library wearing a Python coat than like requests. And because the wrapper follows libcurl, its feature set is tied to the libcurl version you link against, which means the behaviour of a given PycURL version can differ across platforms with different libcurl builds. For a one-off script doing a plain fetch, urllib or requests is the better answer, and the README's own comparison makes the case for PycURL by reference to the Stack Overflow discussion rather than by argument.

Editorial conclusion

Adopt PycURL when you need a libcurl capability that higher-level Python HTTP clients do not expose, such as the multi interface, share handles, WebSockets or byte-level socket control. Skip it for ordinary requests, because building a C extension against a system libcurl is a real cost that a pure Python client does not carry. Before you install, confirm you have libcurl 7.19.0 or better and a Python between 3.10 and 3.15, and note that the async support comes from `AsyncCurlMulti` rather than from the ordinary interface, so an asyncio application has to use the right entry point.

Frequently asked questions

What are PycURL's requirements?

Python 3.10 to 3.15 and libcurl 7.19.0 or better. Source and binary distributions are on PyPI, and binary wheels are available for 32 and 64 bit Windows versions. Installation instructions are in INSTALL.rst, with a separate section for installing from a Git checkout.

How do I run the PycURL test suite?

Create a virtual environment, install with `python -m pip install -e . --group dev` and run `python -m pytest tests/`. The --group option needs pip 25.1 or newer, the suite depends on pytest and flask, and the vsftpd tests are skipped unless you set PYCURL_VSFTPD_PATH.

Does PycURL support asyncio?

Yes, through pycurl.AsyncCurlMulti, an asyncio wrapper around CurlMulti driven by libcurl's multi-socket API. PycURL can also be integrated into an application's own I/O loop, for example with Tornado, and supports low-level byte-level socket control with CONNECT_ONLY.

What licence is PycURL under?

Dual licensed under the LGPL and an MIT/X derivative license based on the cURL license, and you can redistribute and modify it under the terms of either. The project metadata records LGPL-2.1-only OR MIT.

Official sources

  1. License: LGPL-2.1
  2. Project website
  3. pycurl/pycurl on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pycurl-pycurl.svg)](https://hysenlabs.com/projects/pycurl-pycurl)

Was this useful?