Skip to content

feat(sdk): deprecate source: Union[str, Path]; Callable canonical (fixes one-covenant/basilica-backend#663)#487

Merged
epappas merged 1 commit into
mainfrom
sdk-simplification/663-source-callable-only
May 18, 2026
Merged

feat(sdk): deprecate source: Union[str, Path]; Callable canonical (fixes one-covenant/basilica-backend#663)#487
epappas merged 1 commit into
mainfrom
sdk-simplification/663-source-callable-only

Conversation

@epappas
Copy link
Copy Markdown
Contributor

@epappas epappas commented May 18, 2026

Summary

Collapse the BasilicaClient.deploy_distributed(source=...) parameter to a Callable-only surface via the @basilica.distributed decorator. The str and pathlib.Path shapes remain functional for the next two minor versions, but now emit a DeprecationWarning pointing at the canonical alternatives.

This ships SDK-S4 in the SDK API simplification plan (docs/plans/SDK-API-SIMPLIFICATION-PLAN.md on one-covenant/basilica-backend@main, Problem 2 / SDK-S4). Sits in the converging surface alongside the previously-merged S1, S2 and S3 work.

What changed

Implementation in crates/basilica-sdk-python/python/basilica/__init__.py:

  • New _normalize_source_param(source, *, emit_deprecation=True) helper (lines 248-298) that:
    • returns source unchanged when it is None, a Callable, or when emit_deprecation=False;
    • emits a DeprecationWarning (stacklevel=3) for str and pathlib.Path inputs, pointing the user at the @basilica.distributed decorator and the runpy.run_path('/workspace/...') wrapping pattern for external scripts;
    • cites basilica-backend#663 / SDK-S4 in the warning message itself.
  • The sync path (deploy_distributed, lines 1340-1346) and the async path (deploy_distributed_async, lines 2502-2506) call the helper immediately after the existing S1 _emit_deprecation gate, before request building. The same gate that already silences the S1 deploy_distributed-itself deprecation now also silences the S4 source-shape deprecation, so users on the canonical surface (@basilica.distributed decorator or the S3 basilica.distributed(command=[...]) factory) see no warnings.

Wire contract

Untouched. This is a Python-side ergonomics warning only. The request payload still ships the same command/args/source shape over JSON; the operator's decoding path is unchanged. The Callable shape is already what the decorator passes internally (via inspect.getsource(...)); S4 formalises that the decorator IS the canonical input surface.

Tests

New file crates/basilica-sdk-python/tests/test_source_param_deprecation.py (10 tests, sync + async coverage):

  • TestSourceStringEmitsDeprecation: source='<inline python>' warns; warning message mentions @basilica.distributed.
  • TestSourcePathEmitsDeprecation: source=Path(...) AND source='<filepath>' both warn (both flow through the same SourcePackager file-reading path).
  • TestSourceCallableStaysSilent: source=<function> does NOT emit a source-shape warning (only the S1 deploy_distributed-itself warning, which is a separate concern handled by SDK-S1).
  • TestDecoratorPathDoesNotEmitSourceDeprecation: both the decorator path (@basilica.distributed -> deploy()) and the S3 factory path (basilica.distributed(command=[...], client=...)) emit NO warnings — the _emit_deprecation=False gate covers both S1 and S4.

Test pattern (BasilicaClient.__new__ + MagicMock stub for the PyO3 binding) mirrors test_distributed_canonical_surface.py and test_distributed_command_factory.py. No network or auth calls fire.

Evidence

  • Pre-fix (in basilica-backend at data/evidence/sdk-simpl-663/01-failing-test-pre-fix.txt): 6 of the new tests fail — captures the anti-pattern (no warning today for str/Path source inputs).
  • Post-fix (at data/evidence/sdk-simpl-663/02-tests-pass-post-fix.txt): 211 passed in the full SDK Python suite (the unrelated test_dns_propagation_e2e.py is excluded because it requires httpx, which is not in the SDK dev deps and not installed in CI either — CI's pytest tests/ -v || echo swallows the collection error).
  • Runtime evidence (at data/evidence/sdk-simpl-663/05-runtime-verify/00-runtime-warnings.txt): captures the actual DeprecationWarning text the runtime emits to stderr when a user calls deploy_distributed(source='<str>', ...).

Cross-references

Version bump

crates/basilica-sdk-python bumped 0.29.6 -> 0.29.7 across Cargo.toml, pyproject.toml, and Cargo.lock. This satisfies the basilica-sdk-python version-drift guard in .github/workflows/ci.yml (Check basilica-sdk-python version consistency step).

Test plan

  • New unit tests in test_source_param_deprecation.py (10 tests) pass on the worktree.
  • Full SDK Python suite: 211 passed (e2e excluded; same as CI behaviour).
  • cargo fmt --all -- --check: clean.
  • cargo clippy -p basilica-sdk-python -- -D warnings: no warnings introduced.
  • Runtime smoke: python -c "import basilica; ..." produces the expected DeprecationWarning to stderr.
  • CI green (will block on this before merge).

Fixes one-covenant/basilica-backend#663

Summary by CodeRabbit

  • Deprecations

    • Passing file paths or strings as source parameters to distributed deployments now emits deprecation warnings. Users should migrate to the decorator-based approach instead.
  • Tests

    • Added comprehensive test coverage for source parameter deprecation behavior.

Review Change Stack

…anonical surface (refs basilica-backend#663)

Collapse the `BasilicaClient.deploy_distributed(source=...)` parameter
to a Callable-only surface via the `@basilica.distributed` decorator.
The `str` and `pathlib.Path` shapes remain functional but now emit a
`DeprecationWarning` pointing at the canonical alternatives.

Implementation:
  - `crates/basilica-sdk-python/python/basilica/__init__.py:248-298`:
    new `_normalize_source_param(source, emit_deprecation=True)` helper
    that warns on `str`/`Path` inputs and stays silent on `Callable`
    or when the caller is the decorator (which forwards
    `_emit_deprecation=False`, the same gate that already silences
    the S1 `deploy_distributed`-itself deprecation).
  - `crates/basilica-sdk-python/python/basilica/__init__.py:1340-1346`
    (sync) and `:2502-2506` (async): call the helper after the S1
    gate but before request building, so warnings emit at the
    user-facing boundary with `stacklevel=3`.

Wire contract: untouched. This is a Python-side ergonomics warning
only; the request payload still ships the same `command`/`args`/
`source` shape the operator decodes today. The `Callable` shape is
already what the decorator passes (via `inspect.getsource(...)`); S4
formalises that the decorator IS the canonical input surface.

Tests:
  - `crates/basilica-sdk-python/tests/test_source_param_deprecation.py`
    (new, 10 tests):
      * `str` (inline code) -> warns, message points at the decorator.
      * `pathlib.Path` and `str` (file path) -> both warn (same
        SourcePackager path).
      * `Callable` -> silent (canonical shape; only the S1 warning
        which is a separate concern).
      * Decorator path -> silent (the
        `_emit_deprecation=False` gate covers both S1 and S4).
      * S3 factory path (`basilica.distributed(command=[...])`) ->
        no source-shape warning.
    All async variants covered.
  - Pre-fix evidence at
    `data/evidence/sdk-simpl-663/01-failing-test-pre-fix.txt`: 6
    failures captured the anti-pattern (no warning today).
  - Post-fix evidence at
    `data/evidence/sdk-simpl-663/02-tests-pass-post-fix.txt`: 211
    passed in the full SDK Python suite (e2e test excluded; same
    behaviour CI swallows via `|| echo`).

Refs the SDK API simplification plan
(`docs/plans/SDK-API-SIMPLIFICATION-PLAN.md` on basilica-backend
main, Problem 2 / SDK-S4). Sits in the converging surface with
S1 (#484), S2 (#483 / #485) and S3 (#486).

Version bumped 0.29.6 -> 0.29.7 across Cargo.toml, pyproject.toml,
and Cargo.lock to satisfy the basilica-sdk-python version-drift
guard in CI.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0be5407b-f5b9-4846-9119-3cabe2e8b1c5

📥 Commits

Reviewing files that changed from the base of the PR and between 6080d95 and a2b1c8e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • crates/basilica-sdk-python/CHANGELOG.md
  • crates/basilica-sdk-python/Cargo.toml
  • crates/basilica-sdk-python/pyproject.toml
  • crates/basilica-sdk-python/python/basilica/__init__.py
  • crates/basilica-sdk-python/tests/test_source_param_deprecation.py

Walkthrough

This PR implements SDK-S4 deprecation for the source parameter in distributed deployments. Version numbers are bumped to 0.29.7, a new helper validates source input shapes and conditionally emits deprecation warnings for str/pathlib.Path inputs while remaining silent for callables and decorator paths, and comprehensive tests verify the warning behavior across all code paths.

Changes

SDK-S4 Source Deprecation

Layer / File(s) Summary
Version and release documentation
crates/basilica-sdk-python/Cargo.toml, crates/basilica-sdk-python/pyproject.toml, crates/basilica-sdk-python/CHANGELOG.md
Version incremented from 0.29.6 to 0.29.7 across package manifests. Changelog documents the new deprecation: deploy_distributed(source=...) emits DeprecationWarning for str/Path inputs, decorator path suppresses via _emit_deprecation=False, and notes planned removal alongside the method itself.
Source parameter normalization and integration
crates/basilica-sdk-python/python/basilica/__init__.py
_normalize_source_param helper conditionally emits DeprecationWarning when source is str or Path, while accepting None/callable silently. Integrated into both deploy_distributed and deploy_distributed_async to gate warnings via existing _emit_deprecation plumbing.
Deprecation behavior verification tests
crates/basilica-sdk-python/tests/test_source_param_deprecation.py
Test infrastructure stubs PyO3 bindings and provides test helpers. Separate test classes verify: str and Path sources emit warnings (both sync/async), callable sources stay silent, and decorator/command-factory surfaces remain silent even when forwarding str internally.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A string source now whispers goodbye,
With warnings so gentle, not shy,
But callables glow in the light,
The decorator path runs just right,
To the async and sync worlds, they fly! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.19% 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 accurately reflects the main objective: deprecating str/Path variants of the source parameter while establishing Callable as the canonical form, addressing basilica-backend#663 (SDK-S4).
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/663-source-callable-only

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.

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