geventhttpclient 2.0.11__tar.gz → 2.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.
Files changed (53) hide show
  1. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/MANIFEST.in +3 -4
  2. geventhttpclient-2.1.0/PKG-INFO +238 -0
  3. geventhttpclient-2.0.11/README.mdown → geventhttpclient-2.1.0/README.md +19 -11
  4. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/llhttp/include/llhttp.h +1 -1
  5. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/llhttp/src/llhttp.c +495 -421
  6. geventhttpclient-2.1.0/pyproject.toml +103 -0
  7. geventhttpclient-2.1.0/setup.py +20 -0
  8. geventhttpclient-2.1.0/src/geventhttpclient/__init__.py +7 -0
  9. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/client.py +65 -59
  10. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/connectionpool.py +63 -84
  11. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/header.py +11 -23
  12. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/httplib.py +18 -26
  13. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/response.py +29 -53
  14. geventhttpclient-2.1.0/src/geventhttpclient/tests/conftest.py +3 -0
  15. geventhttpclient-2.1.0/src/geventhttpclient/tests/test_client.py +368 -0
  16. geventhttpclient-2.1.0/src/geventhttpclient/tests/test_headers.py +197 -0
  17. geventhttpclient-2.1.0/src/geventhttpclient/tests/test_http_host.py +14 -0
  18. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_httplib.py +28 -25
  19. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_keep_alive.py +7 -8
  20. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_network_failures.py +60 -43
  21. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_no_module_ssl.py +11 -17
  22. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_parser.py +46 -32
  23. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/test_ssl.py +68 -78
  24. geventhttpclient-2.1.0/src/geventhttpclient/tests/test_url.py +141 -0
  25. geventhttpclient-2.1.0/src/geventhttpclient/tests/test_useragent.py +249 -0
  26. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/url.py +72 -61
  27. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/useragent.py +158 -176
  28. geventhttpclient-2.1.0/src/geventhttpclient.egg-info/PKG-INFO +238 -0
  29. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient.egg-info/SOURCES.txt +3 -2
  30. geventhttpclient-2.1.0/src/geventhttpclient.egg-info/requires.txt +15 -0
  31. geventhttpclient-2.0.11/PKG-INFO +0 -32
  32. geventhttpclient-2.0.11/pytest.ini +0 -3
  33. geventhttpclient-2.0.11/setup.py +0 -68
  34. geventhttpclient-2.0.11/src/geventhttpclient/__init__.py +0 -6
  35. geventhttpclient-2.0.11/src/geventhttpclient/tests/test_client.py +0 -350
  36. geventhttpclient-2.0.11/src/geventhttpclient/tests/test_headers.py +0 -191
  37. geventhttpclient-2.0.11/src/geventhttpclient/tests/test_http_host.py +0 -30
  38. geventhttpclient-2.0.11/src/geventhttpclient/tests/test_url.py +0 -131
  39. geventhttpclient-2.0.11/src/geventhttpclient/tests/test_useragent.py +0 -205
  40. geventhttpclient-2.0.11/src/geventhttpclient.egg-info/PKG-INFO +0 -32
  41. geventhttpclient-2.0.11/src/geventhttpclient.egg-info/requires.txt +0 -4
  42. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/LICENSE.txt +0 -0
  43. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/ext/Python_compat.h +0 -0
  44. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/ext/_parser.c +0 -0
  45. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/llhttp/LICENSE-MIT +0 -0
  46. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/llhttp/src/api.c +0 -0
  47. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/llhttp/src/http.c +0 -0
  48. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/setup.cfg +0 -0
  49. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/oncert.pem +0 -0
  50. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/server.crt +0 -0
  51. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient/tests/server.key +0 -0
  52. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient.egg-info/dependency_links.txt +0 -0
  53. {geventhttpclient-2.0.11 → geventhttpclient-2.1.0}/src/geventhttpclient.egg-info/top_level.txt +0 -0
@@ -5,7 +5,6 @@ recursive-include llhttp *.h *.c LICENSE-MIT
5
5
  recursive-include src/geventhttpclient/tests *
6
6
  global-exclude __pycache__
7
7
  global-exclude *.py[co]
