Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 62
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mixedbread%2Fmixedbread-b091721a627d75feb8567f628f99405d5778b0b88e9cc09fc664dd8e97c6d720.yml
openapi_spec_hash: a23a2aecdcff5fa1d6c8cdc0df0bdfb7
config_hash: 22ce3b96e325037f81e7dbf22bdd8d24
config_hash: c56a6c9375e7640ce70ff00420e8605a
2 changes: 1 addition & 1 deletion src/mixedbread/_utils/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]:
# Type safe methods for narrowing types with TypeVars.
# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown],
# however this cause Pyright to rightfully report errors. As we know we don't
# care about the contained types we can safely use `object` in it's place.
# care about the contained types we can safely use `object` in its place.
#
# There are two separate functions defined, `is_*` and `is_*_t` for different use cases.
# `is_*` is for when you're dealing with an unknown input
Expand Down
120 changes: 110 additions & 10 deletions src/mixedbread/resources/stores/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import httpx

from ...lib import polling
from ..._types import Body, FileTypes, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, SequenceNotStr, omit, not_given
from ..._utils import maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
Expand Down Expand Up @@ -356,7 +356,7 @@ def search(

def poll(
self,
file_id: str,
file_identifier: str,
*,
store_identifier: str,
poll_interval_ms: int | NotGiven = not_given,
Expand All @@ -366,7 +366,7 @@ def poll(
"""
Poll for a file's status until it reaches a terminal state.
Args:
file_id: The ID of the file to poll
file_identifier: The ID or external_id of the file to poll
store_identifier: The ID of the store
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Expand All @@ -376,7 +376,7 @@ def poll(
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
return polling.poll(
fn=functools.partial(self.retrieve, file_id, store_identifier=store_identifier, **kwargs),
fn=functools.partial(self.retrieve, file_identifier, store_identifier=store_identifier, **kwargs),
condition=lambda res: res.status == "completed" or res.status == "failed" or res.status == "cancelled",
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
Expand All @@ -388,6 +388,9 @@ def create_and_poll(
*,
store_identifier: str,
metadata: Optional[object] | NotGiven = not_given,
config: file_create_params.Config | Omit = omit,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Type Mismatch: Metadata Omission in Create Flow

Type inconsistency for metadata parameter in create_and_poll method. The create() method expects metadata: object | Omit = omit, but create_and_poll() declares it as metadata: Optional[object] | NotGiven = not_given. When create_and_poll passes metadata to create(), there's a type mismatch between NotGiven and Omit, which could cause the metadata to not be properly omitted from the request.

Fix in Cursor Fix in Web

external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
poll_interval_ms: int | NotGiven = not_given,
poll_timeout_ms: float | NotGiven = not_given,
Expand All @@ -405,7 +408,14 @@ def create_and_poll(
The file object once it reaches a terminal state
"""
self.create(
store_identifier=store_identifier, file_id=file_id, metadata=metadata, experimental=experimental, **kwargs
store_identifier=store_identifier,
file_id=file_id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
**kwargs,
)
return self.poll(
file_id,
Expand All @@ -421,18 +431,39 @@ def upload(
store_identifier: str,
file: FileTypes,
metadata: Optional[object] | Omit = omit,
config: file_create_params.Config | Omit = omit,
external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
**kwargs: Any,
) -> StoreFile:
"""Upload a file to the `files` API and then attach it to the given store.
Note the file will be asynchronously processed (you can use the alternative
polling helper method to wait for processing to complete).

Args:
store_identifier: The ID or name of the store
file: The file to upload
metadata: Optional metadata for the file
config: Configuration for adding the file
external_id: External identifier for this file in the store
overwrite: If true, overwrite an existing file with the same external_id
experimental: Configuration for a file.
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
extra_body: Add additional JSON properties to the request
timeout: Override the client-level default timeout for this request, in seconds
Returns:
The file object once it reaches a terminal state
"""
file_obj = self._client.files.create(file=file, **kwargs)
return self.create(
store_identifier=store_identifier,
file_id=file_obj.id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
**kwargs,
)
Expand All @@ -443,17 +474,37 @@ def upload_and_poll(
store_identifier: str,
file: FileTypes,
metadata: Optional[object] | NotGiven = not_given,
config: file_create_params.Config | Omit = omit,
external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
poll_interval_ms: int | NotGiven = not_given,
poll_timeout_ms: float | NotGiven = not_given,
**kwargs: Any,
) -> StoreFile:
"""Add a file to a store and poll until processing is complete."""
"""Add a file to a store and poll until processing is complete.

Args:
store_identifier: The ID or name of the store
file: The file to upload
metadata: Optional metadata for the file
config: Configuration for adding the file
external_id: External identifier for this file in the store
overwrite: If true, overwrite an existing file with the same external_id
experimental: Configuration for a file.
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Returns:
The file object once it reaches a terminal state
"""
file_obj = self._client.files.create(file=file, **kwargs)
return self.create_and_poll(
store_identifier=store_identifier,
file_id=file_obj.id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
poll_interval_ms=poll_interval_ms,
poll_timeout_ms=poll_timeout_ms,
Expand Down Expand Up @@ -790,7 +841,7 @@ async def search(

async def poll(
self,
file_id: str,
file_identifier: str,
*,
store_identifier: str,
poll_interval_ms: int | NotGiven = not_given,
Expand All @@ -800,7 +851,7 @@ async def poll(
"""
Poll for a file's status until it reaches a terminal state.
Args:
file_id: The ID of the file to poll
file_identifier: The ID or external_id of the file to poll
store_identifier: The ID of the store
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Expand All @@ -810,7 +861,7 @@ async def poll(
polling_interval_ms = poll_interval_ms or 500
polling_timeout_ms = poll_timeout_ms or None
return await polling.poll_async(
fn=functools.partial(self.retrieve, file_id, store_identifier=store_identifier, **kwargs),
fn=functools.partial(self.retrieve, file_identifier, store_identifier=store_identifier, **kwargs),
condition=lambda res: res.status == "completed" or res.status == "failed" or res.status == "cancelled",
interval_seconds=polling_interval_ms / 1000,
timeout_seconds=polling_timeout_ms / 1000 if polling_timeout_ms else None,
Expand All @@ -822,6 +873,9 @@ async def create_and_poll(
*,
store_identifier: str,
metadata: Optional[object] | NotGiven = not_given,
config: file_create_params.Config | Omit = omit,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Async metadata type mismatch in poller method

Type inconsistency for metadata parameter in async create_and_poll method. The async create() method expects metadata: object | Omit = omit, but async create_and_poll() declares it as metadata: Optional[object] | NotGiven = not_given. When create_and_poll passes metadata to create(), there's a type mismatch between NotGiven and Omit, which could cause the metadata to not be properly omitted from the request.

Fix in Cursor Fix in Web

external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
poll_interval_ms: int | NotGiven = not_given,
poll_timeout_ms: float | NotGiven = not_given,
Expand All @@ -833,6 +887,10 @@ async def create_and_poll(
file_id: The ID of the file to poll
store_identifier: The ID of the store
metadata: The metadata to attach to the file
config: Configuration for adding the file
external_id: External identifier for this file in the store
overwrite: If true, overwrite an existing file with the same external_id
experimental: Configuration for a file.
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Returns:
Expand All @@ -842,6 +900,9 @@ async def create_and_poll(
store_identifier=store_identifier,
file_id=file_id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
**kwargs,
)
Expand All @@ -859,18 +920,37 @@ async def upload(
store_identifier: str,
file: FileTypes,
metadata: Optional[object] | NotGiven = not_given,
config: file_create_params.Config | Omit = omit,
external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
**kwargs: Any,
) -> StoreFile:
"""Upload a file to the `files` API and then attach it to the given vector store.
Note the file will be asynchronously processed (you can use the alternative
polling helper method to wait for processing to complete).

Args:
store_identifier: The ID or name of the store
file: The file to upload
metadata: Optional metadata for the file
config: Configuration for adding the file
external_id: External identifier for this file in the store
overwrite: If true, overwrite an existing file with the same external_id
experimental: Configuration for a file.
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Returns:
The file object once it reaches a terminal state
"""
file_obj = await self._client.files.create(file=file, **kwargs)
return await self.create(
store_identifier=store_identifier,
file_id=file_obj.id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
**kwargs,
)
Expand All @@ -881,17 +961,37 @@ async def upload_and_poll(
store_identifier: str,
file: FileTypes,
metadata: Optional[object] | NotGiven = not_given,
config: file_create_params.Config | Omit = omit,
external_id: Optional[str] | Omit = omit,
overwrite: bool | Omit = omit,
experimental: file_create_params.Experimental | Omit = omit,
poll_interval_ms: int | NotGiven = not_given,
poll_timeout_ms: float | NotGiven = not_given,
**kwargs: Any,
) -> StoreFile:
"""Add a file to a store and poll until processing is complete."""
"""Add a file to a store and poll until processing is complete.

Args:
store_identifier: The ID or name of the store
file: The file to upload
metadata: Optional metadata for the file
config: Configuration for adding the file
external_id: External identifier for this file in the store
overwrite: If true, overwrite an existing file with the same external_id
experimental: Configuration for a file.
poll_interval_ms: The interval between polls in milliseconds
poll_timeout_ms: The maximum time to poll for in milliseconds
Returns:
The file object once it reaches a terminal state
"""
file_obj = await self._client.files.create(file=file, **kwargs)
return await self.create_and_poll(
store_identifier=store_identifier,
file_id=file_obj.id,
metadata=metadata,
config=config,
external_id=external_id,
overwrite=overwrite,
experimental=experimental,
poll_interval_ms=poll_interval_ms,
poll_timeout_ms=poll_timeout_ms,
Expand Down
Loading