Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ Swapnil Khanapurkar <swapnil_khanapurkar@persistent.co.in>
The SoftLayer Developer Network <sldn@softlayer.com>
Tim Ariyeh <tim.ariyeh@gmail.com>
Wissam Elriachy <wissam.elriachy@gmail.com>
Anthony Monthe (ZuluPro) <anthony.monthe@gmail.com>
61 changes: 42 additions & 19 deletions SoftLayer/transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import time

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

from SoftLayer import consts
from SoftLayer import exceptions
Expand Down Expand Up @@ -38,6 +40,18 @@
}


def get_session(user_agent):
client = requests.Session()
client.headers.update({
'Content-Type': 'application/json',
'User-Agent': user_agent,
})
retry = Retry(connect=3, backoff_factor=3)
adapter = HTTPAdapter(max_retries=retry)
client.mount('https://', adapter)
return client


class Request(object):
"""Transport request object."""

Expand Down Expand Up @@ -108,6 +122,12 @@ def __init__(self, endpoint_url=None, timeout=None, proxy=None, user_agent=None,
self.user_agent = user_agent or consts.USER_AGENT
self.verify = verify

@property
def client(self):
if not hasattr(self, '_client'):
self._client = get_session(self.user_agent)
return self._client

def __call__(self, request):
"""Makes a SoftLayer API call against the XML-RPC endpoint.

Expand Down Expand Up @@ -154,13 +174,13 @@ def __call__(self, request):
LOGGER.debug(payload)

try:
resp = requests.request('POST', url,
data=payload,
headers=request.transport_headers,
timeout=self.timeout,
verify=verify,
cert=request.cert,
proxies=_proxies_dict(self.proxy))
resp = self.client.request('POST', url,
data=payload,
headers=request.transport_headers,
timeout=self.timeout,
verify=verify,
cert=request.cert,
proxies=_proxies_dict(self.proxy))
LOGGER.debug("=== RESPONSE ===")
LOGGER.debug(resp.headers)
LOGGER.debug(resp.content)
Expand Down Expand Up @@ -209,6 +229,12 @@ def __init__(self, endpoint_url=None, timeout=None, proxy=None, user_agent=None,
self.user_agent = user_agent or consts.USER_AGENT
self.verify = verify

@property
def client(self):
if not hasattr(self, '_client'):
self._client = get_session(self.user_agent)
return self._client

def __call__(self, request):
"""Makes a SoftLayer API call against the REST endpoint.

Expand All @@ -217,9 +243,6 @@ def __call__(self, request):

:param request request: Request object
"""
request.transport_headers.setdefault('Content-Type', 'application/json')
request.transport_headers.setdefault('User-Agent', self.user_agent)

params = request.headers.copy()
if request.mask:
params['objectMask'] = _format_object_mask(request.mask)
Expand Down Expand Up @@ -275,15 +298,15 @@ def __call__(self, request):
LOGGER.debug(request.transport_headers)
LOGGER.debug(raw_body)
try:
resp = requests.request(method, url,
auth=auth,
headers=request.transport_headers,
params=params,
data=raw_body,
timeout=self.timeout,
verify=verify,
cert=request.cert,
proxies=_proxies_dict(self.proxy))
resp = self.client.request(method, url,
auth=auth,
headers=request.transport_headers,
params=params,
data=raw_body,
timeout=self.timeout,
verify=verify,
cert=request.cert,
proxies=_proxies_dict(self.proxy))
LOGGER.debug("=== RESPONSE ===")
LOGGER.debug(resp.headers)
LOGGER.debug(resp.text)
Expand Down
38 changes: 19 additions & 19 deletions tests/transport_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def set_up(self):
)
self.response = get_xmlrpc_response()

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_call(self, request):
request.return_value = self.response

Expand Down Expand Up @@ -95,7 +95,7 @@ def test_proxy_without_protocol(self):
warnings.warn("Incorrect Exception raised. Expected a "
"SoftLayer.TransportError error")

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_valid_proxy(self, request):
request.return_value = self.response
self.transport.proxy = 'http://localhost:3128'
Expand All @@ -116,7 +116,7 @@ def test_valid_proxy(self, request):
cert=None,
verify=True)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_identifier(self, request):
request.return_value = self.response

Expand All @@ -134,7 +134,7 @@ def test_identifier(self, request):
<value><int>1234</int></value>
</member>""", kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_filter(self, request):
request.return_value = self.response

Expand All @@ -152,7 +152,7 @@ def test_filter(self, request):
<value><string>^= prefix</string></value>
</member>""", kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_limit_offset(self, request):
request.return_value = self.response

Expand All @@ -172,7 +172,7 @@ def test_limit_offset(self, request):
<value><int>10</int></value>
</member>""", kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_old_mask(self, request):
request.return_value = self.response

Expand All @@ -194,7 +194,7 @@ def test_old_mask(self, request):
</struct></value>
</member>""", kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_mask_call_no_mask_prefix(self, request):
request.return_value = self.response

Expand All @@ -210,7 +210,7 @@ def test_mask_call_no_mask_prefix(self, request):
"<value><string>mask[something.nested]</string></value>",
kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_mask_call_v2(self, request):
request.return_value = self.response

Expand All @@ -226,7 +226,7 @@ def test_mask_call_v2(self, request):
"<value><string>mask[something[nested]]</string></value>",
kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_mask_call_v2_dot(self, request):
request.return_value = self.response

Expand All @@ -241,7 +241,7 @@ def test_mask_call_v2_dot(self, request):
self.assertIn("<value><string>mask.something.nested</string></value>",
kwargs['data'])

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_request_exception(self, request):
# Test Text Error
e = requests.HTTPError('error')
Expand All @@ -257,7 +257,7 @@ def test_request_exception(self, request):
self.assertRaises(SoftLayer.TransportError, self.transport, req)


@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
@pytest.mark.parametrize(
"transport_verify,request_verify,expected",
[
Expand Down Expand Up @@ -313,7 +313,7 @@ def set_up(self):
endpoint_url='http://something.com',
)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_basic(self, request):
request().content = '[]'
request().text = '[]'
Expand All @@ -340,7 +340,7 @@ def test_basic(self, request):
proxies=None,
timeout=None)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_error(self, request):
# Test JSON Error
e = requests.HTTPError('error')
Expand Down Expand Up @@ -369,7 +369,7 @@ def test_proxy_without_protocol(self):
warnings.warn("AssertionError raised instead of a "
"SoftLayer.TransportError error")

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_valid_proxy(self, request):
request().text = '{}'
self.transport.proxy = 'http://localhost:3128'
Expand All @@ -392,7 +392,7 @@ def test_valid_proxy(self, request):
timeout=mock.ANY,
headers=mock.ANY)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_with_id(self, request):
request().text = '{}'

Expand All @@ -416,7 +416,7 @@ def test_with_id(self, request):
proxies=None,
timeout=None)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_with_args(self, request):
request().text = '{}'

Expand All @@ -440,7 +440,7 @@ def test_with_args(self, request):
proxies=None,
timeout=None)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_with_filter(self, request):
request().text = '{}'

Expand All @@ -465,7 +465,7 @@ def test_with_filter(self, request):
proxies=None,
timeout=None)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_with_mask(self, request):
request().text = '{}'

Expand Down Expand Up @@ -510,7 +510,7 @@ def test_with_mask(self, request):
proxies=None,
timeout=None)

@mock.patch('requests.request')
@mock.patch('SoftLayer.transports.requests.Session.request')
def test_unknown_error(self, request):
e = requests.RequestException('error')
e.response = mock.MagicMock()
Expand Down