Skip to content

Commit 1b6efb3

Browse files
authored
Python: expose BamlAbortError (#2674)
## Summary Align Python abort error behavior with docs and TS: - Expose `BamlAbortError` in the Python typing stub - Raise native `BamlAbortError` on early‑abort (pre‑runtime) instead of a generic Exception - Add tests to validate import/isinstance and early‑abort type ## Motivation / Context - Docs: `fern/03-reference/baml_client/errors/overview.mdx` describe error types and behavior. - In Python: - Runtime aborts already surface as native `BamlAbortError` via PyO3 - Early‑abort (already‑aborted controller) raised a generic `Exception("BamlAbortError: ...")` - `baml_py.pyi` didn’t declare `BamlAbortError` - This PR makes Python match the documented behavior and enables type checkers to see `BamlAbortError`. ## Changes - engine/language_client_python/python_src/baml_py/baml_py.pyi - Add `class BamlAbortError(BamlError): ...` - engine/generators/languages/python/src/_templates/runtime.py.j2 - Early‑abort now raises `baml_py.baml_py.BamlAbortError("Operation was aborted")` - integ-tests/python/tests/test_abort_handlers.py - Update `test_early_abort` to expect `BamlAbortError` - Add `test_baml_abort_error_import_and_instanceof` sanity check Not included: regenerated client artifacts, to keep diff focused. Regeneration picks up the template change. ## Testing Targeted tests (run without provider keys): ```bash cd integ-tests/python uv sync uv run maturin develop --uv --manifest-path ../../engine/language_client_python/Cargo.toml uv run baml-cli generate --from ../baml_src uv run pytest -q -k 'early_abort or baml_abort_error_import_and_instanceof' # Result: both tests passed locally ``` Full Python suite (requires provider env vars in `integ-tests/.env`): ```bash cd integ-tests/python uv sync uv run maturin develop --uv --manifest-path ../../engine/language_client_python/Cargo.toml uv run baml-cli generate --from ../baml_src dotenv -e ../.env -- uv run pytest -q ``` ## Backwards Compatibility - Early‑abort Exception type changes from a generic `Exception` to `BamlAbortError` (more specific); downstream code that caught generic errors continues to work. Typed checks (`isinstance(e, BamlAbortError)`) now work consistently for both early and in‑flight aborts.
1 parent c1ec923 commit 1b6efb3

File tree

5 files changed

+19
-8
lines changed

5 files changed

+19
-8
lines changed

engine/generators/languages/python/src/_templates/runtime.py.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class {{ call_manager_name }}:
124124

125125
# Check if already aborted
126126
if resolved_options.abort_controller is not None and resolved_options.abort_controller.aborted:
127-
raise Exception("BamlAbortError: Operation was aborted")
127+
raise baml_py.baml_py.BamlAbortError("Operation was aborted")
128128

129129
return await __runtime__.call_function(
130130
function_name,
@@ -154,7 +154,7 @@ class {{ call_manager_name }}:
154154

155155
# Check if already aborted
156156
if resolved_options.abort_controller is not None and resolved_options.abort_controller.aborted:
157-
raise Exception("BamlAbortError: Operation was aborted")
157+
raise baml_py.baml_py.BamlAbortError("Operation was aborted")
158158

159159
ctx = __ctx__manager__.get()
160160
return __runtime__.call_function_sync(

engine/language_client_python/python_src/baml_py/baml_py.pyi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,3 +561,8 @@ class BamlClientHttpError(BamlClientError):
561561
"""Raised for HTTP-related client errors."""
562562

563563
...
564+
565+
class BamlAbortError(BamlError):
566+
"""Raised when a BAML operation is cancelled (abort)."""
567+
568+
...

integ-tests/python-v1/baml_client/runtime.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integ-tests/python/baml_client/runtime.py

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integ-tests/python/tests/test_abort_handlers.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import time
44
from baml_client import b
55
from baml_py import AbortController
6+
from baml_py.errors import BamlAbortError
67

78

89
@pytest.mark.asyncio
@@ -170,12 +171,17 @@ async def test_early_abort():
170171
abort_controller = AbortController()
171172
abort_controller.abort()
172173

173-
with pytest.raises(Exception) as exc_info:
174+
with pytest.raises(BamlAbortError):
174175
await b.ExtractName(
175176
text="John Doe", baml_options={"abort_controller": abort_controller}
176177
)
177178

178-
assert "abort" in str(exc_info.value).lower()
179+
180+
def test_baml_abort_error_import_and_instanceof():
181+
try:
182+
raise BamlAbortError("Operation was aborted")
183+
except Exception as e:
184+
assert isinstance(e, BamlAbortError)
179185

180186

181187
@pytest.mark.asyncio

0 commit comments

Comments
 (0)