Hello community,

here is the log from the commit of package python-msrest for openSUSE:Factory 
checked in at 2018-05-13 16:03:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-msrest (Old)
 and      /work/SRC/openSUSE:Factory/.python-msrest.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-msrest"

Sun May 13 16:03:43 2018 rev:5 rq:601547 version:0.4.28

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-msrest/python-msrest.changes      
2018-02-14 09:27:23.732669346 +0100
+++ /work/SRC/openSUSE:Factory/.python-msrest.new/python-msrest.changes 
2018-05-13 16:03:43.821253496 +0200
@@ -1,0 +2,13 @@
+Tue Apr 24 10:52:43 UTC 2018 - [email protected]
+
+- New upstream release
+  + Version 0.4.28
+  + For detailed information about changes see the
+    README.rst file provided with this package
+- Install HISTORY.rst into doc directory
+- Refresh patches for new version
+  + m_drop-compatible-releases-operator.patch
+  + m_drop-extras-require.patch
+- Update Requires from setup.py
+
+-------------------------------------------------------------------

Old:
----
  msrest-0.4.25.tar.gz

New:
----
  msrest-0.4.28.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-msrest.spec ++++++
--- /var/tmp/diff_new_pack.xnQbrx/_old  2018-05-13 16:03:44.549226937 +0200
+++ /var/tmp/diff_new_pack.xnQbrx/_new  2018-05-13 16:03:44.549226937 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-msrest
-Version:        0.4.25
+Version:        0.4.28
 Release:        0
 Summary:        AutoRest swagger generator Python client runtime
 License:        MIT
@@ -32,7 +32,7 @@
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-certifi >= 2017.4.17
-Requires:       python-isodate >= 0.5.4
+Requires:       python-isodate >= 0.6.0
 Requires:       python-requests < 3.00
 Requires:       python-requests >= 2.14
 Requires:       python-requests-oauthlib >= 0.5.0
@@ -60,6 +60,7 @@
 
 %files %{python_files}
 %defattr(-,root,root,-)
+%doc README.rst
 %{python_sitelib}/*
 
 %changelog

++++++ m_drop-compatible-releases-operator.patch ++++++
--- /var/tmp/diff_new_pack.xnQbrx/_old  2018-05-13 16:03:44.573226061 +0200
+++ /var/tmp/diff_new_pack.xnQbrx/_new  2018-05-13 16:03:44.573226061 +0200
@@ -1,12 +1,12 @@
-diff -Nru msrest-0.4.11.orig/setup.py msrest-0.4.11/setup.py
---- msrest-0.4.11.orig/setup.py        2017-06-21 21:21:28.000000000 +0200
-+++ msrest-0.4.11/setup.py     2017-09-19 21:48:38.208520870 +0200
-@@ -48,7 +48,7 @@
+diff -Nru msrest-0.4.28.orig/setup.py msrest-0.4.28/setup.py
+--- msrest-0.4.28.orig/setup.py        2018-04-18 23:08:15.000000000 +0200
++++ msrest-0.4.28/setup.py     2018-04-24 12:46:33.099513431 +0200
+@@ -47,7 +47,7 @@
          'License :: OSI Approved :: MIT License',
          'Topic :: Software Development'],
      install_requires=[
 -        "requests~=2.14",
 +        "requests>=2.14",
          "requests_oauthlib>=0.5.0",
-         "isodate>=0.5.4",
+         "isodate>=0.6.0",
          "certifi>=2017.4.17",

++++++ m_drop-extras-require.patch ++++++
--- /var/tmp/diff_new_pack.xnQbrx/_old  2018-05-13 16:03:44.585225624 +0200
+++ /var/tmp/diff_new_pack.xnQbrx/_new  2018-05-13 16:03:44.585225624 +0200
@@ -1,13 +1,11 @@
-diff -Nru msrest-0.4.11.orig/setup.py msrest-0.4.11/setup.py
---- msrest-0.4.11.orig/setup.py        2017-09-19 21:48:38.208520870 +0200
-+++ msrest-0.4.11/setup.py     2017-09-19 21:50:56.557685936 +0200
-@@ -52,8 +52,5 @@
-         "requests_oauthlib>=0.5.0",
-         "isodate>=0.5.4",
+diff -Nru msrest-0.4.28.orig/setup.py msrest-0.4.28/setup.py
+--- msrest-0.4.28.orig/setup.py        2018-04-24 12:46:33.099513431 +0200
++++ msrest-0.4.28/setup.py     2018-04-24 12:47:31.784002289 +0200
+@@ -52,7 +52,4 @@
+         "isodate>=0.6.0",
          "certifi>=2017.4.17",
--    ],
+     ],
 -    extras_require={
 -        ":python_version<'3.4'": ['enum34>=1.0.4'],
 -    }
-+    ]
  )

++++++ msrest-0.4.25.tar.gz -> msrest-0.4.28.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/PKG-INFO new/msrest-0.4.28/PKG-INFO
--- old/msrest-0.4.25/PKG-INFO  2018-01-08 22:52:45.000000000 +0100
+++ new/msrest-0.4.28/PKG-INFO  2018-04-18 23:08:55.000000000 +0200
@@ -1,14 +1,13 @@
 Metadata-Version: 1.1
 Name: msrest
-Version: 0.4.25
+Version: 0.4.28
 Summary: AutoRest swagger generator Python client runtime.
 Home-page: https://github.com/Azure/msrest-for-python
 Author: Microsoft Corporation
 Author-email: UNKNOWN
 License: MIT License
-Description-Content-Type: UNKNOWN
 Description: AutoRest: Python Client Runtime
-        ================================
+        ===============================
         
         .. image:: 
https://travis-ci.org/Azure/msrest-for-python.svg?branch=master
          :target: https://travis-ci.org/Azure/msrest-for-python
@@ -29,6 +28,49 @@
         Release History
         ---------------
         
+        2018-04-18 Version 0.4.28
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - msrest is now able to keep the "requests.Session" alive for 
performance. To activate this behavior:
+        
+          - Use the final Client as a context manager (requires generation 
with Autorest.Python 3.0.50 at least)
+          - Use `client.config.keep_alive = True` and `client.close()` 
(requires generation with Autorest.Python 3.0.50 at least)
+          - Use `client.config.keep_alive = True` and client._client.close() 
(not recommended, but available in old releases of SDK)
+        
+        - All Authentication classes now define `signed_session` and 
`refresh_session` with an optional `session` parameter.
+          To take benefits of the session improvement, a subclass of 
Authentication *MUST* add this optional parameter
+          and use it if it's not `None`:
+        
+             def signed_session(self, session=None):
+                 session = session or requests.Session()
+        
+                 # As usual from here.
+        
+        2018-03-07 Version 0.4.27
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - Disable HTTP log by default (security), add `enable_http_log` to 
restore it #86
+        
+        **BugFixes**
+        
+        - Fix incorrect date parsing if ms precision is over 6 digits #82
+        
+        2018-01-30 Version 0.4.26
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - Add TopicCredentials for EventGrid client
+        
+        **Bugfixes**
+        
+        - Fix minimal dependency of isodate
+        - Fix serialisation from dict if datetime provided
+        
         2018-01-08 Version 0.4.25
         +++++++++++++++++++++++++
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/README.rst new/msrest-0.4.28/README.rst
--- old/msrest-0.4.25/README.rst        2018-01-08 22:52:05.000000000 +0100
+++ new/msrest-0.4.28/README.rst        2018-04-18 23:08:15.000000000 +0200
@@ -1,5 +1,5 @@
 AutoRest: Python Client Runtime
-================================
+===============================
 
 .. image:: https://travis-ci.org/Azure/msrest-for-python.svg?branch=master
  :target: https://travis-ci.org/Azure/msrest-for-python
@@ -20,6 +20,49 @@
 Release History
 ---------------
 
+2018-04-18 Version 0.4.28
++++++++++++++++++++++++++
+
+**Features**
+
+- msrest is now able to keep the "requests.Session" alive for performance. To 
activate this behavior:
+
+  - Use the final Client as a context manager (requires generation with 
Autorest.Python 3.0.50 at least)
+  - Use `client.config.keep_alive = True` and `client.close()` (requires 
generation with Autorest.Python 3.0.50 at least)
+  - Use `client.config.keep_alive = True` and client._client.close() (not 
recommended, but available in old releases of SDK)
+
+- All Authentication classes now define `signed_session` and `refresh_session` 
with an optional `session` parameter.
+  To take benefits of the session improvement, a subclass of Authentication 
*MUST* add this optional parameter
+  and use it if it's not `None`:
+
+     def signed_session(self, session=None):
+         session = session or requests.Session()
+
+         # As usual from here.
+
+2018-03-07 Version 0.4.27
++++++++++++++++++++++++++
+
+**Features**
+
+- Disable HTTP log by default (security), add `enable_http_log` to restore it 
#86
+
+**BugFixes**
+
+- Fix incorrect date parsing if ms precision is over 6 digits #82
+
+2018-01-30 Version 0.4.26
++++++++++++++++++++++++++
+
+**Features**
+
+- Add TopicCredentials for EventGrid client
+
+**Bugfixes**
+
+- Fix minimal dependency of isodate
+- Fix serialisation from dict if datetime provided
+
 2018-01-08 Version 0.4.25
 +++++++++++++++++++++++++
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/__init__.py 
new/msrest-0.4.28/msrest/__init__.py
--- old/msrest-0.4.25/msrest/__init__.py        2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/__init__.py        2018-04-18 23:08:15.000000000 
+0200
@@ -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"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/authentication.py 
new/msrest-0.4.28/msrest/authentication.py
--- old/msrest-0.4.25/msrest/authentication.py  2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/authentication.py  2018-04-18 23:08:15.000000000 
+0200
@@ -36,17 +36,21 @@
 
     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.
 
-        :rtype: requests.Session.
+        :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):
-    """Implmentation of Basic Authentication.
+    """Implementation of Basic Authentication.
 
     :param str username: Authentication username.
     :param str password: Authentication password.
@@ -57,13 +61,18 @@
         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.
 
-        :rtype: requests.Session.
+        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
 
@@ -72,7 +81,7 @@
     """Simple Token Authentication.
     Does not adhere to OAuth, simply adds provided token as a header.
 
-    :param dict token: Authentication token, must have 'access_token' key.
+    :param dict[str,str] token: Authentication token, must have 'access_token' 
key.
     """
 
     def __init__(self, token):
@@ -87,13 +96,18 @@
         """
         pass
 
-    def signed_session(self):
+    def signed_session(self, session=None):
         """Create requests session with any required auth headers
         applied.
 
-        :rtype: requests.Session.
+        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
@@ -101,50 +115,62 @@
 
 class OAuthTokenAuthentication(BasicTokenAuthentication):
     """OAuth Token Authentication.
+
     Requires that supplied token contains an expires_in field.
 
     :param str client_id: Account Client ID.
-    :param dict token: OAuth2 token.
+    :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):
         """Format token header.
 
-        :rtype: str.
+        :rtype: str
         """
         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.
 
-        :rtype: requests.Session.
+        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):
-        """Create requests session with any required auth headers
-        applied.
+    def signed_session(self, session=None):
+        """Create requests session with any required auth headers applied.
 
-        :rtype: requests.Session.
+        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.
 
-    Dict should be dict[str, str] to be accepted by requests.
+    Dict should be dict[str,str] to be accepted by requests.
 
-    :param dict[str, str] in_headers: Headers part of the ApiKey
-    :param dict[str, str] in_query: ApiKey in the query as parameters.
+    :param dict[str,str] in_headers: Headers part of the ApiKey
+    :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:
@@ -156,12 +182,17 @@
         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.
 
-        :rtype: requests.Session.
+        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
@@ -183,3 +214,21 @@
                 'X-BingApis-SDK-Client': 'Python-SDK'
             }
         )
+
+class TopicCredentials(ApiKeyCredentials):
+    """Event Grid authentication.
+
+    :param str topic_key: The Event Grid topic key
+    """
+
+    _topic_key_header = 'aeg-sas-key'
+
+    def __init__(self, topic_key):
+        if not topic_key:
+            raise ValueError("Topic key cannot be None")
+        super(TopicCredentials, self).__init__(
+            in_headers={
+                self._topic_key_header: topic_key,
+            }
+        )
+    
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/configuration.py 
new/msrest-0.4.28/msrest/configuration.py
--- old/msrest-0.4.25/msrest/configuration.py   2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/configuration.py   2018-04-18 23:08:15.000000000 
+0200
@@ -49,10 +49,10 @@
 
     :param requests.Session session: The session.
     :param Configuration global_config: The global configuration.
-    :param dict local_config: The on-the-fly configuration passed on the call.
-    :param dict kwargs: The current computed values for session.request method.
+    :param dict[str,str] local_config: The on-the-fly configuration passed on 
the call.
+    :param dict[str,str] kwargs: The current computed values for 
session.request method.
     :return: Must return kwargs, to be passed to session.request. If None is 
return, initial kwargs will be used.
-    :rtype: dict
+    :rtype: dict[str,str]
     """
     return kwargs
 
@@ -87,6 +87,9 @@
             requests.__version__,
             msrest_version)
 
+        # Should we log HTTP requests/response?
+        self.enable_http_logger = False
+
         # Requests hooks. Must respect requests hook callback signature
         # Note that we will inject the following parameters:
         # - kwargs['msrest']['session'] with the current session
@@ -94,6 +97,9 @@
 
         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
 
@@ -102,9 +108,14 @@
 
     @property
     def user_agent(self):
+        """The current user agent value."""
         return self._user_agent
 
     def add_user_agent(self, value):
+        """Add value to current user agent with a space.
+
+        :param str value: value to add to user agent.
+        """
         self._user_agent = "{} {}".format(self._user_agent, value)
 
     def _clear_config(self):
@@ -117,7 +128,6 @@
 
         :param str filepath: Path to file where settings will be saved.
         :raises: ValueError if supplied filepath cannot be written to.
-        :rtype: None
         """
         sections = [
             "Connection",
@@ -159,7 +169,6 @@
 
         :param str filepath: Path to existing config file.
         :raises: ValueError if supplied config file is invalid.
-        :rtype: None
         """
         try:
             self._config.read(filepath)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/paging.py 
new/msrest-0.4.28/msrest/paging.py
--- old/msrest-0.4.25/msrest/paging.py  2018-01-08 22:52:05.000000000 +0100
+++ new/msrest-0.4.28/msrest/paging.py  2018-04-18 23:08:15.000000000 +0200
@@ -65,6 +65,10 @@
 
     @property
     def raw(self):
+        """Get current page as ClientRawResponse.
+
+        :rtype: ClientRawResponse
+        """
         raw = ClientRawResponse(self.current_page, self._response)
         if self._raw_headers:
             raw.add_headers(self._raw_headers)
@@ -89,6 +93,14 @@
         self._current_page_iter_index = 0
 
     def advance_page(self):
+        """Force moving the cursor to the next azure call.
+
+        This method is for advanced usage, iterator protocol is prefered.
+
+        :raises: StopIteration if no further page
+        :return: The current page list
+        :rtype: list
+        """
         if self.next_link is None:
             raise StopIteration("End of paging")
         self._current_page_iter_index = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/pipeline.py 
new/msrest-0.4.28/msrest/pipeline.py
--- old/msrest-0.4.25/msrest/pipeline.py        2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/pipeline.py        2018-04-18 23:08:15.000000000 
+0200
@@ -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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/serialization.py 
new/msrest-0.4.28/msrest/serialization.py
--- old/msrest-0.4.25/msrest/serialization.py   2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/serialization.py   2018-04-18 23:08:15.000000000 
+0200
@@ -138,10 +138,11 @@
         self.additional_properties = {}
         for k in kwargs:
             if k not in self._attribute_map:
-                raise TypeError("{} is not a known attribute of class 
{}".format(k, self.__class__))
-            if k in self._validation and self._validation[k].get("readonly", 
False):
-                _LOGGER.warning("Readonly attribute {} will be ignored in 
class {}".format(k, self.__class__))
-            setattr(self, k, kwargs[k])
+                _LOGGER.warning("%s is not a known attribute of class %s and 
will be ignored", k, self.__class__)
+            elif k in self._validation and self._validation[k].get("readonly", 
False):
+                _LOGGER.warning("Readonly attribute %s will be ignored in 
class %s", k, self.__class__)
+            else:
+                setattr(self, k, kwargs[k])
 
     def __eq__(self, other):
         """Compare objects by comparing all attributes."""
@@ -953,7 +954,8 @@
             '{}': self.deserialize_dict
             }
         self.deserialize_expected_types = {
-            'duration': (isodate.Duration, datetime.timedelta)
+            'duration': (isodate.Duration, datetime.timedelta),
+            'iso-8601': (datetime.datetime)
         }
         self.dependencies = dict(classes) if classes else {}
         self.key_extractors = [
@@ -1453,7 +1455,7 @@
                     else:
                         break
                 if len(decimal_str) > 6:
-                    attr = attr.replace(decimal_str, decimal_str[0:-1])
+                    attr = attr.replace(decimal_str, decimal_str[0:6])
 
             date_obj = isodate.parse_datetime(attr)
             test_utc = date_obj.utctimetuple()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/service_client.py 
new/msrest-0.4.28/msrest/service_client.py
--- old/msrest-0.4.25/msrest/service_client.py  2018-01-08 22:52:05.000000000 
+0100
+++ new/msrest-0.4.28/msrest/service_client.py  2018-04-18 23:08:15.000000000 
+0200
@@ -46,6 +46,23 @@
 
 _LOGGER = logging.getLogger(__name__)
 
+class SDKClient(object):
+    """The base class of all generated SDK client.
+    """
+    def __init__(self, creds, config):
+        self._client = ServiceClient(creds, config)
+    
+    def close(self):
+        """Close the client if keep_alive is True.
+        """
+        self._client.close()
+
+    def __enter__(self):
+        self._client.__enter__()
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self._client.__exit__(exc_type, exc_val, exc_tb)
 
 class ServiceClient(object):
     """REST Service Client.
@@ -61,6 +78,22 @@
         self.config = config
         self.creds = creds if creds else Authentication()
         self._headers = {}
+        self._session = None
+
+    def __enter__(self):
+        self.config.keep_alive = True
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.close()
+        self.config.keep_alive = False
+
+    def close(self):
+        """Close the session if keep_alive is True.
+        """
+        if self._session:
+            self._session.close()
+        self._session = None
 
     def _format_data(self, data):
         """Format field data according to whether it is a stream or
@@ -100,35 +133,48 @@
 
         :param requests.Session session: Current request session.
         :param config: Specific configuration overrides.
+        :rtype: dict
+        :return: A dict that will be kwarg-send to session.request
         """
         kwargs = self.config.connection()
         for opt in ['timeout', 'verify', 'cert']:
             kwargs[opt] = config.get(opt, kwargs[opt])
-        for opt in ['cookies', 'files']:
-            kwargs[opt] = config.get(opt)
+        kwargs.update({k:config[k] for k in ['cookies', 'files'] if k in 
config})
         kwargs['allow_redirects'] = config.get(
             'allow_redirects', bool(self.config.redirect_policy))
 
-        session.headers.update(self._headers)
-        session.headers['User-Agent'] = self.config.user_agent
-        session.headers['Accept'] = 'application/json'
-        session.max_redirects = config.get(
-            'max_redirects', self.config.redirect_policy())
-        session.proxies = config.get(
-            'proxies', self.config.proxies())
-        session.trust_env = config.get(
-            'use_env_proxies', self.config.proxies.use_env_settings)
-        redirect_logic = session.resolve_redirects
-
-        def wrapped_redirect(resp, req, **kwargs):
-            attempt = self.config.redirect_policy.check_redirect(resp, req)
-            return redirect_logic(resp, req, **kwargs) if attempt else []
-
-        session.resolve_redirects = wrapped_redirect
-        def log_hook(r, *args, **kwargs):
-            log_request(None, r.request)
-            log_response(None, r.request, r, result=r)
-        session.hooks['response'].append(log_hook)
+        kwargs['headers'] = dict(self._headers)
+        kwargs['headers']['User-Agent'] = self.config.user_agent
+        kwargs['headers']['Accept'] = 'application/json'
+        proxies = config.get('proxies', self.config.proxies())
+        if proxies:
+            kwargs['proxies'] = proxies
+
+        kwargs['stream'] = config.get('stream', True)
+
+        session.max_redirects = config.get('max_redirects', 
self.config.redirect_policy())
+        session.trust_env = config.get('use_env_proxies', 
self.config.proxies.use_env_settings)
+
+        # Patch the redirect method directly *if not done already*
+        if not getattr(session.resolve_redirects, 'is_mrest_patched', False):
+            redirect_logic = session.resolve_redirects
+
+            def wrapped_redirect(resp, req, **kwargs):
+                attempt = self.config.redirect_policy.check_redirect(resp, req)
+                return redirect_logic(resp, req, **kwargs) if attempt else []
+            wrapped_redirect.is_mrest_patched = True
+
+            session.resolve_redirects = wrapped_redirect
+
+        # if "enable_http_logger" is defined at the operation level, take the 
value.
+        # if not, take the one in the client config
+        # if not, disable http_logger
+        hooks = []
+        if config.get("enable_http_logger", self.config.enable_http_logger):
+            def log_hook(r, *args, **kwargs):
+                log_request(None, r.request)
+                log_response(None, r.request, r, result=r)
+            hooks.append(log_hook)
 
         def make_user_hook_cb(user_hook, session):
             def user_hook_cb(r, *args, **kwargs):
@@ -137,13 +183,15 @@
             return user_hook_cb
 
         for user_hook in self.config.hooks:
-            session.hooks['response'].append(make_user_hook_cb(user_hook, 
session))
+            hooks.append(make_user_hook_cb(user_hook, session))
 
-        max_retries = config.get(
-            'retries', self.config.retry_policy())
+        if hooks:
+            kwargs['hooks'] = {'response': hooks}
+
+        # Change max_retries in current all installed adapters
+        max_retries = config.get('retries', self.config.retry_policy())
         for protocol in self._protocols:
-            session.mount(protocol,
-                          
requests.adapters.HTTPAdapter(max_retries=max_retries))
+            session.adapters[protocol].max_retries=max_retries
 
         output_kwargs = self.config.session_configuration_callback(session, 
self.config, config, **kwargs)
         if output_kwargs is not None:
@@ -151,7 +199,7 @@
 
         return kwargs
 
-    def send_formdata(self, request, headers=None, content=None, stream=True, 
**config):
+    def send_formdata(self, request, headers=None, content=None, **config):
         """Send data as a multipart form-data request.
         We only deal with file-like objects or strings at this point.
         The requests is not yet streamed.
@@ -159,7 +207,6 @@
         :param ClientRequest request: The request object to be sent.
         :param dict headers: Any headers to add to the request.
         :param dict content: Dictionary of the fields of the formdata.
-        :param bool stream: Is the session in stream mode. True by default for 
compat.
         :param config: Any specific config overrides.
         """
         if content is None:
@@ -169,35 +216,44 @@
         if content_type and content_type.lower() == 
'application/x-www-form-urlencoded':
             # Do NOT use "add_content" that assumes input is JSON
             request.data = {f: d for f, d in content.items() if d is not None}
-            return self.send(request, headers, None, stream=stream, **config)
+            return self.send(request, headers, None, **config)
         else: # Assume "multipart/form-data"
             file_data = {f: self._format_data(d) for f, d in content.items() 
if d is not None}
-            return self.send(request, headers, None, files=file_data, 
stream=stream, **config)
+            return self.send(request, headers, None, files=file_data, **config)
 
-    def send(self, request, headers=None, content=None, stream=True, **config):
+    def send(self, request, headers=None, content=None, **config):
         """Prepare and send request object according to configuration.
 
         :param ClientRequest request: The request object to be sent.
         :param dict headers: Any headers to add to the request.
         :param content: Any body data to add to the request.
-        :param bool stream: Is the session in stream mode. True by default for 
compat.
         :param config: Any specific config overrides
         """
-        response = None
-        session = self.creds.signed_session()
+        if self.config.keep_alive and self._session is None:
+            self._session = requests.Session()
+        try:
+            session = self.creds.signed_session(self._session)
+        except TypeError: # Credentials does not support session injection
+            session = self.creds.signed_session()
+            if self._session is not None:
+                _LOGGER.warning("Your credentials class does not support 
session injection. Performance will not be at the maximum.")
+
         kwargs = self._configure_session(session, **config)
-        kwargs['stream'] = stream
+        if headers:
+            request.headers.update(headers)
 
-        request.add_headers(headers if headers else {})
         if not kwargs.get('files'):
             request.add_content(content)
-        try:
+        if request.data:
+            kwargs['data']=request.data
+        kwargs['headers'].update(request.headers)
 
+        response = None
+        try:
             try:
                 response = session.request(
-                    request.method, request.url,
-                    data=request.data,
-                    headers=request.headers,
+                    request.method,
+                    request.url,
                     **kwargs)
                 return response
 
@@ -208,12 +264,14 @@
 
             try:
                 session = self.creds.refresh_session()
-                kwargs = self._configure_session(session)
+                kwargs = self._configure_session(session, **config)
+                if request.data:
+                    kwargs['data']=request.data
+                kwargs['headers'].update(request.headers)
 
                 response = session.request(
-                    request.method, request.url,
-                    request.data,
-                    request.headers,
+                    request.method,
+                    request.url,
                     **kwargs)
                 return response
             except (oauth2.rfc6749.errors.InvalidGrantError,
@@ -226,8 +284,15 @@
             msg = "Error occurred in request."
             raise_with_traceback(ClientRequestError, msg, err)
         finally:
-            if not response or not stream:
-                session.close()
+            self._close_local_session_if_necessary(response, session, 
kwargs['stream'])
+
+    def _close_local_session_if_necessary(self, response, session, stream):
+        # Do NOT close session if session is self._session. No exception.
+        if self._session is session:
+            return
+        # Here, it's a local session, I might close it.
+        if not response or not stream:
+            session.close()
 
     def stream_download(self, data, callback):
         """Generator for streaming request body data.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest/version.py 
new/msrest-0.4.28/msrest/version.py
--- old/msrest-0.4.25/msrest/version.py 2018-01-08 22:52:05.000000000 +0100
+++ new/msrest-0.4.28/msrest/version.py 2018-04-18 23:08:15.000000000 +0200
@@ -24,5 +24,5 @@
 #
 # --------------------------------------------------------------------------
 
-
-msrest_version = "0.4.25"
+#: version of this package. Use msrest.__version__ instead
+msrest_version = "0.4.28"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest.egg-info/PKG-INFO 
new/msrest-0.4.28/msrest.egg-info/PKG-INFO
--- old/msrest-0.4.25/msrest.egg-info/PKG-INFO  2018-01-08 22:52:45.000000000 
+0100
+++ new/msrest-0.4.28/msrest.egg-info/PKG-INFO  2018-04-18 23:08:55.000000000 
+0200
@@ -1,14 +1,13 @@
 Metadata-Version: 1.1
 Name: msrest
-Version: 0.4.25
+Version: 0.4.28
 Summary: AutoRest swagger generator Python client runtime.
 Home-page: https://github.com/Azure/msrest-for-python
 Author: Microsoft Corporation
 Author-email: UNKNOWN
 License: MIT License
-Description-Content-Type: UNKNOWN
 Description: AutoRest: Python Client Runtime
-        ================================
+        ===============================
         
         .. image:: 
https://travis-ci.org/Azure/msrest-for-python.svg?branch=master
          :target: https://travis-ci.org/Azure/msrest-for-python
@@ -29,6 +28,49 @@
         Release History
         ---------------
         
+        2018-04-18 Version 0.4.28
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - msrest is now able to keep the "requests.Session" alive for 
performance. To activate this behavior:
+        
+          - Use the final Client as a context manager (requires generation 
with Autorest.Python 3.0.50 at least)
+          - Use `client.config.keep_alive = True` and `client.close()` 
(requires generation with Autorest.Python 3.0.50 at least)
+          - Use `client.config.keep_alive = True` and client._client.close() 
(not recommended, but available in old releases of SDK)
+        
+        - All Authentication classes now define `signed_session` and 
`refresh_session` with an optional `session` parameter.
+          To take benefits of the session improvement, a subclass of 
Authentication *MUST* add this optional parameter
+          and use it if it's not `None`:
+        
+             def signed_session(self, session=None):
+                 session = session or requests.Session()
+        
+                 # As usual from here.
+        
+        2018-03-07 Version 0.4.27
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - Disable HTTP log by default (security), add `enable_http_log` to 
restore it #86
+        
+        **BugFixes**
+        
+        - Fix incorrect date parsing if ms precision is over 6 digits #82
+        
+        2018-01-30 Version 0.4.26
+        +++++++++++++++++++++++++
+        
+        **Features**
+        
+        - Add TopicCredentials for EventGrid client
+        
+        **Bugfixes**
+        
+        - Fix minimal dependency of isodate
+        - Fix serialisation from dict if datetime provided
+        
         2018-01-08 Version 0.4.25
         +++++++++++++++++++++++++
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/msrest.egg-info/requires.txt 
new/msrest-0.4.28/msrest.egg-info/requires.txt
--- old/msrest-0.4.25/msrest.egg-info/requires.txt      2018-01-08 
22:52:45.000000000 +0100
+++ new/msrest-0.4.28/msrest.egg-info/requires.txt      2018-04-18 
23:08:55.000000000 +0200
@@ -1,6 +1,6 @@
 requests~=2.14
 requests_oauthlib>=0.5.0
-isodate>=0.5.4
+isodate>=0.6.0
 certifi>=2017.4.17
 
 [:python_version<'3.4']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msrest-0.4.25/setup.py new/msrest-0.4.28/setup.py
--- old/msrest-0.4.25/setup.py  2018-01-08 22:52:05.000000000 +0100
+++ new/msrest-0.4.28/setup.py  2018-04-18 23:08:15.000000000 +0200
@@ -28,7 +28,7 @@
 
 setup(
     name='msrest',
-    version='0.4.25',
+    version='0.4.28',
     author='Microsoft Corporation',
     packages=find_packages(exclude=["tests", "tests.*"]),
     url=("https://github.com/Azure/msrest-for-python";),
@@ -49,7 +49,7 @@
     install_requires=[
         "requests~=2.14",
         "requests_oauthlib>=0.5.0",
-        "isodate>=0.5.4",
+        "isodate>=0.6.0",
         "certifi>=2017.4.17",
     ],
     extras_require={


Reply via email to