Skip to content

Commit

Permalink
Add timeout parameter to new methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jwodder committed Oct 14, 2020
1 parent 94e2b3f commit e1e6af8
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 12 deletions.
31 changes: 24 additions & 7 deletions src/pypi_simple/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import platform
from typing import Any, Iterator, List, Optional
from typing import Any, Iterator, List, Optional, Tuple, Union
from warnings import warn
from packaging.utils import canonicalize_name as normalize
import requests
Expand Down Expand Up @@ -64,7 +64,10 @@ def __init__(self, endpoint: str = PYPI_SIMPLE_ENDPOINT, auth: Any = None,
if auth is not None:
self.s.auth = auth

def get_index_page(self) -> IndexPage:
def get_index_page(
self,
timeout: Union[float, Tuple[float,float], None] = None,
) -> IndexPage:
"""
.. versionadded:: 0.7.0
Expand All @@ -76,17 +79,23 @@ def get_index_page(self) -> IndexPage:
PyPI's project index file is very large and takes several seconds
to parse. Use this method sparingly.
:param timeout: optional timeout to pass to the ``requests`` call
:type timeout: Union[float, Tuple[float,float], None]
:rtype: IndexPage
:raises requests.HTTPError: if the repository responds with an HTTP
error code
:raises UnsupportedRepoVersionError: if the repository version has a
greater major component than the supported repository version
"""
r = self.s.get(self.endpoint)
r = self.s.get(self.endpoint, timeout=timeout)
r.raise_for_status()
return parse_repo_index_response(r)

def stream_project_names(self, chunk_size: int = 65535) -> Iterator[str]:
def stream_project_names(
self,
chunk_size: int = 65535,
timeout: Union[float, Tuple[float,float], None] = None,
) -> Iterator[str]:
"""
.. versionadded:: 0.7.0
Expand All @@ -106,18 +115,24 @@ def stream_project_names(self, chunk_size: int = 65535) -> Iterator[str]:
:param int chunk_size: how many bytes to read from the response at a
time
:param timeout: optional timeout to pass to the ``requests`` call
:type timeout: Union[float, Tuple[float,float], None]
:rtype: Iterator[str]
:raises requests.HTTPError: if the repository responds with an HTTP
error code
:raises UnsupportedRepoVersionError: if the repository version has a
greater major component than the supported repository version
"""
with self.s.get(self.endpoint, stream=True) as r:
with self.s.get(self.endpoint, stream=True, timeout=timeout) as r:
r.raise_for_status()
for link in parse_links_stream_response(r, chunk_size):
yield link.text

def get_project_page(self, project: str) -> Optional[ProjectPage]:
def get_project_page(
self,
project: str,
timeout: Union[float, Tuple[float,float], None] = None,
) -> Optional[ProjectPage]:
"""
.. versionadded:: 0.7.0
Expand All @@ -128,14 +143,16 @@ def get_project_page(self, project: str) -> Optional[ProjectPage]:
:param str project: The name of the project to fetch information on.
The name does not need to be normalized.
:param timeout: optional timeout to pass to the ``requests`` call
:type timeout: Union[float, Tuple[float,float], None]
:rtype: Optional[ProjectPage]
:raises requests.HTTPError: if the repository responds with an HTTP
error code other than 404
:raises UnsupportedRepoVersionError: if the repository version has a
greater major component than the supported repository version
"""
url = self.get_project_url(project)
r = self.s.get(url)
r = self.s.get(url, timeout=timeout)
if r.status_code == 404:
return None
r.raise_for_status()
Expand Down
20 changes: 15 additions & 5 deletions test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
'text/html; charset=utf-8',
])
@responses.activate
def test_session(content_type):
def test_session(mocker, content_type):
session_dir = DATA_DIR / 'session01'
with (session_dir / 'simple.html').open() as fp:
responses.add(
Expand Down Expand Up @@ -43,14 +43,18 @@ def test_session(content_type):
status=404,
)
simple = PyPISimple('https://test.nil/simple/')
assert simple.get_index_page() == IndexPage(
spy = mocker.spy(simple.s, 'get')
assert simple.get_index_page(timeout=3.14) == IndexPage(
projects=['in_place', 'foo', 'BAR'],
last_serial='12345',
repository_version='1.0',
)
call, = spy.call_args_list
assert call.kwargs["timeout"] == 3.14
spy.reset_mock()
assert simple.get_project_url('IN.PLACE') \
== 'https://test.nil/simple/in-place/'
assert simple.get_project_page('IN.PLACE') == ProjectPage(
assert simple.get_project_page('IN.PLACE', timeout=2.718) == ProjectPage(
project='IN.PLACE',
packages=[
DistributionPackage(
Expand Down Expand Up @@ -117,6 +121,8 @@ def test_session(content_type):
last_serial='54321',
repository_version='1.0',
)
call, = spy.call_args_list
assert call.kwargs["timeout"] == 2.718
assert simple.get_project_page('nonexistent') is None

@responses.activate
Expand Down Expand Up @@ -303,7 +309,7 @@ def test_auth_override_custom_session():
assert simple.s.auth == ('user', 'password')

@responses.activate
def test_stream_project_names():
def test_stream_project_names(mocker):
session_dir = DATA_DIR / 'session01'
with (session_dir / 'simple.html').open() as fp:
responses.add(
Expand All @@ -321,4 +327,8 @@ def test_stream_project_names():
status=500,
)
simple = PyPISimple('https://test.nil/simple/')
assert list(simple.stream_project_names()) == ['in_place', 'foo', 'BAR']
spy = mocker.spy(simple.s, 'get')
assert list(simple.stream_project_names(timeout=1.618)) \
== ['in_place', 'foo', 'BAR']
call, = spy.call_args_list
assert call.kwargs["timeout"] == 1.618
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ deps =
flake8-import-order-jwodder
pytest~=6.0
pytest-cov~=2.0
pytest-mock~=3.0
responses~=0.12.0
commands =
flake8 src test
Expand Down

0 comments on commit e1e6af8

Please sign in to comment.