8
- include LICENSE-MIT
9
- include README.mdown
10
- include CHANGELOG
11
- include pytest.ini
8
+ include pyproject.toml
9
+ include LICENSE.txt
10
+ include README.md
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.1
2
+ Name: geventhttpclient
3
+ Version: 2.1.0
4
+ Summary: HTTP client library for gevent
5
+ Author-email: Antonin Amand <antonin.amand@gmail.com>
6
+ License: Based on llhttp, copyright Fedor Indutny, 2018.
7
+
8
+ Python extension is copyright Antonin Amand <antonin.amand@gmail.com>,
9
+ licensed under the same terms.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to
13
+ deal in the Software without restriction, including without limitation the
14
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15
+ sell copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in
19
+ all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27
+ IN THE SOFTWARE.
28
+
29
+ Note: Previous versions of gevenhttpclient used http_parser.c, which in turn
30
+ was based on src/http/ngx_http_parse.c from NGINX, copyright Igor Sysoev,
31
+ Joyent, Inc. and other Node contributors. See http://github.com/joyent/http-parser
32
+ for more information
33
+
34
+ Project-URL: homepage, http://github.com/geventhttpclient/geventhttpclient
35
+ Project-URL: issues, http://github.com/geventhttpclient/geventhttpclient/issues
36
+ Project-URL: download, https://pypi.org/project/geventhttpclient/#files
37
+ Keywords: http,gevent,client
38
+ Classifier: Development Status :: 5 - Production/Stable
39
+ Classifier: Intended Audience :: Developers
40
+ Classifier: Intended Audience :: Information Technology
41
+ Classifier: Operating System :: OS Independent
42
+ Classifier: Programming Language :: Python :: 3
43
+ Classifier: Programming Language :: Python :: 3.9
44
+ Classifier: Programming Language :: Python :: 3.10
45
+ Classifier: Programming Language :: Python :: 3.11
46
+ Classifier: Programming Language :: Python :: 3.12
47
+ Classifier: Programming Language :: Python :: 3 :: Only
48
+ Classifier: Topic :: Software Development :: Libraries
49
+ Requires-Python: >=3.9
50
+ Description-Content-Type: text/markdown
51
+ License-File: LICENSE.txt
52
+ Requires-Dist: gevent
53
+ Requires-Dist: certifi
54
+ Requires-Dist: brotli
55
+ Requires-Dist: urllib3
56
+ Provides-Extra: dev
57
+ Requires-Dist: pytest; extra == "dev"
58
+ Requires-Dist: dpkt; extra == "dev"
59
+ Requires-Dist: requests; extra == "dev"
60
+ Provides-Extra: benchmarks
61
+ Requires-Dist: requests; extra == "benchmarks"
62
+ Requires-Dist: httpx; extra == "benchmarks"
63
+ Requires-Dist: urllib3; extra == "benchmarks"
64
+ Requires-Dist: httplib2; extra == "benchmarks"
65
+
66
+ [![GitHub Workflow CI Status](https://img.shields.io/github/actions/workflow/status/geventhttpclient/geventhttpclient/test.yml?branch=master&logo=github&style=flat)](https://github.com/geventhttpclient/geventhttpclient/actions)
67
+ [![PyPI](https://img.shields.io/pypi/v/geventhttpclient.svg?style=flat)](https://pypi.org/project/geventhttpclient/)
68
+ ![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fgeventhttpclient%2Fgeventhttpclient%2Fmaster%2Fpyproject.toml)
69
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/geventhttpclient)
70
+
71
+ # geventhttpclient
72
+
73
+ A high performance, concurrent HTTP client library for python using
74
+ [gevent](http://gevent.org).
75
+
76
+ `gevent.httplib` support was removed in [gevent 1.0](https://github.com/surfly/gevent/commit/b45b83b1bc4de14e3c4859362825044b8e3df7d6
77
+ ), **geventhttpclient** now provides that missing functionality.
78
+
79
+ **geventhttpclient** uses a fast [http parser](https://github.com/nodejs/llhttp),
80
+ written in C.
81
+
82
+ **geventhttpclient** has been specifically designed for high concurrency,
83
+ streaming and support HTTP 1.1 persistent connections. More generally it is
84
+ designed for efficiently pulling from REST APIs and streaming APIs
85
+ like Twitter's.
86
+
87
+ Safe SSL support is provided by default. **geventhttpclient** depends on
88
+ the certifi CA Bundle. This is the same CA Bundle which ships with the
89
+ Requests codebase, and is derived from Mozilla Firefox's canonical set.
90
+
91
+ As of version 2.1, only Python 3.9+ is fully supported (with prebuilt wheels).
92
+
93
+ A simple example:
94
+
95
+ ```python
96
+ #!/usr/bin/python
97
+
98
+ from geventhttpclient import HTTPClient
99
+ from geventhttpclient.url import URL
100
+
101
+ url = URL('http://gevent.org/')
102
+
103
+ http = HTTPClient(url.host)
104
+
105
+ # issue a get request
106
+ response = http.get(url.request_uri)
107
+
108
+ # read status_code
109
+ response.status_code
110
+
111
+ # read response body
112
+ body = response.read()
113
+
114
+ # close connections
115
+ http.close()
116
+ ```
117
+
118
+ ## httplib compatibility and monkey patch
119
+
120
+ **geventhttpclient.httplib** module contains classes for drop in
121
+ replacement of httplib connection and response objects.
122
+ If you use httplib directly you can replace the **httplib** imports
123
+ by **geventhttpclient.httplib**.
124
+
125
+ ```python
126
+ # from httplib import HTTPConnection
127
+ from geventhttpclient.httplib import HTTPConnection
128
+ ```
129
+
130
+ If you use **httplib2**, **urllib** or **urllib2**; you can patch **httplib** to
131
+ use the wrappers from **geventhttpclient**.
132
+ For **httplib2**, make sure you patch before you import or the *super*
133
+ calls will fail.
134
+
135
+ ```python
136
+ import geventhttpclient.httplib
137
+ geventhttpclient.httplib.patch()
138
+
139
+ import httplib2
140
+ ```
141
+
142
+ ## High Concurrency
143
+
144
+ HTTPClient has connection pool built in and is greenlet safe by design.
145
+ You can use the same instance among several greenlets.
146
+
147
+ ```python
148
+ #!/usr/bin/env python
149
+
150
+ import gevent.pool
151
+ import json
152
+
153
+ from geventhttpclient import HTTPClient
154
+ from geventhttpclient.url import URL
155
+
156
+
157
+ # go to http://developers.facebook.com/tools/explorer and copy the access token
158
+ TOKEN = '<go to http://developers.facebook.com/tools/explorer and copy the access token>'
159
+
160
+ url = URL('https://graph.facebook.com/me/friends')
161
+ url['access_token'] = TOKEN
162
+
163
+ # setting the concurrency to 10 allow to create 10 connections and
164
+ # reuse them.
165
+ http = HTTPClient.from_url(url, concurrency=10)
166
+
167
+ response = http.get(url.request_uri)
168
+ assert response.status_code == 200
169
+
170
+ # response comply to the read protocol. It passes the stream to
171
+ # the json parser as it's being read.
172
+ data = json.load(response)['data']
173
+
174
+ def print_friend_username(http, friend_id):
175
+ friend_url = URL('/' + str(friend_id))
176
+ friend_url['access_token'] = TOKEN
177
+ # the greenlet will block until a connection is available
178
+ response = http.get(friend_url.request_uri)
179
+ assert response.status_code == 200
180
+ friend = json.load(response)
181
+ if 'username' in friend:
182
+ print('%s: %s' % (friend['username'], friend['name']))
183
+ else:
184
+ print('%s has no username.' % friend['name'])
185
+
186
+ # allow to run 20 greenlet at a time, this is more than concurrency
187
+ # of the http client but isn't a problem since the client has its own
188
+ # connection pool.
189
+ pool = gevent.pool.Pool(20)
190
+ for item in data:
191
+ friend_id = item['id']
192
+ pool.spawn(print_friend_username, http, friend_id)
193
+
194
+ pool.join()
195
+ http.close()
196
+ ```
197
+
198
+ ## Streaming
199
+
200
+ **geventhttpclient** supports streaming.
201
+ Response objects have a read(N) and readline() method that read the stream
202
+ incrementally.
203
+ See *src/examples/twitter_streaming.py* for pulling twitter stream API.
204
+
205
+ Here is an example on how to download a big file chunk by chunk to save memory:
206
+
207
+ ```python
208
+ #!/usr/bin/env python
209
+
210
+ from geventhttpclient import HTTPClient, URL
211
+
212
+ url = URL('http://127.0.0.1:80/100.dat')
213
+ http = HTTPClient.from_url(url)
214
+ response = http.get(url.query_string)
215
+ assert response.status_code == 200
216
+
217
+ CHUNK_SIZE = 1024 * 16 # 16KB
218
+ with open('/tmp/100.dat', 'w') as f:
219
+ data = response.read(CHUNK_SIZE)
220
+ while data:
221
+ f.write(data)
222
+ data = response.read(CHUNK_SIZE)
223
+ ```
224
+
225
+ ## Benchmarks
226
+
227
+ The benchmark does 10000 get requests against a local nginx server in the default
228
+ configuration with a concurrency of 10. See `benchmarks` folder. The requests per
229
+ second for a couple of popular clients is given in the table below.
230
+
231
+ | HTTP Client | RPS |
232
+ |----------------------|--------|
233
+ | GeventHTTPClient | 7181.2 |
234
+ | Urllib3 | 2847.5 |
235
+ | Httpx | 1682.9 |
236
+ | Requests | 1186.4 |
237
+
238
+ *Linux(x86_64), Python 3.11.6 @ Intel i7-7560U*
@@ -1,3 +1,8 @@
1
+ [![GitHub Workflow CI Status](https://img.shields.io/github/actions/workflow/status/geventhttpclient/geventhttpclient/test.yml?branch=master&logo=github&style=flat)](https://github.com/geventhttpclient/geventhttpclient/actions)
2
+ [![PyPI](https://img.shields.io/pypi/v/geventhttpclient.svg?style=flat)](https://pypi.org/project/geventhttpclient/)
3
+ ![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fgeventhttpclient%2Fgeventhttpclient%2Fmaster%2Fpyproject.toml)
4
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/geventhttpclient)
5
+
1
6
  # geventhttpclient
2
7
 
3
8
  A high performance, concurrent HTTP client library for python using
@@ -18,10 +23,7 @@ Safe SSL support is provided by default. **geventhttpclient** depends on
18
23
  the certifi CA Bundle. This is the same CA Bundle which ships with the
19
24
  Requests codebase, and is derived from Mozilla Firefox's canonical set.
20
25
 
21
- As of version 1.5, only Python 3.6+ is fully supported (with prebuilt wheels),
22
- but Python 2.7 and 3.5 *should* work too.
23
-
24
- Use of SSL/TLS with python 2.7.9 is not recommended and may be broken.
26
+ As of version 2.1, only Python 3.9+ is fully supported (with prebuilt wheels).
25
27
 
26
28
  A simple example:
27
29
 
@@ -111,10 +113,10 @@ def print_friend_username(http, friend_id):
111
113
  response = http.get(friend_url.request_uri)
112
114
  assert response.status_code == 200
113
115
  friend = json.load(response)
114
- if friend.has_key('username'):
115
- print '%s: %s' % (friend['username'], friend['name'])
116
+ if 'username' in friend:
117
+ print('%s: %s' % (friend['username'], friend['name']))
116
118
  else:
117
- print '%s has no username.' % friend['name']
119
+ print('%s has no username.' % friend['name'])
118
120
 
119
121
  # allow to run 20 greenlet at a time, this is more than concurrency
120
122
  # of the http client but isn't a problem since the client has its own
@@ -157,9 +159,15 @@ with open('/tmp/100.dat', 'w') as f:
157
159
 
158
160
  ## Benchmarks
159
161
 
160
- The benchmark does 1000 get requests against a local nginx server with
161
- a concurrency of 10. See *benchmarks* folder.
162
+ The benchmark does 10000 get requests against a local nginx server in the default
163
+ configuration with a concurrency of 10. See `benchmarks` folder. The requests per
164
+ second for a couple of popular clients is given in the table below.
162
165
 
163
- - httplib2 with geventhttpclient monkey patch (*benchmarks/httplib2_patched.py*): **~2500 req/s**
164
- - geventhttpclient.HTTPClient (*benchmarks/httpclient.py*): **~4000 req/s**
166
+ | HTTP Client | RPS |
167
+ |----------------------|--------|
168
+ | GeventHTTPClient | 7181.2 |
169
+ | Urllib3 | 2847.5 |
170
+ | Httpx | 1682.9 |
171
+ | Requests | 1186.4 |
165
172
 
173
+ *Linux(x86_64), Python 3.11.6 @ Intel i7-7560U*
@@ -3,7 +3,7 @@
3
3
 
4
4
  #define LLHTTP_VERSION_MAJOR 6
5
5
  #define LLHTTP_VERSION_MINOR 0
6
- #define LLHTTP_VERSION_PATCH 10
6
+ #define LLHTTP_VERSION_PATCH 11
7
7
 
8
8
  #ifndef LLHTTP_STRICT_MODE
9
9
  # define LLHTTP_STRICT_MODE 0