Skip to content

Commit 2e960bf

Browse files
Replace httplib with requests
Not that is really matters, but I also fixed the Phabricator URL in the tests (the url has to have a / at the end and typically the path is also /api/). Fixed setup.py so that it is possible to install the test requires.
1 parent cecdbe3 commit 2e960bf

5 files changed

Lines changed: 55 additions & 90 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: python
22
python:
33
- '2.7'
44
- '3.5'
5-
install: pip install .
5+
install: pip install .[tests]
66
script: python -m phabricator.tests.test_phabricator
77
deploy:
88
provider: pypi

phabricator/__init__.py

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
import socket
2424
import pkgutil
2525
import time
26+
import requests
2627

2728
from ._compat import (
28-
MutableMapping, iteritems, string_types, httplib, urlparse, urlencode,
29+
MutableMapping, iteritems, string_types, urlencode,
2930
)
3031

3132

@@ -290,43 +291,28 @@ def validate_kwarg(key, target):
290291
self.api.connect()
291292
kwargs['__conduit__'] = self.api._conduit
292293

293-
url = urlparse.urlparse(self.api.host)
294-
if url.scheme == 'https':
295-
conn = httplib.HTTPSConnection(url.netloc, timeout=self.api.timeout)
296-
else:
297-
conn = httplib.HTTPConnection(url.netloc, timeout=self.api.timeout)
298-
299-
path = url.path + '%s.%s' % (self.method, self.endpoint)
300294

301295
headers = {
302296
'User-Agent': 'python-phabricator/%s' % str(self.api.clientVersion),
303297
'Content-Type': 'application/x-www-form-urlencoded'
304298
}
305299

306-
body = urlencode({
300+
body = {
307301
"params": json.dumps(kwargs),
308302
"output": self.api.response_format
309-
})
303+
}
310304

311305
# TODO: Use HTTP "method" from interfaces.json
312-
conn.request('POST', path, body, headers)
313-
response = conn.getresponse()
306+
path = '%s%s.%s' % (self.api.host, self.method, self.endpoint)
307+
response = requests.post(path, data=body, headers=headers, timeout=self.api.timeout)
314308

