Skip to content

Commit 44634d2

Browse files
Replace urllib3 with httpx
1 parent 7377408 commit 44634d2

File tree

3 files changed

+38
-44
lines changed

3 files changed

+38
-44
lines changed

gabbi/case.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
The test case encapsulates the request headers and body and expected
1616
response headers and body. When the test is run an HTTP request is
17-
made using urllib3. Assertions are made against the response.
17+
made using httpx. Assertions are made against the response.
1818
"""
1919

2020
from collections import OrderedDict
@@ -500,7 +500,7 @@ def _run_request(
500500
"""
501501

502502
if 'user-agent' not in (key.lower() for key in headers):
503-
headers['user-agent'] = "gabbi/%s (Python urllib3)" % __version__
503+
headers['user-agent'] = "gabbi/%s (Python httpx)" % __version__
504504

505505
try:
506506
response, content = self.http.request(

gabbi/httpclient.py

+35-41
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,53 @@
1111
# License for the specific language governing permissions and limitations
1212
# under the License.
1313

14+
import logging
1415
import os
1516
import sys
1617

17-
import certifi
18-
import urllib3
18+
import httpx
1919

2020
from gabbi.handlers import jsonhandler
2121
from gabbi import utils
2222

23-
# Disable SSL warnings otherwise tests which process stderr will get
24-
# extra information.
25-
urllib3.disable_warnings()
23+
logging.getLogger('httpx').setLevel(logging.WARNING)
2624

2725

28-
class Http(urllib3.PoolManager):
29-
"""A subclass of the ``urllib3.PoolManager`` to munge the data.
26+
class Http:
27+
"""A class to munge the HTTP response.
3028
3129
This transforms the response to look more like what httplib2
3230
provided when it was used as the HTTP client.
3331
"""
3432

33+
def __init__(self, **kwargs):
34+
self.extensions = {}
35+
if 'server_hostname' in kwargs:
36+
self.extensions['sni_hostname'] = kwargs['server_hostname']
37+
self.client = httpx.Client(verify=kwargs.get('cert_validate', True))
38+
3539
def request(self, absolute_uri, method, body, headers, redirect, timeout):
36-
if redirect:
37-
retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5)
38-
else:
39-
retry = urllib3.util.Retry(total=False, redirect=False)
40-
response = super(Http, self).request(
41-
method,
42-
absolute_uri,
43-
body=body,
40+
response = self.client.request(
41+
method=method,
42+
url=absolute_uri,
4443
headers=headers,
45-
retries=retry,
44+
content=body,
4645
timeout=timeout,
46+
follow_redirects=redirect,
47+
extensions=self.extensions,
4748
)
4849

4950
# Transform response into something akin to httplib2
5051
# response object.
51-
content = response.data
52-
status = response.status
53-
reason = response.reason
52+
content = response.content
53+
status = response.status_code
54+
reason = response.reason_phrase
55+
http_version = response.http_version
5456
headers = response.headers
5557
headers['status'] = str(status)
56-
headers['reason'] = reason
58+
headers['reason'] = str(reason)
59+
headers['http_protocol_version'] = str(http_version)
5760

58-
# Shut down open PoolManagers whose connections have completed to
59-
# save on socket file descriptors.
60-
self.clear()
6161
return headers, content
6262

6363

@@ -87,6 +87,7 @@ class VerboseHttp(Http):
8787
HEADER_BLACKLIST = [
8888
'status',
8989
'reason',
90+
'http_protocol_version',
9091
]
9192

9293
REQUEST_PREFIX = '>'
@@ -106,27 +107,26 @@ def __init__(self, **kwargs):
106107
self._stream = kwargs.pop('stream')
107108
if self._use_color:
108109
self.colorize = utils.get_colorizer(self._stream)
109-
super(VerboseHttp, self).__init__(**kwargs)
110+
super().__init__(**kwargs)
110111

111112
def request(self, absolute_uri, method, body, headers, redirect, timeout):
112113
"""Display request parameters before requesting."""
113114

114-
self._verbose_output('#### %s ####' % self.caption,
115+
self._verbose_output(f'#### {self.caption} ####',
115116
color=self.COLORMAP['caption'])
116-
self._verbose_output('%s %s' % (method, absolute_uri),
117+
self._verbose_output(f'{method} {absolute_uri}',
117118
prefix=self.REQUEST_PREFIX,
118119
color=self.COLORMAP['request'])
119120

120121
self._print_headers(headers, prefix=self.REQUEST_PREFIX)
121122
self._print_body(headers, body)
122123

123-
response, content = super(VerboseHttp, self).request(
124+
response, content = super().request(
124125
absolute_uri, method, body, headers, redirect, timeout)
125126

126127
# Blank line for division
127128
self._verbose_output('')
128-
self._verbose_output('%s %s' % (response['status'],
129-
response['reason']),
129+
self._verbose_output(f'{response["status"]} {response["reason"]}',
130130
prefix=self.RESPONSE_PREFIX,
131131
color=self.COLORMAP['status'])
132132
self._print_headers(response, prefix=self.RESPONSE_PREFIX)
@@ -172,8 +172,8 @@ def _print_body(self, headers, content):
172172

173173
def _print_header(self, name, value, prefix='', stream=None):
174174
"""Output one single header."""
175-
header = self.colorize(self.COLORMAP['header'], "%s:" % name)
176-
self._verbose_output("%s %s" % (header, value), prefix=prefix,
175+
header = self.colorize(self.COLORMAP['header'], f'{name}:')
176+
self._verbose_output(f'{header} {value}', prefix=prefix,
177177
stream=stream)
178178

179179
def _verbose_output(self, message, prefix='', color=None, stream=None):
@@ -194,29 +194,23 @@ def get_http(
194194
timeout=30,
195195
):
196196
"""Return an ``Http`` class for making requests."""
197-
cert_validation = {'cert_reqs': 'CERT_NONE'} if not cert_validate else {}
198-
199197
if not verbose:
200198
return Http(
201-
strict=True,
202-
ca_certs=certifi.where(),
203199
server_hostname=hostname,
204200
timeout=timeout,
205-
**cert_validation
201+
cert_validate=cert_validate,
206202
)
207203

208-
headers = False if verbose == 'body' else True
209-
body = False if verbose == 'headers' else True
204+
headers = verbose != 'body'
205+
body = verbose != 'headers'
210206

211207
return VerboseHttp(
212208
headers=headers,
213209
body=body,
214210
stream=sys.stdout,
215211
caption=caption,
216212
colorize=True,
217-
strict=True,
218-
ca_certs=certifi.where(),
219213
server_hostname=hostname,
220214
timeout=timeout,
221-
**cert_validation
215+
cert_validate=cert_validate,
222216
)

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pbr
22
pytest
33
PyYAML
4-
urllib3>=1.26.9,<2.0.0
4+
httpx
55
certifi
66
jsonpath-rw-ext>=1.0.0
77
wsgi-intercept>=1.13.0

0 commit comments

Comments
 (0)