Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-langsmith for 
openSUSE:Factory checked in at 2026-07-29 19:00:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langsmith (Old)
 and      /work/SRC/openSUSE:Factory/.python-langsmith.new.2004 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-langsmith"

Wed Jul 29 19:00:42 2026 rev:15 rq:1368286 version:0.10.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-langsmith/python-langsmith.changes        
2026-07-24 22:05:21.649747222 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-langsmith.new.2004/python-langsmith.changes  
    2026-07-29 19:02:31.096408380 +0200
@@ -1,0 +2,11 @@
+Wed Jul 29 06:16:13 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 0.10.11:
+  * Remove the composite feedback formula APIs
+  * Restore _get_openapi_base_url stripping /api/v1 before it is
+    passed to the OpenAPI client
+  * Retry sandbox exec on a graceful close arriving before 'started'
+  * Fall back to HTTP exec only when the ws library is unavailable
+  * Keep dataplane_url after stop()
+
+-------------------------------------------------------------------

Old:
----
  langsmith-0.10.10.tar.gz

New:
----
  langsmith-0.10.11.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-langsmith.spec ++++++
--- /var/tmp/diff_new_pack.OYFBd5/_old  2026-07-29 19:02:31.712429611 +0200
+++ /var/tmp/diff_new_pack.OYFBd5/_new  2026-07-29 19:02:31.712429611 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python-langsmith
-Version:        0.10.10
+Version:        0.10.11
 Release:        0
 Summary:        Client library for the LangSmith LLM tracing and evaluation 
platform
 License:        MIT

++++++ langsmith-0.10.10.tar.gz -> langsmith-0.10.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/.bumpversion.cfg 
new/langsmith-0.10.11/.bumpversion.cfg
--- old/langsmith-0.10.10/.bumpversion.cfg      2020-02-02 01:00:00.000000000 
+0100
+++ new/langsmith-0.10.11/.bumpversion.cfg      2020-02-02 01:00:00.000000000 
+0100
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 0.10.10
+current_version = 0.10.11
 parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)
 serialize = {major}.{minor}.{patch}
 search = {current_version}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/PKG-INFO 
new/langsmith-0.10.11/PKG-INFO
--- old/langsmith-0.10.10/PKG-INFO      2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/PKG-INFO      2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: langsmith
-Version: 0.10.10
+Version: 0.10.11
 Summary: Client library to connect to the LangSmith Observability and 
Evaluation Platform.
 Project-URL: Homepage, https://smith.langchain.com/
 Project-URL: Documentation, https://docs.smith.langchain.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/__init__.py 
new/langsmith-0.10.11/langsmith/__init__.py
--- old/langsmith-0.10.10/langsmith/__init__.py 2020-02-02 01:00:00.000000000 
+0100
+++ new/langsmith-0.10.11/langsmith/__init__.py 2020-02-02 01:00:00.000000000 
+0100
@@ -49,7 +49,7 @@
 
 # Avoid calling into importlib on every call to __version__
 
-__version__ = "0.10.10"
+__version__ = "0.10.11"
 version = __version__  # for backwards compatibility
 
 # Metadata key to hide a traced run from LangSmith's Messages View.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/async_client.py 
new/langsmith-0.10.11/langsmith/async_client.py
--- old/langsmith-0.10.10/langsmith/async_client.py     2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/langsmith/async_client.py     2020-02-02 
01:00:00.000000000 +0100
@@ -23,6 +23,7 @@
 import httpx
 
 import langsmith._openapi_client as _langsmith_api_module
+from langsmith.client import _get_openapi_base_url
 
 if TYPE_CHECKING:
     from langsmith._openapi_client.resources.runs import AsyncRunsResource
@@ -300,7 +301,7 @@
         self._langsmith_api = _langsmith_api_module.AsyncLangsmith(
             api_key=self._api_key,
             tenant_id=self._workspace_id,
-            base_url=str(self._client.base_url),
+            base_url=_get_openapi_base_url(str(self._client.base_url)),
             timeout=self._client.timeout,
             default_headers=_headers or None,
         )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/client.py 
new/langsmith-0.10.11/langsmith/client.py
--- old/langsmith-0.10.10/langsmith/client.py   2020-02-02 01:00:00.000000000 
+0100
+++ new/langsmith-0.10.11/langsmith/client.py   2020-02-02 01:00:00.000000000 
+0100
@@ -62,7 +62,7 @@
 from requests_toolbelt import (  # type: ignore[import-untyped]
     multipart as rqtb_multipart,
 )
-from typing_extensions import TypeGuard, overload
+from typing_extensions import TypeGuard, deprecated, overload
 from urllib3.poolmanager import PoolKey  # type: ignore[attr-defined, 
import-untyped]
 from urllib3.util import Retry  # type: ignore[import-untyped]
 
@@ -153,6 +153,14 @@
         _tracing_drops_last_log_time = 0.0
 
 
+def _get_openapi_base_url(api_url: str) -> str:
+    """Convert a handwritten client API URL to a generated OpenAPI base URL."""
+    api_url = api_url.rstrip("/")
+    if api_url.endswith("/api/v1"):
+        return api_url[: -len("/api/v1")]
+    return api_url[:-3] if api_url.endswith("/v1") else api_url
+
+
 _TRACING_SEND_TIMEOUT = (3, 10)  # (connect, read) seconds for background sends
 
 _OPENAI_API_KEY = "OPENAI_API_KEY"
