Commit 4fbb870e authored by Abhilash Raj's avatar Abhilash Raj

Merge branch 'requests' into 'master'

Migrate to use requests instead of httplib2.

See merge request !92
parents 3eea9277 70f5dfde
Pipeline #50013786 failed with stage
in 4 minutes and 39 seconds
......@@ -50,11 +50,10 @@ setup(
'Topic :: Internet :: WWW/HTTP ',
],
install_requires=[
'httplib2',
'requests',
],
extras_require={
'testing': [
'requests',
'pytest',
'pytest-vcr',
'pytest-services',
......@@ -62,6 +61,6 @@ setup(
],
'lint': [
'flake8>3.0'
]
]
},
)
......@@ -274,7 +274,7 @@ class Client:
if alias_domain is not None:
data['alias_domain'] = alias_domain
response, content = self._connection.call('domains', data)
return Domain(self._connection, response['location'])
return Domain(self._connection, response.headers.get('location'))
def delete_domain(self, mail_host):
"""Delete a Domain.
......@@ -308,7 +308,7 @@ class Client:
'users', dict(email=email,
password=password,
display_name=display_name))
return User(self._connection, response['location'])
return User(self._connection, response.headers.get('location'))
def get_user(self, address):
"""Given an Email Address, return the User it belongs to.
......
......@@ -951,13 +951,13 @@ A held message can be retrieved by ID, and have attributes:
A moderation action can be taken on them using the list methods or the held
message's methods.
>>> print(test_one.defer_message(heldmsg.request_id)['status'])
>>> print(test_one.defer_message(heldmsg.request_id).status_code)
204
>>> len(test_one.held)
1
>>> print(heldmsg.discard()['status'])
>>> print(heldmsg.discard().status_code)
204
>>> len(test_one.held)
......
......@@ -13,12 +13,11 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with mailmanclient. If not, see <http://www.gnu.org/licenses/>.
import json
from base64 import b64encode
from urllib.error import HTTPError
from urllib.parse import urljoin, urlencode
from httplib2 import Http
from requests import request
from mailmanclient.constants import __version__
......@@ -55,10 +54,9 @@ class Connection:
if name is None and password is not None:
raise TypeError('`name` is required when `password` is given')
if name is None:
self.basic_auth = None
self.auth = None
else:
auth = '{0}:{1}'.format(name, password)
self.basic_auth = b64encode(auth.encode('utf-8')).decode('utf-8')
self.auth = (name, password)
def call(self, path, data=None, method=None):
"""Make a call to the Mailman REST API.
......@@ -88,21 +86,23 @@ class Connection:
else:
method = 'POST'
method = method.upper()
if self.basic_auth:
headers['Authorization'] = 'Basic ' + self.basic_auth
url = urljoin(self.baseurl, path)
try:
response, content = Http().request(url, method, data_str, headers)
response = request(
url=url,
auth=self.auth,
method=method,
data=data_str,
headers=headers)
# content = response.content
# If we did not get a 2xx status code, make this look like a
# urllib2 exception, for backward compatibility.
if response.status // 100 != 2:
raise HTTPError(url, response.status, content, response, None)
if len(content) == 0:
if response.status_code // 100 != 2:
raise HTTPError(url, response.status_code,
response.content, response, None)
if len(response.content) == 0:
return response, None
# XXX Work around for http://bugs.python.org/issue10038
if isinstance(content, bytes):
content = content.decode('utf-8')
return response, json.loads(content)
return response, response.json()
except HTTPError:
raise
except IOError:
......
......@@ -69,7 +69,8 @@ class Bans(RESTList):
def add(self, email):
response, content = self._connection.call(self._url, dict(email=email))
self._reset_cache()
return BannedAddress(self._connection, response['location'])
return BannedAddress(
self._connection, response.headers.get('location'))
def find_by_email(self, email):
for ban in self:
......
......@@ -89,7 +89,7 @@ class Domain(RESTObject):
if style_name is not None:
data['style_name'] = style_name
response, content = self._connection.call('lists', data)
return MailingList(self._connection, response['location'])
return MailingList(self._connection, response.headers.get('location'))
# TODO: Add this when the API supports removing a single owner.
# def remove_owner(self, owner):
......
......@@ -58,7 +58,7 @@ class HeaderMatches(RESTList):
data['action'] = action
response, content = self._connection.call(self._url, data)
self._reset_cache()
return HeaderMatch(self._connection, response['location'])
return HeaderMatch(self._connection, response.headers.get('location'))
class HeaderMatch(RESTObject):
......
......@@ -302,11 +302,11 @@ class MailingList(RESTObject):
response, content = self._connection.call('members', data)
# If a member is not immediately subscribed (i.e. verificatoin,
# confirmation or approval need), the response content is returned.
if response.status == 202:
if response.status_code == 202:
return content
# I the subscription is executed immediately, a member object
# is returned.
return Member(self._connection, response['location'])
return Member(self._connection, response.headers.get('location'))
def unsubscribe(self, email):
"""Unsubscribe an email address from a mailing list.
......
......@@ -99,6 +99,6 @@ class User(RESTObject, PreferencesMixin):
response, content = self._connection.call(url, data)
address = {
'email': email,
'self_link': response['location'],
'self_link': response.headers.get('location'),
}
return Address(self._connection, address['self_link'], address)
......@@ -3,7 +3,7 @@ envlist = py{35,36,37},lint
[testenv]
usedevelop = True
commands = pytest --vcr-record=all
commands = pytest --vcr-record=all {posargs}
extras = testing
[testenv:record]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment