aind-codeocean-dispatch 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/CHANGELOG.md +6 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/PKG-INFO +1 -1
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/pyproject.toml +1 -1
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/src/aind_codeocean_dispatch/runner.py +18 -3
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/tests/fakes.py +1 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/tests/test_runner.py +29 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/uv.lock +1 -1
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.copier-answers.yml +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/ISSUE_TEMPLATE/user-story.md +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/dependabot.yml +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/bump-call.yml +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/ci-call.yml +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/publish-call.yml +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.gitignore +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.python-version +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/CLAUDE.md +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/LICENSE +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/README.md +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/scripts/run_linters_and_checks.sh +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/src/aind_codeocean_dispatch/__init__.py +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/src/aind_codeocean_dispatch/py.typed +0 -0
- {aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/tests/__init__.py +0 -0
|
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## v0.2.2 (2026-10-15)
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
- run on a non-retrying copy of the caller's client
|
|
13
|
+
|
|
8
14
|
## v0.2.1 (2026-10-15)
|
|
9
15
|
|
|
10
16
|
### Fix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: aind-codeocean-dispatch
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Launch, monitor, and capture batches of Code Ocean capsule runs
|
|
5
5
|
Project-URL: Repository, https://github.com/AllenNeuralDynamics/aind-codeocean-dispatch/
|
|
6
6
|
Project-URL: Issues, https://github.com/AllenNeuralDynamics/aind-codeocean-dispatch/issues
|
|
@@ -6,7 +6,9 @@ counters rather than locks, and no thread is parked per job.
|
|
|
6
6
|
|
|
7
7
|
Error policy
|
|
8
8
|
------------
|
|
9
|
-
|
|
9
|
+
Every 429 or 5xx must surface here, so :func:`run_jobs` works on a copy of the
|
|
10
|
+
client with ``retries=0``: transport-level retries would resend POSTs below this
|
|
11
|
+
policy, and their exhausted retries raise without the status code it reads.
|
|
10
12
|
|
|
11
13
|
- **429** is retried on every call, honouring ``Retry-After``: the server rejected
|
|
12
14
|
the request without acting on it.
|
|
@@ -232,7 +234,8 @@ def run_jobs(
|
|
|
232
234
|
Parameters
|
|
233
235
|
----------
|
|
234
236
|
client : CodeOcean
|
|
235
|
-
Authenticated client.
|
|
237
|
+
Authenticated client. Its own ``retries`` setting is overridden on a copy;
|
|
238
|
+
the caller's client is left unchanged.
|
|
236
239
|
jobs : Sequence[Job]
|
|
237
240
|
Launched in order, subject to the cap and pacing.
|
|
238
241
|
max_in_flight : int, optional
|
|
@@ -271,7 +274,7 @@ def run_jobs(
|
|
|
271
274
|
"""
|
|
272
275
|
_validate(jobs, max_in_flight=max_in_flight, start_retries=start_retries, capture_retries=capture_retries)
|
|
273
276
|
return _Dispatcher(
|
|
274
|
-
client,
|
|
277
|
+
_without_transport_retries(client),
|
|
275
278
|
jobs,
|
|
276
279
|
max_in_flight=max_in_flight,
|
|
277
280
|
launch_interval_s=launch_interval_s,
|
|
@@ -284,6 +287,18 @@ def run_jobs(
|
|
|
284
287
|
).run()
|
|
285
288
|
|
|
286
289
|
|
|
290
|
+
def _without_transport_retries(client: CodeOcean) -> CodeOcean:
|
|
291
|
+
"""Return *client*, or a copy with ``retries=0`` if it retries requests itself.
|
|
292
|
+
|
|
293
|
+
The copy opens a new session, so anything mounted on the original's ``session``
|
|
294
|
+
by hand is not carried over.
|
|
295
|
+
"""
|
|
296
|
+
if client.retries in (0, None):
|
|
297
|
+
return client
|
|
298
|
+
logger.info("using a copy of the client with retries=0 (was %r); run_jobs retries what is safe", client.retries)
|
|
299
|
+
return dataclasses.replace(client, retries=0)
|
|
300
|
+
|
|
301
|
+
|
|
287
302
|
def _validate(jobs: Sequence[Job], *, max_in_flight: int | None, start_retries: int, capture_retries: int) -> None:
|
|
288
303
|
labels = [job.label for job in jobs]
|
|
289
304
|
if len(set(labels)) != len(labels):
|
|
@@ -5,9 +5,11 @@ from typing import Any
|
|
|
5
5
|
import pytest
|
|
6
6
|
import requests
|
|
7
7
|
from aind_code_ocean_pipeline_utils.process import GracefulExit
|
|
8
|
+
from codeocean import CodeOcean
|
|
8
9
|
from codeocean.components import Ownership
|
|
9
10
|
from codeocean.computation import Computation, DataAssetsRunParam, NamedRunParam, RunParams
|
|
10
11
|
from codeocean.data_asset import DataAssetParams, DataAssetState
|
|
12
|
+
from urllib3.util import Retry
|
|
11
13
|
|
|
12
14
|
from aind_codeocean_dispatch import (
|
|
13
15
|
DispatchFailed,
|
|
@@ -315,6 +317,33 @@ def test_duplicate_labels_are_rejected(clock: FakeClock) -> None:
|
|
|
315
317
|
run_jobs(make_client(clock, {}), [job("a"), job("a")])
|
|
316
318
|
|
|
317
319
|
|
|
320
|
+
@pytest.mark.parametrize("retries", [3, Retry(total=5, allowed_methods=["POST"])])
|
|
321
|
+
def test_client_that_retries_itself_still_runs(clock: FakeClock, retries: Any) -> None:
|
|
322
|
+
client = make_client(clock, {"a": [[SUCCEEDED]]})
|
|
323
|
+
client.retries = retries
|
|
324
|
+
|
|
325
|
+
outcomes = run_jobs(client, [job("a")])
|
|
326
|
+
|
|
327
|
+
assert [o.status for o in outcomes] == ["captured"]
|
|
328
|
+
assert client.retries is retries
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def test_retrying_client_is_copied_without_retries() -> None:
|
|
332
|
+
original = CodeOcean(domain="https://codeocean.example", token="x", retries=Retry(total=5))
|
|
333
|
+
|
|
334
|
+
copy = runner._without_transport_retries(original)
|
|
335
|
+
|
|
336
|
+
assert copy is not original and copy.session is not original.session
|
|
337
|
+
assert (copy.retries, copy.domain, copy.token) == (0, original.domain, original.token)
|
|
338
|
+
assert isinstance(original.retries, Retry)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def test_non_retrying_client_is_used_as_is() -> None:
|
|
342
|
+
client = CodeOcean(domain="https://codeocean.example", token="x")
|
|
343
|
+
|
|
344
|
+
assert runner._without_transport_retries(client) is client
|
|
345
|
+
|
|
346
|
+
|
|
318
347
|
def test_invalid_key_is_rejected() -> None:
|
|
319
348
|
with pytest.raises(ValueError, match="key"):
|
|
320
349
|
job("a", key="has space")
|
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/ISSUE_TEMPLATE/bug_report.md
RENAMED
|
File without changes
|
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/ISSUE_TEMPLATE/user-story.md
RENAMED
|
File without changes
|
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/bump-call.yml
RENAMED
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/ci-call.yml
RENAMED
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/.github/workflows/publish-call.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/scripts/run_linters_and_checks.sh
RENAMED
|
File without changes
|
|
File without changes
|
{aind_codeocean_dispatch-0.2.1 → aind_codeocean_dispatch-0.2.2}/src/aind_codeocean_dispatch/py.typed
RENAMED
|
File without changes
|
|
File without changes
|