Hello community,

here is the log from the commit of package python-requests-toolbelt for 
openSUSE:Factory checked in at 2019-05-10 09:14:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-requests-toolbelt (Old)
 and      /work/SRC/openSUSE:Factory/.python-requests-toolbelt.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-requests-toolbelt"

Fri May 10 09:14:14 2019 rev:4 rq:701116 version:0.9.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-requests-toolbelt/python-requests-toolbelt.changes
        2017-07-04 11:58:26.460974825 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-requests-toolbelt.new.5148/python-requests-toolbelt.changes
      2019-05-10 09:14:16.447801717 +0200
@@ -1,0 +2,30 @@
+Mon May  6 14:06:37 UTC 2019 - Tomáš Chvátal <[email protected]>
+
+- Add patch to fix tests fix-tests.patch
+- Use pytest to execute the tests, same as the upstream
+
+-------------------------------------------------------------------
+Thu Apr 25 19:57:47 UTC 2019 - Dirk Mueller <[email protected]>
+
+- update to 0.9.1:
+  - Fix import of pyOpenSSL shim from urllib3 for PKCS12 adapter
+  - Add X509 Adapter that can handle PKCS12 
+  - Add stateless solution for streaming files by MultipartEncoder from one 
host to another (in chunks)
+  - Update link to example
+  - Move import of ``ABCs`` from collections into version-specific part of
+    _compat module
+  - Fix backwards incompatibility in ``get_encodings_from_content``
+  - Correct callback documentation for ``MultipartEncoderMonitor``
+  - Fix bug when ``MultipartEncoder`` is asked to encode zero parts
+  - Correct the type of non string request body dumps
+  - Removed content from being stored in MultipartDecoder
+  - Fix bug by enabling support for contenttype with capital letters. 
+  - Coerce proxy URL to bytes before dumping request
+  - Avoid bailing out with exception upon empty response reason
+  - Corrected Pool documentation
+  - Corrected parentheses match in example usage
+  - Fix "oject" to "object" in ``MultipartEncoder``
+  - Fix URL for the project after the move 
+  - Add fix for OSX TCPKeepAliveAdapter
+
+-------------------------------------------------------------------

Old:
----
  requests-toolbelt-0.8.0.tar.gz

New:
----
  fix-tests.patch
  requests-toolbelt-0.9.1.tar.gz

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

Other differences:
------------------
++++++ python-requests-toolbelt.spec ++++++
--- /var/tmp/diff_new_pack.ZQSsHq/_old  2019-05-10 09:14:17.667805200 +0200
+++ /var/tmp/diff_new_pack.ZQSsHq/_new  2019-05-10 09:14:17.671805212 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-requests-toolbelt
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,31 +12,32 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-requests-toolbelt
-Version:        0.8.0
+Version:        0.9.1
 Release:        0
 Summary:        A utility belt for advanced users of python3-requests
 License:        Apache-2.0
 Group:          Development/Languages/Python
-Url:            https://toolbelt.readthedocs.org
+URL:            https://github.com/requests/toolbelt
 Source:         
https://files.pythonhosted.org/packages/source/r/requests-toolbelt/requests-toolbelt-%{version}.tar.gz
-BuildRequires:  %{python_module requests >= 2.0.1}
+Patch0:         fix-tests.patch
+BuildRequires:  %{python_module requests >= 2.12.2}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  fdupes
+BuildRequires:  python-rpm-macros
+Requires:       python-requests >= 2.12.2
+BuildArch:      noarch
 # SECTION test requirements
-BuildRequires:  %{python_module betamax}
+BuildRequires:  %{python_module betamax >= 0.5.0}
 BuildRequires:  %{python_module mock}
+BuildRequires:  %{python_module pyOpenSSL}
 BuildRequires:  %{python_module pytest}
 # /SECTION
-BuildRequires:  fdupes
-BuildRequires:  python-rpm-macros
-Requires:       python-requests >= 2.0.1
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-BuildArch:      noarch
 %python_subpackages
 
 %description
@@ -47,21 +48,24 @@
 
 %prep
 %setup -q -n requests-toolbelt-%{version}
+%patch0 -p1
 rm -rf requests_toolbelt.egg-info
+# requires network access
+rm -v tests/test_multipart_encoder.py
 
 %build
 %python_build
 
 %install
 %python_install
-%python_expand %fdupes -s %{buildroot}%{$python_sitelib}
+%python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %files %{python_files}
-%defattr(-,root,root,-)
-%doc AUTHORS.rst HISTORY.rst LICENSE README.rst
+%license LICENSE
+%doc README.rst
 %{python_sitelib}/*
 
 %changelog

++++++ fix-tests.patch ++++++
From c4f918572751151eb3bfc7dfa94580b3e2867a9e Mon Sep 17 00:00:00 2001
From: Jon Dufresne <[email protected]>
Date: Sun, 3 Feb 2019 09:02:24 -0800
Subject: [PATCH] Fix unhandled exceptions from threads during tests

A queue.Queue() object was not always passed to SessionThread. In this
case, SessionThread._make_request() would raise an exception trying to
call methods on the expected object. Now, always pass a usable object to
SessionThread.

Previously appeared as:

    Traceback (most recent call last):
      File "/usr/lib64/python3.7/threading.py", line 917, in _bootstrap_inner
        self.run()
      File "/usr/lib64/python3.7/threading.py", line 865, in run
        self._target(*self._args, **self._kwargs)
      File "toolbelt/requests_toolbelt/threaded/thread.py", line 41, in 
_make_request
        kwargs = self._jobs.get_nowait()
    AttributeError: 'NoneType' object has no attribute 'get_nowait'

    Exception in thread cd08fad6-d21d-41b0-921e-737a149b12be:
    Traceback (most recent call last):
      File "/usr/lib64/python3.7/threading.py", line 917, in _bootstrap_inner
        self.run()
      File "/usr/lib64/python3.7/threading.py", line 865, in run
        self._target(*self._args, **self._kwargs)
      File "toolbelt/requests_toolbelt/threaded/thread.py", line 41, in 
_make_request
        kwargs = self._jobs.get_nowait()
    AttributeError: 'NoneType' object has no attribute 'get_nowait'

    Exception in thread 4fb72f0d-ba1c-4a78-97a2-4a7283ea01fe:
    Traceback (most recent call last):
      File "/usr/lib64/python3.7/threading.py", line 917, in _bootstrap_inner
        self.run()
      File "/usr/lib64/python3.7/threading.py", line 865, in run
        self._target(*self._args, **self._kwargs)
      File "toolbelt/requests_toolbelt/threaded/thread.py", line 41, in 
_make_request
        kwargs = self._jobs.get_nowait()
    AttributeError: 'NoneType' object has no attribute 'get_nowait'

    Exception in thread 5f3711af-0c01-4821-9e25-8074bbbf769b:
    Traceback (most recent call last):
      File "/usr/lib64/python3.7/threading.py", line 917, in _bootstrap_inner
        self.run()
      File "/usr/lib64/python3.7/threading.py", line 865, in run
        self._target(*self._args, **self._kwargs)
      File "toolbelt/requests_toolbelt/threaded/thread.py", line 41, in 
_make_request
        kwargs = self._jobs.get_nowait()
    AttributeError: 'NoneType' object has no attribute 'get_nowait'
---
 tests/threaded/test_pool.py   | 15 ++++++++++-----
 tests/threaded/test_thread.py |  5 ++++-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/tests/threaded/test_pool.py b/tests/threaded/test_pool.py
index b0653bb..b949dd8 100644
--- a/tests/threaded/test_pool.py
+++ b/tests/threaded/test_pool.py
@@ -26,32 +26,37 @@ def test_requires_positive_number_of_processes(self):
 
     def test_number_of_processes_can_be_arbitrary(self):
         """Show that the number of processes can be set."""
-        p = pool.Pool(None, num_processes=100)
+        job_queue = queue.Queue()
+        p = pool.Pool(job_queue, num_processes=100)
         assert p._processes == 100
         assert len(p._pool) == 100
 
-        p = pool.Pool(None, num_processes=1)
+        job_queue = queue.Queue()
+        p = pool.Pool(job_queue, num_processes=1)
         assert p._processes == 1
         assert len(p._pool) == 1
 
     def test_initializer_is_called(self):
         """Ensure that the initializer function is called."""
+        job_queue = queue.Queue()
         initializer = mock.MagicMock()
-        pool.Pool(None, num_processes=1, initializer=initializer)
+        pool.Pool(job_queue, num_processes=1, initializer=initializer)
         assert initializer.called is True
         initializer.assert_called_once_with(mock.ANY)
 
     def test_auth_generator_is_called(self):
         """Ensure that the auth_generator function is called."""
+        job_queue = queue.Queue()
         auth_generator = mock.MagicMock()
-        pool.Pool(None, num_processes=1, auth_generator=auth_generator)
+        pool.Pool(job_queue, num_processes=1, auth_generator=auth_generator)
         assert auth_generator.called is True
         auth_generator.assert_called_once_with(mock.ANY)
 
     def test_session_is_called(self):
         """Ensure that the session function is called."""
+        job_queue = queue.Queue()
         session = mock.MagicMock()
-        pool.Pool(None, num_processes=1, session=session)
+        pool.Pool(job_queue, num_processes=1, session=session)
         assert session.called is True
         session.assert_called_once_with()
 
diff --git a/tests/threaded/test_thread.py b/tests/threaded/test_thread.py
index bb92f7f..fd7e96b 100644
--- a/tests/threaded/test_thread.py
+++ b/tests/threaded/test_thread.py
@@ -19,6 +19,8 @@ def _make_mocks():
 
 def _initialize_a_session_thread(session=None, job_queue=None,
                                  response_queue=None, exception_queue=None):
+    if job_queue is None:
+        job_queue = queue.Queue()
     with mock.patch.object(threading, 'Thread') as Thread:
         thread_instance = mock.MagicMock()
         Thread.return_value = thread_instance
@@ -52,10 +54,11 @@ def test_thread_initialization(self):
 
     def test_is_alive_proxies_to_worker(self):
         """Test that we proxy the is_alive method to the Thread."""
+        job_queue = queue.Queue()
         with mock.patch.object(threading, 'Thread') as Thread:
             thread_instance = mock.MagicMock()
             Thread.return_value = thread_instance
-            st = thread.SessionThread(None, None, None, None)
+            st = thread.SessionThread(None, job_queue, None, None)
 
         st.is_alive()
         thread_instance.is_alive.assert_called_once_with()
++++++ requests-toolbelt-0.8.0.tar.gz -> requests-toolbelt-0.9.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/AUTHORS.rst 
new/requests-toolbelt-0.9.1/AUTHORS.rst
--- old/requests-toolbelt-0.8.0/AUTHORS.rst     2017-01-19 15:23:03.000000000 
+0100
+++ new/requests-toolbelt-0.9.1/AUTHORS.rst     2019-01-29 18:43:40.000000000 
+0100
@@ -41,3 +41,13 @@
 - Mike Lambert (@mikelambert)
 
 - Ryan Barrett (https://snarfed.org/)
+
+- Victor Grau Serrat (@lacabra)
+
+- Yorgos Pagles <[email protected]>
+
+- Thomas Hauk <[email protected]>
+
+- Achim Herwig <[email protected]>
+
+- Ryan Ashley <rashley-iqt>
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/HISTORY.rst 
new/requests-toolbelt-0.9.1/HISTORY.rst
--- old/requests-toolbelt-0.8.0/HISTORY.rst     2017-05-20 23:31:29.000000000 
+0200
+++ new/requests-toolbelt-0.9.1/HISTORY.rst     2019-01-30 02:28:28.000000000 
+0100
@@ -1,6 +1,48 @@
 History
 =======
 
+0.9.1 -- 2019-01-29
+-------------------
+
+Fixed Bugs
+~~~~~~~~~~
+
+- Fix import of pyOpenSSL shim from urllib3 for PKCS12 adapter
+
+0.9.0 -- 2019-01-29
+-------------------
+
+New Features
+~~~~~~~~~~~~
+
+- Add X509 Adapter that can handle PKCS12 
+- Add stateless solution for streaming files by MultipartEncoder from one host 
to another (in chunks)
+
+Fixed Bugs
+~~~~~~~~~~
+
+- Update link to example
+- Move import of ``ABCs`` from collections into version-specific part of
+  _compat module
+- Fix backwards incompatibility in ``get_encodings_from_content``
+- Correct callback documentation for ``MultipartEncoderMonitor``
+- Fix bug when ``MultipartEncoder`` is asked to encode zero parts
+- Correct the type of non string request body dumps
+- Removed content from being stored in MultipartDecoder
+- Fix bug by enabling support for contenttype with capital letters. 
+- Coerce proxy URL to bytes before dumping request
+- Avoid bailing out with exception upon empty response reason
+- Corrected Pool documentation
+- Corrected parentheses match in example usage
+- Fix "oject" to "object" in ``MultipartEncoder``
+- Fix URL for the project after the move 
+- Add fix for OSX TCPKeepAliveAdapter
+
+Miscellaneous
+~~~~~~~~~~~~~
+
+- Remove py33 from testing and add Python 3.6 and nightly testing to the 
travis matrix.
+
 0.8.0 -- 2017-05-20
 -------------------
 
@@ -20,7 +62,7 @@
 - Fix backwards incompatibility in ``get_encodings_from_content``
 
 .. _0.8.0 milestone:
-    https://github.com/sigmavirus24/requests-toolbelt/milestones/0.8.0
+    https://github.com/requests/toolbelt/milestones/0.8.0
 
 0.7.1 -- 2017-02-13
 -------------------
@@ -40,7 +82,7 @@
 
 .. links
 .. _0.7.1 milestone:
-    https://github.com/sigmavirus24/requests-toolbelt/milestone/9
+    https://github.com/requests/toolbelt/milestone/9
 
 0.7.0 -- 2016-07-21
 -------------------
@@ -69,7 +111,7 @@
 
 
 .. _0.7.0 milestone:
-    https://github.com/sigmavirus24/requests-toolbelt/milestones/0.7.0
+    https://github.com/requests/toolbelt/milestones/0.7.0
 
 0.6.2 -- 2016-05-10
 -------------------
@@ -123,7 +165,7 @@
 
 
 .. _0.6.0 milestone:
-    https://github.com/sigmavirus24/requests-toolbelt/milestones/0.6.0
+    https://github.com/requests/toolbelt/milestones/0.6.0
 
 0.5.1 -- 2015-12-16
 -------------------
@@ -138,13 +180,13 @@
 
 
 .. _0.5.1 milestone:
-    https://github.com/sigmavirus24/requests-toolbelt/milestones/0.5.1
+    https://github.com/requests/toolbelt/milestones/0.5.1
 
 0.5.0 -- 2015-11-24
 -------------------
 
 More information about this release can be found on the `milestone
-<https://github.com/sigmavirus24/requests-toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
+<https://github.com/requests/toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
 for 0.5.0.
 
 New Features
@@ -183,7 +225,7 @@
 -------------------
 
 For more information about this release, please see `milestone 0.4.0
-<https://github.com/sigmavirus24/requests-toolbelt/issues?q=milestone%3A0.4>`_
+<https://github.com/requests/toolbelt/issues?q=milestone%3A0.4>`_
 on the project's page.
 
 New Features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/PKG-INFO 
new/requests-toolbelt-0.9.1/PKG-INFO
--- old/requests-toolbelt-0.8.0/PKG-INFO        2017-05-20 23:32:33.000000000 
+0200
+++ new/requests-toolbelt-0.9.1/PKG-INFO        2019-01-30 02:29:41.000000000 
+0100
@@ -1,13 +1,13 @@
 Metadata-Version: 1.1
 Name: requests-toolbelt
-Version: 0.8.0
+Version: 0.9.1
 Summary: A utility belt for advanced users of python-requests
 Home-page: https://toolbelt.readthedocs.org
 Author: Ian Cordasco, Cory Benfield
 Author-email: [email protected]
 License: Apache 2.0
-Description: requests toolbelt
-        =================
+Description: The Requests Toolbelt
+        =====================
         
         This is just a collection of utilities for `python-requests`_, but 
don't 
         really belong in ``requests`` proper. The minimum tested requests 
version is 
@@ -118,13 +118,58 @@
         <https://toolbelt.readthedocs.org/en/latest/contributing.html>`_ for
         contributing to this project.
         
+        Please report any bugs on the `issue tracker`_
+        
         .. _Cory Benfield's blog: 
https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/
         .. _python-requests: https://github.com/kennethreitz/requests
+        .. _issue tracker: https://github.com/requests/toolbelt/issues
         
         
         History
         =======
         
+        0.9.1 -- 2019-01-29
+        -------------------
+        
+        Fixed Bugs
+        ~~~~~~~~~~
+        
+        - Fix import of pyOpenSSL shim from urllib3 for PKCS12 adapter
+        
+        0.9.0 -- 2019-01-29
+        -------------------
+        
+        New Features
+        ~~~~~~~~~~~~
+        
+        - Add X509 Adapter that can handle PKCS12 
+        - Add stateless solution for streaming files by MultipartEncoder from 
one host to another (in chunks)
+        
+        Fixed Bugs
+        ~~~~~~~~~~
+        
+        - Update link to example
+        - Move import of ``ABCs`` from collections into version-specific part 
of
+          _compat module
+        - Fix backwards incompatibility in ``get_encodings_from_content``
+        - Correct callback documentation for ``MultipartEncoderMonitor``
+        - Fix bug when ``MultipartEncoder`` is asked to encode zero parts
+        - Correct the type of non string request body dumps
+        - Removed content from being stored in MultipartDecoder
+        - Fix bug by enabling support for contenttype with capital letters. 
+        - Coerce proxy URL to bytes before dumping request
+        - Avoid bailing out with exception upon empty response reason
+        - Corrected Pool documentation
+        - Corrected parentheses match in example usage
+        - Fix "oject" to "object" in ``MultipartEncoder``
+        - Fix URL for the project after the move 
+        - Add fix for OSX TCPKeepAliveAdapter
+        
+        Miscellaneous
+        ~~~~~~~~~~~~~
+        
+        - Remove py33 from testing and add Python 3.6 and nightly testing to 
the travis matrix.
+        
         0.8.0 -- 2017-05-20
         -------------------
         
@@ -144,7 +189,7 @@
         - Fix backwards incompatibility in ``get_encodings_from_content``
         
         .. _0.8.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.8.0
+            https://github.com/requests/toolbelt/milestones/0.8.0
         
         0.7.1 -- 2017-02-13
         -------------------
@@ -164,7 +209,7 @@
         
         .. links
         .. _0.7.1 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestone/9
+            https://github.com/requests/toolbelt/milestone/9
         
         0.7.0 -- 2016-07-21
         -------------------
@@ -193,7 +238,7 @@
         
         
         .. _0.7.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.7.0
+            https://github.com/requests/toolbelt/milestones/0.7.0
         
         0.6.2 -- 2016-05-10
         -------------------
@@ -247,7 +292,7 @@
         
         
         .. _0.6.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.6.0
+            https://github.com/requests/toolbelt/milestones/0.6.0
         
         0.5.1 -- 2015-12-16
         -------------------
@@ -262,13 +307,13 @@
         
         
         .. _0.5.1 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.5.1
+            https://github.com/requests/toolbelt/milestones/0.5.1
         
         0.5.0 -- 2015-11-24
         -------------------
         
         More information about this release can be found on the `milestone
-        
<https://github.com/sigmavirus24/requests-toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
+        
<https://github.com/requests/toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
         for 0.5.0.
         
         New Features
@@ -307,7 +352,7 @@
         -------------------
         
         For more information about this release, please see `milestone 0.4.0
-        
<https://github.com/sigmavirus24/requests-toolbelt/issues?q=milestone%3A0.4>`_
+        <https://github.com/requests/toolbelt/issues?q=milestone%3A0.4>`_
         on the project's page.
         
         New Features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/README.rst 
new/requests-toolbelt-0.9.1/README.rst
--- old/requests-toolbelt-0.8.0/README.rst      2017-01-19 15:23:03.000000000 
+0100
+++ new/requests-toolbelt-0.9.1/README.rst      2017-06-03 02:35:47.000000000 
+0200
@@ -1,5 +1,5 @@
-requests toolbelt
-=================
+The Requests Toolbelt
+=====================
 
 This is just a collection of utilities for `python-requests`_, but don't 
 really belong in ``requests`` proper. The minimum tested requests version is 
@@ -110,5 +110,8 @@
 <https://toolbelt.readthedocs.org/en/latest/contributing.html>`_ for
 contributing to this project.
 
+Please report any bugs on the `issue tracker`_
+
 .. _Cory Benfield's blog: 
https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/
 .. _python-requests: https://github.com/kennethreitz/requests
+.. _issue tracker: https://github.com/requests/toolbelt/issues
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/dev-requirements.txt 
new/requests-toolbelt-0.9.1/dev-requirements.txt
--- old/requests-toolbelt-0.8.0/dev-requirements.txt    2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/dev-requirements.txt    2019-01-29 
18:43:40.000000000 +0100
@@ -1,3 +1,4 @@
 pytest
 mock
+pyopenssl
 git+git://github.com/sigmavirus24/betamax
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/docs/adapters.rst 
new/requests-toolbelt-0.9.1/docs/adapters.rst
--- old/requests-toolbelt-0.8.0/docs/adapters.rst       2017-03-25 
12:07:58.000000000 +0100
+++ new/requests-toolbelt-0.9.1/docs/adapters.rst       2019-01-29 
18:43:40.000000000 +0100
@@ -21,6 +21,8 @@
 
 - :class:`requests_toolbelt.adapters.host_header_ssl.HostHeaderSSLAdapter`
 
+- :class:`requests_toolbelt.adapters.x509.X509Adapter`
+
 AppEngineAdapter
 ----------------
 
@@ -243,3 +245,25 @@
 
 .. autoclass:: requests_toolbelt.adapters.socket_options.TCPKeepAliveAdapter
 
+X509Adapter
+-----------
+
+Requests supports SSL Verification using a certificate in .pem format by 
default. 
+In some cases it is necessary to pass a full cert chain as part of a request 
or it
+is deemed too great a risk to decrypt the certificate into a .pem file.  
+
+For such use cases we have created
+:class:`~requests_toolbelt.adapters.x509.X509Adapter`.
+Example usage:
+
+.. code-block:: python
+
+      import requests
+      from requests_toolbelt.adapters.x509 import X509Adapter
+      s = requests.Session()
+      a = X509Adapter(max_retries=3,
+                      cert_bytes=b'...', pk_bytes=b'...', encoding='...')
+      s.mount('https://', a)
+
+.. autoclass:: requests_toolbelt.adapters.x509.X509Adapter
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/docs/contributing.rst 
new/requests-toolbelt-0.9.1/docs/contributing.rst
--- old/requests-toolbelt-0.8.0/docs/contributing.rst   2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/docs/contributing.rst   2017-06-03 
02:35:47.000000000 +0200
@@ -155,7 +155,7 @@
        squash your commits or may squash them for you and perform a manual
        merge.
 
-.. _GitHub: https://github.com/sigmavirus24/requests-toolbelt
+.. _GitHub: https://github.com/requests/toolbelt
 .. _GitLab: https://gitlab.com/sigmavirus24/toolbelt
 .. _tox: https://tox.readthedocs.org/en/latest/
 .. _pytest: http://pytest.org/latest/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/docs/uploading-data.rst 
new/requests-toolbelt-0.9.1/docs/uploading-data.rst
--- old/requests-toolbelt-0.8.0/docs/uploading-data.rst 2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/docs/uploading-data.rst 2019-01-29 
18:43:40.000000000 +0100
@@ -109,7 +109,7 @@
 .. autoclass:: requests_toolbelt.multipart.encoder.MultipartEncoderMonitor
 
 .. _an example using clint:
-    
https://gitlab.com/sigmavirus24/toolbelt/blob/master/examples/monitor/progress_bar.py
+    
https://github.com/requests/toolbelt/blob/master/examples/monitor/progress_bar.py
 
 Streaming Data from a Generator
 -------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/__init__.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/__init__.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/__init__.py   2017-05-20 
23:20:06.000000000 +0200
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/__init__.py   2019-01-30 
02:27:51.000000000 +0100
@@ -22,7 +22,7 @@
 __authors__ = 'Ian Cordasco, Cory Benfield'
 __license__ = 'Apache v2.0'
 __copyright__ = 'Copyright 2014 Ian Cordasco, Cory Benfield'
-__version__ = '0.8.0'
+__version__ = '0.9.1'
 __version_info__ = tuple(int(i) for i in __version__.split('.'))
 
 __all__ = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/requests_toolbelt/_compat.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/_compat.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/_compat.py    2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/_compat.py    2019-01-30 
02:26:45.000000000 +0100
@@ -8,7 +8,6 @@
     This module is private. If you use it, and something breaks, you were
     warned
 """
-from collections import Mapping, MutableMapping
 import sys
 
 import requests
@@ -50,12 +49,26 @@
     except ImportError:
         from urllib3.contrib import appengine as gaecontrib
 
+if requests.__build__ < 0x021200:
+    PyOpenSSLContext = None
+else:
+    try:
+        from requests.packages.urllib3.contrib.pyopenssl \
+                import PyOpenSSLContext
+    except ImportError:
+        try:
+            from urllib3.contrib.pyopenssl import PyOpenSSLContext
+        except ImportError:
+            PyOpenSSLContext = None
+
 PY3 = sys.version_info > (3, 0)
 
 if PY3:
+    from collections.abc import Mapping, MutableMapping
     import queue
     from urllib.parse import urlencode, urljoin
 else:
+    from collections import Mapping, MutableMapping
     import Queue as queue
     from urllib import urlencode
     from urlparse import urljoin
@@ -307,4 +320,5 @@
     'urlencode',
     'gaecontrib',
     'urljoin',
+    'PyOpenSSLContext',
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/socket_options.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/socket_options.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/socket_options.py    
2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/socket_options.py    
2017-06-03 02:35:47.000000000 +0200
@@ -2,6 +2,7 @@
 """The implementation of the SocketOptionsAdapter."""
 import socket
 import warnings
+import sys
 
 import requests
 from requests import adapters
@@ -103,13 +104,23 @@
         interval = kwargs.pop('interval', 20)
         count = kwargs.pop('count', 5)
         socket_options = socket_options + [
-            (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
-            (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval),
-            (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, count),
+            (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
         ]
 
-        # NOTE(Ian): Apparently OSX does not have this constant defined, so we
-        # set it conditionally.
+        # NOTE(Ian): OSX does not have these constants defined, so we
+        # set them conditionally.
+        if getattr(socket, 'TCP_KEEPINTVL', None) is not None:
+            socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL,
+                                interval)]
+        elif sys.platform == 'darwin':
+            # On OSX, TCP_KEEPALIVE from netinet/tcp.h is not exported
+            # by python's socket module
+            TCP_KEEPALIVE = getattr(socket, 'TCP_KEEPALIVE', 0x10)
+            socket_options += [(socket.IPPROTO_TCP, TCP_KEEPALIVE, interval)]
+
+        if getattr(socket, 'TCP_KEEPCNT', None) is not None:
+            socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, count)]
+
         if getattr(socket, 'TCP_KEEPIDLE', None) is not None:
             socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, idle)]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/source.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/source.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/source.py    
2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/source.py    
2018-01-05 13:36:25.000000000 +0100
@@ -40,7 +40,7 @@
 
         s = requests.Session()
         s.mount('http://', SourceAddressAdapter('10.10.10.10'))
-        s.mount('https://', SourceAddressAdapter(('10.10.10.10', 8999))
+        s.mount('https://', SourceAddressAdapter(('10.10.10.10', 8999)))
     """
     def __init__(self, source_address, **kwargs):
         if isinstance(source_address, basestring):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/x509.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/x509.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/adapters/x509.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/adapters/x509.py      
2019-01-29 18:43:40.000000000 +0100
@@ -0,0 +1,178 @@
+# -*- coding: utf-8 -*-
+"""A X509Adapter for use with the requests library.
+
+This file contains an implementation of the X509Adapter that will
+allow users to authenticate a request using an arbitrary
+X.509 certificate without needing to convert it to a .pem file
+
+"""
+
+from OpenSSL.crypto import PKey, X509
+from cryptography import x509
+from cryptography.hazmat.primitives.serialization import (load_pem_private_key,
+                                                          load_der_private_key)
+from cryptography.hazmat.primitives.serialization import Encoding
+from cryptography.hazmat.backends import default_backend
+
+from datetime import datetime
+from requests.adapters import HTTPAdapter
+import requests
+
+from .._compat import PyOpenSSLContext
+from .. import exceptions as exc
+
+"""
+importing the protocol constants from _ssl instead of ssl because only the
+constants are needed and to handle issues caused by importing from ssl on
+the 2.7.x line.
+"""
+try:
+    from _ssl import PROTOCOL_TLS as PROTOCOL
+except ImportError:
+    from _ssl import PROTOCOL_SSLv23 as PROTOCOL
+
+
+class X509Adapter(HTTPAdapter):
+    r"""Adapter for use with X.509 certificates.
+
+    Provides an interface for Requests sessions to contact HTTPS urls and
+    authenticate  with an X.509 cert by implementing the Transport Adapter
+    interface. This class will need to be manually instantiated and mounted
+    to the session
+
+    :param pool_connections: The number of urllib3 connection pools to
+           cache.
+    :param pool_maxsize: The maximum number of connections to save in the
+            pool.
+    :param max_retries: The maximum number of retries each connection
+        should attempt. Note, this applies only to failed DNS lookups,
+        socket connections and connection timeouts, never to requests where
+        data has made it to the server. By default, Requests does not retry
+        failed connections. If you need granular control over the
+        conditions under which we retry a request, import urllib3's
+        ``Retry`` class and pass that instead.
+    :param pool_block: Whether the connection pool should block for
+            connections.
+
+    :param bytes cert_bytes:
+        bytes object containing contents of a cryptography.x509Certificate
+        object using the encoding specified by the ``encoding`` parameter.
+    :param bytes pk_bytes:
+        bytes object containing contents of a object that implements
+        ``cryptography.hazmat.primitives.serialization.PrivateFormat``
+        using the encoding specified by the ``encoding`` parameter.
+    :param password:
+        string or utf8 encoded bytes containing the passphrase used for the
+        private key. None if unencrypted. Defaults to None.
+    :param encoding:
+        Enumeration detailing the encoding method used on the ``cert_bytes``
+        parameter. Can be either PEM or DER. Defaults to PEM.
+    :type encoding:
+        :class: `cryptography.hazmat.primitives.serialization.Encoding`
+
+    Usage::
+
+      >>> import requests
+      >>> from requests_toolbelt.adapters.x509 import X509Adapter
+      >>> s = requests.Session()
+      >>> a = X509Adapter(max_retries=3,
+                cert_bytes=b'...', pk_bytes=b'...', encoding='...'
+      >>> s.mount('https://', a)
+    """
+
+    def __init__(self, *args, **kwargs):
+        self._check_version()
+        cert_bytes = kwargs.pop('cert_bytes', None)
+        pk_bytes = kwargs.pop('pk_bytes', None)
+        password = kwargs.pop('password', None)
+        encoding = kwargs.pop('encoding', Encoding.PEM)
+
+        password_bytes = None
+
+        if cert_bytes is None or not isinstance(cert_bytes, bytes):
+            raise ValueError('Invalid cert content provided. '
+                             'You must provide an X.509 cert '
+                             'formatted as a byte array.')
+        if pk_bytes is None or not isinstance(pk_bytes, bytes):
+            raise ValueError('Invalid private key content provided. '
+                             'You must provide a private key '
+                             'formatted as a byte array.')
+
+        if isinstance(password, bytes):
+            password_bytes = password
+        elif password:
+            password_bytes = password.encode('utf8')
+
+        self.ssl_context = create_ssl_context(cert_bytes, pk_bytes,
+                                              password_bytes, encoding)
+
+        super(X509Adapter, self).__init__(*args, **kwargs)
+
+    def init_poolmanager(self, *args, **kwargs):
+        if self.ssl_context:
+            kwargs['ssl_context'] = self.ssl_context
+        return super(X509Adapter, self).init_poolmanager(*args, **kwargs)
+
+    def proxy_manager_for(self, *args, **kwargs):
+        if self.ssl_context:
+            kwargs['ssl_context'] = self.ssl_context
+        return super(X509Adapter, self).proxy_manager_for(*args, **kwargs)
+
+    def _check_version(self):
+        if PyOpenSSLContext is None:
+            raise exc.VersionMismatchError(
+                "The X509Adapter requires at least Requests 2.12.0 to be "
+                "installed. Version {0} was found instead.".format(
+                    requests.__version__
+                )
+            )
+
+
+def check_cert_dates(cert):
+    """Verify that the supplied client cert is not invalid."""
+
+    now = datetime.utcnow()
+    if cert.not_valid_after < now or cert.not_valid_before > now:
+        raise ValueError('Client certificate expired: Not After: '
+                         '{0:%Y-%m-%d %H:%M:%SZ} '
+                         'Not Before: {1:%Y-%m-%d %H:%M:%SZ}'
+                         .format(cert.not_valid_after, cert.not_valid_before))
+
+
+def create_ssl_context(cert_byes, pk_bytes, password=None,
+                       encoding=Encoding.PEM):
+    """Create an SSL Context with the supplied cert/password.
+
+    :param cert_bytes array of bytes containing the cert encoded
+           using the method supplied in the ``encoding`` parameter
+    :param pk_bytes array of bytes containing the private key encoded
+           using the method supplied in the ``encoding`` parameter
+    :param password array of bytes containing the passphrase to be used
+           with the supplied private key. None if unencrypted.
+           Defaults to None.
+    :param encoding ``cryptography.hazmat.primitives.serialization.Encoding``
+            details the encoding method used on the ``cert_bytes``  and
+            ``pk_bytes`` parameters. Can be either PEM or DER.
+            Defaults to PEM.
+    """
+    backend = default_backend()
+
+    cert = None
+    key = None
+    if encoding == Encoding.PEM:
+        cert = x509.load_pem_x509_certificate(cert_byes, backend)
+        key = load_pem_private_key(pk_bytes, password, backend)
+    elif encoding == Encoding.DER:
+        cert = x509.load_der_x509_certificate(cert_byes, backend)
+        key = load_der_private_key(pk_bytes, password, backend)
+    else:
+        raise ValueError('Invalid encoding provided: Must be PEM or DER')
+
+    if not (cert and key):
+        raise ValueError('Cert and key could not be parsed from '
+                         'provided data')
+    check_cert_dates(cert)
+    ssl_context = PyOpenSSLContext(PROTOCOL)
+    ssl_context._ctx.use_certificate(X509.from_cryptography(cert))
+    ssl_context._ctx.use_privatekey(PKey.from_cryptography_key(key))
+    return ssl_context
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/multipart/decoder.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/multipart/decoder.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/multipart/decoder.py  
2017-02-10 22:55:25.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/multipart/decoder.py  
2018-10-08 13:43:24.000000000 +0200
@@ -45,7 +45,7 @@
     subpart of a multipart response. It is expected that these will
     generally be created by objects of the ``MultipartDecoder`` class.
 
-    Like ``Response``, there is a ``CaseInsensitiveDict`` object named header,
+    Like ``Response``, there is a ``CaseInsensitiveDict`` object named headers,
     ``content`` to access bytes, ``text`` to access unicode, and ``encoding``
     to access the unicode codec.
 
@@ -85,7 +85,7 @@
         response = request.get(url)
         decoder = MultipartDecoder.from_response(response)
         for part in decoder.parts:
-            print(part.header['content-type'])
+            print(part.headers['content-type'])
 
     If the multipart content is not from a response, basic usage is::
 
@@ -93,7 +93,7 @@
 
         decoder = MultipartDecoder(content, content_type)
         for part in decoder.parts:
-            print(part.header['content-type'])
+            print(part.headers['content-type'])
 
     For both these usages, there is an optional ``encoding`` parameter. This is
     a string, which is the name of the unicode codec to use (default is
@@ -101,8 +101,6 @@
 
     """
     def __init__(self, content, content_type, encoding='utf-8'):
-        #: Original content
-        self.content = content
         #: Original Content-Type header
         self.content_type = content_type
         #: Response body encoding
@@ -110,12 +108,12 @@
         #: Parsed parts of the multipart response body
         self.parts = tuple()
         self._find_boundary()
-        self._parse_body()
+        self._parse_body(content)
 
     def _find_boundary(self):
         ct_info = tuple(x.strip() for x in self.content_type.split(';'))
         mimetype = ct_info[0]
-        if mimetype.split('/')[0] != 'multipart':
+        if mimetype.split('/')[0].lower() != 'multipart':
             raise NonMultipartContentTypeException(
                 "Unexpected mimetype in content-type: '{0}'".format(mimetype)
             )
@@ -135,7 +133,7 @@
         else:
             return part
 
-    def _parse_body(self):
+    def _parse_body(self, content):
         boundary = b''.join((b'--', self.boundary))
 
         def body_part(part):
@@ -148,7 +146,7 @@
                     part[:4] != b'--\r\n' and
                     part != b'--')
 
-        parts = self.content.split(b''.join((b'\r\n', boundary)))
+        parts = content.split(b''.join((b'\r\n', boundary)))
         self.parts = tuple(body_part(x) for x in parts if test_part(x))
 
     @classmethod
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/multipart/encoder.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/multipart/encoder.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/multipart/encoder.py  
2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/multipart/encoder.py  
2018-10-08 13:43:24.000000000 +0200
@@ -12,14 +12,20 @@
 import os
 from uuid import uuid4
 
+import requests
+
 from .._compat import fields
 
 
+class FileNotSupportedError(Exception):
+    """File not supported error."""
+
+
 class MultipartEncoder(object):
 
     """
 
-    The ``MultipartEncoder`` oject is a generic interface to the engine that
+    The ``MultipartEncoder`` object is a generic interface to the engine that
     will create a ``multipart/form-data`` body for you.
 
     The basic usage is:
@@ -74,7 +80,7 @@
         please weigh in on `this issue`_.
 
     .. _this issue:
-        https://github.com/sigmavirus24/requests-toolbelt/issues/75
+        https://github.com/requests/toolbelt/issues/75
 
     """
 
@@ -136,7 +142,7 @@
         As such, we now calculate the length lazily as a property.
 
         .. _bug #80:
-            https://github.com/sigmavirus24/requests-toolbelt/issues/80
+            https://github.com/requests/toolbelt/issues/80
         """
         # If _len isn't already calculated, calculate, return, and set it
         return self._len or self._calculate_length()
@@ -184,7 +190,7 @@
         part = self._current_part or self._next_part()
         while amount == -1 or amount > 0:
             written = 0
-            if not part.bytes_left_to_write():
+            if part and not part.bytes_left_to_write():
                 written += self._write(b'\r\n')
                 written += self._write_boundary()
                 part = self._next_part()
@@ -333,13 +339,13 @@
                                        MultipartEncoderMonitor)
         import requests
 
-        def callback(encoder, bytes_read):
+        def callback(monitor):
             # Do something with this information
             pass
 
         m = MultipartEncoder(fields={'field0': 'value0'})
         monitor = MultipartEncoderMonitor(m, callback)
-        headers = {'Content-Type': montior.content_type}
+        headers = {'Content-Type': monitor.content_type}
         r = requests.post('https://httpbin.org/post', data=monitor,
                           headers=headers)
 
@@ -351,7 +357,7 @@
         from requests_toolbelt import MultipartEncoderMonitor
         import requests
 
-        def callback(encoder, bytes_read):
+        def callback(monitor):
             # Do something with this information
             pass
 
@@ -568,3 +574,82 @@
 
     def read(self, length=-1):
         return self.fd.read(length)
+
+
+class FileFromURLWrapper(object):
+    """File from URL wrapper.
+
+    The :class:`FileFromURLWrapper` object gives you the ability to stream file
+    from provided URL in chunks by :class:`MultipartEncoder`.
+    Provide a stateless solution for streaming file from one server to another.
+    You can use the :class:`FileFromURLWrapper` without a session or with
+    a session as demonstated by the examples below:
+
+    .. code-block:: python
+        # no session
+
+        import requests
+        from requests_toolbelt import MultipartEncoder, FileFromURLWrapper
+
+        url = 'https://httpbin.org/image/png'
+        streaming_encoder = MultipartEncoder(
+            fields={
+                'file': FileFromURLWrapper(url)
+            }
+        )
+        r = requests.post(
+            'https://httpbin.org/post', data=streaming_encoder,
+            headers={'Content-Type': streaming_encoder.content_type}
+        )
+
+    .. code-block:: python
+        # using a session
+
+        import requests
+        from requests_toolbelt import MultipartEncoder, FileFromURLWrapper
+
+        session = requests.Session()
+        url = 'https://httpbin.org/image/png'
+        streaming_encoder = MultipartEncoder(
+            fields={
+                'file': FileFromURLWrapper(url, session=session)
+            }
+        )
+        r = session.post(
+            'https://httpbin.org/post', data=streaming_encoder,
+            headers={'Content-Type': streaming_encoder.content_type}
+        )
+
+    """
+
+    def __init__(self, file_url, session=None):
+        self.session = session or requests.Session()
+        requested_file = self._request_for_file(file_url)
+        self.len = int(requested_file.headers['content-length'])
+        self.raw_data = requested_file.raw
+
+    def _request_for_file(self, file_url):
+        """Make call for file under provided URL."""
+        response = self.session.get(file_url, stream=True)
+        content_length = response.headers.get('content-length', None)
+        if content_length is None:
+            error_msg = (
+                "Data from provided URL {url} is not supported. Lack of "
+                "content-length Header in requested file response.".format(
+                    url=file_url)
+            )
+            raise FileNotSupportedError(error_msg)
+        elif not content_length.isdigit():
+            error_msg = (
+                "Data from provided URL {url} is not supported. content-length"
+                " header value is not a digit.".format(url=file_url)
+            )
+            raise FileNotSupportedError(error_msg)
+        return response
+
+    def read(self, chunk_size):
+        """Read file in chunks."""
+        chunk_size = chunk_size if chunk_size >= 0 else self.len
+        chunk = self.raw_data.read(chunk_size) or b''
+        self.len -= len(chunk) if chunk else 0  # left to read
+        return chunk
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/threaded/__init__.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/threaded/__init__.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/threaded/__init__.py  
2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/threaded/__init__.py  
2017-06-03 02:35:47.000000000 +0200
@@ -14,7 +14,7 @@
         'url': 'https://api.github.com/users/sigmavirus24',
         'method': 'GET',
     }, {
-        'url': 'https://api.github.com/repos/sigmavirus24/requests-toolbelt',
+        'url': 'https://api.github.com/repos/requests/toolbelt',
         'method': 'GET',
     }, {
         'url': 'https://google.com',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/threaded/pool.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/threaded/pool.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/threaded/pool.py      
2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/threaded/pool.py      
2018-01-05 13:36:25.000000000 +0100
@@ -18,7 +18,7 @@
     :param auth_generator:
         Function used to generate new auth credentials for the session.
     :type auth_generator: collections.Callable
-    :param int num_threads:
+    :param int num_process:
         Number of threads to create.
     :param session:
     :type session: requests.Session
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt/utils/dump.py 
new/requests-toolbelt-0.9.1/requests_toolbelt/utils/dump.py
--- old/requests-toolbelt-0.8.0/requests_toolbelt/utils/dump.py 2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/requests_toolbelt/utils/dump.py 2019-01-29 
18:43:33.000000000 +0100
@@ -44,7 +44,8 @@
     uri = compat.urlparse(url)
     proxy_url = proxy_info.get('request_path')
     if proxy_url is not None:
-        return proxy_url, uri
+        request_path = _coerce_to_bytes(proxy_url)
+        return request_path, uri
 
     request_path = _coerce_to_bytes(uri.path)
     if uri.query:
@@ -79,7 +80,7 @@
         else:
             # In the event that the body is a file-like object, let's not try
             # to read everything into memory.
-            bytearr.extend('<< Request body is not a string-like type >>')
+            bytearr.extend(b'<< Request body is not a string-like type >>')
     bytearr.extend(b'\r\n')
 
 
@@ -109,7 +110,8 @@
 def _coerce_to_bytes(data):
     if not isinstance(data, bytes) and hasattr(data, 'encode'):
         data = data.encode('utf-8')
-    return data
+    # Don't bail out with an exception if data is None
+    return data if data is not None else b''
 
 
 def dump_response(response, request_prefix=b'< ', response_prefix=b'> ',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/PKG-INFO 
new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/PKG-INFO
--- old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/PKG-INFO     
2017-05-20 23:32:32.000000000 +0200
+++ new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/PKG-INFO     
2019-01-30 02:29:41.000000000 +0100
@@ -1,13 +1,13 @@
 Metadata-Version: 1.1
 Name: requests-toolbelt
-Version: 0.8.0
+Version: 0.9.1
 Summary: A utility belt for advanced users of python-requests
 Home-page: https://toolbelt.readthedocs.org
 Author: Ian Cordasco, Cory Benfield
 Author-email: [email protected]
 License: Apache 2.0
-Description: requests toolbelt
-        =================
+Description: The Requests Toolbelt
+        =====================
         
         This is just a collection of utilities for `python-requests`_, but 
don't 
         really belong in ``requests`` proper. The minimum tested requests 
version is 
@@ -118,13 +118,58 @@
         <https://toolbelt.readthedocs.org/en/latest/contributing.html>`_ for
         contributing to this project.
         
+        Please report any bugs on the `issue tracker`_
+        
         .. _Cory Benfield's blog: 
https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/
         .. _python-requests: https://github.com/kennethreitz/requests
+        .. _issue tracker: https://github.com/requests/toolbelt/issues
         
         
         History
         =======
         
+        0.9.1 -- 2019-01-29
+        -------------------
+        
+        Fixed Bugs
+        ~~~~~~~~~~
+        
+        - Fix import of pyOpenSSL shim from urllib3 for PKCS12 adapter
+        
+        0.9.0 -- 2019-01-29
+        -------------------
+        
+        New Features
+        ~~~~~~~~~~~~
+        
+        - Add X509 Adapter that can handle PKCS12 
+        - Add stateless solution for streaming files by MultipartEncoder from 
one host to another (in chunks)
+        
+        Fixed Bugs
+        ~~~~~~~~~~
+        
+        - Update link to example
+        - Move import of ``ABCs`` from collections into version-specific part 
of
+          _compat module
+        - Fix backwards incompatibility in ``get_encodings_from_content``
+        - Correct callback documentation for ``MultipartEncoderMonitor``
+        - Fix bug when ``MultipartEncoder`` is asked to encode zero parts
+        - Correct the type of non string request body dumps
+        - Removed content from being stored in MultipartDecoder
+        - Fix bug by enabling support for contenttype with capital letters. 
+        - Coerce proxy URL to bytes before dumping request
+        - Avoid bailing out with exception upon empty response reason
+        - Corrected Pool documentation
+        - Corrected parentheses match in example usage
+        - Fix "oject" to "object" in ``MultipartEncoder``
+        - Fix URL for the project after the move 
+        - Add fix for OSX TCPKeepAliveAdapter
+        
+        Miscellaneous
+        ~~~~~~~~~~~~~
+        
+        - Remove py33 from testing and add Python 3.6 and nightly testing to 
the travis matrix.
+        
         0.8.0 -- 2017-05-20
         -------------------
         
@@ -144,7 +189,7 @@
         - Fix backwards incompatibility in ``get_encodings_from_content``
         
         .. _0.8.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.8.0
+            https://github.com/requests/toolbelt/milestones/0.8.0
         
         0.7.1 -- 2017-02-13
         -------------------
@@ -164,7 +209,7 @@
         
         .. links
         .. _0.7.1 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestone/9
+            https://github.com/requests/toolbelt/milestone/9
         
         0.7.0 -- 2016-07-21
         -------------------
@@ -193,7 +238,7 @@
         
         
         .. _0.7.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.7.0
+            https://github.com/requests/toolbelt/milestones/0.7.0
         
         0.6.2 -- 2016-05-10
         -------------------
@@ -247,7 +292,7 @@
         
         
         .. _0.6.0 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.6.0
+            https://github.com/requests/toolbelt/milestones/0.6.0
         
         0.5.1 -- 2015-12-16
         -------------------
@@ -262,13 +307,13 @@
         
         
         .. _0.5.1 milestone:
-            https://github.com/sigmavirus24/requests-toolbelt/milestones/0.5.1
+            https://github.com/requests/toolbelt/milestones/0.5.1
         
         0.5.0 -- 2015-11-24
         -------------------
         
         More information about this release can be found on the `milestone
-        
<https://github.com/sigmavirus24/requests-toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
+        
<https://github.com/requests/toolbelt/issues?utf8=%E2%9C%93&q=is%3Aall+milestone%3A0.5+>`_
         for 0.5.0.
         
         New Features
@@ -307,7 +352,7 @@
         -------------------
         
         For more information about this release, please see `milestone 0.4.0
-        
<https://github.com/sigmavirus24/requests-toolbelt/issues?q=milestone%3A0.4>`_
+        <https://github.com/requests/toolbelt/issues?q=milestone%3A0.4>`_
         on the project's page.
         
         New Features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/SOURCES.txt 
new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/SOURCES.txt
--- old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/SOURCES.txt  
2017-05-20 23:32:33.000000000 +0200
+++ new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/SOURCES.txt  
2019-01-30 02:29:41.000000000 +0100
@@ -42,6 +42,7 @@
 requests_toolbelt/adapters/socket_options.py
 requests_toolbelt/adapters/source.py
 requests_toolbelt/adapters/ssl.py
+requests_toolbelt/adapters/x509.py
 requests_toolbelt/auth/__init__.py
 requests_toolbelt/auth/_digest_auth_compat.py
 requests_toolbelt/auth/guess.py
@@ -84,6 +85,8 @@
 tests/test_ssladapter.py
 tests/test_streaming_iterator.py
 tests/test_user_agent.py
+tests/test_x509_adapter.py
+tests/cassettes/file_for_download.json
 tests/cassettes/http2bin_cookies.json
 tests/cassettes/http2bin_fingerprint.json
 tests/cassettes/httpbin_guess_auth_basic.json
@@ -93,6 +96,9 @@
 tests/cassettes/redirect_request_for_dump_all.json
 tests/cassettes/simple_get_request.json
 tests/cassettes/stream_response_to_file.json
+tests/cassettes/test_x509_adapter_der.json
+tests/cassettes/test_x509_adapter_pem.json
+tests/certs/test_cert.p12
 tests/threaded/__init__.py
 tests/threaded/test_api.py
 tests/threaded/test_pool.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/requires.txt 
new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/requires.txt
--- old/requests-toolbelt-0.8.0/requests_toolbelt.egg-info/requires.txt 
2017-05-20 23:32:32.000000000 +0200
+++ new/requests-toolbelt-0.9.1/requests_toolbelt.egg-info/requires.txt 
2019-01-30 02:29:41.000000000 +0100
@@ -1 +1 @@
-requests>=2.0.1,<3.0.0
+requests<3.0.0,>=2.0.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/tests/cassettes/file_for_download.json 
new/requests-toolbelt-0.9.1/tests/cassettes/file_for_download.json
--- old/requests-toolbelt-0.8.0/tests/cassettes/file_for_download.json  
1970-01-01 01:00:00.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/cassettes/file_for_download.json  
2018-10-08 13:43:24.000000000 +0200
@@ -0,0 +1 @@
+{"http_interactions": [{"request": {"uri": 
"https://stxnext.com/static/img/logo.830ebe551641.svg";, "body": {"encoding": 
"utf-8", "string": ""}, "method": "GET", "headers": {"User-Agent": 
["python-requests/2.2.1 CPython/3.5.2 Darwin/17.3.0"], "Accept-Encoding": 
["gzip, deflate, compress"], "Accept": ["*/*"]}}, "recorded_at": 
"2018-01-04T23:00:12", "response": {"url": 
"https://stxnext.com/static/img/logo.830ebe551641.svg";, "status": {"message": 
"OK", "code": 200}, "body": {"encoding": null, "string": "<svg 
xmlns=\"http://www.w3.org/2000/svg\"; 
xmlns:xlink=\"http://www.w3.org/1999/xlink\"; viewBox=\"-16169 -10492.84 144.98 
39.947\"><defs><style>.a{fill:url(#a);}</style><linearGradient id=\"a\" 
x2=\"1\" y2=\"1\" gradientUnits=\"objectBoundingBox\"><stop offset=\"0\" 
stop-color=\"#15c9c2\"/><stop offset=\"1\" 
stop-color=\"#39769b\"/></linearGradient></defs><path class=\"a\" 
d=\"M88.841,54.948V48.514a3.665,3.665,0,0,1,1.541-.336,2.169,2.169,0,0,1,2.266,2.435A2.182,2.182,0,0,1,90.435,53.1a2.9,2.9,0,0,1-.85-.125v1.974Zm.744-6.019v3.46a2.558,2.558,0,0,0,.8.125c1,0,1.523-.807,1.523-1.9s-.525-1.84-1.506-1.84h-.041A1.986,1.986,0,0,0,89.585,48.929ZM62.838,54.948l.717-1.9-1.788-4.769h.805l1.187,3.472a5.008,5.008,0,0,1,.167.682h.019a5.01,5.01,0,0,1,.167-.682l1.177-3.472h.815l-2.5,6.672Zm-5.749,0V48.514a3.669,3.669,0,0,1,1.541-.336A2.169,2.169,0,0,1,60.9,50.613,2.185,2.185,0,0,1,58.683,53.1a2.9,2.9,0,0,1-.85-.125v1.974Zm.74-6.019v3.46a2.558,2.558,0,0,0,.8.125c1,0,1.523-.807,1.523-1.9s-.529-1.84-1.513-1.84H58.6A1.986,1.986,0,0,0,57.829,48.929Zm79.213,4.213a2.19,2.19,0,0,1-2.282-2.487c0-1.462.788-2.478,2.08-2.478a1.825,1.825,0,0,1,1.9,2.044c0,.1,0,.205-.008.318l-3.257.469a1.5,1.5,0,0,0,1.6,1.532,2.886,2.886,0,0,0,1.3-.292l.23.557a3.431,3.431,0,0,1-1.484.336ZM135.432,50.5l2.6-.366c-.011-.944-.488-1.386-1.2-1.386C135.989,48.744,135.45,49.416,135.432,50.5ZM130.4,52.8l.265-.567a2.665,2.665,0,0,0,1.143.3c.611,0,1.018-.3,1.018-.77,0-.5-.407-.7-.965-.9-.673-.248-1.336-.549-1.336-1.408,0-.744.575-1.279,1.585-1.279a2.6,2.6,0,0,1,1.327.336l-.257.523a2.054,2.054,0,0,0-1-.283c-.576,0-.9.309-.9.707,0,.5.388.682.913.875.708.265,1.4.549,1.4,1.434.006.823-.649,1.372-1.772,1.372A3.261,3.261,0,0,1,130.4,52.8Zm-3.008.34c-1.187,0-1.841-.523-1.841-1.672V48.276h.744v3.2c0,.707.366,1.043,1.1,1.043a2.914,2.914,0,0,0,1.008-.158V48.276h.73V52.8a4.263,4.263,0,0,1-1.664.34Zm-7.256-2.487c0-1.417.708-2.478,2.028-2.478s2.026,1.061,2.026,2.478-.709,2.487-2.026,2.487S120.14,52.071,120.14,50.655Zm.735-.007c0,1.1.424,1.884,1.292,1.884s1.291-.788,1.291-1.884-.425-1.866-1.291-1.866v0C121.3,48.779,120.875,49.549,120.875,50.648Zm-12.187,2.494a2.19,2.19,0,0,1-2.282-2.487c0-1.462.788-2.478,2.08-2.478a1.825,1.825,0,0,1,1.9,2.044c0,.1,0,.205-.009.318l-3.256.469a1.494,1.494,0,0,0,1.6,1.532,2.886,2.886,0,0,0,1.3-.292l.23.557a3.431,3.431,0,0,1-1.484.336ZM107.079,50.5l2.6-.366c-.01-.944-.488-1.386-1.2-1.386C107.636,48.744,107.1,49.416,107.079,50.5Zm-13.249.159c0-1.417.708-2.478,2.028-2.478s2.026,1.061,2.026,2.478-.707,2.487-2.026,2.487S93.83,52.071,93.83,50.655Zm.735-.007c0,1.1.424,1.884,1.292,1.884s1.291-.788,1.291-1.884-.424-1.866-1.291-1.866v0C94.989,48.779,94.565,49.549,94.565,50.648Zm-18.973.007c0-1.417.708-2.478,2.028-2.478s2.032,1.061,2.032,2.478-.715,2.487-2.032,2.487S75.592,52.071,75.592,50.655Zm.735-.007c0,1.1.424,1.884,1.292,1.884s1.292-.788,1.292-1.884-.426-1.866-1.292-1.866v0C76.752,48.779,76.328,49.549,76.328,50.648ZM68.85,53.1a1.149,1.149,0,0,1-1.257-1.292V48.833H66.9v-.557h.688V47.123l.716-.239v1.389h1.027v.557H68.306v2.939a.634.634,0,0,0,.716.673,1.006,1.006,0,0,0,.309-.044v.619a1.308,1.308,0,0,1-.453.081Zm15.078-.053V49.823c0-.638-.39-1.044-1.158-1.044a2.968,2.968,0,0,0-1.018.169v4.1h-.745V48.513a4.5,4.5,0,0,1,1.753-.336c1.257,0,1.9.584,1.9,1.585v3.289Zm34.114-3.212c0-.7-.461-1.037-1.187-1.037a2.036,2.036,0,0,0-.989.265v3.983h-.744V46.1h.744v2.376A2.616,2.616,0,0,1,117,48.191c1.1,0,1.778.557,1.778,1.585v3.265l-.734,0Zm-6.285,3.212V48.513a4.493,4.493,0,0,1,1.743-.336,3.273,3.273,0,0,1,.47.034l-.143.621a2.031,2.031,0,0,0-.424-.034,2.461,2.461,0,0,0-.9.15v4.1Zm-8.485,0-.974-3.327a5.884,5.884,0,0,1-.14-.654h-.019s-.062.354-.15.654l-.974,3.327h-.753l-1.45-4.769h.744l.93,3.371a7.42,7.42,0,0,1,.15.732h.019s.07-.407.158-.732l.974-3.371h.709l.966,3.371c.088.318.167.732.167.732h.019a6.418,6.418,0,0,1,.143-.732l.947-3.371h.731l-1.442,4.769ZM73.5,49.833c0-.7-.461-1.037-1.187-1.037a2.044,2.044,0,0,0-.991.265v3.983h-.744V46.1h.744v2.376a2.612,2.612,0,0,1,1.133-.283c1.1,0,1.778.557,1.778,1.585v3.265l-.734,0Zm-27.141-6,8.837-14.534L46.91,15.475h7.926l7.925,13.819L54.32,43.828Zm-15.478,0V21.688H23.911V15.474H44.819v6.213H37.846V43.828ZM0,40.086l4.455-4.463c1.473,1.473,4.064,1.99,6.331,1.99,2.741,0,4.062-.913,4.062-2.548a2.4,2.4,0,0,0-.548-1.671,3.133,3.133,0,0,0-1.872-.757L9,32.158A9.631,9.631,0,0,1,3.31,29.651a7.847,7.847,0,0,1-1.953-5.7C1.358,18.778,5.26,15,11.712,15c4.06,0,7.127.956,9.558,3.385l-4.387,4.385C15.092,20.98,12.742,21.1,11.506,21.1c-2.429,0-3.424,1.394-3.424,2.63a1.868,1.868,0,0,0,.557,1.315,3.179,3.179,0,0,0,1.952.836l3.426.48a9.569,9.569,0,0,1,5.576,2.348c1.513,1.473,2.111,3.584,2.111,6.213,0,5.761-4.982,8.907-10.95,8.907C6.412,43.828,2.866,43.031,0,40.086Zm111.6,3.73,6.958-11.665-6.518-11.076h2.81l5.048,8.975,5.046-8.975h2.812L121.2,32.15l7.027,11.658-2.812.006L119.9,34.265l-5.558,9.55Zm24.376,0V23.245h-6.579V21.074h15.588v2.171H138.4V43.814ZM95.878,21.074H109.99v2.173h-11.7v8.018h9.966v2.165H98.3v8.21H110v2.173l-14.123,0ZM90.192,43.814,78.12,25.571V43.808H75.692V21.074h2.3L90.069,39.247V21.074H92.5V43.814ZM63.528,43.8l-2.683-5.029,3.7-6.344,6.611,11.379Zm-2.7-24.291,2.094-4.046h7.919L64.668,26.125Z\"
 transform=\"translate(-16169 -10507.84)\"/></svg>"}, "headers": {"date": 
["Thu, 04 Jan 2018 23:00:15 GMT"], "strict-transport-security": ["max-age=0; 
includeSubdomains; preload"], "last-modified": ["Wed, 22 Nov 2017 09:22:00 
GMT"], "content-type": ["image/svg+xml"], "content-length": ["5177"]}}}], 
"recorded_with": "betamax/0.8.0"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/tests/cassettes/test_x509_adapter_der.json 
new/requests-toolbelt-0.9.1/tests/cassettes/test_x509_adapter_der.json
--- old/requests-toolbelt-0.8.0/tests/cassettes/test_x509_adapter_der.json      
1970-01-01 01:00:00.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/cassettes/test_x509_adapter_der.json      
2019-01-29 18:43:40.000000000 +0100
@@ -0,0 +1 @@
+{"http_interactions": [{"request": {"body": {"encoding": "utf-8", "string": 
""}, "headers": {"User-Agent": ["python-requests/2.21.0"], "Accept-Encoding": 
["gzip, deflate"], "Accept": ["*/*"], "Connection": ["keep-alive"]}, "method": 
"GET", "uri": "https://pkiprojecttest01.dev.labs.internal/"}, "response": 
{"body": {"encoding": "ISO-8859-1", "base64_string": 
"H4sIAAAAAAAAA7NRdPF3DokMcFXIKMnNseOygVJJ+SmVdlxArqFdSGpxiY0+kAHkFoB5CsGlycmpxcU2+gUgQX2IYqAasBEAYvDs5FMAAAA=",
 "string": ""}, "headers": {"Server": ["nginx/1.10.3 (Ubuntu)"], "Date": ["Thu, 
20 Dec 2018 20:02:30 GMT"], "Content-Type": ["text/html"], "Last-Modified": 
["Mon, 19 Nov 2018 20:48:30 GMT"], "Transfer-Encoding": ["chunked"], 
"Connection": ["keep-alive"], "ETag": ["W/\"5bf3219e-53\""], 
"Content-Encoding": ["gzip"]}, "status": {"code": 200, "message": "OK"}, "url": 
"https://pkiprojecttest01.dev.labs.internal/"}, "recorded_at": 
"2018-12-20T20:02:30"}], "recorded_with": "betamax/0.8.1"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/tests/cassettes/test_x509_adapter_pem.json 
new/requests-toolbelt-0.9.1/tests/cassettes/test_x509_adapter_pem.json
--- old/requests-toolbelt-0.8.0/tests/cassettes/test_x509_adapter_pem.json      
1970-01-01 01:00:00.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/cassettes/test_x509_adapter_pem.json      
2019-01-29 18:43:40.000000000 +0100
@@ -0,0 +1 @@
+{"http_interactions": [{"request": {"body": {"encoding": "utf-8", "string": 
""}, "headers": {"User-Agent": ["python-requests/2.21.0"], "Accept-Encoding": 
["gzip, deflate"], "Accept": ["*/*"], "Connection": ["keep-alive"]}, "method": 
"GET", "uri": "https://pkiprojecttest01.dev.labs.internal/"}, "response": 
{"body": {"encoding": "ISO-8859-1", "base64_string": 
"H4sIAAAAAAAAA7NRdPF3DokMcFXIKMnNseOygVJJ+SmVdlxArqFdSGpxiY0+kAHkFoB5CsGlycmpxcU2+gUgQX2IYqAasBEAYvDs5FMAAAA=",
 "string": ""}, "headers": {"Server": ["nginx/1.10.3 (Ubuntu)"], "Date": ["Thu, 
20 Dec 2018 20:02:30 GMT"], "Content-Type": ["text/html"], "Last-Modified": 
["Mon, 19 Nov 2018 20:48:30 GMT"], "Transfer-Encoding": ["chunked"], 
"Connection": ["keep-alive"], "ETag": ["W/\"5bf3219e-53\""], 
"Content-Encoding": ["gzip"]}, "status": {"code": 200, "message": "OK"}, "url": 
"https://pkiprojecttest01.dev.labs.internal/"}, "recorded_at": 
"2018-12-20T20:02:30"}], "recorded_with": "betamax/0.8.1"}
\ No newline at end of file
Binary files old/requests-toolbelt-0.8.0/tests/certs/test_cert.p12 and 
new/requests-toolbelt-0.9.1/tests/certs/test_cert.p12 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/tests/test_dump.py 
new/requests-toolbelt-0.9.1/tests/test_dump.py
--- old/requests-toolbelt-0.8.0/tests/test_dump.py      2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/test_dump.py      2019-01-29 
18:43:33.000000000 +0100
@@ -211,6 +211,26 @@
         assert b'request:GET / HTTP/1.1\r\n' in array
         assert b'request:Host: example.com\r\n' in array
 
+    def test_dump_non_string_request_data(self):
+        """Build up the request data into a bytearray."""
+        self.configure_request(
+            url='http://example.com/',
+            method='POST',
+            body=1
+        )
+
+        array = bytearray()
+        prefixes = dump.PrefixSettings('request:', 'response:')
+        dump._dump_request_data(
+            request=self.request,
+            prefixes=prefixes,
+            bytearr=array,
+            proxy_info={},
+        )
+        assert b'request:POST / HTTP/1.1\r\n' in array
+        assert b'request:Host: example.com\r\n' in array
+        assert b'<< Request body is not a string-like type >>\r\n' in array
+
     def test_dump_request_data_with_proxy_info(self):
         """Build up the request data into a bytearray."""
         self.configure_request(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/tests/test_multipart_decoder.py 
new/requests-toolbelt-0.9.1/tests/test_multipart_decoder.py
--- old/requests-toolbelt-0.8.0/tests/test_multipart_decoder.py 2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/test_multipart_decoder.py 2018-01-05 
13:36:25.000000000 +0100
@@ -162,3 +162,30 @@
         assert decoder_2.parts[0].headers[b'Header-1'] == b'Header-Value-1'
         assert len(decoder_2.parts[1].headers) == 0
         assert decoder_2.parts[1].content == b'Body 2, Line 1'
+
+    def test_from_responsecaplarge(self):
+        response = mock.NonCallableMagicMock(spec=requests.Response)
+        response.headers = {
+            'content-type': 'Multipart/Related; boundary="samp1"'
+        }
+        cnt = io.BytesIO()
+        cnt.write(b'\r\n--samp1\r\n')
+        cnt.write(b'Header-1: Header-Value-1\r\n')
+        cnt.write(b'Header-2: Header-Value-2\r\n')
+        cnt.write(b'\r\n')
+        cnt.write(b'Body 1, Line 1\r\n')
+        cnt.write(b'Body 1, Line 2\r\n')
+        cnt.write(b'--samp1\r\n')
+        cnt.write(b'\r\n')
+        cnt.write(b'Body 2, Line 1\r\n')
+        cnt.write(b'--samp1--\r\n')
+        response.content = cnt.getvalue()
+        decoder_2 = MultipartDecoder.from_response(response)
+        assert decoder_2.content_type == response.headers['content-type']
+        assert (
+            decoder_2.parts[0].content == b'Body 1, Line 1\r\nBody 1, Line 2'
+        )
+        assert decoder_2.parts[0].headers[b'Header-1'] == b'Header-Value-1'
+        assert len(decoder_2.parts[1].headers) == 0
+        assert decoder_2.parts[1].content == b'Body 2, Line 1'
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/requests-toolbelt-0.8.0/tests/test_multipart_encoder.py 
new/requests-toolbelt-0.9.1/tests/test_multipart_encoder.py
--- old/requests-toolbelt-0.8.0/tests/test_multipart_encoder.py 2017-01-19 
15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/test_multipart_encoder.py 2018-10-08 
13:43:24.000000000 +0200
@@ -1,8 +1,16 @@
 # -*- coding: utf-8 -*-
 import unittest
 import io
-from requests_toolbelt.multipart.encoder import CustomBytesIO, MultipartEncoder
+
+import requests
+
+from requests_toolbelt.multipart.encoder import (
+    CustomBytesIO, MultipartEncoder, FileFromURLWrapper, FileNotSupportedError)
 from requests_toolbelt._compat import filepost
+from . import get_betamax
+
+
+preserve_bytes = {'preserve_exact_body_bytes': True}
 
 
 class LargeFileMock(object):
@@ -81,6 +89,44 @@
         assert self.instance.read() == s
 
 
+class TestFileFromURLWrapper(unittest.TestCase):
+    def setUp(self):
+        s = requests.Session()
+        self.recorder = get_betamax(s)
+
+    def test_read_file(self):
+        url = ('https://stxnext.com/static/img/logo.830ebe551641.svg')
+        with self.recorder.use_cassette(
+                'file_for_download', **preserve_bytes):
+            self.instance = FileFromURLWrapper(url)
+            assert self.instance.len == 5177
+            chunk = self.instance.read(20)
+            assert chunk == b'<svg xmlns="http://w'
+            assert self.instance.len == 5157
+            chunk = self.instance.read(0)
+            assert chunk == b''
+            assert self.instance.len == 5157
+            chunk = self.instance.read(10)
+            assert chunk == b'ww.w3.org/'
+            assert self.instance.len == 5147
+
+    def test_no_content_length_header(self):
+        url = (
+            'https://api.github.com/repos/sigmavirus24/github3.py/releases/'
+            'assets/37944'
+        )
+        with self.recorder.use_cassette(
+                'stream_response_to_file', **preserve_bytes):
+            with self.assertRaises(FileNotSupportedError) as context:
+                FileFromURLWrapper(url)
+            assert context.exception.__str__() == (
+                'Data from provided URL https://api.github.com/repos/s'
+                'igmavirus24/github3.py/releases/assets/37944 is not '
+                'supported. Lack of content-length Header in requested'
+                ' file response.'
+            )
+
+
 class TestMultipartEncoder(unittest.TestCase):
     def setUp(self):
         self.parts = [('field', 'value'), ('other_field', 'other_value')]
@@ -145,6 +191,16 @@
             m = MultipartEncoder([('field', 'foo'), ('file', fd)])
             assert m.read() is not None
 
+    def test_reads_file_from_url_wrapper(self):
+        s = requests.Session()
+        recorder = get_betamax(s)
+        url = ('https://stxnext.com/static/img/logo.830ebe551641.svg')
+        with recorder.use_cassette(
+                'file_for_download'):
+            m = MultipartEncoder(
+                [('field', 'foo'), ('file', FileFromURLWrapper(url))])
+        assert m.read() is not None
+
     def test_reads_open_file_objects_with_a_specified_filename(self):
         with open('setup.py', 'rb') as fd:
             m = MultipartEncoder(
@@ -219,7 +275,7 @@
     def test_handles_empty_unicode_values(self):
         """Verify that the Encoder can handle empty unicode strings.
 
-        See https://github.com/sigmavirus24/requests-toolbelt/issues/46 for
+        See https://github.com/requests/toolbelt/issues/46 for
         more context.
         """
         fields = [(b'test'.decode('utf-8'), b''.decode('utf-8'))]
@@ -229,7 +285,7 @@
     def test_accepts_custom_content_type(self):
         """Verify that the Encoder handles custom content-types.
 
-        See https://github.com/sigmavirus24/requests-toolbelt/issues/52
+        See https://github.com/requests/toolbelt/issues/52
         """
         fields = [
             (b'test'.decode('utf-8'), (b'filename'.decode('utf-8'),
@@ -243,7 +299,7 @@
     def test_accepts_custom_headers(self):
         """Verify that the Encoder handles custom headers.
 
-        See https://github.com/sigmavirus24/requests-toolbelt/issues/52
+        See https://github.com/requests/toolbelt/issues/52
         """
         fields = [
             (b'test'.decode('utf-8'), (b'filename'.decode('utf-8'),
@@ -255,6 +311,12 @@
         output = m.read().decode('utf-8')
         assert output.index('X-My-Header: my-value\r\n') > 0
 
+    def test_no_parts(self):
+        fields = []
+        boundary = '--90967316f8404798963cce746a4f4ef9'
+        m = MultipartEncoder(fields=fields, boundary=boundary)
+        output = m.read().decode('utf-8')
+        assert output == '----90967316f8404798963cce746a4f4ef9--\r\n'
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/tests/test_x509_adapter.py 
new/requests-toolbelt-0.9.1/tests/test_x509_adapter.py
--- old/requests-toolbelt-0.8.0/tests/test_x509_adapter.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tests/test_x509_adapter.py      2019-01-29 
18:43:40.000000000 +0100
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+import requests
+import unittest
+import pytest
+
+from OpenSSL.crypto import load_pkcs12
+from cryptography.hazmat.primitives.serialization import (Encoding, 
+                                                          PrivateFormat,
+                                                          NoEncryption,
+                                                          
BestAvailableEncryption)
+
+from requests_toolbelt import exceptions as exc
+from requests_toolbelt.adapters.x509 import X509Adapter
+from . import get_betamax
+
+REQUESTS_SUPPORTS_SSL_CONTEXT = requests.__build__ >= 0x021200
+
+
+class TestX509Adapter(unittest.TestCase):
+    """Tests a simple requests.get() call using a .p12 cert.
+    """
+    def setUp(self):
+        with open('./tests/certs/test_cert.p12', 'rb') as pkcs12_file:
+            self.pkcs12_data = pkcs12_file.read()
+
+        self.pkcs12_password_bytes = "test".encode('utf8')
+        self.session = requests.Session()
+
+    @pytest.mark.skipif(not REQUESTS_SUPPORTS_SSL_CONTEXT,
+                    reason="Requires Requests v2.12.0 or later")
+    def test_x509_pem(self):
+        p12 = load_pkcs12(self.pkcs12_data, self.pkcs12_password_bytes)
+        cert_bytes = 
p12.get_certificate().to_cryptography().public_bytes(Encoding.PEM)
+        pk_bytes = p12.get_privatekey().\
+                       to_cryptography_key().\
+                       private_bytes(Encoding.PEM, PrivateFormat.PKCS8, 
+                                     
BestAvailableEncryption(self.pkcs12_password_bytes))
+
+        adapter = X509Adapter(max_retries=3, cert_bytes=cert_bytes, 
+                              pk_bytes=pk_bytes, 
password=self.pkcs12_password_bytes)
+        self.session.mount('https://', adapter)
+        recorder = get_betamax(self.session)
+        with recorder.use_cassette('test_x509_adapter_pem'):
+            r = 
self.session.get('https://pkiprojecttest01.dev.labs.internal/', verify=False)
+
+        assert r.status_code == 200
+        assert r.text
+
+    @pytest.mark.skipif(not REQUESTS_SUPPORTS_SSL_CONTEXT,
+                    reason="Requires Requests v2.12.0 or later")
+    def test_x509_der(self):
+        p12 = load_pkcs12(self.pkcs12_data, self.pkcs12_password_bytes)
+        cert_bytes = 
p12.get_certificate().to_cryptography().public_bytes(Encoding.DER)
+        pk_bytes = 
p12.get_privatekey().to_cryptography_key().private_bytes(Encoding.DER, 
PrivateFormat.PKCS8, NoEncryption())
+        adapter = X509Adapter(max_retries=3, cert_bytes=cert_bytes, 
pk_bytes=pk_bytes, encoding=Encoding.DER)
+        self.session.mount('https://', adapter)
+        recorder = get_betamax(self.session)
+        with recorder.use_cassette('test_x509_adapter_der'):
+            r = 
self.session.get('https://pkiprojecttest01.dev.labs.internal/', verify=False)
+
+        assert r.status_code == 200
+        assert r.text
+
+    @pytest.mark.skipif(REQUESTS_SUPPORTS_SSL_CONTEXT, reason="Will not raise 
exc")
+    def test_requires_new_enough_requests(self):
+        with pytest.raises(exc.VersionMismatchError):
+            X509Adapter()      
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/requests-toolbelt-0.8.0/tox.ini 
new/requests-toolbelt-0.9.1/tox.ini
--- old/requests-toolbelt-0.8.0/tox.ini 2017-01-19 15:23:03.000000000 +0100
+++ new/requests-toolbelt-0.9.1/tox.ini 2019-01-30 02:28:21.000000000 +0100
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py33,py34,py35,pypy,{py27,py34}-flake8,docstrings
+envlist = py27,py34,py35,py36,pypy,{py27,py34}-flake8,docstrings
 
 [testenv]
 pip_pre = False
@@ -7,8 +7,11 @@
     requests{env:REQUESTS_VERSION:>=2.0.1,<3.0.0}
     pytest
     mock
+    pyopenssl
+    ndg-httpsclient
     betamax>0.5.0
-commands = py.test {posargs}
+commands = 
+    py.test {posargs}
 
 [testenv:py27-flake8]
 basepython = python2.7
@@ -32,6 +35,7 @@
 deps =
     sphinx>=1.3.0
     sphinx_rtd_theme
+    pyopenssl
     .
 commands =
     sphinx-build -E -c docs -b html docs/ docs/_build/html


Reply via email to