Skip to content

Commit

Permalink
HTTP improvement (#87)
Browse files Browse the repository at this point in the history
* Move parameters from session to request

* Patch adapter instead of changing them

* Patch session.resolve_redirects only once

* Keep session alive

* Add contextmanager to base SDKClient

* Fix scope of maxretries

* Make stream simpler

* Improve close behavior
  • Loading branch information
lmazuel authored Apr 18, 2018
1 parent 1cd895a commit 31c02e3
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 143 deletions.
3 changes: 2 additions & 1 deletion msrest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
# --------------------------------------------------------------------------

from .configuration import Configuration
from .service_client import ServiceClient
from .service_client import ServiceClient, SDKClient
from .serialization import Serializer, Deserializer
from .version import msrest_version

__all__ = [
"ServiceClient",
"SDKClient",
"Serializer",
"Deserializer",
"Configuration"
Expand Down
64 changes: 48 additions & 16 deletions msrest/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ class Authentication(object):

header = "Authorization"

def signed_session(self):
"""Create requests session with any required auth headers
applied.
def signed_session(self, session=None):
"""Create requests session with any required auth headers applied.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
return requests.Session()
return session or requests.Session()


class BasicAuthentication(Authentication):
Expand All @@ -57,13 +61,18 @@ def __init__(self, username, password):
self.username = username
self.password = password

def signed_session(self):
def signed_session(self, session=None):
"""Create requests session with any required auth headers
applied.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
session = super(BasicAuthentication, self).signed_session()
session = super(BasicAuthentication, self).signed_session(session)
session.auth = HTTPBasicAuth(self.username, self.password)
return session

Expand All @@ -87,30 +96,35 @@ def set_token(self):
"""
pass

def signed_session(self):
def signed_session(self, session=None):
"""Create requests session with any required auth headers
applied.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
session = super(BasicTokenAuthentication, self).signed_session()
session = super(BasicTokenAuthentication, self).signed_session(session)
header = "{} {}".format(self.scheme, self.token['access_token'])
session.headers['Authorization'] = header
return session


class OAuthTokenAuthentication(BasicTokenAuthentication):
"""OAuth Token Authentication.
Requires that supplied token contains an expires_in field.
:param str client_id: Account Client ID.
:param dict[str,str] token: OAuth2 token.
"""

def __init__(self, client_id, token):
self.scheme = 'Bearer'
super(OAuthTokenAuthentication, self).__init__(token)
self.id = client_id
self.token = token
self.store_key = self.id

def construct_auth(self):
Expand All @@ -120,20 +134,32 @@ def construct_auth(self):
"""
return "{} {}".format(self.scheme, self.token)

def refresh_session(self):
def refresh_session(self, session=None):
"""Return updated session if token has expired, attempts to
refresh using refresh token.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
return self.signed_session()
return self.signed_session(session)

def signed_session(self):
def signed_session(self, session=None):
"""Create requests session with any required auth headers applied.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
return oauth.OAuth2Session(self.id, token=self.token)
session = session or requests.Session() # Don't call super on purpose, let's "auth" manage the headers.
session.auth = oauth.OAuth2(self.id, token=self.token)
return session

class ApiKeyCredentials(Authentication):
"""Represent the ApiKey feature of Swagger.
Expand All @@ -144,6 +170,7 @@ class ApiKeyCredentials(Authentication):
:param dict[str,str] in_query: ApiKey in the query as parameters
"""
def __init__(self, in_headers=None, in_query=None):
super(ApiKeyCredentials, self).__init__()
if in_headers is None:
in_headers = {}
if in_query is None:
Expand All @@ -155,12 +182,17 @@ def __init__(self, in_headers=None, in_query=None):
self.in_headers = in_headers
self.in_query = in_query

def signed_session(self):
def signed_session(self, session=None):
"""Create requests session with ApiKey.
If a session object is provided, configure it directly. Otherwise,
create a new session and return it.
:param session: The session to configure for authentication
:type session: requests.Session
:rtype: requests.Session
"""
session = super(ApiKeyCredentials, self).signed_session()
session = super(ApiKeyCredentials, self).signed_session(session)
session.headers.update(self.in_headers)
session.params.update(self.in_query)
return session
Expand Down
3 changes: 3 additions & 0 deletions msrest/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def __init__(self, base_url, filepath=None):

self.session_configuration_callback = default_session_configuration_callback

# If set to True, ServiceClient will own the sessionn
self.keep_alive = False

self._config = configparser.ConfigParser()
self._config.optionxform = str

Expand Down
16 changes: 0 additions & 16 deletions msrest/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,6 @@
class ClientRequest(requests.Request):
"""Wrapper for requests.Request object."""

def add_header(self, header, value):
"""Add a header to the single request.
:param str header: The header name.
:param str value: The header value.
"""
self.headers[header] = value

def add_headers(self, headers):
"""Add multiple headers to the single request.
:param dict headers: A dictionary of headers.
"""
for key, value in headers.items():
self.add_header(key, value)

def format_parameters(self, params):
"""Format parameters into a valid query string.
It's assumed all parameters have already been quoted as
Expand Down
Loading

0 comments on commit 31c02e3

Please sign in to comment.