pymcurl 8.18.0.1__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.
- pymcurl-8.18.0.1/LICENSE.txt +21 -0
- pymcurl-8.18.0.1/MANIFEST.in +1 -0
- pymcurl-8.18.0.1/PKG-INFO +249 -0
- pymcurl-8.18.0.1/README.md +218 -0
- pymcurl-8.18.0.1/mcurl/__init__.py +1222 -0
- pymcurl-8.18.0.1/mcurl/cacert.pem +3556 -0
- pymcurl-8.18.0.1/mcurl/gen.py +418 -0
- pymcurl-8.18.0.1/pymcurl.egg-info/PKG-INFO +249 -0
- pymcurl-8.18.0.1/pymcurl.egg-info/SOURCES.txt +18 -0
- pymcurl-8.18.0.1/pymcurl.egg-info/dependency_links.txt +1 -0
- pymcurl-8.18.0.1/pymcurl.egg-info/requires.txt +3 -0
- pymcurl-8.18.0.1/pymcurl.egg-info/top_level.txt +2 -0
- pymcurl-8.18.0.1/pyproject.toml +156 -0
- pymcurl-8.18.0.1/setup.cfg +4 -0
- pymcurl-8.18.0.1/setup.py +40 -0
- pymcurl-8.18.0.1/tests/test_auth.py +73 -0
- pymcurl-8.18.0.1/tests/test_easy.py +246 -0
- pymcurl-8.18.0.1/tests/test_multi.py +250 -0
- pymcurl-8.18.0.1/tests/test_raw.py +79 -0
- pymcurl-8.18.0.1/tests/test_utils.py +181 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Ganesh Viswanathan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include mcurl/cacert.pem
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymcurl
|
|
3
|
+
Version: 8.18.0.1
|
|
4
|
+
Summary: Manage outbound HTTP connections using Curl & CurlMulti
|
|
5
|
+
Author-email: Ganesh Viswanathan <dev@genotrance.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/genotrance/mcurl
|
|
7
|
+
Project-URL: Repository, https://github.com/genotrance/mcurl
|
|
8
|
+
Project-URL: Issues, https://github.com/genotrance/mcurl/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
11
|
+
Classifier: Environment :: MacOS X
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
26
|
+
Requires-Python: >=3.9
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE.txt
|
|
29
|
+
Requires-Dist: cffi; implementation_name == "cpython"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# mcurl
|
|
33
|
+
|
|
34
|
+
[](https://github.com/genotrance/mcurl/actions/workflows/main.yml?query=branch%3Amain)
|
|
35
|
+
[](https://pypi.org/project/pymcurl/)
|
|
36
|
+
[](https://github.com/genotrance/mcurl/blob/main/LICENSE.txt)
|
|
37
|
+
|
|
38
|
+
Python wrapper for [libcurl](https://curl.haxx.se/libcurl/) with a high-level
|
|
39
|
+
API for the easy and multi interfaces. Originally created for the
|
|
40
|
+
[Px](https://github.com/genotrance/px) proxy server.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
mcurl can be installed using pip:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install pymcurl
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Binary [packages](https://pypi.org/project/pymcurl) are provided for the following platforms:
|
|
51
|
+
- aarch64-linux-gnu
|
|
52
|
+
- aarch64-linux-musl
|
|
53
|
+
- arm64-mac
|
|
54
|
+
- i686-linux-gnu
|
|
55
|
+
- x86_64-linux-gnu
|
|
56
|
+
- x86_64-linux-musl
|
|
57
|
+
- x86_64-windows
|
|
58
|
+
|
|
59
|
+
mcurl leverages [cffi](https://pypi.org/project/cffi) to interface with libcurl
|
|
60
|
+
and all binary dependencies are sourced from [binarybuilder.org](https://binarybuilder.org/).
|
|
61
|
+
auditwheel on Linux, delocate on macOS and delvewheel on Windows are used to bundle
|
|
62
|
+
the shared libraries into the wheels.
|
|
63
|
+
|
|
64
|
+
Thanks to [cffi](https://cffi.readthedocs.io/en/latest/cdef.html#ffibuilder-compile-etc-compiling-out-of-line-modules)
|
|
65
|
+
and [Py_LIMITED_API](https://docs.python.org/3/c-api/stable.html#limited-c-api),
|
|
66
|
+
the CPython wheel works on any CPython ≥ 3.9. Separate wheels are provided for
|
|
67
|
+
PyPy.
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
### Easy interface
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import mcurl
|
|
75
|
+
|
|
76
|
+
mcurl.dprint = print
|
|
77
|
+
|
|
78
|
+
c = mcurl.Curl('http://httpbin.org/get')
|
|
79
|
+
c.set_debug()
|
|
80
|
+
c.buffer()
|
|
81
|
+
ret = c.perform()
|
|
82
|
+
if ret == 0:
|
|
83
|
+
ret, resp = c.get_response()
|
|
84
|
+
headers = c.get_headers()
|
|
85
|
+
data = c.get_data()
|
|
86
|
+
print(f"Response: {resp}\n\n{headers}{data}")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Multi interface
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import mcurl
|
|
93
|
+
|
|
94
|
+
mcurl.dprint = print
|
|
95
|
+
|
|
96
|
+
m = mcurl.MCurl()
|
|
97
|
+
|
|
98
|
+
c1 = mcurl.Curl('http://httpbin.org/get')
|
|
99
|
+
c1.set_debug()
|
|
100
|
+
c1.buffer()
|
|
101
|
+
m.add(c1)
|
|
102
|
+
|
|
103
|
+
data = "test8192".encode("utf-8")
|
|
104
|
+
c2 = mcurl.Curl('https://httpbin.org/post', 'POST')
|
|
105
|
+
c2.set_debug()
|
|
106
|
+
c2.buffer(data=data)
|
|
107
|
+
c2.set_headers({"Content-Length": len(data)})
|
|
108
|
+
m.add(c2)
|
|
109
|
+
|
|
110
|
+
ret1 = m.do(c1)
|
|
111
|
+
ret2 = m.do(c2)
|
|
112
|
+
|
|
113
|
+
if ret1:
|
|
114
|
+
print(f"Response: {c1.get_response()}\n\n" +
|
|
115
|
+
f"{c1.get_headers()}{c1.get_data()}")
|
|
116
|
+
else:
|
|
117
|
+
print(f"Failed with error: {c1.errstr}")
|
|
118
|
+
|
|
119
|
+
if ret2:
|
|
120
|
+
print(f"Response: {c2.get_response()}\n\n" +
|
|
121
|
+
f"{c2.get_headers()}{c2.get_data()}")
|
|
122
|
+
else:
|
|
123
|
+
print(f"Failed with error: {c2.errstr}")
|
|
124
|
+
|
|
125
|
+
m.close()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Raw libcurl API
|
|
129
|
+
|
|
130
|
+
The [libcurl C API](https://curl.se/libcurl/c/) can also be accessed directly:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from _libcurl_cffi import lib as libcurl
|
|
134
|
+
from _libcurl_cffi import ffi
|
|
135
|
+
|
|
136
|
+
url = "http://httpbin.org/get"
|
|
137
|
+
curl = ffi.new("char []", url.encode("utf-8"))
|
|
138
|
+
|
|
139
|
+
easy = libcurl.curl_easy_init()
|
|
140
|
+
libcurl.curl_easy_setopt(easy, libcurl.CURLOPT_URL, curl)
|
|
141
|
+
cerr = libcurl.curl_easy_perform(easy)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Threading
|
|
145
|
+
|
|
146
|
+
Each `MCurl` instance manages its own curl multi handle with internal locking for thread-safe concurrent operations. Multiple threads can safely call `add()`, `do()`, `remove()`, and `stop()` on the same `MCurl` instance.
|
|
147
|
+
|
|
148
|
+
**Recommended patterns:**
|
|
149
|
+
|
|
150
|
+
- **MCurl per thread** — create a separate `MCurl` in each thread for maximum parallelism:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
import threading, mcurl
|
|
154
|
+
|
|
155
|
+
def worker(url):
|
|
156
|
+
m = mcurl.MCurl()
|
|
157
|
+
c = mcurl.Curl(url)
|
|
158
|
+
c.buffer()
|
|
159
|
+
m.do(c)
|
|
160
|
+
print(c.get_data())
|
|
161
|
+
m.close()
|
|
162
|
+
|
|
163
|
+
threads = [threading.Thread(target=worker, args=(f"http://httpbin.org/get?id={i}",)) for i in range(4)]
|
|
164
|
+
for t in threads: t.start()
|
|
165
|
+
for t in threads: t.join()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- **Shared MCurl** — multiple threads can share one `MCurl` instance (internally locked):
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
m = mcurl.MCurl()
|
|
172
|
+
|
|
173
|
+
def worker(url):
|
|
174
|
+
c = mcurl.Curl(url)
|
|
175
|
+
c.buffer()
|
|
176
|
+
m.do(c)
|
|
177
|
+
print(c.get_data())
|
|
178
|
+
m.remove(c)
|
|
179
|
+
|
|
180
|
+
threads = [threading.Thread(target=worker, args=(f"http://httpbin.org/get?id={i}",)) for i in range(4)]
|
|
181
|
+
for t in threads: t.start()
|
|
182
|
+
for t in threads: t.join()
|
|
183
|
+
m.close()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Versioning
|
|
187
|
+
|
|
188
|
+
Version format is `X.Y.Z.P` where `X.Y.Z` matches the upstream libcurl version and `P` is the wrapper patch (starts at 1 per upstream release). Wheels are built automatically when a new [LibCURL_jll.jl](https://github.com/genotrance/LibCURL_jll.jl) release is detected.
|
|
189
|
+
|
|
190
|
+
## Documentation
|
|
191
|
+
|
|
192
|
+
See the [`docs/`](docs/) folder for detailed documentation:
|
|
193
|
+
|
|
194
|
+
- [**Build system**](docs/build.md) — `pyproject.toml`, `setup.py`, cffi, cibuildwheel, wheel matrix
|
|
195
|
+
- [**CI & GitHub Actions**](docs/ci.md) — workflows, deployment flow
|
|
196
|
+
- [**API reference**](docs/api.md) — `Curl`, `MCurl`, utility functions
|
|
197
|
+
- [**Changelog**](docs/changelog.md) — release history
|
|
198
|
+
- [**Testing**](docs/testing.md) — test layout, running tests, fixtures
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
Requires a C compiler and [uv](https://docs.astral.sh/uv/).
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
git clone https://github.com/genotrance/mcurl.git
|
|
206
|
+
cd mcurl
|
|
207
|
+
make install
|
|
208
|
+
make test
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
| Target | Description |
|
|
212
|
+
|----------------|----------------------------------------------------|
|
|
213
|
+
| `make install` | Create venv, build C extension, install pre-commit |
|
|
214
|
+
| `make test` | Run tests with coverage |
|
|
215
|
+
| `make check` | Run linters and type checking |
|
|
216
|
+
| `make build` | Build sdist and wheel |
|
|
217
|
+
| `make clean` | Remove build artifacts |
|
|
218
|
+
| `make env` | Print LD_LIBRARY_PATH for local development |
|
|
219
|
+
|
|
220
|
+
## Contributing
|
|
221
|
+
|
|
222
|
+
Bug reports and pull requests are welcome at <https://github.com/genotrance/mcurl/issues>.
|
|
223
|
+
|
|
224
|
+
1. Fork and clone the repository.
|
|
225
|
+
2. Run `make install` to set up the venv, build the C extension, and install pre-commit hooks.
|
|
226
|
+
3. Create a feature branch, make changes, add tests in `tests/`.
|
|
227
|
+
4. Run `make check && make test` — all checks must pass.
|
|
228
|
+
5. Open a pull request. CI runs on Ubuntu, Windows, and macOS across Python 3.9–3.14 and PyPy 3.10/3.11.
|
|
229
|
+
|
|
230
|
+
## Building
|
|
231
|
+
|
|
232
|
+
mcurl is built using gcc on Linux, clang on macOS and mingw-x64 on Windows. The
|
|
233
|
+
shared libraries are downloaded from [binarybuilder.org](https://binarybuilder.org/)
|
|
234
|
+
using [jbb](https://pypi.org/project/jbb) for Linux and Windows. Custom libcurl
|
|
235
|
+
binaries that include `kerberos` support on Linux and remove the `libssh2` dependency
|
|
236
|
+
are [available](https://github.com/genotrance/LibCURL_jll.jl). macOS uses the
|
|
237
|
+
libcurl binaries and dependencies installed via Homebrew.
|
|
238
|
+
|
|
239
|
+
[cibuildwheel](https://cibuildwheel.pypa.io/) is used to build wheels for all
|
|
240
|
+
platforms and architectures via GitHub Actions. See [docs/build.md](docs/build.md)
|
|
241
|
+
for details.
|
|
242
|
+
|
|
243
|
+
## Acknowledgments
|
|
244
|
+
|
|
245
|
+
The modernization of this project — including expanded test suite, CI/CD infrastructure, and comprehensive documentation — was developed with the assistance of LLMs.
|
|
246
|
+
|
|
247
|
+
## License
|
|
248
|
+
|
|
249
|
+
MIT
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# mcurl
|
|
2
|
+
|
|
3
|
+
[](https://github.com/genotrance/mcurl/actions/workflows/main.yml?query=branch%3Amain)
|
|
4
|
+
[](https://pypi.org/project/pymcurl/)
|
|
5
|
+
[](https://github.com/genotrance/mcurl/blob/main/LICENSE.txt)
|
|
6
|
+
|
|
7
|
+
Python wrapper for [libcurl](https://curl.haxx.se/libcurl/) with a high-level
|
|
8
|
+
API for the easy and multi interfaces. Originally created for the
|
|
9
|
+
[Px](https://github.com/genotrance/px) proxy server.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
mcurl can be installed using pip:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install pymcurl
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Binary [packages](https://pypi.org/project/pymcurl) are provided for the following platforms:
|
|
20
|
+
- aarch64-linux-gnu
|
|
21
|
+
- aarch64-linux-musl
|
|
22
|
+
- arm64-mac
|
|
23
|
+
- i686-linux-gnu
|
|
24
|
+
- x86_64-linux-gnu
|
|
25
|
+
- x86_64-linux-musl
|
|
26
|
+
- x86_64-windows
|
|
27
|
+
|
|
28
|
+
mcurl leverages [cffi](https://pypi.org/project/cffi) to interface with libcurl
|
|
29
|
+
and all binary dependencies are sourced from [binarybuilder.org](https://binarybuilder.org/).
|
|
30
|
+
auditwheel on Linux, delocate on macOS and delvewheel on Windows are used to bundle
|
|
31
|
+
the shared libraries into the wheels.
|
|
32
|
+
|
|
33
|
+
Thanks to [cffi](https://cffi.readthedocs.io/en/latest/cdef.html#ffibuilder-compile-etc-compiling-out-of-line-modules)
|
|
34
|
+
and [Py_LIMITED_API](https://docs.python.org/3/c-api/stable.html#limited-c-api),
|
|
35
|
+
the CPython wheel works on any CPython ≥ 3.9. Separate wheels are provided for
|
|
36
|
+
PyPy.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Easy interface
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import mcurl
|
|
44
|
+
|
|
45
|
+
mcurl.dprint = print
|
|
46
|
+
|
|
47
|
+
c = mcurl.Curl('http://httpbin.org/get')
|
|
48
|
+
c.set_debug()
|
|
49
|
+
c.buffer()
|
|
50
|
+
ret = c.perform()
|
|
51
|
+
if ret == 0:
|
|
52
|
+
ret, resp = c.get_response()
|
|
53
|
+
headers = c.get_headers()
|
|
54
|
+
data = c.get_data()
|
|
55
|
+
print(f"Response: {resp}\n\n{headers}{data}")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Multi interface
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import mcurl
|
|
62
|
+
|
|
63
|
+
mcurl.dprint = print
|
|
64
|
+
|
|
65
|
+
m = mcurl.MCurl()
|
|
66
|
+
|
|
67
|
+
c1 = mcurl.Curl('http://httpbin.org/get')
|
|
68
|
+
c1.set_debug()
|
|
69
|
+
c1.buffer()
|
|
70
|
+
m.add(c1)
|
|
71
|
+
|
|
72
|
+
data = "test8192".encode("utf-8")
|
|
73
|
+
c2 = mcurl.Curl('https://httpbin.org/post', 'POST')
|
|
74
|
+
c2.set_debug()
|
|
75
|
+
c2.buffer(data=data)
|
|
76
|
+
c2.set_headers({"Content-Length": len(data)})
|
|
77
|
+
m.add(c2)
|
|
78
|
+
|
|
79
|
+
ret1 = m.do(c1)
|
|
80
|
+
ret2 = m.do(c2)
|
|
81
|
+
|
|
82
|
+
if ret1:
|
|
83
|
+
print(f"Response: {c1.get_response()}\n\n" +
|
|
84
|
+
f"{c1.get_headers()}{c1.get_data()}")
|
|
85
|
+
else:
|
|
86
|
+
print(f"Failed with error: {c1.errstr}")
|
|
87
|
+
|
|
88
|
+
if ret2:
|
|
89
|
+
print(f"Response: {c2.get_response()}\n\n" +
|
|
90
|
+
f"{c2.get_headers()}{c2.get_data()}")
|
|
91
|
+
else:
|
|
92
|
+
print(f"Failed with error: {c2.errstr}")
|
|
93
|
+
|
|
94
|
+
m.close()
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Raw libcurl API
|
|
98
|
+
|
|
99
|
+
The [libcurl C API](https://curl.se/libcurl/c/) can also be accessed directly:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
from _libcurl_cffi import lib as libcurl
|
|
103
|
+
from _libcurl_cffi import ffi
|
|
104
|
+
|
|
105
|
+
url = "http://httpbin.org/get"
|
|
106
|
+
curl = ffi.new("char []", url.encode("utf-8"))
|
|
107
|
+
|
|
108
|
+
easy = libcurl.curl_easy_init()
|
|
109
|
+
libcurl.curl_easy_setopt(easy, libcurl.CURLOPT_URL, curl)
|
|
110
|
+
cerr = libcurl.curl_easy_perform(easy)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Threading
|
|
114
|
+
|
|
115
|
+
Each `MCurl` instance manages its own curl multi handle with internal locking for thread-safe concurrent operations. Multiple threads can safely call `add()`, `do()`, `remove()`, and `stop()` on the same `MCurl` instance.
|
|
116
|
+
|
|
117
|
+
**Recommended patterns:**
|
|
118
|
+
|
|
119
|
+
- **MCurl per thread** — create a separate `MCurl` in each thread for maximum parallelism:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import threading, mcurl
|
|
123
|
+
|
|
124
|
+
def worker(url):
|
|
125
|
+
m = mcurl.MCurl()
|
|
126
|
+
c = mcurl.Curl(url)
|
|
127
|
+
c.buffer()
|
|
128
|
+
m.do(c)
|
|
129
|
+
print(c.get_data())
|
|
130
|
+
m.close()
|
|
131
|
+
|
|
132
|
+
threads = [threading.Thread(target=worker, args=(f"http://httpbin.org/get?id={i}",)) for i in range(4)]
|
|
133
|
+
for t in threads: t.start()
|
|
134
|
+
for t in threads: t.join()
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- **Shared MCurl** — multiple threads can share one `MCurl` instance (internally locked):
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
m = mcurl.MCurl()
|
|
141
|
+
|
|
142
|
+
def worker(url):
|
|
143
|
+
c = mcurl.Curl(url)
|
|
144
|
+
c.buffer()
|
|
145
|
+
m.do(c)
|
|
146
|
+
print(c.get_data())
|
|
147
|
+
m.remove(c)
|
|
148
|
+
|
|
149
|
+
threads = [threading.Thread(target=worker, args=(f"http://httpbin.org/get?id={i}",)) for i in range(4)]
|
|
150
|
+
for t in threads: t.start()
|
|
151
|
+
for t in threads: t.join()
|
|
152
|
+
m.close()
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Versioning
|
|
156
|
+
|
|
157
|
+
Version format is `X.Y.Z.P` where `X.Y.Z` matches the upstream libcurl version and `P` is the wrapper patch (starts at 1 per upstream release). Wheels are built automatically when a new [LibCURL_jll.jl](https://github.com/genotrance/LibCURL_jll.jl) release is detected.
|
|
158
|
+
|
|
159
|
+
## Documentation
|
|
160
|
+
|
|
161
|
+
See the [`docs/`](docs/) folder for detailed documentation:
|
|
162
|
+
|
|
163
|
+
- [**Build system**](docs/build.md) — `pyproject.toml`, `setup.py`, cffi, cibuildwheel, wheel matrix
|
|
164
|
+
- [**CI & GitHub Actions**](docs/ci.md) — workflows, deployment flow
|
|
165
|
+
- [**API reference**](docs/api.md) — `Curl`, `MCurl`, utility functions
|
|
166
|
+
- [**Changelog**](docs/changelog.md) — release history
|
|
167
|
+
- [**Testing**](docs/testing.md) — test layout, running tests, fixtures
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
Requires a C compiler and [uv](https://docs.astral.sh/uv/).
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git clone https://github.com/genotrance/mcurl.git
|
|
175
|
+
cd mcurl
|
|
176
|
+
make install
|
|
177
|
+
make test
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
| Target | Description |
|
|
181
|
+
|----------------|----------------------------------------------------|
|
|
182
|
+
| `make install` | Create venv, build C extension, install pre-commit |
|
|
183
|
+
| `make test` | Run tests with coverage |
|
|
184
|
+
| `make check` | Run linters and type checking |
|
|
185
|
+
| `make build` | Build sdist and wheel |
|
|
186
|
+
| `make clean` | Remove build artifacts |
|
|
187
|
+
| `make env` | Print LD_LIBRARY_PATH for local development |
|
|
188
|
+
|
|
189
|
+
## Contributing
|
|
190
|
+
|
|
191
|
+
Bug reports and pull requests are welcome at <https://github.com/genotrance/mcurl/issues>.
|
|
192
|
+
|
|
193
|
+
1. Fork and clone the repository.
|
|
194
|
+
2. Run `make install` to set up the venv, build the C extension, and install pre-commit hooks.
|
|
195
|
+
3. Create a feature branch, make changes, add tests in `tests/`.
|
|
196
|
+
4. Run `make check && make test` — all checks must pass.
|
|
197
|
+
5. Open a pull request. CI runs on Ubuntu, Windows, and macOS across Python 3.9–3.14 and PyPy 3.10/3.11.
|
|
198
|
+
|
|
199
|
+
## Building
|
|
200
|
+
|
|
201
|
+
mcurl is built using gcc on Linux, clang on macOS and mingw-x64 on Windows. The
|
|
202
|
+
shared libraries are downloaded from [binarybuilder.org](https://binarybuilder.org/)
|
|
203
|
+
using [jbb](https://pypi.org/project/jbb) for Linux and Windows. Custom libcurl
|
|
204
|
+
binaries that include `kerberos` support on Linux and remove the `libssh2` dependency
|
|
205
|
+
are [available](https://github.com/genotrance/LibCURL_jll.jl). macOS uses the
|
|
206
|
+
libcurl binaries and dependencies installed via Homebrew.
|
|
207
|
+
|
|
208
|
+
[cibuildwheel](https://cibuildwheel.pypa.io/) is used to build wheels for all
|
|
209
|
+
platforms and architectures via GitHub Actions. See [docs/build.md](docs/build.md)
|
|
210
|
+
for details.
|
|
211
|
+
|
|
212
|
+
## Acknowledgments
|
|
213
|
+
|
|
214
|
+
The modernization of this project — including expanded test suite, CI/CD infrastructure, and comprehensive documentation — was developed with the assistance of LLMs.
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT
|