We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Make a clear distinction between the transport timeout and the total method time timeout
It turned out that the concern from #406 was valid, unfortunately:

> A downstream library that is timeout-sensitive might still be affected by the change, because the new explicit timeout parameter changes the semantics of AuthorizedSession.request() . The timeout represents the total allowed time for all requests made behind the scenes (e.g. credentials refresh attempts), as opposed to a previous per-request timeout.

The changed semantics of `timeout` caused an [issue](https://github.com/googleapis/google-cloud-python/issues/10137) in the `storage` library. A user reported that if a large file upload takes, say, minutes _and succeeds_, a ``Timeout`` error is still raised, because the total execution time takes more than ~60 seconds, which the default transport timeout configured here in this library here.

### Proposed solution
Leave the `timeout` parameter as is and still pass it to the transport, but introduce and expose a new optional parameter `max_allowed_time` that can be used instead to configure the "total timeout".

> NOTE: The method itself might still take longer than `max_allowed_time`, because the underlying request might take longer, which is the nature of the `requests` library's timeout ([docs](https://2.python-requests.org/en/master/user/quickstart/#timeouts)).

### Alternatives
Modifying the library code so that it supports "absolute total timeouts", but that would require interrupting requests in-flight, which does not seem to be a straightforward task -https://stackoverflow.com/q/21965484/5040035


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `google/auth/transport/requests.py`
Content:
```
1 # Copyright 2016 Google Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 """Transport adapter for Requests."""
16 
17 from __future__ import absolute_import
18 
19 import functools
20 import logging
21 import numbers
22 import time
23 
24 try:
25     import requests
26 except ImportError as caught_exc:  # pragma: NO COVER
27     import six
28 
29     six.raise_from(
30         ImportError(
31             "The requests library is not installed, please install the "
32             "requests package to use the requests transport."
33         ),
34         caught_exc,
35     )
36 import requests.adapters  # pylint: disable=ungrouped-imports
37 import requests.exceptions  # pylint: disable=ungrouped-imports
38 import six  # pylint: disable=ungrouped-imports
39 
40 from google.auth import exceptions
41 from google.auth import transport
42 
43 _LOGGER = logging.getLogger(__name__)
44 
45 
46 class _Response(transport.Response):
47     """Requests transport response adapter.
48 
49     Args:
50         response (requests.Response): The raw Requests response.
51     """
52 
53     def __init__(self, response):
54         self._response = response
55 
56     @property
57     def status(self):
58         return self._response.status_code
59 
60     @property
61     def headers(self):
62         return self._response.headers
63 
64     @property
65     def data(self):
66         return self._response.content
67 
68 
69 class TimeoutGuard(object):
70     """A context manager raising an error if the suite execution took too long.
71 
72     Args:
73         timeout ([Union[None, float, Tuple[float, float]]]):
74             The maximum number of seconds a suite can run without the context
75             manager raising a timeout exception on exit. If passed as a tuple,
76             the smaller of the values is taken as a timeout. If ``None``, a
77             timeout error is never raised.
78         timeout_error_type (Optional[Exception]):
79             The type of the error to raise on timeout. Defaults to
80             :class:`requests.exceptions.Timeout`.
81     """
82 
83     def __init__(self, timeout, timeout_error_type=requests.exceptions.Timeout):
84         self._timeout = timeout
85         self.remaining_timeout = timeout
86         self._timeout_error_type = timeout_error_type
87 
88     def __enter__(self):
89         self._start = time.time()
90         return self
91 
92     def __exit__(self, exc_type, exc_value, traceback):
93         if exc_value:
94             return  # let the error bubble up automatically
95 
96         if self._timeout is None:
97             return  # nothing to do, the timeout was not specified
98 
99         elapsed = time.time() - self._start
100         deadline_hit = False
101 
102         if isinstance(self._timeout, numbers.Number):
103             self.remaining_timeout = self._timeout - elapsed
104             deadline_hit = self.remaining_timeout <= 0
105         else:
106             self.remaining_timeout = tuple(x - elapsed for x in self._timeout)
107             deadline_hit = min(self.remaining_timeout) <= 0
108 
109         if deadline_hit:
110             raise self._timeout_error_type()
111 
112 
113 class Request(transport.Request):
114     """Requests request adapter.
115 
116     This class is used internally for making requests using various transports
117     in a consistent way. If you use :class:`AuthorizedSession` you do not need
118     to construct or use this class directly.
119 
120     This class can be useful if you want to manually refresh a
121     :class:`~google.auth.credentials.Credentials` instance::
122 
123         import google.auth.transport.requests
124         import requests
125 
126         request = google.auth.transport.requests.Request()
127 
128         credentials.refresh(request)
129 
130     Args:
131         session (requests.Session): An instance :class:`requests.Session` used
132             to make HTTP requests. If not specified, a session will be created.
133 
134     .. automethod:: __call__
135     """
136 
137     def __init__(self, session=None):
138         if not session:
139             session = requests.Session()
140 
141         self.session = session
142 
143     def __call__(
144         self, url, method="GET", body=None, headers=None, timeout=120, **kwargs
145     ):
146         """Make an HTTP request using requests.
147 
148         Args:
149             url (str): The URI to be requested.
150             method (str): The HTTP method to use for the request. Defaults
151                 to 'GET'.
152             body (bytes): The payload / body in HTTP request.
153             headers (Mapping[str, str]): Request headers.
154             timeout (Optional[int]): The number of seconds to wait for a
155                 response from the server. If not specified or if None, the
156                 requests default timeout will be used.
157             kwargs: Additional arguments passed through to the underlying
158                 requests :meth:`~requests.Session.request` method.
159 
160         Returns:
161             google.auth.transport.Response: The HTTP response.
162 
163         Raises:
164             google.auth.exceptions.TransportError: If any exception occurred.
165         """
166         try:
167             _LOGGER.debug("Making request: %s %s", method, url)
168             response = self.session.request(
169                 method, url, data=body, headers=headers, timeout=timeout, **kwargs
170             )
171             return _Response(response)
172         except requests.exceptions.RequestException as caught_exc:
173             new_exc = exceptions.TransportError(caught_exc)
174             six.raise_from(new_exc, caught_exc)
175 
176 
177 class AuthorizedSession(requests.Session):
178     """A Requests Session class with credentials.
179 
180     This class is used to perform requests to API endpoints that require
181     authorization::
182 
183         from google.auth.transport.requests import AuthorizedSession
184 
185         authed_session = AuthorizedSession(credentials)
186 
187         response = authed_session.request(
188             'GET', 'https://www.googleapis.com/storage/v1/b')
189 
190     The underlying :meth:`request` implementation handles adding the
191     credentials' headers to the request and refreshing credentials as needed.
192 
193     Args:
194         credentials (google.auth.credentials.Credentials): The credentials to
195             add to the request.
196         refresh_status_codes (Sequence[int]): Which HTTP status codes indicate
197             that credentials should be refreshed and the request should be
198             retried.
199         max_refresh_attempts (int): The maximum number of times to attempt to
200             refresh the credentials and retry the request.
201         refresh_timeout (Optional[int]): The timeout value in seconds for
202             credential refresh HTTP requests.
203         auth_request (google.auth.transport.requests.Request):
204             (Optional) An instance of
205             :class:`~google.auth.transport.requests.Request` used when
206             refreshing credentials. If not passed,
207             an instance of :class:`~google.auth.transport.requests.Request`
208             is created.
209     """
210 
211     def __init__(
212         self,
213         credentials,
214         refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,
215         max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,
216         refresh_timeout=None,
217         auth_request=None,
218     ):
219         super(AuthorizedSession, self).__init__()
220         self.credentials = credentials
221         self._refresh_status_codes = refresh_status_codes
222         self._max_refresh_attempts = max_refresh_attempts
223         self._refresh_timeout = refresh_timeout
224 
225         if auth_request is None:
226             auth_request_session = requests.Session()
227 
228             # Using an adapter to make HTTP requests robust to network errors.
229             # This adapter retrys HTTP requests when network errors occur
230             # and the requests seems safely retryable.
231             retry_adapter = requests.adapters.HTTPAdapter(max_retries=3)
232             auth_request_session.mount("https://", retry_adapter)
233 
234             # Do not pass `self` as the session here, as it can lead to
235             # infinite recursion.
236             auth_request = Request(auth_request_session)
237 
238         # Request instance used by internal methods (for example,
239         # credentials.refresh).
240         self._auth_request = auth_request
241 
242     def request(self, method, url, data=None, headers=None, timeout=None, **kwargs):
243         """Implementation of Requests' request.
244 
245         Args:
246             timeout (Optional[Union[float, Tuple[float, float]]]): The number
247                 of seconds to wait before raising a ``Timeout`` exception. If
248                 multiple requests are made under the hood, ``timeout`` is
249                 interpreted as the approximate total time of **all** requests.
250 
251                 If passed as a tuple ``(connect_timeout, read_timeout)``, the
252                 smaller of the values is taken as the total allowed time across
253                 all requests.
254         """
255         # pylint: disable=arguments-differ
256         # Requests has a ton of arguments to request, but only two
257         # (method, url) are required. We pass through all of the other
258         # arguments to super, so no need to exhaustively list them here.
259 
260         # Use a kwarg for this instead of an attribute to maintain
261         # thread-safety.
262         _credential_refresh_attempt = kwargs.pop("_credential_refresh_attempt", 0)
263 
264         # Make a copy of the headers. They will be modified by the credentials
265         # and we want to pass the original headers if we recurse.
266         request_headers = headers.copy() if headers is not None else {}
267 
268         # Do not apply the timeout unconditionally in order to not override the
269         # _auth_request's default timeout.
270         auth_request = (
271             self._auth_request
272             if timeout is None
273             else functools.partial(self._auth_request, timeout=timeout)
274         )
275 
276         with TimeoutGuard(timeout) as guard:
277             self.credentials.before_request(auth_request, method, url, request_headers)
278         timeout = guard.remaining_timeout
279 
280         with TimeoutGuard(timeout) as guard:
281             response = super(AuthorizedSession, self).request(
282                 method,
283                 url,
284                 data=data,
285                 headers=request_headers,
286                 timeout=timeout,
287                 **kwargs
288             )
289         timeout = guard.remaining_timeout
290 
291         # If the response indicated that the credentials needed to be
292         # refreshed, then refresh the credentials and re-attempt the
293         # request.
294         # A stored token may expire between the time it is retrieved and
295         # the time the request is made, so we may need to try twice.
296         if (
297             response.status_code in self._refresh_status_codes
298             and _credential_refresh_attempt < self._max_refresh_attempts
299         ):
300 
301             _LOGGER.info(
302                 "Refreshing credentials due to a %s response. Attempt %s/%s.",
303                 response.status_code,
304                 _credential_refresh_attempt + 1,
305                 self._max_refresh_attempts,
306             )
307 
308             if self._refresh_timeout is not None:
309                 if timeout is None:
310                     timeout = self._refresh_timeout
311                 elif isinstance(timeout, numbers.Number):
312                     timeout = min(timeout, self._refresh_timeout)
313                 else:
314                     timeout = tuple(min(x, self._refresh_timeout) for x in timeout)
315 
316             # Do not apply the timeout unconditionally in order to not override the
317             # _auth_request's default timeout.
318             auth_request = (
319                 self._auth_request
320                 if timeout is None
321                 else functools.partial(self._auth_request, timeout=timeout)
322             )
323 
324             with TimeoutGuard(timeout) as guard:
325                 self.credentials.refresh(auth_request)
326             timeout = guard.remaining_timeout
327 
328             # Recurse. Pass in the original headers, not our modified set, but
329             # do pass the adjusted timeout (i.e. the remaining time).
330             return self.request(
331                 method,
332                 url,
333                 data=data,
334                 headers=headers,
335                 timeout=timeout,
336                 _credential_refresh_attempt=_credential_refresh_attempt + 1,
337                 **kwargs
338             )
339 
340         return response
341
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py
--- a/google/auth/transport/requests.py
+++ b/google/auth/transport/requests.py
@@ -239,18 +239,38 @@
         # credentials.refresh).
         self._auth_request = auth_request
 
-    def request(self, method, url, data=None, headers=None, timeout=None, **kwargs):
+    def request(
+        self,
+        method,
+        url,
+        data=None,
+        headers=None,
+        max_allowed_time=None,
+        timeout=None,
+        **kwargs
+    ):
         """Implementation of Requests' request.
 
         Args:
-            timeout (Optional[Union[float, Tuple[float, float]]]): The number
-                of seconds to wait before raising a ``Timeout`` exception. If
-                multiple requests are made under the hood, ``timeout`` is
-                interpreted as the approximate total time of **all** requests.
-
-                If passed as a tuple ``(connect_timeout, read_timeout)``, the
-                smaller of the values is taken as the total allowed time across
-                all requests.
+            timeout (Optional[Union[float, Tuple[float, float]]]):
+                The amount of time in seconds to wait for the server response
+                with each individual request.
+
+                Can also be passed as a tuple (connect_timeout, read_timeout).
+                See :meth:`requests.Session.request` documentation for details.
+
+            max_allowed_time (Optional[float]):
+                If the method runs longer than this, a ``Timeout`` exception is
+                automatically raised. Unlike the ``timeout` parameter, this
+                value applies to the total method execution time, even if
+                multiple requests are made under the hood.
+
+                Mind that it is not guaranteed that the timeout error is raised
+                at ``max_allowed_time`. It might take longer, for example, if
+                an underlying request takes a lot of time, but the request
+                itself does not timeout, e.g. if a large file is being
+                transmitted. The timout error will be raised after such
+                request completes.
         """
         # pylint: disable=arguments-differ
         # Requests has a ton of arguments to request, but only two
@@ -273,11 +293,13 @@
             else functools.partial(self._auth_request, timeout=timeout)
         )
 
-        with TimeoutGuard(timeout) as guard:
+        remaining_time = max_allowed_time
+
+        with TimeoutGuard(remaining_time) as guard:
             self.credentials.before_request(auth_request, method, url, request_headers)
-        timeout = guard.remaining_timeout
+        remaining_time = guard.remaining_timeout
 
-        with TimeoutGuard(timeout) as guard:
+        with TimeoutGuard(remaining_time) as guard:
             response = super(AuthorizedSession, self).request(
                 method,
                 url,
@@ -286,7 +308,7 @@
                 timeout=timeout,
                 **kwargs
             )
-        timeout = guard.remaining_timeout
+        remaining_time = guard.remaining_timeout
 
         # If the response indicated that the credentials needed to be
         # refreshed, then refresh the credentials and re-attempt the
@@ -305,14 +327,6 @@
                 self._max_refresh_attempts,
             )
 
-            if self._refresh_timeout is not None:
-                if timeout is None:
-                    timeout = self._refresh_timeout
-                elif isinstance(timeout, numbers.Number):
-                    timeout = min(timeout, self._refresh_timeout)
-                else:
-                    timeout = tuple(min(x, self._refresh_timeout) for x in timeout)
-
             # Do not apply the timeout unconditionally in order to not override the
             # _auth_request's default timeout.
             auth_request = (
@@ -321,17 +335,18 @@
                 else functools.partial(self._auth_request, timeout=timeout)
             )
 
-            with TimeoutGuard(timeout) as guard:
+            with TimeoutGuard(remaining_time) as guard:
                 self.credentials.refresh(auth_request)
-            timeout = guard.remaining_timeout
+            remaining_time = guard.remaining_timeout
 
             # Recurse. Pass in the original headers, not our modified set, but
-            # do pass the adjusted timeout (i.e. the remaining time).
+            # do pass the adjusted max allowed time (i.e. the remaining total time).
             return self.request(
                 method,
                 url,
                 data=data,
                 headers=headers,
+                max_allowed_time=remaining_time,
                 timeout=timeout,
                 _credential_refresh_attempt=_credential_refresh_attempt + 1,
                 **kwargs

{"golden_diff": "diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py\n--- a/google/auth/transport/requests.py\n+++ b/google/auth/transport/requests.py\n@@ -239,18 +239,38 @@\n         # credentials.refresh).\n         self._auth_request = auth_request\n \n-    def request(self, method, url, data=None, headers=None, timeout=None, **kwargs):\n+    def request(\n+        self,\n+        method,\n+        url,\n+        data=None,\n+        headers=None,\n+        max_allowed_time=None,\n+        timeout=None,\n+        **kwargs\n+    ):\n         \"\"\"Implementation of Requests' request.\n \n         Args:\n-            timeout (Optional[Union[float, Tuple[float, float]]]): The number\n-                of seconds to wait before raising a ``Timeout`` exception. If\n-                multiple requests are made under the hood, ``timeout`` is\n-                interpreted as the approximate total time of **all** requests.\n-\n-                If passed as a tuple ``(connect_timeout, read_timeout)``, the\n-                smaller of the values is taken as the total allowed time across\n-                all requests.\n+            timeout (Optional[Union[float, Tuple[float, float]]]):\n+                The amount of time in seconds to wait for the server response\n+                with each individual request.\n+\n+                Can also be passed as a tuple (connect_timeout, read_timeout).\n+                See :meth:`requests.Session.request` documentation for details.\n+\n+            max_allowed_time (Optional[float]):\n+                If the method runs longer than this, a ``Timeout`` exception is\n+                automatically raised. Unlike the ``timeout` parameter, this\n+                value applies to the total method execution time, even if\n+                multiple requests are made under the hood.\n+\n+                Mind that it is not guaranteed that the timeout error is raised\n+                at ``max_allowed_time`. It might take longer, for example, if\n+                an underlying request takes a lot of time, but the request\n+                itself does not timeout, e.g. if a large file is being\n+                transmitted. The timout error will be raised after such\n+                request completes.\n         \"\"\"\n         # pylint: disable=arguments-differ\n         # Requests has a ton of arguments to request, but only two\n@@ -273,11 +293,13 @@\n             else functools.partial(self._auth_request, timeout=timeout)\n         )\n \n-        with TimeoutGuard(timeout) as guard:\n+        remaining_time = max_allowed_time\n+\n+        with TimeoutGuard(remaining_time) as guard:\n             self.credentials.before_request(auth_request, method, url, request_headers)\n-        timeout = guard.remaining_timeout\n+        remaining_time = guard.remaining_timeout\n \n-        with TimeoutGuard(timeout) as guard:\n+        with TimeoutGuard(remaining_time) as guard:\n             response = super(AuthorizedSession, self).request(\n                 method,\n                 url,\n@@ -286,7 +308,7 @@\n                 timeout=timeout,\n                 **kwargs\n             )\n-        timeout = guard.remaining_timeout\n+        remaining_time = guard.remaining_timeout\n \n         # If the response indicated that the credentials needed to be\n         # refreshed, then refresh the credentials and re-attempt the\n@@ -305,14 +327,6 @@\n                 self._max_refresh_attempts,\n             )\n \n-            if self._refresh_timeout is not None:\n-                if timeout is None:\n-                    timeout = self._refresh_timeout\n-                elif isinstance(timeout, numbers.Number):\n-                    timeout = min(timeout, self._refresh_timeout)\n-                else:\n-                    timeout = tuple(min(x, self._refresh_timeout) for x in timeout)\n-\n             # Do not apply the timeout unconditionally in order to not override the\n             # _auth_request's default timeout.\n             auth_request = (\n@@ -321,17 +335,18 @@\n                 else functools.partial(self._auth_request, timeout=timeout)\n             )\n \n-            with TimeoutGuard(timeout) as guard:\n+            with TimeoutGuard(remaining_time) as guard:\n                 self.credentials.refresh(auth_request)\n-            timeout = guard.remaining_timeout\n+            remaining_time = guard.remaining_timeout\n \n             # Recurse. Pass in the original headers, not our modified set, but\n-            # do pass the adjusted timeout (i.e. the remaining time).\n+            # do pass the adjusted max allowed time (i.e. the remaining total time).\n             return self.request(\n                 method,\n                 url,\n                 data=data,\n                 headers=headers,\n+                max_allowed_time=remaining_time,\n                 timeout=timeout,\n                 _credential_refresh_attempt=_credential_refresh_attempt + 1,\n                 **kwargs\n", "issue": "Make a clear distinction between the transport timeout and the total method time timeout\nIt turned out that the concern from #406 was valid, unfortunately:\r\n\r\n> A downstream library that is timeout-sensitive might still be affected by the change, because the new explicit timeout parameter changes the semantics of AuthorizedSession.request() . The timeout represents the total allowed time for all requests made behind the scenes (e.g. credentials refresh attempts), as opposed to a previous per-request timeout.\r\n\r\nThe changed semantics of `timeout` caused an [issue](https://github.com/googleapis/google-cloud-python/issues/10137) in the `storage` library. A user reported that if a large file upload takes, say, minutes _and succeeds_, a ``Timeout`` error is still raised, because the total execution time takes more than ~60 seconds, which the default transport timeout configured here in this library here.\r\n\r\n### Proposed solution\r\nLeave the `timeout` parameter as is and still pass it to the transport, but introduce and expose a new optional parameter `max_allowed_time` that can be used instead to configure the \"total timeout\".\r\n\r\n> NOTE: The method itself might still take longer than `max_allowed_time`, because the underlying request might take longer, which is the nature of the `requests` library's timeout ([docs](https://2.python-requests.org/en/master/user/quickstart/#timeouts)).\r\n\r\n### Alternatives\r\nModifying the library code so that it supports \"absolute total timeouts\", but that would require interrupting requests in-flight, which does not seem to be a straightforward task -https://stackoverflow.com/q/21965484/5040035\r\n\n", "before_files": [{"content": "# Copyright 2016 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Transport adapter for Requests.\"\"\"\n\nfrom __future__ import absolute_import\n\nimport functools\nimport logging\nimport numbers\nimport time\n\ntry:\n    import requests\nexcept ImportError as caught_exc:  # pragma: NO COVER\n    import six\n\n    six.raise_from(\n        ImportError(\n            \"The requests library is not installed, please install the \"\n            \"requests package to use the requests transport.\"\n        ),\n        caught_exc,\n    )\nimport requests.adapters  # pylint: disable=ungrouped-imports\nimport requests.exceptions  # pylint: disable=ungrouped-imports\nimport six  # pylint: disable=ungrouped-imports\n\nfrom google.auth import exceptions\nfrom google.auth import transport\n\n_LOGGER = logging.getLogger(__name__)\n\n\nclass _Response(transport.Response):\n    \"\"\"Requests transport response adapter.\n\n    Args:\n        response (requests.Response): The raw Requests response.\n    \"\"\"\n\n    def __init__(self, response):\n        self._response = response\n\n    @property\n    def status(self):\n        return self._response.status_code\n\n    @property\n    def headers(self):\n        return self._response.headers\n\n    @property\n    def data(self):\n        return self._response.content\n\n\nclass TimeoutGuard(object):\n    \"\"\"A context manager raising an error if the suite execution took too long.\n\n    Args:\n        timeout ([Union[None, float, Tuple[float, float]]]):\n            The maximum number of seconds a suite can run without the context\n            manager raising a timeout exception on exit. If passed as a tuple,\n            the smaller of the values is taken as a timeout. If ``None``, a\n            timeout error is never raised.\n        timeout_error_type (Optional[Exception]):\n            The type of the error to raise on timeout. Defaults to\n            :class:`requests.exceptions.Timeout`.\n    \"\"\"\n\n    def __init__(self, timeout, timeout_error_type=requests.exceptions.Timeout):\n        self._timeout = timeout\n        self.remaining_timeout = timeout\n        self._timeout_error_type = timeout_error_type\n\n    def __enter__(self):\n        self._start = time.time()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        if exc_value:\n            return  # let the error bubble up automatically\n\n        if self._timeout is None:\n            return  # nothing to do, the timeout was not specified\n\n        elapsed = time.time() - self._start\n        deadline_hit = False\n\n        if isinstance(self._timeout, numbers.Number):\n            self.remaining_timeout = self._timeout - elapsed\n            deadline_hit = self.remaining_timeout <= 0\n        else:\n            self.remaining_timeout = tuple(x - elapsed for x in self._timeout)\n            deadline_hit = min(self.remaining_timeout) <= 0\n\n        if deadline_hit:\n            raise self._timeout_error_type()\n\n\nclass Request(transport.Request):\n    \"\"\"Requests request adapter.\n\n    This class is used internally for making requests using various transports\n    in a consistent way. If you use :class:`AuthorizedSession` you do not need\n    to construct or use this class directly.\n\n    This class can be useful if you want to manually refresh a\n    :class:`~google.auth.credentials.Credentials` instance::\n\n        import google.auth.transport.requests\n        import requests\n\n        request = google.auth.transport.requests.Request()\n\n        credentials.refresh(request)\n\n    Args:\n        session (requests.Session): An instance :class:`requests.Session` used\n            to make HTTP requests. If not specified, a session will be created.\n\n    .. automethod:: __call__\n    \"\"\"\n\n    def __init__(self, session=None):\n        if not session:\n            session = requests.Session()\n\n        self.session = session\n\n    def __call__(\n        self, url, method=\"GET\", body=None, headers=None, timeout=120, **kwargs\n    ):\n        \"\"\"Make an HTTP request using requests.\n\n        Args:\n            url (str): The URI to be requested.\n            method (str): The HTTP method to use for the request. Defaults\n                to 'GET'.\n            body (bytes): The payload / body in HTTP request.\n            headers (Mapping[str, str]): Request headers.\n            timeout (Optional[int]): The number of seconds to wait for a\n                response from the server. If not specified or if None, the\n                requests default timeout will be used.\n            kwargs: Additional arguments passed through to the underlying\n                requests :meth:`~requests.Session.request` method.\n\n        Returns:\n            google.auth.transport.Response: The HTTP response.\n\n        Raises:\n            google.auth.exceptions.TransportError: If any exception occurred.\n        \"\"\"\n        try:\n            _LOGGER.debug(\"Making request: %s %s\", method, url)\n            response = self.session.request(\n                method, url, data=body, headers=headers, timeout=timeout, **kwargs\n            )\n            return _Response(response)\n        except requests.exceptions.RequestException as caught_exc:\n            new_exc = exceptions.TransportError(caught_exc)\n            six.raise_from(new_exc, caught_exc)\n\n\nclass AuthorizedSession(requests.Session):\n    \"\"\"A Requests Session class with credentials.\n\n    This class is used to perform requests to API endpoints that require\n    authorization::\n\n        from google.auth.transport.requests import AuthorizedSession\n\n        authed_session = AuthorizedSession(credentials)\n\n        response = authed_session.request(\n            'GET', 'https://www.googleapis.com/storage/v1/b')\n\n    The underlying :meth:`request` implementation handles adding the\n    credentials' headers to the request and refreshing credentials as needed.\n\n    Args:\n        credentials (google.auth.credentials.Credentials): The credentials to\n            add to the request.\n        refresh_status_codes (Sequence[int]): Which HTTP status codes indicate\n            that credentials should be refreshed and the request should be\n            retried.\n        max_refresh_attempts (int): The maximum number of times to attempt to\n            refresh the credentials and retry the request.\n        refresh_timeout (Optional[int]): The timeout value in seconds for\n            credential refresh HTTP requests.\n        auth_request (google.auth.transport.requests.Request):\n            (Optional) An instance of\n            :class:`~google.auth.transport.requests.Request` used when\n            refreshing credentials. If not passed,\n            an instance of :class:`~google.auth.transport.requests.Request`\n            is created.\n    \"\"\"\n\n    def __init__(\n        self,\n        credentials,\n        refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,\n        max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,\n        refresh_timeout=None,\n        auth_request=None,\n    ):\n        super(AuthorizedSession, self).__init__()\n        self.credentials = credentials\n        self._refresh_status_codes = refresh_status_codes\n        self._max_refresh_attempts = max_refresh_attempts\n        self._refresh_timeout = refresh_timeout\n\n        if auth_request is None:\n            auth_request_session = requests.Session()\n\n            # Using an adapter to make HTTP requests robust to network errors.\n            # This adapter retrys HTTP requests when network errors occur\n            # and the requests seems safely retryable.\n            retry_adapter = requests.adapters.HTTPAdapter(max_retries=3)\n            auth_request_session.mount(\"https://\", retry_adapter)\n\n            # Do not pass `self` as the session here, as it can lead to\n            # infinite recursion.\n            auth_request = Request(auth_request_session)\n\n        # Request instance used by internal methods (for example,\n        # credentials.refresh).\n        self._auth_request = auth_request\n\n    def request(self, method, url, data=None, headers=None, timeout=None, **kwargs):\n        \"\"\"Implementation of Requests' request.\n\n        Args:\n            timeout (Optional[Union[float, Tuple[float, float]]]): The number\n                of seconds to wait before raising a ``Timeout`` exception. If\n                multiple requests are made under the hood, ``timeout`` is\n                interpreted as the approximate total time of **all** requests.\n\n                If passed as a tuple ``(connect_timeout, read_timeout)``, the\n                smaller of the values is taken as the total allowed time across\n                all requests.\n        \"\"\"\n        # pylint: disable=arguments-differ\n        # Requests has a ton of arguments to request, but only two\n        # (method, url) are required. We pass through all of the other\n        # arguments to super, so no need to exhaustively list them here.\n\n        # Use a kwarg for this instead of an attribute to maintain\n        # thread-safety.\n        _credential_refresh_attempt = kwargs.pop(\"_credential_refresh_attempt\", 0)\n\n        # Make a copy of the headers. They will be modified by the credentials\n        # and we want to pass the original headers if we recurse.\n        request_headers = headers.copy() if headers is not None else {}\n\n        # Do not apply the timeout unconditionally in order to not override the\n        # _auth_request's default timeout.\n        auth_request = (\n            self._auth_request\n            if timeout is None\n            else functools.partial(self._auth_request, timeout=timeout)\n        )\n\n        with TimeoutGuard(timeout) as guard:\n            self.credentials.before_request(auth_request, method, url, request_headers)\n        timeout = guard.remaining_timeout\n\n        with TimeoutGuard(timeout) as guard:\n            response = super(AuthorizedSession, self).request(\n                method,\n                url,\n                data=data,\n                headers=request_headers,\n                timeout=timeout,\n                **kwargs\n            )\n        timeout = guard.remaining_timeout\n\n        # If the response indicated that the credentials needed to be\n        # refreshed, then refresh the credentials and re-attempt the\n        # request.\n        # A stored token may expire between the time it is retrieved and\n        # the time the request is made, so we may need to try twice.\n        if (\n            response.status_code in self._refresh_status_codes\n            and _credential_refresh_attempt < self._max_refresh_attempts\n        ):\n\n            _LOGGER.info(\n                \"Refreshing credentials due to a %s response. Attempt %s/%s.\",\n                response.status_code,\n                _credential_refresh_attempt + 1,\n                self._max_refresh_attempts,\n            )\n\n            if self._refresh_timeout is not None:\n                if timeout is None:\n                    timeout = self._refresh_timeout\n                elif isinstance(timeout, numbers.Number):\n                    timeout = min(timeout, self._refresh_timeout)\n                else:\n                    timeout = tuple(min(x, self._refresh_timeout) for x in timeout)\n\n            # Do not apply the timeout unconditionally in order to not override the\n            # _auth_request's default timeout.\n            auth_request = (\n                self._auth_request\n                if timeout is None\n                else functools.partial(self._auth_request, timeout=timeout)\n            )\n\n            with TimeoutGuard(timeout) as guard:\n                self.credentials.refresh(auth_request)\n            timeout = guard.remaining_timeout\n\n            # Recurse. Pass in the original headers, not our modified set, but\n            # do pass the adjusted timeout (i.e. the remaining time).\n            return self.request(\n                method,\n                url,\n                data=data,\n                headers=headers,\n                timeout=timeout,\n                _credential_refresh_attempt=_credential_refresh_attempt + 1,\n                **kwargs\n            )\n\n        return response\n", "path": "google/auth/transport/requests.py"}], "after_files": [{"content": "# Copyright 2016 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"Transport adapter for Requests.\"\"\"\n\nfrom __future__ import absolute_import\n\nimport functools\nimport logging\nimport numbers\nimport time\n\ntry:\n    import requests\nexcept ImportError as caught_exc:  # pragma: NO COVER\n    import six\n\n    six.raise_from(\n        ImportError(\n            \"The requests library is not installed, please install the \"\n            \"requests package to use the requests transport.\"\n        ),\n        caught_exc,\n    )\nimport requests.adapters  # pylint: disable=ungrouped-imports\nimport requests.exceptions  # pylint: disable=ungrouped-imports\nimport six  # pylint: disable=ungrouped-imports\n\nfrom google.auth import exceptions\nfrom google.auth import transport\n\n_LOGGER = logging.getLogger(__name__)\n\n\nclass _Response(transport.Response):\n    \"\"\"Requests transport response adapter.\n\n    Args:\n        response (requests.Response): The raw Requests response.\n    \"\"\"\n\n    def __init__(self, response):\n        self._response = response\n\n    @property\n    def status(self):\n        return self._response.status_code\n\n    @property\n    def headers(self):\n        return self._response.headers\n\n    @property\n    def data(self):\n        return self._response.content\n\n\nclass TimeoutGuard(object):\n    \"\"\"A context manager raising an error if the suite execution took too long.\n\n    Args:\n        timeout ([Union[None, float, Tuple[float, float]]]):\n            The maximum number of seconds a suite can run without the context\n            manager raising a timeout exception on exit. If passed as a tuple,\n            the smaller of the values is taken as a timeout. If ``None``, a\n            timeout error is never raised.\n        timeout_error_type (Optional[Exception]):\n            The type of the error to raise on timeout. Defaults to\n            :class:`requests.exceptions.Timeout`.\n    \"\"\"\n\n    def __init__(self, timeout, timeout_error_type=requests.exceptions.Timeout):\n        self._timeout = timeout\n        self.remaining_timeout = timeout\n        self._timeout_error_type = timeout_error_type\n\n    def __enter__(self):\n        self._start = time.time()\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        if exc_value:\n            return  # let the error bubble up automatically\n\n        if self._timeout is None:\n            return  # nothing to do, the timeout was not specified\n\n        elapsed = time.time() - self._start\n        deadline_hit = False\n\n        if isinstance(self._timeout, numbers.Number):\n            self.remaining_timeout = self._timeout - elapsed\n            deadline_hit = self.remaining_timeout <= 0\n        else:\n            self.remaining_timeout = tuple(x - elapsed for x in self._timeout)\n            deadline_hit = min(self.remaining_timeout) <= 0\n\n        if deadline_hit:\n            raise self._timeout_error_type()\n\n\nclass Request(transport.Request):\n    \"\"\"Requests request adapter.\n\n    This class is used internally for making requests using various transports\n    in a consistent way. If you use :class:`AuthorizedSession` you do not need\n    to construct or use this class directly.\n\n    This class can be useful if you want to manually refresh a\n    :class:`~google.auth.credentials.Credentials` instance::\n\n        import google.auth.transport.requests\n        import requests\n\n        request = google.auth.transport.requests.Request()\n\n        credentials.refresh(request)\n\n    Args:\n        session (requests.Session): An instance :class:`requests.Session` used\n            to make HTTP requests. If not specified, a session will be created.\n\n    .. automethod:: __call__\n    \"\"\"\n\n    def __init__(self, session=None):\n        if not session:\n            session = requests.Session()\n\n        self.session = session\n\n    def __call__(\n        self, url, method=\"GET\", body=None, headers=None, timeout=120, **kwargs\n    ):\n        \"\"\"Make an HTTP request using requests.\n\n        Args:\n            url (str): The URI to be requested.\n            method (str): The HTTP method to use for the request. Defaults\n                to 'GET'.\n            body (bytes): The payload / body in HTTP request.\n            headers (Mapping[str, str]): Request headers.\n            timeout (Optional[int]): The number of seconds to wait for a\n                response from the server. If not specified or if None, the\n                requests default timeout will be used.\n            kwargs: Additional arguments passed through to the underlying\n                requests :meth:`~requests.Session.request` method.\n\n        Returns:\n            google.auth.transport.Response: The HTTP response.\n\n        Raises:\n            google.auth.exceptions.TransportError: If any exception occurred.\n        \"\"\"\n        try:\n            _LOGGER.debug(\"Making request: %s %s\", method, url)\n            response = self.session.request(\n                method, url, data=body, headers=headers, timeout=timeout, **kwargs\n            )\n            return _Response(response)\n        except requests.exceptions.RequestException as caught_exc:\n            new_exc = exceptions.TransportError(caught_exc)\n            six.raise_from(new_exc, caught_exc)\n\n\nclass AuthorizedSession(requests.Session):\n    \"\"\"A Requests Session class with credentials.\n\n    This class is used to perform requests to API endpoints that require\n    authorization::\n\n        from google.auth.transport.requests import AuthorizedSession\n\n        authed_session = AuthorizedSession(credentials)\n\n        response = authed_session.request(\n            'GET', 'https://www.googleapis.com/storage/v1/b')\n\n    The underlying :meth:`request` implementation handles adding the\n    credentials' headers to the request and refreshing credentials as needed.\n\n    Args:\n        credentials (google.auth.credentials.Credentials): The credentials to\n            add to the request.\n        refresh_status_codes (Sequence[int]): Which HTTP status codes indicate\n            that credentials should be refreshed and the request should be\n            retried.\n        max_refresh_attempts (int): The maximum number of times to attempt to\n            refresh the credentials and retry the request.\n        refresh_timeout (Optional[int]): The timeout value in seconds for\n            credential refresh HTTP requests.\n        auth_request (google.auth.transport.requests.Request):\n            (Optional) An instance of\n            :class:`~google.auth.transport.requests.Request` used when\n            refreshing credentials. If not passed,\n            an instance of :class:`~google.auth.transport.requests.Request`\n            is created.\n    \"\"\"\n\n    def __init__(\n        self,\n        credentials,\n        refresh_status_codes=transport.DEFAULT_REFRESH_STATUS_CODES,\n        max_refresh_attempts=transport.DEFAULT_MAX_REFRESH_ATTEMPTS,\n        refresh_timeout=None,\n        auth_request=None,\n    ):\n        super(AuthorizedSession, self).__init__()\n        self.credentials = credentials\n        self._refresh_status_codes = refresh_status_codes\n        self._max_refresh_attempts = max_refresh_attempts\n        self._refresh_timeout = refresh_timeout\n\n        if auth_request is None:\n            auth_request_session = requests.Session()\n\n            # Using an adapter to make HTTP requests robust to network errors.\n            # This adapter retrys HTTP requests when network errors occur\n            # and the requests seems safely retryable.\n            retry_adapter = requests.adapters.HTTPAdapter(max_retries=3)\n            auth_request_session.mount(\"https://\", retry_adapter)\n\n            # Do not pass `self` as the session here, as it can lead to\n            # infinite recursion.\n            auth_request = Request(auth_request_session)\n\n        # Request instance used by internal methods (for example,\n        # credentials.refresh).\n        self._auth_request = auth_request\n\n    def request(\n        self,\n        method,\n        url,\n        data=None,\n        headers=None,\n        max_allowed_time=None,\n        timeout=None,\n        **kwargs\n    ):\n        \"\"\"Implementation of Requests' request.\n\n        Args:\n            timeout (Optional[Union[float, Tuple[float, float]]]):\n                The amount of time in seconds to wait for the server response\n                with each individual request.\n\n                Can also be passed as a tuple (connect_timeout, read_timeout).\n                See :meth:`requests.Session.request` documentation for details.\n\n            max_allowed_time (Optional[float]):\n                If the method runs longer than this, a ``Timeout`` exception is\n                automatically raised. Unlike the ``timeout` parameter, this\n                value applies to the total method execution time, even if\n                multiple requests are made under the hood.\n\n                Mind that it is not guaranteed that the timeout error is raised\n                at ``max_allowed_time`. It might take longer, for example, if\n                an underlying request takes a lot of time, but the request\n                itself does not timeout, e.g. if a large file is being\n                transmitted. The timout error will be raised after such\n                request completes.\n        \"\"\"\n        # pylint: disable=arguments-differ\n        # Requests has a ton of arguments to request, but only two\n        # (method, url) are required. We pass through all of the other\n        # arguments to super, so no need to exhaustively list them here.\n\n        # Use a kwarg for this instead of an attribute to maintain\n        # thread-safety.\n        _credential_refresh_attempt = kwargs.pop(\"_credential_refresh_attempt\", 0)\n\n        # Make a copy of the headers. They will be modified by the credentials\n        # and we want to pass the original headers if we recurse.\n        request_headers = headers.copy() if headers is not None else {}\n\n        # Do not apply the timeout unconditionally in order to not override the\n        # _auth_request's default timeout.\n        auth_request = (\n            self._auth_request\n            if timeout is None\n            else functools.partial(self._auth_request, timeout=timeout)\n        )\n\n        remaining_time = max_allowed_time\n\n        with TimeoutGuard(remaining_time) as guard:\n            self.credentials.before_request(auth_request, method, url, request_headers)\n        remaining_time = guard.remaining_timeout\n\n        with TimeoutGuard(remaining_time) as guard:\n            response = super(AuthorizedSession, self).request(\n                method,\n                url,\n                data=data,\n                headers=request_headers,\n                timeout=timeout,\n                **kwargs\n            )\n        remaining_time = guard.remaining_timeout\n\n        # If the response indicated that the credentials needed to be\n        # refreshed, then refresh the credentials and re-attempt the\n        # request.\n        # A stored token may expire between the time it is retrieved and\n        # the time the request is made, so we may need to try twice.\n        if (\n            response.status_code in self._refresh_status_codes\n            and _credential_refresh_attempt < self._max_refresh_attempts\n        ):\n\n            _LOGGER.info(\n                \"Refreshing credentials due to a %s response. Attempt %s/%s.\",\n                response.status_code,\n                _credential_refresh_attempt + 1,\n                self._max_refresh_attempts,\n            )\n\n            # Do not apply the timeout unconditionally in order to not override the\n            # _auth_request's default timeout.\n            auth_request = (\n                self._auth_request\n                if timeout is None\n                else functools.partial(self._auth_request, timeout=timeout)\n            )\n\n            with TimeoutGuard(remaining_time) as guard:\n                self.credentials.refresh(auth_request)\n            remaining_time = guard.remaining_timeout\n\n            # Recurse. Pass in the original headers, not our modified set, but\n            # do pass the adjusted max allowed time (i.e. the remaining total time).\n            return self.request(\n                method,\n                url,\n                data=data,\n                headers=headers,\n                max_allowed_time=remaining_time,\n                timeout=timeout,\n                _credential_refresh_attempt=_credential_refresh_attempt + 1,\n                **kwargs\n            )\n\n        return response\n", "path": "google/auth/transport/requests.py"}]}