315309
# Make sure we got a 2xx response indicating success
316-
if not response.status >= 200 or not response.status < 300:
317-
conn.close()
318-
raise httplib.HTTPException(
319-
'Bad response status: {0}'.format(response.status)
310+
if not response.status_code >= 200 or not response.status_code < 300:
311+
raise requests.exceptions.HTTPError(
312+
'Bad response status: {0}'.format(response.status_code)
320313
)
321314

322-
response_data = response.read()
323-
conn.close()
324-
if isinstance(response_data, str):
325-
response = response_data
326-
else:
327-
response = response_data.decode("utf-8")
328-
329-
data = self._parse_response(response)
315+
data = self._parse_response(response.text)
330316

331317
return Result(data['result'])
332318

phabricator/_compat.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,6 @@
77
except ImportError:
88
from collections import MutableMapping
99

10-
try:
11-
import httplib
12-
except ImportError:
13-
import http.client as httplib
14-
15-
try:
16-
import urlparse
17-
except ImportError:
18-
import urllib.parse as urlparse
19-
2010
try:
2111
from urllib import urlencode
2212
except ImportError:

phabricator/tests/test_phabricator.py

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@
33
except ImportError:
44
import unittest
55

6-
try:
7-
from StringIO import StringIO
8-
except ImportError:
9-
from io import StringIO
10-
11-
try:
12-
import unittest.mock as mock
13-
except ImportError:
14-
import mock
6+
import requests
7+
import responses
158

169
from pkg_resources import resource_string
1710
import json
1811

1912
import phabricator
13+
phabricator.ARCRC = {} # overwrite any arcrc that might be read
2014

2115

2216
RESPONSES = json.loads(
@@ -40,7 +34,7 @@ def setUp(self):
4034
self.api = phabricator.Phabricator(
4135
username='test',
4236
certificate='test',
43-
host='http://localhost'
37+
host='http://localhost/api/'
4438
)
4539
self.api.certificate = CERTIFICATE
4640

@@ -49,37 +43,32 @@ def test_generate_hash(self):
4943
hashed = self.api.generate_hash(token)
5044
self.assertEqual(hashed, 'f8d3bea4e58a2b2967d93d5b307bfa7c693b2e7f')
5145

52-
@mock.patch('phabricator.httplib.HTTPConnection')
53-
def test_connect(self, mock_connection):
54-
mock_obj = mock_connection.return_value = mock.Mock()
55-
mock_obj.getresponse.return_value = StringIO(
56-
RESPONSES['conduit.connect']
57-
)
58-
mock_obj.getresponse.return_value.status = 200
59-
mock_obj.close = mock.Mock()
46+
@responses.activate
47+
def test_connect(self):
48+
responses.add('POST', 'http://localhost/api/conduit.connect',
49+
body=RESPONSES['conduit.connect'], status=200)
6050

6151
api = phabricator.Phabricator(
6252
username='test',
6353
certificate='test',
64-
host='http://localhost'
54+
host='http://localhost/api/'
6555
)
6656

6757
api.connect()
6858
keys = api._conduit.keys()
6959
self.assertIn('sessionKey', keys)
7060
self.assertIn('connectionID', keys)
71-
mock_obj.close.assert_called_once_with()
61+
assert len(responses.calls) == 1
7262

73-
@mock.patch('phabricator.httplib.HTTPConnection')
74-
def test_user_whoami(self, mock_connection):
75-
mock_obj = mock_connection.return_value = mock.Mock()
76-
mock_obj.getresponse.return_value = StringIO(RESPONSES['user.whoami'])
77-
mock_obj.getresponse.return_value.status = 200
63+
@responses.activate
64+
def test_user_whoami(self):
65+
responses.add('POST', 'http://localhost/api/user.whoami',
66+
body=RESPONSES['user.whoami'], status=200)
7867

7968
api = phabricator.Phabricator(
8069
username='test',
8170
certificate='test',
82-
host='http://localhost'
71+
host='http://localhost/api/'
8372
)
8473
api._conduit = True
8574

@@ -89,7 +78,7 @@ def test_classic_resources(self):
8978
api = phabricator.Phabricator(
9079
username='test',
9180
certificate='test',
92-
host='http://localhost'
81+
host='http://localhost/api/'
9382
)
9483

9584
self.assertEqual(api.user.whoami.method, 'user')
@@ -99,42 +88,37 @@ def test_nested_resources(self):
9988
api = phabricator.Phabricator(
10089
username='test',
10190
certificate='test',
102-
host='http://localhost'
91+
host='http://localhost/api/'
10392
)
10493

10594
self.assertEqual(api.diffusion.repository.edit.method, 'diffusion')
106-
self.assertEqual(api.diffusion.repository.edit.endpoint, 'repository.edit')
95+
self.assertEqual(
96+
api.diffusion.repository.edit.endpoint, 'repository.edit')
10797

108-
@mock.patch('phabricator.httplib.HTTPConnection')
109-
def test_bad_status(self, mock_connection):
110-
mock_obj = mock_connection.return_value = mock.Mock()
111-
mock_obj.getresponse.return_value = mock.Mock()
112-
mock_obj.getresponse.return_value.status = 400
113-
mock_obj.close = mock.Mock()
98+
@responses.activate
99+
def test_bad_status(self):
100+
responses.add(
101+
'POST', 'http://localhost/api/conduit.connect', status=400)
114102

115103
api = phabricator.Phabricator(
116-
username='test',
117-
certificate='test',
118-
host='http://localhost'
104+
username='test',
105+
certificate='test',
106+
host='http://localhost/api/'
119107
)
120-
api._conduit = True
121108

122-
with self.assertRaises(phabricator.httplib.HTTPException):
109+
with self.assertRaises(requests.exceptions.HTTPError):
123110
api.user.whoami()
124-
mock_obj.close.assert_called_once_with()
111+
assert len(responses.calls) == 1
125112

126-
@mock.patch('phabricator.httplib.HTTPConnection')
127-
def test_maniphest_find(self, mock_connection):
128-
mock_obj = mock_connection.return_value = mock.Mock()
129-
mock_obj.getresponse.return_value = StringIO(
130-
RESPONSES['maniphest.find']
131-
)
132-
mock_obj.getresponse.return_value.status = 200
113+
@responses.activate
114+
def test_maniphest_find(self):
115+
responses.add('POST', 'http://localhost/api/maniphest.find',
116+
body=RESPONSES['maniphest.find'], status=200)
133117

134118
api = phabricator.Phabricator(
135119
username='test',
136120
certificate='test',
137-
host='http://localhost'
121+
host='http://localhost/api/'
138122
)
139123
api._conduit = True
140124

@@ -165,16 +149,18 @@ def test_validation(self):
165149

166150
def test_map_param_type(self):
167151
uint = 'uint'
168-
self.assertEqual(phabricator.map_param_type(uint), int)
152+
self.assertEqual(phabricator.map_param_type(uint), int)
169153

170154
list_bool = 'list<bool>'
171-
self.assertEqual(phabricator.map_param_type(list_bool), [bool])
155+
self.assertEqual(phabricator.map_param_type(list_bool), [bool])
172156

173157
list_pair = 'list<pair<callsign, path>>'
174-
self.assertEqual(phabricator.map_param_type(list_pair), [tuple])
158+
self.assertEqual(phabricator.map_param_type(list_pair), [tuple])
175159

176160
complex_list_pair = 'list<pair<string-constant<"gtcm">, string>>'
177-
self.assertEqual(phabricator.map_param_type(complex_list_pair), [tuple])
161+
self.assertEqual(phabricator.map_param_type(
162+
complex_list_pair), [tuple])
163+
178164

179165
def test_endpoint_shadowing(self):
180166
shadowed_endpoints = [e for e in self.api.interface.keys() if e in self.api.__dict__]

setup.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from setuptools import setup, find_packages
66

7-
tests_requires = []
7+
tests_requires = ['responses>=0.12']
88

99
if sys.version_info[:2] < (2, 7):
1010
tests_requires.append('unittest2')
@@ -21,8 +21,11 @@
2121
description='Phabricator API Bindings',
2222
packages=find_packages(),
2323
zip_safe=False,
24+
install_requires=['requests>=2.22'],
2425
test_suite='phabricator.tests.test_phabricator',
25-
tests_require=tests_requires,
26+
extras_require={
27+
'tests': tests_requires,
28+
},
2629
include_package_data=True,
2730
classifiers=[
2831
'Intended Audience :: Developers',

0 commit comments

Comments
 (0)