Skip to content

feat(sdk)!: 0.30.0 remove deprecated distributed surface (fixes one-covenant/basilica-backend#666)#490

Merged
epappas merged 1 commit into
mainfrom
sdk-simplification/666-remove-deprecated-surfaces
May 18, 2026
Merged

feat(sdk)!: 0.30.0 remove deprecated distributed surface (fixes one-covenant/basilica-backend#666)#490
epappas merged 1 commit into
mainfrom
sdk-simplification/666-remove-deprecated-surfaces

Conversation

@epappas
Copy link
Copy Markdown
Contributor

@epappas epappas commented May 18, 2026

Summary

S7 of the SDK API simplification plan. Removes every public surface that
was deprecated by S1-S4 (issues 660, 661, 662, 663 on basilica-backend),
bumps the SDK to 0.30.0, and routes the canonical @basilica.distributed
decorator through private impl methods on BasilicaClient. The user
contract is now exactly ONE shape: the decorator (or the BYO-launcher
factory) returns a DistributedTraining context manager.

This is the major-equivalent (pre-1.0) bump: 0.29.7 -> 0.30.0. The
ticket allowed 0.30.0 OR 1.0.0; pyproject.toml carries
Development Status :: 4 - Beta, which excludes a 1.0.0 stability
declaration. 0.30.0 is the only target consistent with both
"breaking" and "beta".

BREAKING CHANGE

The following public symbols are REMOVED. Calls now raise
AttributeError / ImportError / ValidationError; migrate via the
mapping below before upgrading.

Removed (0.29.x) Replacement (0.30.0)
client.deploy_distributed(source=fn, ...) @basilica.distributed(...)\ndef fn(): ...\ntraining = fn()
client.deploy_distributed(source="<inline>", ...) wrap inline as a function body; decorate it
client.deploy_distributed(source=Path("./train.py"), ...) runpy.run_path('/workspace/train.py') inside a decorated function
client.deploy_distributed_managed(command=[...], ...) basilica.distributed(command=[...], ...)
client.deploy_distributed_managed(source=fn, ...) with fn() as training: after @basilica.distributed on fn
bench="on-start" bench=True
bench="off" bench=False
training.wait_until_bench_complete(timeout=t) block via with training: then read training.bench
training.bench_status.phase training.bench_diagnostics["phase"]
BenchStatus (re-export from basilica) BenchResult (result payload) or the dict from training.bench_diagnostics
DistributedTrainingManaged / DistributedTrainingManagedAsync DistributedTraining (itself context-manager-able)

Plus internal: _emit_deprecation kwarg on the (now-private) deploy
impl is removed; the deprecation-gating plumbing it controlled no
longer has any deprecation paths to suppress.

Refactor (no public-surface change)

  • The deploy logic that previously lived behind the public
    deploy_distributed* methods now lives on the private
    BasilicaClient._deploy_distributed_impl /
    _deploy_distributed_impl_async methods. The decorator
    (@basilica.distributed) and the BYO-launcher factory
    (basilica.distributed(command=[...])) both route through these
    private methods.
  • The post-deploy wait_for_bench polling no longer routes through
    the removed wait_until_bench_complete wrapper -- it reads
    training._bench_status_raw directly. The wait_for_bench /
    bench_timeout kwargs on @basilica.distributed keep their
    existing semantics (never / best_effort / required).
  • The BenchStatus dataclass remains in basilica.distributed as an
    internal type backing _bench_status_raw (and therefore
    bench_diagnostics); it is no longer re-exported from the top-level
    basilica package.
  • Function-body packaging for @basilica.distributed is now in a
    shared helper basilica.source._package_function_for_torchrun(...);
    the decorator's DistributedFunction._extract_source() is a thin
    shim over the same helper used by the deploy impl, so existing
    decorator-introspection tests exercise the production code path.

Files

  • SDK source:
    crates/basilica-sdk-python/python/basilica/__init__.py (removals +
    private impl), distributed.py (drop bench_status / wait waiters /
    Managed wrapper classes), decorators.py (route through private
    impl), source.py (shared packager helper), exceptions.py +
    src/lib.rs (docstring updates).
  • Tests: test_bench_bool_simplification.py,
    test_distributed.py, test_distributed_canonical_surface.py,
    test_distributed_command_factory.py updated to call
    _deploy_distributed_impl[_async], assert removed-surface
    AttributeError / ValidationError, and read bench data via
    training.bench / training.bench_diagnostics. Removed:
    test_deploy_distributed_managed.py,
    test_bench_status_skipped.py, test_source_param_deprecation.py
    (entirely about removed surfaces).
  • Version: pyproject.toml, Cargo.toml, Cargo.lock bumped to
    0.30.0. CHANGELOG entry under [0.30.0] documents every removed
    symbol + the migration matrix.
  • Docs: crates/basilica-sdk-python/README.md "Migration from the
    legacy surface" rewritten to reflect post-removal state. AGENTS.md
    • crates/basilica-cli/src/cli/commands.rs docstrings updated.

Test plan

  • pytest: 169 passed (reduced suite -- 211 baseline minus the 42
    tests that pinned removed surfaces, which are deleted or
    rewritten)
  • cargo fmt -p basilica-sdk-python -p basilica-cli -- --check:
    clean
  • cargo clippy -p basilica-sdk-python --release -- -D warnings:
    clean
  • Removed-symbol probes: every removed symbol raises
    AttributeError / ImportError / ValidationError (evidence
    in basilica-backend repo's
    data/evidence/sdk-simpl-666/02-post-removal-attribute-errors.txt)
  • Examples 20/21/22 parse + module-load + zero DeprecationWarning
    leaked to the user (evidence dir 05-runtime-verify/)
  • Pre-removal baseline pytest: 211 passed (captured before any
    change in 01-pytest-baseline.txt)

Not in this PR

  • PyPI publish (separate authorized step per the release contract).
  • Operator-side or autoscaler-side changes (substrate is already
    delivered).

Cross-refs

Summary by CodeRabbit

Release Notes v0.30.0

  • Breaking Changes

    • Removed legacy deploy_distributed and deploy_distributed_managed methods. Use @basilica.distributed decorator instead.
    • Removed string-based bench parameter modes. The bench option now accepts boolean values only.
    • Removed deprecated BenchStatus accessor and legacy bench helper methods.
  • Documentation

    • Updated migration guide with canonical interface path and parameter mappings.
    • Updated distributed training guidance to emphasize decorator-based approach.

Review Change Stack

…ovenant/basilica-backend#666)

S7 of the SDK API simplification plan. Removes every surface that was
deprecated by S1-S4 (basilica-backend issues 660, 661, 662, 663), bumps
the SDK to 0.30.0, and routes the canonical @basilica.distributed
decorator through private impl methods. The user-facing surface is now
exactly ONE shape: the decorator (or the BYO-launcher factory) returns
a DistributedTraining context manager.

BREAKING CHANGE: removed public symbols

- BasilicaClient.deploy_distributed
- BasilicaClient.deploy_distributed_async
- BasilicaClient.deploy_distributed_managed
- BasilicaClient.deploy_distributed_managed_async
- DistributedTrainingManaged / DistributedTrainingManagedAsync (classes)
- DistributedTraining.wait_until_bench_complete
- DistributedTraining.wait_until_bench_complete_async
- DistributedTraining.bench_status (property)
- BenchStatus re-export from `basilica` (kept as internal type in
  basilica.distributed for the private _bench_status_raw helper)
- source: Union[str, Path] shapes -- only Callable accepted (via decorator)
- bench='on-start' / bench='off' string modes -- bench is bool-only
- _emit_deprecation kwarg on the (now-private) deploy impl

The deploy logic that previously lived behind the public
deploy_distributed* methods now lives on the private
BasilicaClient._deploy_distributed_impl / _deploy_distributed_impl_async
helpers. The decorator (@basilica.distributed) and the BYO-launcher
factory (basilica.distributed(command=[...])) both route through these
private methods.

The post-deploy wait_for_bench polling no longer routes through the
removed wait_until_bench_complete wrapper -- it reads
training._bench_status_raw directly. The wait_for_bench / bench_timeout
kwargs on @basilica.distributed keep their existing semantics
(never / best_effort / required).

Migration matrix: see CHANGELOG.md [0.30.0] section for the per-symbol
mapping (legacy -> canonical). README.md "Migration from the legacy
surface" updated to point at the AttributeError / ImportError /
ValidationError users will see post-upgrade.

PyPI publish is NOT done in this PR (per user-facing release contract;
publish is a separate authorized step).

Refs the SDK API simplification plan
(docs/plans/SDK-API-SIMPLIFICATION-PLAN.md on basilica-backend main).
Builds on prior simplification PRs (issue 660 / SDK-S1, issue 661 /
SDK-S2, issue 662 / SDK-S3, issue 663 / SDK-S4, issue 664 / SDK-S5
examples migration, issue 665 / SDK-S6 docs rewrite).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Walkthrough

Basilica Python SDK 0.30.0 removes the public distributed-training entrypoints (BasilicaClient.deploy_distributed* methods and managed wrapper classes), simplifies the bench API to boolean-only, routes all canonical deployments through private _deploy_distributed_impl[_async] helpers, and refactors distributed request construction with a new function-packaging helper and restructured bench handling. Version, documentation, decorators, facades, and tests are updated accordingly.

Changes

SDK 0.30.0 Breaking Release: Distributed Training Refactor

Layer / File(s) Summary
Version metadata and release documentation
crates/basilica-sdk-python/Cargo.toml, crates/basilica-sdk-python/pyproject.toml, crates/basilica-sdk-python/CHANGELOG.md, crates/basilica-sdk-python/README.md, crates/basilica-cli/src/cli/commands.rs, AGENTS.md
Version bumped to 0.30.0 across manifest files; CHANGELOG documents breaking removal of deploy_distributed* and managed wrappers, simplification of bench modes to boolean, and deprecation of bench accessors; README migration table and CLI docstring updated to reflect canonical @basilica.distributed-only surface.
Function-to-torchrun module packaging helper
crates/basilica-sdk-python/python/basilica/source.py
New _package_function_for_torchrun helper extracts decorated function source, dedents it, prepends module-level imports referenced by function body, and wraps with __main__ guard for per-rank torchrun execution; module-level textwrap import added.
Core distributed deployment implementation refactor
crates/basilica-sdk-python/python/basilica/__init__.py
Public deploy_distributed[_async] methods replaced by private _deploy_distributed_impl[_async] with Callable-only source (non-Callable raises ValidationError) and boolean-only bench (string modes raise ValidationError); removed deprecation/normalization helpers; refactored bench polling via training._bench_status_raw directly with three wait_for_bench modes (never/best\_effort/required); restructured distributed request using distributed_spec dict with bench.mode and optional placement.
DistributedTraining facade and deprecated surface removal
crates/basilica-sdk-python/python/basilica/distributed.py
Removed DistributedTrainingManaged[Async] wrapper classes; removed deprecated bench_status property and wait_until_bench_complete[_async] methods; added internal _bench_status_raw typed accessor backing bench_diagnostics; updated bench and bench_diagnostics docstrings to document new collapse semantics (None on non-success, optional debug dict with phase/mode).
Decorator and factory path routing to private impl
crates/basilica-sdk-python/python/basilica/decorators.py
Updated DistributedFunction.deploy() to call _deploy_distributed_impl with user callable directly; simplified _extract_source() to delegate to _package_function_for_torchrun; tightened distributed(...) decorator bench parameter from Union[bool, str] to bool; updated _deploy_command_factory() BYO-launcher path to route through _deploy_distributed_impl.
Exception docstrings and miscellaneous documentation updates
crates/basilica-sdk-python/python/basilica/exceptions.py, crates/basilica-sdk-python/src/lib.rs
Exception docstring examples updated to reference @basilica.distributed and DistributedTraining facade instead of deprecated client.deploy_distributed(...); Rust FFI docstring updated to describe canonical decorator-based request construction.
Test suite updates for removal and API changes
crates/basilica-sdk-python/tests/test_bench_bool_simplification.py, crates/basilica-sdk-python/tests/test_distributed.py, crates/basilica-sdk-python/tests/test_distributed_canonical_surface.py, crates/basilica-sdk-python/tests/test_distributed_command_factory.py, crates/basilica-sdk-python/tests/test_bench_status_skipped.py (removed), crates/basilica-sdk-python/tests/test_deploy_distributed_managed.py (removed), crates/basilica-sdk-python/tests/test_source_param_deprecation.py (removed)
Removed test files for deprecated surfaces (bench-status-skipped, managed-deploy, source-param-deprecation); remaining tests refactored to call private _deploy_distributed_impl[_async]; bench tests updated to expect boolean-only input with ValidationError on string modes and assert deprecated accessors are gone; distributed tests rewired to use _noop_train callable source, verify absence of managed/bench-helper surfaces on BasilicaClient, and assert new bench/bench_diagnostics semantics (None on non-success, phase visibility via diagnostics).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • one-covenant/basilica#447: Introduced the original BasilicaClient.deploy_distributed(_async) and @basilica.distributed surfaces that this PR refactors/removes in favor of private _deploy_distributed_impl routing.
  • one-covenant/basilica#483: Both PRs modify the distributed-training bench API simplification (bool opt-in, bench_diagnostics behavior, deprecation/removal) across overlapping files (__init__.py, decorators.py, distributed.py, test_bench_bool_simplification.py).
  • one-covenant/basilica#462: This PR preserves Issue #486 "best-effort UD deletion on wait_until_min_world failure" cleanup semantics and updates corresponding tests, which directly corresponds to cleanup behavior introduced in PR #462.

🐰 The deprecated surfaces fade away,
Private impl paths now hold the day,
Bench simplifies from strings so vague,
To booleans clean (no more vague league),
SDK 0.30.0—the new way! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: removing deprecated distributed surfaces in version 0.30.0, with a specific issue reference.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sdk-simplification/666-remove-deprecated-surfaces

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/basilica-sdk-python/python/basilica/source.py (1)

473-474: 💤 Low value

Redundant import after module-level change.

textwrap is now imported at module scope (line 30), so this local import is unnecessary.

🧹 Remove redundant import
-        import textwrap
-        source = textwrap.dedent(source)
+        source = textwrap.dedent(source)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/basilica-sdk-python/python/basilica/source.py` around lines 473 - 474,
Remove the redundant local import of textwrap inside the function — since
textwrap is already imported at module scope (top of the file), delete the line
"import textwrap" in the block shown and leave the existing call to
textwrap.dedent(source) unchanged (refer to the local import near the source =
textwrap.dedent(source) statement to locate the removal).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/basilica-sdk-python/CHANGELOG.md`:
- Line 10: Add a missing link-style reference for the new release header "##
[0.30.0] - 2026-05-18" by appending a `[0.30.0]: <release-URL-or-compare-link>`
entry to the bottom of CHANGELOG.md (matching the pattern used for other
versions), ensuring the reference text exactly matches "0.30.0" so the header
link resolves correctly.

In `@crates/basilica-sdk-python/python/basilica/__init__.py`:
- Around line 2353-2393: The async function uses asyncio.get_event_loop() to
obtain loop/time/sleep; replace that call with asyncio.get_running_loop() to
avoid deprecation and be consistent with other async methods (use the existing
loop variable for loop.time() and asyncio.sleep calls), keeping the rest of the
logic that computes deadline, polls training.refresh_async(), and reads
training._bench_status_raw unchanged.

---

Nitpick comments:
In `@crates/basilica-sdk-python/python/basilica/source.py`:
- Around line 473-474: Remove the redundant local import of textwrap inside the
function — since textwrap is already imported at module scope (top of the file),
delete the line "import textwrap" in the block shown and leave the existing call
to textwrap.dedent(source) unchanged (refer to the local import near the source
= textwrap.dedent(source) statement to locate the removal).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f995aa33-bebe-4187-8b10-d7f5af3bf6c0

📥 Commits

Reviewing files that changed from the base of the PR and between 0a610d7 and 728607e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (19)
  • AGENTS.md
  • crates/basilica-cli/src/cli/commands.rs
  • crates/basilica-sdk-python/CHANGELOG.md
  • crates/basilica-sdk-python/Cargo.toml
  • crates/basilica-sdk-python/README.md
  • crates/basilica-sdk-python/pyproject.toml
  • crates/basilica-sdk-python/python/basilica/__init__.py
  • crates/basilica-sdk-python/python/basilica/decorators.py
  • crates/basilica-sdk-python/python/basilica/distributed.py
  • crates/basilica-sdk-python/python/basilica/exceptions.py
  • crates/basilica-sdk-python/python/basilica/source.py
  • crates/basilica-sdk-python/src/lib.rs
  • crates/basilica-sdk-python/tests/test_bench_bool_simplification.py
  • crates/basilica-sdk-python/tests/test_bench_status_skipped.py
  • crates/basilica-sdk-python/tests/test_deploy_distributed_managed.py
  • crates/basilica-sdk-python/tests/test_distributed.py
  • crates/basilica-sdk-python/tests/test_distributed_canonical_surface.py
  • crates/basilica-sdk-python/tests/test_distributed_command_factory.py
  • crates/basilica-sdk-python/tests/test_source_param_deprecation.py
💤 Files with no reviewable changes (3)
  • crates/basilica-sdk-python/tests/test_deploy_distributed_managed.py
  • crates/basilica-sdk-python/tests/test_bench_status_skipped.py
  • crates/basilica-sdk-python/tests/test_source_param_deprecation.py


## [Unreleased]

## [0.30.0] - 2026-05-18
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the missing changelog reference link for 0.30.0.

## [0.30.0] is introduced, but there’s no corresponding [0.30.0]: ... reference at the bottom, which breaks link-style navigation consistency for release entries.

Suggested docs patch
+[0.30.0]: https://github.com/one-covenant/basilica/compare/basilica-sdk-python-v0.29.7...basilica-sdk-python-v0.30.0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/basilica-sdk-python/CHANGELOG.md` at line 10, Add a missing link-style
reference for the new release header "## [0.30.0] - 2026-05-18" by appending a
`[0.30.0]: <release-URL-or-compare-link>` entry to the bottom of CHANGELOG.md
(matching the pattern used for other versions), ensuring the reference text
exactly matches "0.30.0" so the header link resolves correctly.

Comment on lines +2353 to 2393
"""
Async variant of :py:meth:`_handle_post_deploy_bench_wait`. Polls
the operator's bench status directly (does not depend on the
public ``wait_until_bench_complete_async`` wrapper, which was
removed in 0.30.0).
"""
loop = asyncio.get_event_loop()
deadline = loop.time() + max(timeout, 0)
bs = None
while loop.time() < deadline:
await training.refresh_async()
bs = training._bench_status_raw
if bs is None:
return
if bs.is_terminal:
break
await asyncio.sleep(min(5, max(timeout // 10, 1)))
else:
await training.refresh_async()
bs = training._bench_status_raw

if bs is None or not bs.is_terminal:
msg = (
f"wait_for_bench='{mode}': bench did not reach a terminal "
f"phase within {timeout}s (phase="
f"{bs.phase if bs else 'absent'})"
)
if mode == "required":
raise DistributedError(msg)
warnings.warn(msg, stacklevel=3)
return
if bs is None:
return

if bs.phase == BENCH_PHASE_SUCCEEDED:
return
msg = (
f"bench probe phase={bs.phase}"
f"{f' message={bs.message!r}' if bs.message else ''}"
)
if mode == "required":
raise DistributedError(
f"wait_for_bench='required' but {msg}"
)
raise DistributedError(f"wait_for_bench='required' but {msg}")
warnings.warn(f"wait_for_bench='best_effort': {msg}", stacklevel=3)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Inconsistent use of asyncio.get_event_loop() vs asyncio.get_running_loop().

This method uses asyncio.get_event_loop() (lines 2359, 2362) while other async methods in this file correctly use asyncio.get_running_loop() (e.g., line 2222). In Python 3.10+, get_event_loop() inside an already-running async context is deprecated and may emit a DeprecationWarning. Since this is an async method, get_running_loop() is the correct choice.

🔧 Use get_running_loop() for consistency
     async def _handle_post_deploy_bench_wait_async(
         training: DistributedTraining,
         mode: Literal["best_effort", "required"],
         timeout: int,
     ) -> None:
         ...
-        loop = asyncio.get_event_loop()
+        loop = asyncio.get_running_loop()
         deadline = loop.time() + max(timeout, 0)
         bs = None
-        while loop.time() < deadline:
+        while asyncio.get_running_loop().time() < deadline:

Alternatively, capture the loop once and reuse:

-        loop = asyncio.get_event_loop()
+        loop = asyncio.get_running_loop()
         deadline = loop.time() + max(timeout, 0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"""
Async variant of :py:meth:`_handle_post_deploy_bench_wait`. Polls
the operator's bench status directly (does not depend on the
public ``wait_until_bench_complete_async`` wrapper, which was
removed in 0.30.0).
"""
loop = asyncio.get_event_loop()
deadline = loop.time() + max(timeout, 0)
bs = None
while loop.time() < deadline:
await training.refresh_async()
bs = training._bench_status_raw
if bs is None:
return
if bs.is_terminal:
break
await asyncio.sleep(min(5, max(timeout // 10, 1)))
else:
await training.refresh_async()
bs = training._bench_status_raw
if bs is None or not bs.is_terminal:
msg = (
f"wait_for_bench='{mode}': bench did not reach a terminal "
f"phase within {timeout}s (phase="
f"{bs.phase if bs else 'absent'})"
)
if mode == "required":
raise DistributedError(msg)
warnings.warn(msg, stacklevel=3)
return
if bs is None:
return
if bs.phase == BENCH_PHASE_SUCCEEDED:
return
msg = (
f"bench probe phase={bs.phase}"
f"{f' message={bs.message!r}' if bs.message else ''}"
)
if mode == "required":
raise DistributedError(
f"wait_for_bench='required' but {msg}"
)
raise DistributedError(f"wait_for_bench='required' but {msg}")
warnings.warn(f"wait_for_bench='best_effort': {msg}", stacklevel=3)
"""
Async variant of :py:meth:`_handle_post_deploy_bench_wait`. Polls
the operator's bench status directly (does not depend on the
public ``wait_until_bench_complete_async`` wrapper, which was
removed in 0.30.0).
"""
loop = asyncio.get_running_loop()
deadline = loop.time() + max(timeout, 0)
bs = None
while asyncio.get_running_loop().time() < deadline:
await training.refresh_async()
bs = training._bench_status_raw
if bs is None:
return
if bs.is_terminal:
break
await asyncio.sleep(min(5, max(timeout // 10, 1)))
else:
await training.refresh_async()
bs = training._bench_status_raw
if bs is None or not bs.is_terminal:
msg = (
f"wait_for_bench='{mode}': bench did not reach a terminal "
f"phase within {timeout}s (phase="
f"{bs.phase if bs else 'absent'})"
)
if mode == "required":
raise DistributedError(msg)
warnings.warn(msg, stacklevel=3)
return
if bs.phase == BENCH_PHASE_SUCCEEDED:
return
msg = (
f"bench probe phase={bs.phase}"
f"{f' message={bs.message!r}' if bs.message else ''}"
)
if mode == "required":
raise DistributedError(f"wait_for_bench='required' but {msg}")
warnings.warn(f"wait_for_bench='best_effort': {msg}", stacklevel=3)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/basilica-sdk-python/python/basilica/__init__.py` around lines 2353 -
2393, The async function uses asyncio.get_event_loop() to obtain
loop/time/sleep; replace that call with asyncio.get_running_loop() to avoid
deprecation and be consistent with other async methods (use the existing loop
variable for loop.time() and asyncio.sleep calls), keeping the rest of the logic
that computes deadline, polls training.refresh_async(), and reads
training._bench_status_raw unchanged.

@epappas epappas merged commit f9b7c19 into main May 18, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant