Repository: GoogleCloudPlatform/google-auth-library-python
Pull request #14 (2016-10-10 17:32:58)

Add urllib3 transport


Patch:
diff --git a/docs/reference/google.auth.compute_engine.rst b/docs/reference/google.auth.compute_engine.rst
new file mode 100644
index 0000000..9bf9866
--- /dev/null
+++ b/docs/reference/google.auth.compute_engine.rst
@@ -0,0 +1,8 @@
+google.auth.compute_engine package
+==================================
+
+.. automodule:: google.auth.compute_engine
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
diff --git a/docs/reference/google.auth.rst b/docs/reference/google.auth.rst
index 0f147e9..ef0d689 100644
--- a/docs/reference/google.auth.rst
+++ b/docs/reference/google.auth.rst
@@ -11,6 +11,7 @@ Subpackages
 
 .. toctree::
 
+    google.auth.compute_engine
     google.auth.transport
 
 Submodules
diff --git a/docs/reference/google.auth.transport.rst b/docs/reference/google.auth.transport.rst
index 88b427c..7066334 100644
--- a/docs/reference/google.auth.transport.rst
+++ b/docs/reference/google.auth.transport.rst
@@ -6,3 +6,10 @@ google.auth.transport package
     :undoc-members:
     :show-inheritance:
 
+Submodules
+----------
+
+.. toctree::
+
+   google.auth.transport.urllib3
+
diff --git a/docs/reference/google.auth.transport.urllib3.rst b/docs/reference/google.auth.transport.urllib3.rst
new file mode 100644
index 0000000..32de225
--- /dev/null
+++ b/docs/reference/google.auth.transport.urllib3.rst
@@ -0,0 +1,7 @@
+google.auth.transport.urllib3 module
+====================================
+
+.. automodule:: google.auth.transport.urllib3
+    :members:
+    :undoc-members:
+    :show-inheritance:
diff --git a/google/auth/transport/_http_client.py b/google/auth/transport/_http_client.py
index e50a3b5..ddd5818 100644
--- a/google/auth/transport/_http_client.py
+++ b/google/auth/transport/_http_client.py
@@ -24,7 +24,7 @@ from google.auth import transport
 
 
 class Response(transport.Response):
-    """http.client transport request adapter.
+    """http.client transport response adapter.
 
     Args:
         response (http.client.HTTPResponse): The raw http client response.
diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py
new file mode 100644
index 0000000..4ac0f98
--- /dev/null
+++ b/google/auth/transport/urllib3.py
@@ -0,0 +1,91 @@
+# Copyright 2016 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Transport adapter for urllib3."""
+
+from __future__ import absolute_import
+
+import urllib3
+import urllib3.exceptions
+
+from google.auth import exceptions
+from google.auth import transport
+
+
+class Response(transport.Response):
+    """urllib3 transport response adapter.
+
+    Args:
+        response (urllib3.response.HTTPResponse): The raw urllib3 response.
+    """
+    def __init__(self, response):
+        self._response = response
+
+    @property
+    def status(self):
+        return self._response.status
+
+    @property
+    def headers(self):
+        return self._response.headers
+
+    @property
+    def data(self):
+        return self._response.data
+
+
+class Request(transport.Request):
+    """urllib3 request adapter
+
+    Args:
+        http (urllib3.requests.RequestMethods): An instance of any urllib3
+            class that implements :class:`~urllib3.requests.RequestMethods`,
+            usually :class:`urllib3.PoolManager`.
+    """
+    def __init__(self, http):
+        self.http = http
+
+    def __call__(self, url, method='GET', body=None, headers=None,
+                 timeout=None, **kwargs):
+        """Make an HTTP request using urllib3.
+
+        Args:
+            url (str): The URI to be requested.
+            method (str): The HTTP method to use for the request. Defaults
+                to 'GET'.
+            body (bytes): The payload / body in HTTP request.
+            headers (Mapping): Request headers.
+            timeout (Optional(int)): The number of seconds to wait for a
+                response from the server. If not specified or if None, the
+                urllib3 default timeout will be used.
+            kwargs: Additional arguments passed throught to the underlying
+                urllib3 :meth:`urlopen` method.
+
+        Returns:
+            Response: The HTTP response.
+
+        Raises:
+            google.auth.exceptions.TransportError: If any exception occurred.
+        """
+        # urllib3 uses a sentinel default value for timeout, so only set it if
+        # specified.
+        if timeout is not None:
+            kwargs['timeout'] = timeout
+
+        try:
+            response = self.http.request(
+                method, url, body=body, headers=headers, **kwargs)
+            return Response(response)
+        except urllib3.exceptions.HTTPError as exc:
+            raise exceptions.TransportError(exc)


Test patch:
diff --git a/tests/transport/compliance.py b/tests/transport/compliance.py
index ad4e491..6d2a304 100644
--- a/tests/transport/compliance.py
+++ b/tests/transport/compliance.py
@@ -25,7 +25,7 @@ NXDOMAIN = 'test.invalid'
 
 class RequestResponseTests(object):
 
-    @pytest.fixture
+    @pytest.fixture(scope='module')
     def server(self):
         """Provides a test HTTP server.
 
diff --git a/tests/transport/test_urllib3.py b/tests/transport/test_urllib3.py
new file mode 100644
index 0000000..bdd5ac9
--- /dev/null
+++ b/tests/transport/test_urllib3.py
@@ -0,0 +1,33 @@
+# Copyright 2016 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import mock
+import urllib3
+
+import google.auth.transport.urllib3
+from tests.transport import compliance
+
+
+class TestRequestResponse(compliance.RequestResponseTests):
+    def make_request(self):
+        http = urllib3.PoolManager()
+        return google.auth.transport.urllib3.Request(http)
+
+
+def test_timeout():
+    http = mock.Mock()
+    request = google.auth.transport.urllib3.Request(http)
+    request(url='http://example.com', method='GET', timeout=5)
+
+    assert http.request.call_args[1]['timeout'] == 5