Drop request.timer attribute. (#1249)

* Drop request.timer attribute
* Response(..., elapsed_func=...)
This commit is contained in:
Tom Christie 2020-09-07 09:06:14 +01:00 committed by GitHub
parent 78f24203ce
commit a783fe5758
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 44 deletions

View File

@ -47,6 +47,7 @@ from ._types import (
)
from ._utils import (
NetRCInfo,
Timer,
URLPattern,
get_environment_proxies,
get_logger,
@ -811,6 +812,8 @@ class Client(BaseClient):
Sends a single request, without handling any redirections.
"""
transport = self._transport_for_url(request.url)
timer = Timer()
timer.sync_start()
with map_exceptions(HTTPCORE_EXC_MAP, request=request):
(
@ -832,6 +835,7 @@ class Client(BaseClient):
headers=headers,
stream=stream, # type: ignore
request=request,
elapsed_func=timer.sync_elapsed,
)
self.cookies.extract_cookies(response)
@ -1434,6 +1438,8 @@ class AsyncClient(BaseClient):
Sends a single request, without handling any redirections.
"""
transport = self._transport_for_url(request.url)
timer = Timer()
await timer.async_start()
with map_exceptions(HTTPCORE_EXC_MAP, request=request):
(
@ -1455,6 +1461,7 @@ class AsyncClient(BaseClient):
headers=headers,
stream=stream, # type: ignore
request=request,
elapsed_func=timer.async_elapsed,
)
self.cookies.extract_cookies(response)

View File

@ -47,7 +47,6 @@ from ._types import (
URLTypes,
)
from ._utils import (
ElapsedTimer,
flatten_queryparams,
guess_json_utf,
is_known_encoding,
@ -606,7 +605,6 @@ class Request:
else:
self.stream = encode(data, files, json)
self.timer = ElapsedTimer()
self.prepare()
def prepare(self) -> None:
@ -678,6 +676,7 @@ class Response:
stream: ContentStream = None,
content: bytes = None,
history: typing.List["Response"] = None,
elapsed_func: typing.Callable = None,
):
self.status_code = status_code
self.http_version = http_version
@ -688,6 +687,7 @@ class Response:
self.call_next: typing.Optional[typing.Callable] = None
self.history = [] if history is None else list(history)
self._elapsed_func = elapsed_func
self.is_closed = False
self.is_stream_consumed = False
@ -708,7 +708,7 @@ class Response:
"'.elapsed' may only be accessed after the response "
"has been read or closed."
)
return self._elapsed
return datetime.timedelta(seconds=self._elapsed)
@property
def request(self) -> Request:
@ -976,8 +976,8 @@ class Response:
"""
if not self.is_closed:
self.is_closed = True
if self._request is not None:
self._elapsed = self.request.timer.elapsed
if self._elapsed_func is not None:
self._elapsed = self._elapsed_func()
self._raw_stream.close()
async def aread(self) -> bytes:
@ -1056,8 +1056,8 @@ class Response:
"""
if not self.is_closed:
self.is_closed = True
if self._request is not None:
self._elapsed = self.request.timer.elapsed
if self._elapsed_func is not None:
self._elapsed = await self._elapsed_func()
await self._raw_stream.aclose()

View File

@ -6,14 +6,14 @@ import netrc
import os
import re
import sys
import time
import typing
import warnings
from datetime import timedelta
from pathlib import Path
from time import perf_counter
from types import TracebackType
from urllib.request import getproxies
import sniffio
from ._types import PrimitiveData
if typing.TYPE_CHECKING: # pragma: no cover
@ -392,28 +392,35 @@ def flatten_queryparams(
return items
class ElapsedTimer:
def __init__(self) -> None:
self.start: float = perf_counter()
self.end: typing.Optional[float] = None
class Timer:
async def _get_time(self) -> float:
library = sniffio.current_async_library()
if library == "trio":
import trio
def __enter__(self) -> "ElapsedTimer":
self.start = perf_counter()
return self
return trio.current_time()
elif library == "curio": # pragma: nocover
import curio
def __exit__(
self,
exc_type: typing.Type[BaseException] = None,
exc_value: BaseException = None,
traceback: TracebackType = None,
) -> None:
self.end = perf_counter()
return await curio.clock()
@property
def elapsed(self) -> timedelta:
if self.end is None:
return timedelta(seconds=perf_counter() - self.start)
return timedelta(seconds=self.end - self.start)
import asyncio
return asyncio.get_event_loop().time()
def sync_start(self) -> None:
self.started = time.perf_counter()
async def async_start(self) -> None:
self.started = await self._get_time()
def sync_elapsed(self) -> float:
now = time.perf_counter()
return now - self.started
async def async_elapsed(self) -> float:
now = await self._get_time()
return now - self.started
class URLPattern:

View File

@ -1,4 +1,3 @@
import datetime
import json
from unittest import mock
@ -31,7 +30,6 @@ def test_response():
assert response.text == "Hello, world!"
assert response.request.method == "GET"
assert response.request.url == "https://example.org"
assert response.elapsed >= datetime.timedelta(0)
assert not response.is_error

View File

@ -1,4 +1,3 @@
import asyncio
import os
import random
@ -6,7 +5,6 @@ import pytest
import httpx
from httpx._utils import (
ElapsedTimer,
NetRCInfo,
URLPattern,
get_ca_bundle_from_env,
@ -177,17 +175,6 @@ def test_get_ssl_cert_file():
assert get_ca_bundle_from_env() is None
@pytest.mark.asyncio
async def test_elapsed_timer():
with ElapsedTimer() as timer:
assert timer.elapsed.total_seconds() == pytest.approx(0, abs=0.05)
await asyncio.sleep(0.1)
await asyncio.sleep(
0.1
) # test to ensure time spent after timer exits isn't accounted for.
assert timer.elapsed.total_seconds() == pytest.approx(0.1, abs=0.05)
@pytest.mark.parametrize(
["environment", "proxies"],
[