@@ -1484,7 +1492,7 @@
             self._langsmith_api = LangsmithOpenAPIClient(
                 api_key=self._api_key,
                 tenant_id=str(self._workspace_id) if self._workspace_id else 
None,
-                base_url=self.api_url,
+                base_url=_get_openapi_base_url(self.api_url),
                 timeout=_httpx.Timeout(
                     connect=self._timeout[0],
                     read=self._timeout[1],
@@ -8314,6 +8322,21 @@
             if limit is not None and i + 1 >= limit:
                 break
 
+    # Composite feedback formula API (deprecated)
+    #
+    # These operations are no longer supported. The signatures are retained so
+    # existing imports and type checks keep working, but every method now 
raises
+    # NotImplementedError. Add composite feedback scores via the LangSmith UI.
+
+    _FEEDBACK_FORMULA_DEPRECATION_MSG = (
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
+
+    @deprecated(
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
     def list_feedback_formulas(
         self,
         *,
@@ -8324,55 +8347,33 @@
     ) -> Iterator[ls_schemas.FeedbackFormula]:
         """List feedback formulas.
 
-        Args:
-            dataset_id (Optional[Union[UUID, str]]):
-                The ID of the dataset to filter by.
-            session_id (Optional[Union[UUID, str]]):
-                The ID of the session to filter by.
-            limit (Optional[int]):
-                The maximum number of feedback formulas to return.
-            offset (int):
-                The starting offset for pagination.
-
-        Yields:
-            The feedback formulas.
-        """
-        params: dict[str, Any] = {
-            "dataset_id": (
-                _as_uuid(dataset_id, "dataset_id") if dataset_id is not None 
else None
-            ),
-            "session_id": (
-                _as_uuid(session_id, "session_id") if session_id is not None 
else None
-            ),
-            "limit": min(limit, 100) if limit is not None else 100,
-            "offset": offset,
-        }
-        for i, feedback_formula in enumerate(
-            self._get_paginated_list("/feedback/formulas", params=params)
-        ):
-            yield ls_schemas.FeedbackFormula(**feedback_formula)
-            if limit is not None and i + 1 >= limit:
-                break
-
+        .. deprecated::
+            Composite feedback formulas are no longer supported in the SDK.
+            Add composite feedback scores via the LangSmith UI instead.
+            This method now raises ``NotImplementedError``.
+        """
+        raise NotImplementedError(self._FEEDBACK_FORMULA_DEPRECATION_MSG)
+
+    @deprecated(
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
     def get_feedback_formula_by_id(
         self, feedback_formula_id: ID_TYPE
     ) -> ls_schemas.FeedbackFormula:
         """Get a feedback formula by ID.
 
-        Args:
-            feedback_formula_id (Union[UUID, str]):
-                The ID of the feedback formula to retrieve.
-
-        Returns:
-            The requested feedback formula.
-        """
-        response = self.request_with_retries(
-            "GET",
-            f"/feedback/formulas/{_as_uuid(feedback_formula_id, 
'feedback_formula_id')}",
-        )
-        ls_utils.raise_for_status_with_text(response)
-        return ls_schemas.FeedbackFormula(**response.json())
-
+        .. deprecated::
+            Composite feedback formulas are no longer supported in the SDK.
+            Add composite feedback scores via the LangSmith UI instead.
+            This method now raises ``NotImplementedError``.
+        """
+        raise NotImplementedError(self._FEEDBACK_FORMULA_DEPRECATION_MSG)
+
+    @deprecated(
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
     def create_feedback_formula(
         self,
         *,
@@ -8386,48 +8387,17 @@
     ) -> ls_schemas.FeedbackFormula:
         """Create a feedback formula.
 
-        Args:
-            feedback_key (str):
-                The feedback key for the formula.
-            aggregation_type (Literal["sum", "avg"]):
-                The aggregation type to use when combining parts.
-            formula_parts (Sequence[FeedbackFormulaWeightedVariable | dict]):
-                The weighted feedback keys included in the formula.
-            dataset_id (Optional[Union[UUID, str]]):
-                The dataset to scope the formula to.
-            session_id (Optional[Union[UUID, str]]):
-                The session to scope the formula to.
-
-        Returns:
-            The created feedback formula.
-        """
-        typed_parts: list[ls_schemas.FeedbackFormulaWeightedVariable] = [
-            part
-            if isinstance(part, ls_schemas.FeedbackFormulaWeightedVariable)
-            else ls_schemas.FeedbackFormulaWeightedVariable(**part)
-            for part in formula_parts
-        ]
-        payload = ls_schemas.FeedbackFormulaCreate(
-            feedback_key=feedback_key,
-            aggregation_type=aggregation_type,
-            formula_parts=typed_parts,
-            dataset_id=(
-                _as_uuid(dataset_id, "dataset_id") if dataset_id is not None 
else None
-            ),
-            session_id=(
-                _as_uuid(session_id, "session_id") if session_id is not None 
else None
-            ),
-        )
-        response = self.request_with_retries(
-            "POST",
-            "/feedback/formulas",
-            request_kwargs={
-                "data": _dumps_json(payload.model_dump(exclude_none=True)),
-            },
-        )
-        ls_utils.raise_for_status_with_text(response)
-        return ls_schemas.FeedbackFormula(**response.json())
-
+        .. deprecated::
+            Composite feedback formulas are no longer supported in the SDK.
+            Add composite feedback scores via the LangSmith UI instead.
+            This method now raises ``NotImplementedError``.
+        """
+        raise NotImplementedError(self._FEEDBACK_FORMULA_DEPRECATION_MSG)
+
+    @deprecated(
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
     def update_feedback_formula(
         self,
         feedback_formula_id: ID_TYPE,
@@ -8440,52 +8410,26 @@
     ) -> ls_schemas.FeedbackFormula:
         """Update a feedback formula.
 
-        Args:
-            feedback_formula_id (Union[UUID, str]):
-                The ID of the feedback formula to update.
-            feedback_key (str):
-                The feedback key for the formula.
-            aggregation_type (Literal["sum", "avg"]):
-                The aggregation type to use when combining parts.
-            formula_parts (Sequence[FeedbackFormulaWeightedVariable | dict]):
-                The weighted feedback keys included in the formula.
-
-        Returns:
-            The updated feedback formula.
-        """
-        typed_parts: list[ls_schemas.FeedbackFormulaWeightedVariable] = [
-            part
-            if isinstance(part, ls_schemas.FeedbackFormulaWeightedVariable)
-            else ls_schemas.FeedbackFormulaWeightedVariable(**part)
-            for part in formula_parts
-        ]
-        payload = ls_schemas.FeedbackFormulaUpdate(
-            feedback_key=feedback_key,
-            aggregation_type=aggregation_type,
-            formula_parts=typed_parts,
-        )
-        response = self.request_with_retries(
-            "PUT",
-            f"/feedback/formulas/{_as_uuid(feedback_formula_id, 
'feedback_formula_id')}",
-            request_kwargs={
-                "data": _dumps_json(payload.model_dump(exclude_none=True)),
-            },
-        )
-        ls_utils.raise_for_status_with_text(response)
-        return ls_schemas.FeedbackFormula(**response.json())
-
+        .. deprecated::
+            Composite feedback formulas are no longer supported in the SDK.
+            Add composite feedback scores via the LangSmith UI instead.
+            This method now raises ``NotImplementedError``.
+        """
+        raise NotImplementedError(self._FEEDBACK_FORMULA_DEPRECATION_MSG)
+
+    @deprecated(
+        "Composite feedback formulas are no longer supported in the SDK. "
+        "Add composite feedback scores via the LangSmith UI instead."
+    )
     def delete_feedback_formula(self, feedback_formula_id: ID_TYPE) -> None:
         """Delete a feedback formula by ID.
 
-        Args:
-            feedback_formula_id (Union[UUID, str]):
-                The ID of the feedback formula to delete.
+        .. deprecated::
+            Composite feedback formulas are no longer supported in the SDK.
+            Add composite feedback scores via the LangSmith UI instead.
+            This method now raises ``NotImplementedError``.
         """
-        response = self.request_with_retries(
-            "DELETE",
-            f"/feedback/formulas/{_as_uuid(feedback_formula_id, 
'feedback_formula_id')}",
-        )
-        ls_utils.raise_for_status_with_text(response)
+        raise NotImplementedError(self._FEEDBACK_FORMULA_DEPRECATION_MSG)
 
     # Feedback Config API
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/langsmith/sandbox/_async_sandbox.py 
new/langsmith-0.10.11/langsmith/sandbox/_async_sandbox.py
--- old/langsmith-0.10.10/langsmith/sandbox/_async_sandbox.py   2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/langsmith/sandbox/_async_sandbox.py   2020-02-02 
01:00:00.000000000 +0100
@@ -12,7 +12,6 @@
 from langsmith.sandbox._exceptions import (
     DataplaneNotConfiguredError,
     ResourceNotFoundError,
-    SandboxConnectionError,
 )
 from langsmith.sandbox._helpers import handle_sandbox_http_error
 from langsmith.sandbox._models import (
@@ -20,8 +19,10 @@
     AsyncServiceURL,
     ExecutionResult,
     Snapshot,
+    _StreamEndedBeforeStarted,
 )
 from langsmith.sandbox._tunnel import AsyncTunnel
+from langsmith.sandbox._ws_execute import WEBSOCKETS_AVAILABLE
 
 if TYPE_CHECKING:
     from langsmith.sandbox._async_client import AsyncSandboxClient
@@ -335,9 +336,9 @@
                 headers=headers,
             )
 
-        # Catch broad exceptions so that unexpected WS failures (e.g. version
-        # incompatibilities) don't break users who don't need WS features.
-        try:
+        # Default (wait=True, no callbacks): use WebSocket when the client
+        # library is available, otherwise the blocking HTTP endpoint.
+        if WEBSOCKETS_AVAILABLE:
             return await self._run_ws(
                 command,
                 timeout=timeout,
@@ -353,15 +354,14 @@
                 pty=pty,
                 headers=headers,
             )
-        except (SandboxConnectionError, ImportError, OSError, TypeError):
-            return await self._run_http(
-                command,
-                timeout=timeout,
-                env=env,
-                cwd=cwd,
-                shell=shell,
-                headers=headers,
-            )
+        return await self._run_http(
+            command,
+            timeout=timeout,
+            env=env,
+            cwd=cwd,
+            shell=shell,
+            headers=headers,
+        )
 
     async def _run_ws(
         self,
@@ -381,12 +381,22 @@
         headers: RequestHeaders = None,
     ) -> Union[ExecutionResult, AsyncCommandHandle]:
         """Execute via WebSocket /execute/ws."""
+        import asyncio
+
         from langsmith.sandbox._ws_execute import run_ws_stream_async
+        from langsmith.uuid import uuid7
 
         dataplane_url = self._require_dataplane_url()
         api_key = self._client._api_key
 
+        # A client-supplied command_id makes execute idempotent: the daemon 
does
+        # get-or-create keyed on it, so if the tunnel closes before "started" 
we
+        # can re-issue the same id and reattach to the existing command instead
+        # of spawning a second one.
+        command_id = uuid7().hex
+
         ws_kwargs: dict[str, Any] = {
+            "command_id": command_id,
             "timeout": timeout,
             "env": env,
             "cwd": cwd,
@@ -400,21 +410,35 @@
         if merged:
             ws_kwargs["headers"] = merged
 
-        msg_stream, control = await run_ws_stream_async(
-            dataplane_url,
-            api_key,
-            command,
-            **ws_kwargs,
-        )
-
-        handle = AsyncCommandHandle(
-            msg_stream,
-            control,
-            self,
-            on_stdout=on_stdout,
-            on_stderr=on_stderr,
-        )
-        await handle._ensure_started()
+        attempt = 0
+        while True:
+            msg_stream, control = await run_ws_stream_async(
+                dataplane_url,
+                api_key,
+                command,
+                **ws_kwargs,
+            )
+            handle = AsyncCommandHandle(
+                msg_stream,
+                control,
+                self,
+                on_stdout=on_stdout,
+                on_stderr=on_stderr,
+            )
+            try:
+                await handle._ensure_started()
+                break
+            except _StreamEndedBeforeStarted:
+                # Idempotent re-issue (same command_id) after an early close.
+                attempt += 1
+                if attempt > AsyncCommandHandle.MAX_AUTO_RECONNECTS:
+                    raise
+                await asyncio.sleep(
+                    min(
+                        AsyncCommandHandle._BACKOFF_BASE * (2 ** (attempt - 
1)),
+                        AsyncCommandHandle._BACKOFF_MAX,
+                    )
+                )
 
         if not wait:
             return handle
@@ -728,8 +752,9 @@
             SandboxClientError: For other errors.
         """
         await self._client.stop_sandbox(self.name, headers=headers)
+        # dataplane_url stays set: it is stable across stop/start and a request
+        # on it resumes the sandbox.
         self.status = "stopped"
-        self.dataplane_url = None
 
     async def delete(self, *, headers: RequestHeaders = None) -> None:
         """Delete this sandbox.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/sandbox/_models.py 
new/langsmith-0.10.11/langsmith/sandbox/_models.py
--- old/langsmith-0.10.10/langsmith/sandbox/_models.py  2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/langsmith/sandbox/_models.py  2020-02-02 
01:00:00.000000000 +0100
@@ -24,6 +24,16 @@
     )
 
 
+class _StreamEndedBeforeStarted(SandboxOperationError):
+    """A command WebSocket closed before the guest sent its 'started' frame.
+
+    Internal marker for the idempotently-retryable early close (the proxied
+    tunnel was torn down gracefully mid-handshake), as distinct from a
+    command-level failure. Subclasses SandboxOperationError so callers that
+    catch the public type are unaffected.
+    """
+
+
 @dataclass
 class ExecutionResult:
     """Result of executing a command in a sandbox."""
@@ -530,7 +540,7 @@
         try:
             first_msg = next(self._stream)
         except StopIteration:
-            raise SandboxOperationError(
+            raise _StreamEndedBeforeStarted(
                 "Command stream ended before 'started' message",
                 operation="command",
             )
@@ -787,7 +797,7 @@
         try:
             first_msg = await self._stream.__anext__()
         except StopAsyncIteration:
-            raise SandboxOperationError(
+            raise _StreamEndedBeforeStarted(
                 "Command stream ended before 'started' message",
                 operation="command",
             )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/sandbox/_sandbox.py 
new/langsmith-0.10.11/langsmith/sandbox/_sandbox.py
--- old/langsmith-0.10.10/langsmith/sandbox/_sandbox.py 2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/langsmith/sandbox/_sandbox.py 2020-02-02 
01:00:00.000000000 +0100
@@ -11,7 +11,6 @@
 from langsmith.sandbox._exceptions import (
     DataplaneNotConfiguredError,
     ResourceNotFoundError,
-    SandboxConnectionError,
 )
 from langsmith.sandbox._helpers import handle_sandbox_http_error
 from langsmith.sandbox._models import (
@@ -19,8 +18,10 @@
     ExecutionResult,
     ServiceURL,
     Snapshot,
+    _StreamEndedBeforeStarted,
 )
 from langsmith.sandbox._tunnel import Tunnel
+from langsmith.sandbox._ws_execute import WEBSOCKETS_AVAILABLE
 
 if TYPE_CHECKING:
     from langsmith.sandbox._async_client import AsyncSandboxClient
@@ -333,10 +334,9 @@
                 headers=headers,
             )
 
-        # Default (wait=True, no callbacks): try WS, fall back to HTTP.
-        # Catch broad exceptions so that unexpected WS failures (e.g. version
-        # incompatibilities) don't break users who don't need WS features.
-        try:
+        # Default (wait=True, no callbacks): use WebSocket when the client
+        # library is available, otherwise the blocking HTTP endpoint.
+        if WEBSOCKETS_AVAILABLE:
             return self._run_ws(
                 command,
                 timeout=timeout,
@@ -352,15 +352,14 @@
                 pty=pty,
                 headers=headers,
             )
-        except (SandboxConnectionError, ImportError, OSError, TypeError):
-            return self._run_http(
-                command,
-                timeout=timeout,
-                env=env,
-                cwd=cwd,
-                shell=shell,
-                headers=headers,
-            )
+        return self._run_http(
+            command,
+            timeout=timeout,
+            env=env,
+            cwd=cwd,
+            shell=shell,
+            headers=headers,
+        )
 
     def _run_ws(
         self,
@@ -380,12 +379,22 @@
         headers: RequestHeaders = None,
     ) -> Union[ExecutionResult, CommandHandle]:
         """Execute via WebSocket /execute/ws."""
+        import time
+
         from langsmith.sandbox._ws_execute import run_ws_stream
+        from langsmith.uuid import uuid7
 
         dataplane_url = self._require_dataplane_url()
         api_key = self._client._api_key
 
+        # A client-supplied command_id makes execute idempotent: the daemon 
does
+        # get-or-create keyed on it, so if the tunnel closes before "started" 
we
+        # can re-issue the same id and reattach to the existing command instead
+        # of spawning a second one.
+        command_id = uuid7().hex
+
         ws_kwargs: dict[str, Any] = {
+            "command_id": command_id,
             "timeout": timeout,
             "env": env,
             "cwd": cwd,
@@ -399,20 +408,34 @@
         if merged:
             ws_kwargs["headers"] = merged
 
-        msg_stream, control = run_ws_stream(
-            dataplane_url,
-            api_key,
-            command,
-            **ws_kwargs,
-        )
-
-        handle = CommandHandle(
-            msg_stream,
-            control,
-            self,
-            on_stdout=on_stdout,
-            on_stderr=on_stderr,
-        )
+        attempt = 0
+        while True:
+            msg_stream, control = run_ws_stream(
+                dataplane_url,
+                api_key,
+                command,
+                **ws_kwargs,
+            )
+            try:
+                handle = CommandHandle(
+                    msg_stream,
+                    control,
+                    self,
+                    on_stdout=on_stdout,
+                    on_stderr=on_stderr,
+                )
+                break
+            except _StreamEndedBeforeStarted:
+                # Idempotent re-issue (same command_id) after an early close.
+                attempt += 1
+                if attempt > CommandHandle.MAX_AUTO_RECONNECTS:
+                    raise
+                time.sleep(
+                    min(
+                        CommandHandle._BACKOFF_BASE * (2 ** (attempt - 1)),
+                        CommandHandle._BACKOFF_MAX,
+                    )
+                )
 
         if not wait:
             return handle
@@ -731,8 +754,9 @@
             SandboxClientError: For other errors.
         """
         self._client.stop_sandbox(self.name, headers=headers)
+        # dataplane_url stays set: it is stable across stop/start and a request
+        # on it resumes the sandbox.
         self.status = "stopped"
-        self.dataplane_url = None
 
     def delete(self, *, headers: RequestHeaders = None) -> None:
         """Delete this sandbox.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/sandbox/_ws_execute.py 
new/langsmith-0.10.11/langsmith/sandbox/_ws_execute.py
--- old/langsmith-0.10.10/langsmith/sandbox/_ws_execute.py      2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/langsmith/sandbox/_ws_execute.py      2020-02-02 
01:00:00.000000000 +0100
@@ -15,35 +15,39 @@
 )
 from langsmith.sandbox._helpers import merge_headers
 
+# Resolve the optional ``websockets`` dependency once, at import time, instead
+# of re-importing on every WS call. ``WEBSOCKETS_AVAILABLE`` is what run() 
reads
+# to choose WebSocket vs the blocking HTTP fallback.
+try:
+    from websockets.asyncio.client import connect as _ws_connect_async
+    from websockets.exceptions import ConnectionClosed, InvalidHandshake
+    from websockets.sync.client import connect as _ws_connect_sync
+
+    WEBSOCKETS_AVAILABLE = True
+except ImportError:
+    _ws_connect_async = _ws_connect_sync = None  # type: 
ignore[assignment,misc]
+    ConnectionClosed = InvalidHandshake = None  # type: ignore[assignment,misc]
+    WEBSOCKETS_AVAILABLE = False
+
+
+_MISSING_WEBSOCKETS_MSG = (
+    "WebSocket-based execution requires the 'websockets' package, which ships "
+    "with langsmith by default. Reinstall with: pip install --upgrade 
langsmith"
+)
+
 
 def _ensure_websockets():
-    """Import websockets or raise a clear error."""
-    try:
-        from websockets.exceptions import ConnectionClosed, InvalidHandshake
-        from websockets.sync.client import connect as ws_connect
-
-        return ws_connect, ConnectionClosed, InvalidHandshake
-    except ImportError:
-        raise ImportError(
-            "WebSocket-based execution requires the 'websockets' package, "
-            "which ships with langsmith by default. Reinstall with: "
-            "pip install --upgrade langsmith"
-        ) from None
+    """Return the cached sync websockets symbols, or raise if unavailable."""
+    if not WEBSOCKETS_AVAILABLE:
+        raise ImportError(_MISSING_WEBSOCKETS_MSG)
+    return _ws_connect_sync, ConnectionClosed, InvalidHandshake
 
 
 def _ensure_websockets_async():
-    """Import async websockets or raise a clear error."""
-    try:
-        from websockets.asyncio.client import connect as ws_connect_async
-        from websockets.exceptions import ConnectionClosed, InvalidHandshake
-
-        return ws_connect_async, ConnectionClosed, InvalidHandshake
-    except ImportError:
-        raise ImportError(
-            "WebSocket-based execution requires the 'websockets' package, "
-            "which ships with langsmith by default. Reinstall with: "
-            "pip install --upgrade langsmith"
-        ) from None
+    """Return the cached async websockets symbols, or raise if unavailable."""
+    if not WEBSOCKETS_AVAILABLE:
+        raise ImportError(_MISSING_WEBSOCKETS_MSG)
+    return _ws_connect_async, ConnectionClosed, InvalidHandshake
 
 
 def _build_ws_url(dataplane_url: str) -> str:
@@ -228,6 +232,7 @@
     api_key: Optional[str],
     command: str,
     *,
+    command_id: str = "",
     timeout: int = 60,
     env: Optional[dict[str, str]] = None,
     cwd: Optional[str] = None,
@@ -281,6 +286,8 @@
                     "kill_on_disconnect": kill_on_disconnect,
                     "ttl_seconds": ttl_seconds,
                 }
+                if command_id:
+                    payload["command_id"] = command_id
                 if env:
                     payload["env"] = env
                 if cwd:
@@ -425,6 +432,7 @@
     api_key: Optional[str],
     command: str,
     *,
+    command_id: str = "",
     timeout: int = 60,
     env: Optional[dict[str, str]] = None,
     cwd: Optional[str] = None,
@@ -467,6 +475,8 @@
                     "kill_on_disconnect": kill_on_disconnect,
                     "ttl_seconds": ttl_seconds,
                 }
+                if command_id:
+                    payload["command_id"] = command_id
                 if env:
                     payload["env"] = env
                 if cwd:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/langsmith/schemas.py 
new/langsmith-0.10.11/langsmith/schemas.py
--- old/langsmith-0.10.10/langsmith/schemas.py  2020-02-02 01:00:00.000000000 
+0100
+++ new/langsmith-0.10.11/langsmith/schemas.py  2020-02-02 01:00:00.000000000 
+0100
@@ -1657,7 +1657,14 @@
 
 
 class FeedbackFormulaWeightedVariable(BaseModel):
-    """A feedback key and weight used when calculating feedback formulas."""
+    """A feedback key and weight used when calculating feedback formulas.
+
+    .. deprecated::
+        Composite feedback formulas are no longer supported in the SDK.
+        Add composite feedback scores via the LangSmith UI instead. This
+        schema is retained only for backwards compatibility and will be
+        removed in a future release.
+    """
 
     part_type: Literal["weighted_key"]
     weight: float
@@ -1665,7 +1672,14 @@
 
 
 class FeedbackFormulaCreate(BaseModel):
-    """Schema used for creating a feedback formula."""
+    """Schema used for creating a feedback formula.
+
+    .. deprecated::
+        Composite feedback formulas are no longer supported in the SDK.
+        Add composite feedback scores via the LangSmith UI instead. This
+        schema is retained only for backwards compatibility and will be
+        removed in a future release.
+    """
 
     dataset_id: Optional[UUID] = None
     session_id: Optional[UUID] = None
@@ -1677,7 +1691,14 @@
 
 
 class FeedbackFormulaUpdate(BaseModel):
-    """Schema used for updating a feedback formula."""
+    """Schema used for updating a feedback formula.
+
+    .. deprecated::
+        Composite feedback formulas are no longer supported in the SDK.
+        Add composite feedback scores via the LangSmith UI instead. This
+        schema is retained only for backwards compatibility and will be
+        removed in a future release.
+    """
 
     feedback_key: str
     aggregation_type: Literal["sum", "avg"]
@@ -1687,7 +1708,14 @@
 
 
 class FeedbackFormula(FeedbackFormulaCreate):
-    """Schema for getting feedback formulas."""
+    """Schema for getting feedback formulas.
+
+    .. deprecated::
+        Composite feedback formulas are no longer supported in the SDK.
+        Add composite feedback scores via the LangSmith UI instead. This
+        schema is retained only for backwards compatibility and will be
+        removed in a future release.
+    """
 
     id: UUID
     created_at: datetime
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/tests/unit_tests/sandbox/test_async_sandbox.py 
new/langsmith-0.10.11/tests/unit_tests/sandbox/test_async_sandbox.py
--- old/langsmith-0.10.10/tests/unit_tests/sandbox/test_async_sandbox.py        
2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/sandbox/test_async_sandbox.py        
2020-02-02 01:00:00.000000000 +0100
@@ -150,10 +150,13 @@
         assert sb.status_message is None
 
     async def test_dataplane_op_not_gated_on_status(
-        self, client, httpx_mock: HTTPXMock
+        self, client, httpx_mock: HTTPXMock, monkeypatch
     ):
         """The client does not pre-check status: a stopped sandbox still runs;
         the platform resumes it when the dataplane request arrives."""
+        monkeypatch.setattr(
+            "langsmith.sandbox._async_sandbox.WEBSOCKETS_AVAILABLE", False
+        )
         httpx_mock.add_response(
             method="POST",
             url="https://sandbox-router.example.com/sb-123/execute";,
@@ -186,9 +189,42 @@
         with pytest.raises(DataplaneNotConfiguredError):
             await sb.read("/tmp/test.txt")
 
+    async def test_stop_preserves_dataplane_url(self, client, httpx_mock: 
HTTPXMock):
+        """stop() must not clear dataplane_url: it stays valid across
+        stop/start and a request on it resumes the sandbox."""
+        httpx_mock.add_response(
+            method="POST",
+            url="http://test-server:8080/boxes/test-sandbox/stop";,
+            json={},
+        )
+        sb = AsyncSandbox.from_dict(
+            data={
+                "name": "test-sandbox",
+                "status": "ready",
+                "dataplane_url": "https://sandbox-router.example.com/sb-123";,
+            },
+            client=client,
+            auto_delete=False,
+        )
+        await sb.stop()
+        assert sb.status == "stopped"
+        assert sb.dataplane_url == "https://sandbox-router.example.com/sb-123";
+
 
 class TestAsyncSandboxRun:
-    """Tests for async sandbox run command."""
+    """AsyncSandbox.run() over the HTTP fallback path.
+
+    run() uses WebSocket by default; these cases pin the request/response
+    shaping of the blocking HTTP endpoint it falls back to when the websockets
+    library is unavailable.
+    """
+
+    @pytest.fixture(autouse=True)
+    def _ws_unavailable(self, monkeypatch):
+        """Force the missing-websockets condition so run() takes the HTTP 
path."""
+        monkeypatch.setattr(
+            "langsmith.sandbox._async_sandbox.WEBSOCKETS_AVAILABLE", False
+        )
 
     async def test_run_command_success(self, sandbox, httpx_mock: HTTPXMock):
         """Test running a successful command."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/tests/unit_tests/sandbox/test_async_ws_execute.py 
new/langsmith-0.10.11/tests/unit_tests/sandbox/test_async_ws_execute.py
--- old/langsmith-0.10.10/tests/unit_tests/sandbox/test_async_ws_execute.py     
2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/sandbox/test_async_ws_execute.py     
2020-02-02 01:00:00.000000000 +0100
@@ -5,7 +5,7 @@
 import json
 from collections.abc import AsyncIterator
 from typing import Any
-from unittest.mock import AsyncMock, MagicMock, patch
+from unittest.mock import ANY, AsyncMock, MagicMock, patch
 
 import pytest
 
@@ -734,6 +734,7 @@
             "https://router.example.com/sb-123";,
             "test-key",
             "echo hello",
+            command_id=ANY,
             timeout=60,
             env=None,
             cwd=None,
@@ -777,17 +778,12 @@
             )
 
     @pytest.mark.asyncio
-    @pytest.mark.parametrize(
-        "exc",
-        [
-            SandboxConnectionError("WS failed"),
-            ImportError("no websockets"),
-        ],
-    )
-    @patch("langsmith.sandbox._ws_execute.run_ws_stream_async")
-    async def test_run_fallback_to_http(self, mock_run_ws, exc):
-        """WS failure (connection error or missing lib) falls back to HTTP."""
-        mock_run_ws.side_effect = exc
+    async def test_run_fallback_to_http_when_ws_unavailable(self, monkeypatch):
+        """run() falls back to HTTP only when the websockets library is
+        unavailable."""
+        monkeypatch.setattr(
+            "langsmith.sandbox._async_sandbox.WEBSOCKETS_AVAILABLE", False
+        )
         sandbox = self._make_sandbox()
 
         with patch.object(sandbox, "_run_http", new_callable=AsyncMock) as 
mock_http:
@@ -801,6 +797,27 @@
         assert result.stdout == "http output"
         mock_http.assert_called_once()
 
+    @pytest.mark.parametrize(
+        "exc",
+        [
+            SandboxConnectionError("WS failed"),
+            OSError("socket down"),
+        ],
+    )
+    @patch("langsmith.sandbox._ws_execute.run_ws_stream_async")
+    async def test_run_ws_error_propagates_without_http_fallback(
+        self, mock_run_ws, exc
+    ):
+        """Any WS failure other than a missing library propagates; run() must
+        not silently fall back to the capacity-capped blocking HTTP 
endpoint."""
+        mock_run_ws.side_effect = exc
+        sandbox = self._make_sandbox()
+
+        with patch.object(sandbox, "_run_http", new_callable=AsyncMock) as 
mock_http:
+            with pytest.raises(type(exc)):
+                await sandbox.run("echo hello")
+        mock_http.assert_not_called()
+
     @pytest.mark.asyncio
     @pytest.mark.parametrize(
         "kwargs",
@@ -931,7 +948,7 @@
 
     @pytest.mark.asyncio
     async def test_run_ws_stream_async_wraps_invalid_message(self):
-        with patch("websockets.asyncio.client.connect") as mock_connect:
+        with patch("langsmith.sandbox._ws_execute._ws_connect_async") as 
mock_connect:
             mock_connect.side_effect = self._invalid_message()
             msg_stream, _ = await run_ws_stream_async(
                 "https://sb.example.com";, "key", "echo hi"
@@ -942,7 +959,7 @@
 
     @pytest.mark.asyncio
     async def test_reconnect_ws_stream_async_wraps_invalid_message(self):
-        with patch("websockets.asyncio.client.connect") as mock_connect:
+        with patch("langsmith.sandbox._ws_execute._ws_connect_async") as 
mock_connect:
             mock_connect.side_effect = self._invalid_message()
             msg_stream, _ = await reconnect_ws_stream_async(
                 "https://sb.example.com";, "key", "cmd-123"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/tests/unit_tests/sandbox/test_command_id_retry.py 
new/langsmith-0.10.11/tests/unit_tests/sandbox/test_command_id_retry.py
--- old/langsmith-0.10.10/tests/unit_tests/sandbox/test_command_id_retry.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/sandbox/test_command_id_retry.py     
2020-02-02 01:00:00.000000000 +0100
@@ -0,0 +1,140 @@
+"""Idempotent retry when a command WebSocket closes before 'started'.
+
+A proxied exec tunnel can be torn down gracefully before the guest emits its
+'started' frame. run() sends a client-generated command_id and the server does
+get-or-create keyed on it, so re-issuing the same command reattaches to the
+existing session instead of spawning a second one.
+"""
+
+import pytest
+
+from langsmith.sandbox import (
+    AsyncSandboxClient,
+    SandboxClient,
+)
+from langsmith.sandbox._async_sandbox import AsyncSandbox
+from langsmith.sandbox._models import (
+    CommandHandle,
+    _StreamEndedBeforeStarted,
+)
+from langsmith.sandbox._sandbox import Sandbox
+
+
[email protected](autouse=True)
+def _no_sleep(monkeypatch):
+    monkeypatch.setattr("time.sleep", lambda _s: None)
+
+
+def _sandbox():
+    return Sandbox.from_dict(
+        data={
+            "name": "sb",
+            "dataplane_url": "https://sandbox-router.example.com/sb-123";,
+        },
+        client=SandboxClient(api_endpoint="http://test-server:8080";, 
max_retries=0),
+        auto_delete=False,
+    )
+
+
+def _empty():
+    return iter(())
+
+
+def _started_then_exit(command_id):
+    return iter(
+        [
+            {"type": "started", "command_id": command_id, "pid": 1},
+            {"type": "exit", "exit_code": 0},
+        ]
+    )
+
+
+class TestCommandHandle:
+    def test_empty_stream_raises_marker(self):
+        with pytest.raises(_StreamEndedBeforeStarted):
+            CommandHandle(_empty(), None, _sandbox())
+
+
+class TestSyncRetry:
+    def test_retries_with_same_command_id(self, monkeypatch):
+        sandbox = _sandbox()
+        calls: list[dict] = []
+
+        def fake_run_ws_stream(dataplane_url, api_key, command, **kwargs):
+            calls.append(kwargs)
+            if len(calls) == 1:
+                return _empty(), None
+            return _started_then_exit(kwargs["command_id"]), None
+
+        monkeypatch.setattr(
+            "langsmith.sandbox._ws_execute.run_ws_stream", fake_run_ws_stream
+        )
+
+        result = sandbox.run("echo hi")
+
+        assert result.exit_code == 0
+        assert len(calls) == 2
+        # Same id across the retry -> server dedupes, no double-run.
+        assert calls[0]["command_id"] == calls[1]["command_id"]
+
+    def test_gives_up_after_max_attempts(self, monkeypatch):
+        sandbox = _sandbox()
+        calls: list[dict] = []
+
+        def fake_run_ws_stream(dataplane_url, api_key, command, **kwargs):
+            calls.append(kwargs)
+            return _empty(), None
+
+        monkeypatch.setattr(
+            "langsmith.sandbox._ws_execute.run_ws_stream", fake_run_ws_stream
+        )
+
+        with pytest.raises(_StreamEndedBeforeStarted):
+            sandbox.run("echo hi", wait=False)
+        assert len(calls) == CommandHandle.MAX_AUTO_RECONNECTS + 1
+
+
+def _async_sandbox():
+    client = AsyncSandboxClient(api_endpoint="http://test-server:8080";, 
max_retries=0)
+    return AsyncSandbox.from_dict(
+        data={
+            "name": "sb",
+            "dataplane_url": "https://sandbox-router.example.com/sb-123";,
+        },
+        client=client,
+        auto_delete=False,
+    )
+
+
+async def _aempty():
+    return
+    yield  # make it an async generator
+
+
+async def _astarted_then_exit(command_id):
+    yield {"type": "started", "command_id": command_id, "pid": 1}
+    yield {"type": "exit", "exit_code": 0}
+
+
+class TestAsyncRetry:
+    async def test_retries_with_same_command_id(self, monkeypatch):
+        sandbox = _async_sandbox()
+        calls: list[dict] = []
+
+        async def fake(dataplane_url, api_key, command, **kwargs):
+            calls.append(kwargs)
+            if len(calls) == 1:
+                return _aempty(), None
+            return _astarted_then_exit(kwargs["command_id"]), None
+
+        async def _no_sleep(_s):
+            return None
+
+        monkeypatch.setattr("asyncio.sleep", _no_sleep)
+        
monkeypatch.setattr("langsmith.sandbox._ws_execute.run_ws_stream_async", fake)
+
+        result = await sandbox.run("echo hi")
+
+        assert result.exit_code == 0
+        assert len(calls) == 2
+        assert calls[0]["command_id"] == calls[1]["command_id"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/tests/unit_tests/sandbox/test_sandbox.py 
new/langsmith-0.10.11/tests/unit_tests/sandbox/test_sandbox.py
--- old/langsmith-0.10.10/tests/unit_tests/sandbox/test_sandbox.py      
2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/sandbox/test_sandbox.py      
2020-02-02 01:00:00.000000000 +0100
@@ -161,9 +161,12 @@
         assert sb.status == "ready"
         assert sb.status_message is None
 
-    def test_dataplane_op_not_gated_on_status(self, client, httpx_mock: 
HTTPXMock):
+    def test_dataplane_op_not_gated_on_status(
+        self, client, httpx_mock: HTTPXMock, monkeypatch
+    ):
         """The client does not pre-check status: a stopped sandbox still runs;
         the platform resumes it when the dataplane request arrives."""
+        monkeypatch.setattr("langsmith.sandbox._sandbox.WEBSOCKETS_AVAILABLE", 
False)
         httpx_mock.add_response(
             method="POST",
             url="https://sandbox-router.example.com/sb-123/execute";,
@@ -195,9 +198,40 @@
         with pytest.raises(DataplaneNotConfiguredError):
             sb.read("/tmp/test.txt")
 
+    def test_stop_preserves_dataplane_url(self, client, httpx_mock: HTTPXMock):
+        """stop() must not clear dataplane_url: it stays valid across
+        stop/start and a request on it resumes the sandbox."""
+        httpx_mock.add_response(
+            method="POST",
+            url="http://test-server:8080/boxes/test-sandbox/stop";,
+            json={},
+        )
+        sb = Sandbox.from_dict(
+            data={
+                "name": "test-sandbox",
+                "status": "ready",
+                "dataplane_url": "https://sandbox-router.example.com/sb-123";,
+            },
+            client=client,
+            auto_delete=False,
+        )
+        sb.stop()
+        assert sb.status == "stopped"
+        assert sb.dataplane_url == "https://sandbox-router.example.com/sb-123";
+
 
 class TestSandboxRun:
-    """Tests for sandbox run command."""
+    """Sandbox.run() over the HTTP fallback path.
+
+    run() uses WebSocket by default; these cases pin the request/response
+    shaping of the blocking HTTP endpoint it falls back to when the websockets
+    library is unavailable.
+    """
+
+    @pytest.fixture(autouse=True)
+    def _ws_unavailable(self, monkeypatch):
+        """Force the missing-websockets condition so run() takes the HTTP 
path."""
+        monkeypatch.setattr("langsmith.sandbox._sandbox.WEBSOCKETS_AVAILABLE", 
False)
 
     def test_run_command_success(self, sandbox, httpx_mock: HTTPXMock):
         """Test running a successful command."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/langsmith-0.10.10/tests/unit_tests/sandbox/test_ws_execute.py 
new/langsmith-0.10.11/tests/unit_tests/sandbox/test_ws_execute.py
--- old/langsmith-0.10.10/tests/unit_tests/sandbox/test_ws_execute.py   
2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/sandbox/test_ws_execute.py   
2020-02-02 01:00:00.000000000 +0100
@@ -4,7 +4,7 @@
 
 import json
 from typing import Any, Iterator
-from unittest.mock import MagicMock, patch
+from unittest.mock import ANY, MagicMock, patch
 
 import pytest
 
@@ -692,6 +692,7 @@
             "https://router.example.com/sb-123";,
             "test-key",
             "echo hello",
+            command_id=ANY,
             timeout=60,
             env=None,
             cwd=None,
@@ -724,27 +725,39 @@
         with pytest.raises(ValueError, match="Cannot combine"):
             sandbox.run("cmd", wait=False, on_stdout=lambda s: None)
 
+    def test_run_fallback_to_http_when_ws_unavailable(self, monkeypatch):
+        """run() falls back to HTTP only when the websockets library is
+        unavailable."""
+        monkeypatch.setattr("langsmith.sandbox._sandbox.WEBSOCKETS_AVAILABLE", 
False)
+        sandbox = self._make_sandbox()
+
+        with patch.object(sandbox, "_run_http") as mock_http:
+            mock_http.return_value = ExecutionResult(
+                stdout="http output", stderr="", exit_code=0
+            )
+            result = sandbox.run("echo hello")
+
+        assert result.stdout == "http output"
+        mock_http.assert_called_once()
+
     @pytest.mark.parametrize(
         "exc",
         [
             SandboxConnectionError("WS failed"),
-            ImportError("no websockets"),
+            OSError("socket down"),
         ],
     )
     @patch("langsmith.sandbox._ws_execute.run_ws_stream")
-    def test_run_fallback_to_http(self, mock_run_ws, exc):
-        """WS failure (connection error or missing lib) falls back to HTTP."""
+    def test_run_ws_error_propagates_without_http_fallback(self, mock_run_ws, 
exc):
+        """Any WS failure other than a missing library propagates; run() must
+        not silently fall back to the capacity-capped blocking HTTP 
endpoint."""
         mock_run_ws.side_effect = exc
         sandbox = self._make_sandbox()
 
         with patch.object(sandbox, "_run_http") as mock_http:
-            mock_http.return_value = ExecutionResult(
-                stdout="http output", stderr="", exit_code=0
-            )
-            result = sandbox.run("echo hello")
-
-        assert result.stdout == "http output"
-        mock_http.assert_called_once()
+            with pytest.raises(type(exc)):
+                sandbox.run("echo hello")
+        mock_http.assert_not_called()
 
     @pytest.mark.parametrize(
         "kwargs",
@@ -922,14 +935,14 @@
         return InvalidMessage("did not receive a valid HTTP response")
 
     def test_run_ws_stream_wraps_invalid_message(self):
-        with patch("websockets.sync.client.connect") as mock_connect:
+        with patch("langsmith.sandbox._ws_execute._ws_connect_sync") as 
mock_connect:
             mock_connect.side_effect = self._invalid_message()
             msg_stream, _ = run_ws_stream("https://sb.example.com";, "key", 
"echo hi")
             with pytest.raises(SandboxConnectionError, match="no valid HTTP 
response"):
                 list(msg_stream)
 
     def test_reconnect_ws_stream_wraps_invalid_message(self):
-        with patch("websockets.sync.client.connect") as mock_connect:
+        with patch("langsmith.sandbox._ws_execute._ws_connect_sync") as 
mock_connect:
             mock_connect.side_effect = self._invalid_message()
             msg_stream, _ = reconnect_ws_stream(
                 "https://sb.example.com";, "key", "cmd-123"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/tests/unit_tests/test_client.py 
new/langsmith-0.10.11/tests/unit_tests/test_client.py
--- old/langsmith-0.10.10/tests/unit_tests/test_client.py       2020-02-02 
01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/tests/unit_tests/test_client.py       2020-02-02 
01:00:00.000000000 +0100
@@ -50,6 +50,7 @@
     _dataset_examples_path,
     _default_retry_config,
     _dumps_json,
+    _get_openapi_base_url,
     _is_langchain_hosted,
     _parse_token_or_url,
     _reject_filesystem_attachments,
@@ -5481,6 +5482,90 @@
         _construct_url(api_url, pathname)
 
 
[email protected](
+    "api_url,expected",
+    [
+        # Cloud API URL: the /api/v1 suffix is stripped so the generated client
+        # can append its own /v2/... path segments.
+        (
+            "https://api.smith.langchain.com/api/v1";,
+            "https://api.smith.langchain.com";,
+        ),
+        # httpx stringifies base_url with a trailing slash.
+        (
+            "https://api.smith.langchain.com/api/v1/";,
+            "https://api.smith.langchain.com";,
+        ),
+        # Bare /v1 suffix (no /api prefix).
+        (
+            "https://api.smith.langchain.com/v1";,
+            "https://api.smith.langchain.com";,
+        ),
+        ("https://api.smith.langchain.com/v1/";, 
"https://api.smith.langchain.com";),
+        # Self-hosted deployments under a path prefix.
+        (
+            "https://self-hosted.example.com/langsmith/api/v1";,
+            "https://self-hosted.example.com/langsmith";,
+        ),
+        (
+            "https://self-hosted.example.com/langsmith/v1";,
+            "https://self-hosted.example.com/langsmith";,
+        ),
+        # No version suffix: left unchanged (aside from trailing slashes).
+        ("https://api.smith.langchain.com";, "https://api.smith.langchain.com";),
+        ("https://api.smith.langchain.com/";, 
"https://api.smith.langchain.com";),
+        (
+            "https://self-hosted.example.com/api";,
+            "https://self-hosted.example.com/api";,
+        ),
+        ("http://localhost:1984";, "http://localhost:1984";),
+        ("http://localhost:1984/api/v1";, "http://localhost:1984";),
+        # /v1 must be a trailing path segment, not a substring.
+        (
+            "https://api.smith.langchain.com/v1/runs";,
+            "https://api.smith.langchain.com/v1/runs";,
+        ),
+        ("https://v1.example.com";, "https://v1.example.com";),
+    ],
+)
+def test_get_openapi_base_url(api_url: str, expected: str) -> None:
+    """Test _get_openapi_base_url strips the handwritten client's version 
suffix."""
+    assert _get_openapi_base_url(api_url) == expected
+
+
[email protected](
+    "api_url,expected_base_url",
+    [
+        ("https://api.smith.langchain.com/api/v1";, 
"https://api.smith.langchain.com";),
+        ("http://localhost:1984";, "http://localhost:1984";),
+    ],
+)
+def test_get_langsmith_api_uses_normalized_base_url(
+    api_url: str, expected_base_url: str
+) -> None:
+    """The generated OpenAPI client must not receive the /api/v1 suffix."""
+    client = Client(api_url=api_url, api_key="test-api-key", 
auto_batch_tracing=False)
+    openapi_client = client._get_langsmith_api()
+    assert str(openapi_client.base_url).rstrip("/") == expected_base_url
+
+
[email protected](
+    "api_url,expected_base_url",
+    [
+        ("https://api.smith.langchain.com/api/v1";, 
"https://api.smith.langchain.com";),
+        ("http://localhost:1984";, "http://localhost:1984";),
+    ],
+)
+def test_async_client_uses_normalized_base_url(
+    api_url: str, expected_base_url: str
+) -> None:
+    """The async client normalizes its httpx base_url before the generated 
client."""
+    from langsmith.async_client import AsyncClient
+
+    client = AsyncClient(api_url=api_url, api_key="test-api-key")
+    assert str(client._langsmith_api.base_url).rstrip("/") == expected_base_url
+
+
 def test_process_buffered_run_ops_core_functionality():
     """Test core functionality: parameter validation, basic processing, 
compressed traces, and mixed operations."""
     # Test 1: Parameter validation - both parameters must be provided together 
or neither
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/langsmith-0.10.10/uv.lock 
new/langsmith-0.10.11/uv.lock
--- old/langsmith-0.10.10/uv.lock       2020-02-02 01:00:00.000000000 +0100
+++ new/langsmith-0.10.11/uv.lock       2020-02-02 01:00:00.000000000 +0100
@@ -3076,100 +3076,96 @@
 
 [[package]]
 name = "pillow"
-version = "12.2.0"
+version = "12.3.0"
 source = { registry = "https://pypi.org/simple"; }
-sdist = { url = 
"https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz";,
 hash = 
"sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size 
= 46987819, upload-time = "2026-04-01T14:46:17.687Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz";,
 hash = 
"sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size 
= 47025035, upload-time = "2026-07-01T11:56:38.965Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/3a/aa/d0b28e1c811cd4d5f5c2bfe2e022292bd255ae5744a3b9ac7d6c8f72dd75/pillow-12.2.0-cp310-cp310-macosx_10_10_x86_64.whl";,
 hash = 
"sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f", size 
= 5354355, upload-time = "2026-04-01T14:42:15.402Z" },
-    { url = 
"https://files.pythonhosted.org/packages/27/8e/1d5b39b8ae2bd7650d0c7b6abb9602d16043ead9ebbfef4bc4047454da2a/pillow-12.2.0-cp310-cp310-macosx_11_0_arm64.whl";,
 hash = 
"sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97", size 
= 4695871, upload-time = "2026-04-01T14:42:18.234Z" },
-    { url = 
"https://files.pythonhosted.org/packages/f0/c5/dcb7a6ca6b7d3be41a76958e90018d56c8462166b3ef223150360850c8da/pillow-12.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff", size 
= 6269734, upload-time = "2026-04-01T14:42:20.608Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ea/f1/aa1bb13b2f4eba914e9637893c73f2af8e48d7d4023b9d3750d4c5eb2d0c/pillow-12.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec", size 
= 8076080, upload-time = "2026-04-01T14:42:23.095Z" },
-    { url = 
"https://files.pythonhosted.org/packages/a1/2a/8c79d6a53169937784604a8ae8d77e45888c41537f7f6f65ed1f407fe66d/pillow-12.2.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136", size 
= 6382236, upload-time = "2026-04-01T14:42:25.82Z" },
-    { url = 
"https://files.pythonhosted.org/packages/b5/42/bbcb6051030e1e421d103ce7a8ecadf837aa2f39b8f82ef1a8d37c3d4ebc/pillow-12.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c", size 
= 7070220, upload-time = "2026-04-01T14:42:28.68Z" },
-    { url = 
"https://files.pythonhosted.org/packages/3f/e1/c2a7d6dd8cfa6b231227da096fd2d58754bab3603b9d73bf609d3c18b64f/pillow-12.2.0-cp310-cp310-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3", size 
= 6493124, upload-time = "2026-04-01T14:42:31.579Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5f/41/7c8617da5d32e1d2f026e509484fdb6f3ad7efaef1749a0c1928adbb099e/pillow-12.2.0-cp310-cp310-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa", size 
= 7194324, upload-time = "2026-04-01T14:42:34.615Z" },
-    { url = 
"https://files.pythonhosted.org/packages/2d/de/a777627e19fd6d62f84070ee1521adde5eeda4855b5cf60fe0b149118bca/pillow-12.2.0-cp310-cp310-win32.whl";,
 hash = 
"sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032", size 
= 6376363, upload-time = "2026-04-01T14:42:37.19Z" },
-    { url = 
"https://files.pythonhosted.org/packages/e7/34/fc4cb5204896465842767b96d250c08410f01f2f28afc43b257de842eed5/pillow-12.2.0-cp310-cp310-win_amd64.whl";,
 hash = 
"sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5", size 
= 7083523, upload-time = "2026-04-01T14:42:39.62Z" },
-    { url = 
"https://files.pythonhosted.org/packages/2d/a0/32852d36bc7709f14dc3f64f929a275e958ad8c19a6deba9610d458e28b3/pillow-12.2.0-cp310-cp310-win_arm64.whl";,
 hash = 
"sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024", size 
= 2463318, upload-time = "2026-04-01T14:42:42.063Z" },
-    { url = 
"https://files.pythonhosted.org/packages/68/e1/748f5663efe6edcfc4e74b2b93edfb9b8b99b67f21a854c3ae416500a2d9/pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl";,
 hash = 
"sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab", size 
= 5354347, upload-time = "2026-04-01T14:42:44.255Z" },
-    { url = 
"https://files.pythonhosted.org/packages/47/a1/d5ff69e747374c33a3b53b9f98cca7889fce1fd03d79cdc4e1bccc6c5a87/pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl";,
 hash = 
"sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65", size 
= 4695873, upload-time = "2026-04-01T14:42:46.452Z" },
-    { url = 
"https://files.pythonhosted.org/packages/df/21/e3fbdf54408a973c7f7f89a23b2cb97a7ef30c61ab4142af31eee6aebc88/pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7", size 
= 6280168, upload-time = "2026-04-01T14:42:49.228Z" },
-    { url = 
"https://files.pythonhosted.org/packages/d3/f1/00b7278c7dd52b17ad4329153748f87b6756ec195ff786c2bdf12518337d/pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e", size 
= 8088188, upload-time = "2026-04-01T14:42:51.735Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ad/cf/220a5994ef1b10e70e85748b75649d77d506499352be135a4989c957b701/pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705", size 
= 6394401, upload-time = "2026-04-01T14:42:54.343Z" },
-    { url = 
"https://files.pythonhosted.org/packages/e9/bd/e51a61b1054f09437acfbc2ff9106c30d1eb76bc1453d428399946781253/pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176", size 
= 7079655, upload-time = "2026-04-01T14:42:56.954Z" },
-    { url = 
"https://files.pythonhosted.org/packages/6b/3d/45132c57d5fb4b5744567c3817026480ac7fc3ce5d4c47902bc0e7f6f853/pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b", size 
= 6503105, upload-time = "2026-04-01T14:42:59.847Z" },
-    { url = 
"https://files.pythonhosted.org/packages/7d/2e/9df2fc1e82097b1df3dce58dc43286aa01068e918c07574711fcc53e6fb4/pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909", size 
= 7203402, upload-time = "2026-04-01T14:43:02.664Z" },
-    { url = 
"https://files.pythonhosted.org/packages/bd/2e/2941e42858ebb67e50ae741473de81c2984e6eff7b397017623c676e2e8d/pillow-12.2.0-cp311-cp311-win32.whl";,
 hash = 
"sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808", size 
= 6378149, upload-time = "2026-04-01T14:43:05.274Z" },
-    { url = 
"https://files.pythonhosted.org/packages/69/42/836b6f3cd7f3e5fa10a1f1a5420447c17966044c8fbf589cc0452d5502db/pillow-12.2.0-cp311-cp311-win_amd64.whl";,
 hash = 
"sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60", size 
= 7082626, upload-time = "2026-04-01T14:43:08.557Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c2/88/549194b5d6f1f494b485e493edc6693c0a16f4ada488e5bd974ed1f42fad/pillow-12.2.0-cp311-cp311-win_arm64.whl";,
 hash = 
"sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe", size 
= 2463531, upload-time = "2026-04-01T14:43:10.743Z" },
-    { url = 
"https://files.pythonhosted.org/packages/58/be/7482c8a5ebebbc6470b3eb791812fff7d5e0216c2be3827b30b8bb6603ed/pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5", size 
= 5308279, upload-time = "2026-04-01T14:43:13.246Z" },
-    { url = 
"https://files.pythonhosted.org/packages/d8/95/0a351b9289c2b5cbde0bacd4a83ebc44023e835490a727b2a3bd60ddc0f4/pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl";,
 hash = 
"sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421", size 
= 4695490, upload-time = "2026-04-01T14:43:15.584Z" },
-    { url = 
"https://files.pythonhosted.org/packages/de/af/4e8e6869cbed569d43c416fad3dc4ecb944cb5d9492defaed89ddd6fe871/pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987", size 
= 6284462, upload-time = "2026-04-01T14:43:18.268Z" },
-    { url = 
"https://files.pythonhosted.org/packages/e9/9e/c05e19657fd57841e476be1ab46c4d501bffbadbafdc31a6d665f8b737b6/pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76", size 
= 8094744, upload-time = "2026-04-01T14:43:20.716Z" },
-    { url = 
"https://files.pythonhosted.org/packages/2b/54/1789c455ed10176066b6e7e6da1b01e50e36f94ba584dc68d9eebfe9156d/pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005", size 
= 6398371, upload-time = "2026-04-01T14:43:23.443Z" },
-    { url = 
"https://files.pythonhosted.org/packages/43/e3/fdc657359e919462369869f1c9f0e973f353f9a9ee295a39b1fea8ee1a77/pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780", size 
= 7087215, upload-time = "2026-04-01T14:43:26.758Z" },
-    { url = 
"https://files.pythonhosted.org/packages/8b/f8/2f6825e441d5b1959d2ca5adec984210f1ec086435b0ed5f52c19b3b8a6e/pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5", size 
= 6509783, upload-time = "2026-04-01T14:43:29.56Z" },
-    { url = 
"https://files.pythonhosted.org/packages/67/f9/029a27095ad20f854f9dba026b3ea6428548316e057e6fc3545409e86651/pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5", size 
= 7212112, upload-time = "2026-04-01T14:43:32.091Z" },
-    { url = 
"https://files.pythonhosted.org/packages/be/42/025cfe05d1be22dbfdb4f264fe9de1ccda83f66e4fc3aac94748e784af04/pillow-12.2.0-cp312-cp312-win32.whl";,
 hash = 
"sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940", size 
= 6378489, upload-time = "2026-04-01T14:43:34.601Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5d/7b/25a221d2c761c6a8ae21bfa3874988ff2583e19cf8a27bf2fee358df7942/pillow-12.2.0-cp312-cp312-win_amd64.whl";,
 hash = 
"sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5", size 
= 7084129, upload-time = "2026-04-01T14:43:37.213Z" },
-    { url = 
"https://files.pythonhosted.org/packages/10/e1/542a474affab20fd4a0f1836cb234e8493519da6b76899e30bcc5d990b8b/pillow-12.2.0-cp312-cp312-win_arm64.whl";,
 hash = 
"sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414", size 
= 2463612, upload-time = "2026-04-01T14:43:39.421Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl";,
 hash = 
"sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size 
= 4100837, upload-time = "2026-04-01T14:43:41.506Z" },
-    { url = 
"https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl";,
 hash = 
"sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size 
= 4176528, upload-time = "2026-04-01T14:43:43.773Z" },
-    { url = 
"https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl";,
 hash = 
"sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size 
= 3640401, upload-time = "2026-04-01T14:43:45.87Z" },
-    { url = 
"https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size 
= 5308094, upload-time = "2026-04-01T14:43:48.438Z" },
-    { url = 
"https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl";,
 hash = 
"sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size 
= 4695402, upload-time = "2026-04-01T14:43:51.292Z" },
-    { url = 
"https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size 
= 6280005, upload-time = "2026-04-01T14:43:54.242Z" },
-    { url = 
"https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size 
= 8090669, upload-time = "2026-04-01T14:43:57.335Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size 
= 6395194, upload-time = "2026-04-01T14:43:59.864Z" },
-    { url = 
"https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size 
= 7082423, upload-time = "2026-04-01T14:44:02.74Z" },
-    { url = 
"https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size 
= 6505667, upload-time = "2026-04-01T14:44:05.381Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size 
= 7208580, upload-time = "2026-04-01T14:44:08.39Z" },
-    { url = 
"https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl";,
 hash = 
"sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size 
= 6375896, upload-time = "2026-04-01T14:44:11.197Z" },
-    { url = 
"https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl";,
 hash = 
"sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size 
= 7081266, upload-time = "2026-04-01T14:44:13.947Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl";,
 hash = 
"sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size 
= 2463508, upload-time = "2026-04-01T14:44:16.312Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size 
= 5309927, upload-time = "2026-04-01T14:44:18.89Z" },
-    { url = 
"https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size 
= 4698624, upload-time = "2026-04-01T14:44:21.115Z" },
-    { url = 
"https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size 
= 6321252, upload-time = "2026-04-01T14:44:23.663Z" },
-    { url = 
"https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size 
= 8126550, upload-time = "2026-04-01T14:44:26.772Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size 
= 6433114, upload-time = "2026-04-01T14:44:29.615Z" },
-    { url = 
"https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size 
= 7115667, upload-time = "2026-04-01T14:44:32.773Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size 
= 6538966, upload-time = "2026-04-01T14:44:35.252Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size 
= 7238241, upload-time = "2026-04-01T14:44:37.875Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl";,
 hash = 
"sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size 
= 6379592, upload-time = "2026-04-01T14:44:40.336Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl";,
 hash = 
"sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size 
= 7085542, upload-time = "2026-04-01T14:44:43.251Z" },
-    { url = 
"https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl";,
 hash = 
"sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size 
= 2465765, upload-time = "2026-04-01T14:44:45.996Z" },
-    { url = 
"https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl";,
 hash = 
"sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size 
= 4100848, upload-time = "2026-04-01T14:44:48.48Z" },
-    { url = 
"https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl";,
 hash = 
"sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size 
= 4176515, upload-time = "2026-04-01T14:44:51.353Z" },
-    { url = 
"https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl";,
 hash = 
"sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size 
= 3640159, upload-time = "2026-04-01T14:44:53.588Z" },
-    { url = 
"https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size 
= 5312185, upload-time = "2026-04-01T14:44:56.039Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl";,
 hash = 
"sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size 
= 4695386, upload-time = "2026-04-01T14:44:58.663Z" },
-    { url = 
"https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size 
= 6280384, upload-time = "2026-04-01T14:45:01.5Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size 
= 8091599, upload-time = "2026-04-01T14:45:04.5Z" },
-    { url = 
"https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size 
= 6396021, upload-time = "2026-04-01T14:45:07.117Z" },
-    { url = 
"https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size 
= 7083360, upload-time = "2026-04-01T14:45:09.763Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size 
= 6507628, upload-time = "2026-04-01T14:45:12.378Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size 
= 7209321, upload-time = "2026-04-01T14:45:15.122Z" },
-    { url = 
"https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl";,
 hash = 
"sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size 
= 6479723, upload-time = "2026-04-01T14:45:17.797Z" },
-    { url = 
"https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl";,
 hash = 
"sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size 
= 7217400, upload-time = "2026-04-01T14:45:20.529Z" },
-    { url = 
"https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl";,
 hash = 
"sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size 
= 2554835, upload-time = "2026-04-01T14:45:23.162Z" },
-    { url = 
"https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size 
= 5314225, upload-time = "2026-04-01T14:45:25.637Z" },
-    { url = 
"https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size 
= 4698541, upload-time = "2026-04-01T14:45:28.355Z" },
-    { url = 
"https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size 
= 6322251, upload-time = "2026-04-01T14:45:30.924Z" },
-    { url = 
"https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size 
= 8127807, upload-time = "2026-04-01T14:45:33.908Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size 
= 6433935, upload-time = "2026-04-01T14:45:36.623Z" },
-    { url = 
"https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size 
= 7116720, upload-time = "2026-04-01T14:45:39.258Z" },
-    { url = 
"https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size 
= 6540498, upload-time = "2026-04-01T14:45:41.879Z" },
-    { url = 
"https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size 
= 7239413, upload-time = "2026-04-01T14:45:44.705Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl";,
 hash = 
"sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size 
= 6482084, upload-time = "2026-04-01T14:45:47.568Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl";,
 hash = 
"sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size 
= 7225152, upload-time = "2026-04-01T14:45:50.032Z" },
-    { url = 
"https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl";,
 hash = 
"sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size 
= 2556579, upload-time = "2026-04-01T14:45:52.529Z" },
-    { url = 
"https://files.pythonhosted.org/packages/4e/b7/2437044fb910f499610356d1352e3423753c98e34f915252aafecc64889f/pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f", size 
= 5273969, upload-time = "2026-04-01T14:45:55.538Z" },
-    { url = 
"https://files.pythonhosted.org/packages/f6/f4/8316e31de11b780f4ac08ef3654a75555e624a98db1056ecb2122d008d5a/pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl";,
 hash = 
"sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d", size 
= 4659674, upload-time = "2026-04-01T14:45:58.093Z" },
-    { url = 
"https://files.pythonhosted.org/packages/d4/37/664fca7201f8bb2aa1d20e2c3d5564a62e6ae5111741966c8319ca802361/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl";,
 hash = 
"sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f", size 
= 5288479, upload-time = "2026-04-01T14:46:01.141Z" },
-    { url = 
"https://files.pythonhosted.org/packages/49/62/5b0ed78fce87346be7a5cfcfaaad91f6a1f98c26f86bdbafa2066c647ef6/pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl";,
 hash = 
"sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e", size 
= 7032230, upload-time = "2026-04-01T14:46:03.874Z" },
-    { url = 
"https://files.pythonhosted.org/packages/c3/28/ec0fc38107fc32536908034e990c47914c57cd7c5a3ece4d8d8f7ffd7e27/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0", size 
= 5355404, upload-time = "2026-04-01T14:46:06.33Z" },
-    { url = 
"https://files.pythonhosted.org/packages/5e/8b/51b0eddcfa2180d60e41f06bd6d0a62202b20b59c68f5a132e615b75aecf/pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1", size 
= 6002215, upload-time = "2026-04-01T14:46:08.83Z" },
-    { url = 
"https://files.pythonhosted.org/packages/bc/60/5382c03e1970de634027cee8e1b7d39776b778b81812aaf45b694dfe9e28/pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl";,
 hash = 
"sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e", size 
= 7080946, upload-time = "2026-04-01T14:46:11.734Z" },
+    { url = 
"https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl";,
 hash = 
"sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size 
= 5392418, upload-time = "2026-07-01T11:53:27.808Z" },
+    { url = 
"https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl";,
 hash = 
"sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size 
= 4785287, upload-time = "2026-07-01T11:53:29.761Z" },
+    { url = 
"https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size 
= 6253754, upload-time = "2026-07-01T11:53:32.298Z" },
+    { url = 
"https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size 
= 6925605, upload-time = "2026-07-01T11:53:34.487Z" },
+    { url = 
"https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size 
= 6327788, upload-time = "2026-07-01T11:53:36.433Z" },
+    { url = 
"https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size 
= 7036288, upload-time = "2026-07-01T11:53:38.712Z" },
+    { url = 
"https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl";,
 hash = 
"sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size 
= 6472396, upload-time = "2026-07-01T11:53:40.781Z" },
+    { url = 
"https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl";,
 hash = 
"sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size 
= 7226887, upload-time = "2026-07-01T11:53:42.764Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl";,
 hash = 
"sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size 
= 2568039, upload-time = "2026-07-01T11:53:45.372Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl";,
 hash = 
"sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size 
= 5392415, upload-time = "2026-07-01T11:53:47.162Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl";,
 hash = 
"sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size 
= 4785266, upload-time = "2026-07-01T11:53:49.079Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size 
= 6263814, upload-time = "2026-07-01T11:53:51.32Z" },
+    { url = 
"https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size 
= 6934408, upload-time = "2026-07-01T11:53:53.487Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size 
= 6337160, upload-time = "2026-07-01T11:53:55.457Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size 
= 7045172, upload-time = "2026-07-01T11:53:57.736Z" },
+    { url = 
"https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl";,
 hash = 
"sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size 
= 6472232, upload-time = "2026-07-01T11:53:59.767Z" },
+    { url = 
"https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl";,
 hash = 
"sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size 
= 7233653, upload-time = "2026-07-01T11:54:02.066Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl";,
 hash = 
"sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size 
= 2568195, upload-time = "2026-07-01T11:54:04.622Z" },
+    { url = 
"https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size 
= 5345969, upload-time = "2026-07-01T11:54:06.397Z" },
+    { url = 
"https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl";,
 hash = 
"sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size 
= 4780323, upload-time = "2026-07-01T11:54:09.351Z" },
+    { url = 
"https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size 
= 6266838, upload-time = "2026-07-01T11:54:11.71Z" },
+    { url = 
"https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size 
= 6940830, upload-time = "2026-07-01T11:54:13.732Z" },
+    { url = 
"https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size 
= 6344383, upload-time = "2026-07-01T11:54:15.756Z" },
+    { url = 
"https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size 
= 7052934, upload-time = "2026-07-01T11:54:17.721Z" },
+    { url = 
"https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl";,
 hash = 
"sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size 
= 6472684, upload-time = "2026-07-01T11:54:19.839Z" },
+    { url = 
"https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl";,
 hash = 
"sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size 
= 7227137, upload-time = "2026-07-01T11:54:22.025Z" },
+    { url = 
"https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl";,
 hash = 
"sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size 
= 2568267, upload-time = "2026-07-01T11:54:24.051Z" },
+    { url = 
"https://files.pythonhosted.org/packages/9d/ac/31fb64e1e7efb5a4b50cd3d92049ba89ac6e4d8d3bb6a74e15048ca3353e/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl";,
 hash = 
"sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89", size 
= 4161684, upload-time = "2026-07-01T11:54:25.934Z" },
+    { url = 
"https://files.pythonhosted.org/packages/87/b4/9805e23d2b4d77842b468513841fda254ee42f0289d25088340e4ff46e2d/pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl";,
 hash = 
"sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace", size 
= 4255487, upload-time = "2026-07-01T11:54:27.935Z" },
+    { url = 
"https://files.pythonhosted.org/packages/df/39/ecf519435a200c693fe053a6ee4d835b41cf963a4dfc2551c4e637cb2a71/pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl";,
 hash = 
"sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec", size 
= 3696433, upload-time = "2026-07-01T11:54:29.813Z" },
+    { url = 
"https://files.pythonhosted.org/packages/42/92/2fc3ffad878ae8dd5469ec1bc8eb83b71f48e13efdf68f02709003982a32/pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl";,
 hash = 
"sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66", size 
= 5345889, upload-time = "2026-07-01T11:54:31.97Z" },
+    { url = 
"https://files.pythonhosted.org/packages/10/76/8803c13605b763d33d156c4678fc77f8443389c0c51c8aef707bb02015f4/pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl";,
 hash = 
"sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35", size 
= 4780109, upload-time = "2026-07-01T11:54:34.026Z" },
+    { url = 
"https://files.pythonhosted.org/packages/1f/01/e18aff37cb0b4aac47ac90f016d347a49aca667ef97f190b06ac2aabc928/pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65", size 
= 6263736, upload-time = "2026-07-01T11:54:36.131Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f7/62/de5bdd77d935331f4f802edc11e4d82950f642caad6cb2f949837b8560e2/pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3", size 
= 6937129, upload-time = "2026-07-01T11:54:38.216Z" },
+    { url = 
"https://files.pythonhosted.org/packages/70/4d/105627a13300c5e0df1d174230b32fd1273062c96f7745fd552b945d1e1d/pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a", size 
= 6339562, upload-time = "2026-07-01T11:54:40.354Z" },
+    { url = 
"https://files.pythonhosted.org/packages/6b/1d/f13de01a553988ab895ba1c722e06cf3144d4f57656fd5b81b6d881f1179/pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e", size 
= 7049439, upload-time = "2026-07-01T11:54:42.489Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c9/f9/066794cca041b969964f779ee5fa66a9498bbf34248ac39c5d7954e4198f/pillow-12.3.0-cp313-cp313-win32.whl";,
 hash = 
"sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f", size 
= 6473287, upload-time = "2026-07-01T11:54:44.9Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a6/9b/7a58e61d62be561da3a356fe2384d4059a6345fc130e23ef1c36a5b81d24/pillow-12.3.0-cp313-cp313-win_amd64.whl";,
 hash = 
"sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8", size 
= 7239691, upload-time = "2026-07-01T11:54:47.141Z" },
+    { url = 
"https://files.pythonhosted.org/packages/aa/b0/c4ed4f0ef8f8fa5ee8351537db6650bb8189f7e118842978dd6589065692/pillow-12.3.0-cp313-cp313-win_arm64.whl";,
 hash = 
"sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b", size 
= 2568185, upload-time = "2026-07-01T11:54:49.137Z" },
+    { url = 
"https://files.pythonhosted.org/packages/dc/01/001f65b68192f0228cc1dbbc8d2530ab5d58b61037ba0587f946fea607cd/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl";,
 hash = 
"sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330", size 
= 4161736, upload-time = "2026-07-01T11:54:51.156Z" },
+    { url = 
"https://files.pythonhosted.org/packages/1a/d2/0219746d0fd16fc8a84498e79452375be3797d3ce4044596ce565164b84f/pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl";,
 hash = 
"sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217", size 
= 4255435, upload-time = "2026-07-01T11:54:53.414Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c8/02/8d0bc62ef0302318c46ff2a512822d2610e81c7aa46c9b3abe6cbaca5ad0/pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl";,
 hash = 
"sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930", size 
= 3696262, upload-time = "2026-07-01T11:54:55.739Z" },
+    { url = 
"https://files.pythonhosted.org/packages/85/e2/73c77d218410b14f5f2d565e8a998d5317b7b9c75368d29985139f7a46f0/pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8", size 
= 5350344, upload-time = "2026-07-01T11:54:57.657Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c7/da/32c752228ae345f489e3a42499d817b6c3996da7e8a3bc7a04fc806b243b/pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl";,
 hash = 
"sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0", size 
= 4780131, upload-time = "2026-07-01T11:54:59.713Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b1/9d/8b2c807dbef61a5197c047afe99823787eb66f63daf9fb2432f91d6f0462/pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321", size 
= 6263757, upload-time = "2026-07-01T11:55:01.778Z" },
+    { url = 
"https://files.pythonhosted.org/packages/5c/44/c85361f65dbe00eea8576ee467c768d25129989efb76e94f205e9ca9bb46/pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b", size 
= 6936962, upload-time = "2026-07-01T11:55:03.93Z" },
+    { url = 
"https://files.pythonhosted.org/packages/18/7e/e483414b35800b86b6f08dbbc7803fb5cd52c4d6f897f47d53ea2c7e6f65/pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198", size 
= 6339171, upload-time = "2026-07-01T11:55:05.989Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f0/f4/68c491844841ede6bed70189546b3ee9731cf9f2cbad396faff5e1ccba45/pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130", size 
= 7048116, upload-time = "2026-07-01T11:55:08.131Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a3/34/77f3f793fed8efc7d243f21b33c5a3f0d1c97ee70346d3db855587e155ff/pillow-12.3.0-cp314-cp314-win32.whl";,
 hash = 
"sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a", size 
= 6467209, upload-time = "2026-07-01T11:55:10.408Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f1/e0/492879f69d94f91f60fc8cd05ba03650e9520afebb2fb7aa12777d7c7f38/pillow-12.3.0-cp314-cp314-win_amd64.whl";,
 hash = 
"sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d", size 
= 7237707, upload-time = "2026-07-01T11:55:12.745Z" },
+    { url = 
"https://files.pythonhosted.org/packages/c9/ac/6b11f2875f1c2ac040d84e1bbf9cf22a88038f901ca1037898b280b38365/pillow-12.3.0-cp314-cp314-win_arm64.whl";,
 hash = 
"sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838", size 
= 2565995, upload-time = "2026-07-01T11:55:14.736Z" },
+    { url = 
"https://files.pythonhosted.org/packages/52/69/c2208e56af9bfc1913afb24020297a691eb1d4ef688474c8a04913f65e04/pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e", size 
= 5352503, upload-time = "2026-07-01T11:55:17.076Z" },
+    { url = 
"https://files.pythonhosted.org/packages/07/70/e5686d753e898a45d778ff1718dba8516ead6ab6b95d85fc8c4b70650cf2/pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17", size 
= 4782956, upload-time = "2026-07-01T11:55:19.448Z" },
+    { url = 
"https://files.pythonhosted.org/packages/d5/37/25c6692f06927ee973ff18c8d9ee98ad0b4d84ee67a09610c2dd1447958e/pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385", size 
= 6322855, upload-time = "2026-07-01T11:55:21.613Z" },
+    { url = 
"https://files.pythonhosted.org/packages/cc/91/420637fcb8f1bc11029e403b4538e6694744428d8246118e45719f944556/pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c", size 
= 6989642, upload-time = "2026-07-01T11:55:24.006Z" },
+    { url = 
"https://files.pythonhosted.org/packages/10/08/b94d7811281ccf0d143a1cf768d1c49e1e54af63e7b708ab2ee3eb87face/pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d", size 
= 6391281, upload-time = "2026-07-01T11:55:26.252Z" },
+    { url = 
"https://files.pythonhosted.org/packages/d2/87/24233f785f55474dc02ce3e739c5528a77e3a862e9333d1dd7a25cc31f70/pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931", size 
= 7096716, upload-time = "2026-07-01T11:55:28.318Z" },
+    { url = 
"https://files.pythonhosted.org/packages/23/26/fcb2f6e37175b04f53570b59937867e2b80ee1685e744023153028fc14f9/pillow-12.3.0-cp314-cp314t-win32.whl";,
 hash = 
"sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7", size 
= 6474125, upload-time = "2026-07-01T11:55:30.956Z" },
+    { url = 
"https://files.pythonhosted.org/packages/90/de/3634abee5f1c9e13c56787b7d5517b0ba8d6de51700b95578cf338349c9f/pillow-12.3.0-cp314-cp314t-win_amd64.whl";,
 hash = 
"sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c", size 
= 7242939, upload-time = "2026-07-01T11:55:34.044Z" },
+    { url = 
"https://files.pythonhosted.org/packages/ce/2a/fd13f8eb24de5714a6eb444a3d67e2842c6c576e159a43793adf23051351/pillow-12.3.0-cp314-cp314t-win_arm64.whl";,
 hash = 
"sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45", size 
= 2567506, upload-time = "2026-07-01T11:55:35.988Z" },
+    { url = 
"https://files.pythonhosted.org/packages/5d/dc/8fdce34ec725a33c81c6ba122b904d6b9024e50ea9ac7bede62fab54506c/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl";,
 hash = 
"sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139", size 
= 4162063, upload-time = "2026-07-01T11:55:37.941Z" },
+    { url = 
"https://files.pythonhosted.org/packages/76/66/2044b9a63d3b84ff048228dfcb7cd9bf0df983e8470971bf7d4c57b693de/pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl";,
 hash = 
"sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402", size 
= 4255549, upload-time = "2026-07-01T11:55:40.022Z" },
+    { url = 
"https://files.pythonhosted.org/packages/52/7e/1f67e6f4ece6b582ee4b539decbcc9f848dc245a93ed8cd7338bafef72f1/pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl";,
 hash = 
"sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c", size 
= 3696331, upload-time = "2026-07-01T11:55:41.98Z" },
+    { url = 
"https://files.pythonhosted.org/packages/12/40/d306fc2c8e4d45d7f175c77edca7063be7b86fe7fe6e68f4353bf71d808c/pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f", size 
= 5350370, upload-time = "2026-07-01T11:55:44.028Z" },
+    { url = 
"https://files.pythonhosted.org/packages/dd/44/668fb1437e8ce420f62d6106eb66e44a5971602a4d794615bdf79315d82d/pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl";,
 hash = 
"sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701", size 
= 4780147, upload-time = "2026-07-01T11:55:46.073Z" },
+    { url = 
"https://files.pythonhosted.org/packages/0c/08/93fa2e70e30a2d81547e481b6ee2bb9522117221fb1e0ce4b5df70967677/pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace", size 
= 6273659, upload-time = "2026-07-01T11:55:48.264Z" },
+    { url = 
"https://files.pythonhosted.org/packages/f8/6d/043e96ff814fc31a33077e4cba86082167db520c93632afdf2042febbb0c/pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4", size 
= 6947439, upload-time = "2026-07-01T11:55:50.503Z" },
+    { url = 
"https://files.pythonhosted.org/packages/af/92/ba71d2ee2ac0edf3fa33bd9d5ee9ee080da70b1766f3ca3934f9938ddac9/pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39", size 
= 6353577, upload-time = "2026-07-01T11:55:52.697Z" },
+    { url = 
"https://files.pythonhosted.org/packages/0f/ce/e63064e2122923ff687c8ad792d0d736a7b3920a56a46982e81a7fdd25d6/pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71", size 
= 7060394, upload-time = "2026-07-01T11:55:55.149Z" },
+    { url = 
"https://files.pythonhosted.org/packages/54/76/a09cc3ccc8d773a7283d34c38bec1708f9e3cc932093cbc4c5e71ac4060b/pillow-12.3.0-cp315-cp315-win32.whl";,
 hash = 
"sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827", size 
= 6467375, upload-time = "2026-07-01T11:55:57.769Z" },
+    { url = 
"https://files.pythonhosted.org/packages/3e/03/1846c49ba3b1d5550392a4bbd06d6fb4578e1cd91a803198b5c90f5f7d53/pillow-12.3.0-cp315-cp315-win_amd64.whl";,
 hash = 
"sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5", size 
= 7237048, upload-time = "2026-07-01T11:55:59.975Z" },
+    { url = 
"https://files.pythonhosted.org/packages/fb/bb/89f35dcc79610423f9f195504d7def7f0d1416a711541b42867e25fe3412/pillow-12.3.0-cp315-cp315-win_arm64.whl";,
 hash = 
"sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658", size 
= 2566006, upload-time = "2026-07-01T11:56:02.143Z" },
+    { url = 
"https://files.pythonhosted.org/packages/30/88/707027ba09942dfa2c28759b5c222d769290a41c6d20ea60ec250801941f/pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf", size 
= 5352509, upload-time = "2026-07-01T11:56:04.2Z" },
+    { url = 
"https://files.pythonhosted.org/packages/b0/6d/00352fa25332c2569cd387851f568cc5a4b75a9adbfb37ac4fbce4c02eec/pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl";,
 hash = 
"sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64", size 
= 4783167, upload-time = "2026-07-01T11:56:06.631Z" },
+    { url = 
"https://files.pythonhosted.org/packages/13/4f/9e049dfa21af7c22427275720e2490267ba8138120add5c4c574deb69782/pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e", size 
= 6329237, upload-time = "2026-07-01T11:56:08.868Z" },
+    { url = 
"https://files.pythonhosted.org/packages/36/16/cf6eeaae8d0fce8dd390a33437cf68c5d5bd73834a2bc6e2f14efda0ab45/pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777", size 
= 6997047, upload-time = "2026-07-01T11:56:11.379Z" },
+    { url = 
"https://files.pythonhosted.org/packages/1e/69/dbf769bdd55f48bf5733cac28edc6364ffaa072ec9ba336266e4fe66be55/pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl";,
 hash = 
"sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1", size 
= 6400440, upload-time = "2026-07-01T11:56:13.908Z" },
+    { url = 
"https://files.pythonhosted.org/packages/a0/e1/ffc9cfc2eea0d178da8018e18e959301ad9d6bc9f3edb7181e748a474b97/pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl";,
 hash = 
"sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9", size 
= 7105895, upload-time = "2026-07-01T11:56:16.575Z" },
+    { url = 
"https://files.pythonhosted.org/packages/18/f0/a5595c1e8c3ae44b9828cb2f0fa8155e5095ef04d6327b8f61cf44a3df85/pillow-12.3.0-cp315-cp315t-win32.whl";,
 hash = 
"sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8", size 
= 6474384, upload-time = "2026-07-01T11:56:18.855Z" },
+    { url = 
"https://files.pythonhosted.org/packages/e4/04/62bcd9f844984c5938d3b05264a61d797a29d3e0812341a8204af70bbdee/pillow-12.3.0-cp315-cp315t-win_amd64.whl";,
 hash = 
"sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418", size 
= 7243537, upload-time = "2026-07-01T11:56:21.214Z" },
+    { url = 
"https://files.pythonhosted.org/packages/3d/68/1f3066acedf37673694a7141381d8f811ae97f30d34413d236abe7d489f1/pillow-12.3.0-cp315-cp315t-win_arm64.whl";,
 hash = 
"sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59", size 
= 2567491, upload-time = "2026-07-01T11:56:23.506Z" },
+    { url = 
"https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl";,
 hash = 
"sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size 
= 5302510, upload-time = "2026-07-01T11:56:25.736Z" },
+    { url = 
"https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl";,
 hash = 
"sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size 
= 4736058, upload-time = "2026-07-01T11:56:28.041Z" },
+    { url = 
"https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl";,
 hash = 
"sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size 
= 5237776, upload-time = "2026-07-01T11:56:30.263Z" },
+    { url = 
"https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl";,
 hash = 
"sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size 
= 5860358, upload-time = "2026-07-01T11:56:32.68Z" },
+    { url = 
"https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl";,
 hash = 
"sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size 
= 7231786, upload-time = "2026-07-01T11:56:35.046Z" },
 ]
 
 [[package]]
@@ -3409,11 +3405,11 @@
 
 [[package]]
 name = "pyasn1"
-version = "0.6.3"
+version = "0.6.4"
 source = { registry = "https://pypi.org/simple"; }
-sdist = { url = 
"https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz";,
 hash = 
"sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size 
= 148685, upload-time = "2026-03-17T01:06:53.382Z" }
+sdist = { url = 
"https://files.pythonhosted.org/packages/a4/9a/23310166d960def5897e91fe20e5b724601b02a22e84ba1f94232c0b7f67/pyasn1-0.6.4.tar.gz";,
 hash = 
"sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81", size 
= 151262, upload-time = "2026-07-09T01:12:33.988Z" }
 wheels = [
-    { url = 
"https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl";,
 hash = 
"sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size 
= 83997, upload-time = "2026-03-17T01:06:52.036Z" },
+    { url = 
"https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl";,
 hash = 
"sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b", size 
= 84410, upload-time = "2026-07-09T01:12:32.92Z" },
 ]
 
 [[package]]

Reply via email to