Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/mixedbread/lib/parsing_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from . import polling
from .._types import Omit, NotGiven, FileTypes, omit, not_given
from .._utils import is_given
from .multipart_upload import MultipartUploadOptions
from ..types.parsing.parsing_job import ParsingJob
from ..types.parsing.element_type import ElementType
Expand Down Expand Up @@ -35,13 +36,13 @@ def poll(
**kwargs: Any,
) -> ParsingJob:
"""Poll a job's status until it reaches a terminal state."""
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else 500
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return polling.poll(
fn=functools.partial(self.retrieve, job_id, **kwargs),
condition=lambda res: res.status in _TERMINAL,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

def create_and_poll(
Expand Down Expand Up @@ -123,13 +124,13 @@ async def poll(
**kwargs: Any,
) -> ParsingJob:
"""Poll a job's status until it reaches a terminal state."""
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else 500
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return await polling.poll_async(
fn=functools.partial(self.retrieve, job_id, **kwargs),
condition=lambda res: res.status in _TERMINAL,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

async def create_and_poll(
Expand Down
4 changes: 2 additions & 2 deletions src/mixedbread/lib/polling.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def poll(
if max_attempts and attempt >= max_attempts:
raise RuntimeError(f"Maximum attempts ({max_attempts}) reached")

if timeout_seconds:
if timeout_seconds is not None:
elapsed = (datetime.now() - start_time).total_seconds()
if elapsed >= timeout_seconds:
raise TimeoutError(f"Timeout ({timeout_seconds}s) reached")
Expand Down Expand Up @@ -114,7 +114,7 @@ async def poll_async(
if max_attempts and attempt >= max_attempts:
raise RuntimeError(f"Maximum attempts ({max_attempts}) reached")

if timeout_seconds:
if timeout_seconds is not None:
elapsed = (datetime.now() - start_time).total_seconds()
if elapsed >= timeout_seconds:
raise TimeoutError(f"Timeout ({timeout_seconds}s) reached")
Expand Down
13 changes: 7 additions & 6 deletions src/mixedbread/lib/store_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from . import polling
from .._types import Omit, NotGiven, FileTypes, omit, not_given
from .._utils import is_given
from .multipart_upload import MultipartUploadOptions
from ..types.stores.store_file import StoreFile
from ..types.stores.store_file_config_param import StoreFileConfigParam
Expand Down Expand Up @@ -48,13 +49,13 @@ def poll(
Returns:
The file object once it reaches a terminal state
"""
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else 500
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return polling.poll(
fn=functools.partial(self.retrieve, file_identifier, store_identifier=store_identifier, **kwargs),
condition=lambda res: res.status in _TERMINAL,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

def create_and_poll(
Expand Down Expand Up @@ -163,13 +164,13 @@ async def poll(
**kwargs: Any,
) -> StoreFile:
"""Poll a file's status until it reaches a terminal state."""
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else 500
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return await polling.poll_async(
fn=functools.partial(self.retrieve, file_identifier, store_identifier=store_identifier, **kwargs),
condition=lambda res: res.status in _TERMINAL,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

async def create_and_poll(
Expand Down
13 changes: 7 additions & 6 deletions src/mixedbread/lib/stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from . import polling
from .._types import Omit, NotGiven, omit, not_given
from .._utils import is_given
from ..types.store import Store

if TYPE_CHECKING:
Expand Down Expand Up @@ -51,13 +52,13 @@ def poll(
Returns:
The store once it has settled
"""
polling_interval_ms = poll_interval_ms or _DEFAULT_POLL_INTERVAL_MS
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else _DEFAULT_POLL_INTERVAL_MS
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return polling.poll(
fn=functools.partial(self.retrieve, store_identifier, **kwargs),
condition=_is_settled,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

def copy_and_poll(
Expand Down Expand Up @@ -89,13 +90,13 @@ async def poll(
**kwargs: Any,
) -> Store:
"""Poll a store until it is no longer ``in_progress``."""
polling_interval_ms = poll_interval_ms or _DEFAULT_POLL_INTERVAL_MS
polling_timeout_ms = poll_timeout_ms or None
polling_interval_ms = poll_interval_ms if is_given(poll_interval_ms) else _DEFAULT_POLL_INTERVAL_MS
polling_timeout_ms = poll_timeout_ms if is_given(poll_timeout_ms) else None
return await polling.poll_async(
fn=functools.partial(self.retrieve, store_identifier, **kwargs),
condition=_is_settled,
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms is not None else None,
)

async def copy_and_poll(
Expand Down
36 changes: 35 additions & 1 deletion tests/test_store_helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from typing import List
from unittest.mock import Mock, AsyncMock
from unittest.mock import Mock, AsyncMock, patch

import pytest

Expand Down Expand Up @@ -46,6 +46,22 @@ def test_poll_returns_a_failed_copy() -> None:
assert stores.poll("vs_copy", poll_interval_ms=1).status == "failed"


def test_poll_honors_zero_interval() -> None:
stores = _Stores(["in_progress", "completed"])

with patch("time.sleep") as sleep_mock:
assert stores.poll("vs_copy", poll_interval_ms=0).status == "completed"

sleep_mock.assert_called_once_with(0.0)


def test_poll_honors_zero_timeout() -> None:
stores = _Stores(["in_progress", "in_progress", "completed"])

with pytest.raises(TimeoutError):
stores.poll("vs_copy", poll_interval_ms=1, poll_timeout_ms=0)


@pytest.mark.asyncio
async def test_async_copy_and_poll() -> None:
stores = _AsyncStores(["in_progress", "completed"])
Expand All @@ -54,3 +70,21 @@ async def test_async_copy_and_poll() -> None:

assert result.status == "completed"
assert stores.retrieve_mock.await_count == 2


@pytest.mark.asyncio
async def test_async_poll_honors_zero_interval() -> None:
stores = _AsyncStores(["in_progress", "completed"])

with patch("asyncio.sleep", new=AsyncMock()) as sleep_mock:
assert (await stores.poll("vs_copy", poll_interval_ms=0)).status == "completed"

sleep_mock.assert_called_once_with(0.0)


@pytest.mark.asyncio
async def test_async_poll_honors_zero_timeout() -> None:
stores = _AsyncStores(["in_progress", "in_progress", "completed"])

with pytest.raises(TimeoutError):
await stores.poll("vs_copy", poll_interval_ms=1, poll_timeout_ms=0)