You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
chore: harden the extension API before it ships (#1759)
* chore: harden the extension API before it ships
`SessionContext.with_extensions` and `SessionExtensionComponents` landed
in #1679 and have not shipped in a release yet. The bundle stack
(#1738-#1741) reshapes them substantially, and a release would freeze
three surfaces in their current form.
`PhysicalOptimizerRuleExportable` was defined in `datafusion.context` and
not exported from the package root, so `datafusion.context` would become
its canonical import path. Move it to `datafusion.extensions` beside the
rest of the `*Exportable` family, re-export it from `datafusion.context`
so the old path keeps working, and export it from the package root. The
move brings it under `test_extension_api_has_a_doctest`, which drives off
`extensions.__all__`, so it gains the example it was missing.
`SessionExtensionComponents` was positionally constructible with two
fields. The stack takes it to nine, three of them pair-shaped. Make
construction keyword-only so every later field addition is additive; no
call site in the repository constructed it positionally. This is a new
convention rather than a backport, so it has to be applied forward to the
stack as well.
The ordering that makes `with_extensions` transactional was stated in
three docstrings with no canonical home to point at. Record it under
`ffi_internals_commit_order` in the contributor guide, and label the
existing "Failure and rollback" section `extension_bundles_transaction`,
matching the names the stack links to.
No released behaviour changes, so no `api change` label and no
upgrade-guide entry.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* refactor: narrow the extension protocol surface
The capsule-getter protocols are annotations, never arguments: a bundle
author constructs a SessionExtensionComponents but only ever names
SessionComponentsExportable in a type hint. Exporting the hints from the
package root made this one family the exception among sixteen such
protocols, every other one of which is reached through its defining
module.
Drop PhysicalOptimizerRuleExportable, QueryPlannerExportable,
SessionComponentsExportable, and SessionPlannerExportable from the root
(__all__ 58 -> 54), keeping SessionExtensionComponents, which is the one
name a bundle constructs. The three bundle protocols are new in 55.0.0,
so no import path is lost.
PhysicalOptimizerRuleExportable shipped in 54.0.0 from datafusion.context,
so its move is a break: context.py now imports it under TYPE_CHECKING only,
and the upgrade guide records the new path. Nothing else changes for a rule
author -- the protocol is structural and not runtime-checkable, and
add_physical_optimizer_rule is untouched.
Also removes three now-dead autoapi skip entries, repoints three doctests
that imported from the root, and fixes the add_physical_optimizer_rule
cross-reference, which stopped resolving once the class left context.py.
test_extension_protocols_are_exported_together asserted the premise this
reverses, so it goes. The five doctests in extensions.py already prove the
classes exist there, and SessionExtensionComponents' own docstring pins
the remaining root export.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: state the commit-order invariant correctly
The ordering rule said step 4 "cannot raise part-way through", and the
comment in `with_extensions` said "everything above is allowed to raise;
this is not". Neither holds: `_install_extension_planner` runs
`ffi_query_planner_from_pycapsule` before it calls
`set_session_query_planner`, so the commit step has fallible work of its
own.
The guarantee survives, because that import happens before the write. But
the passage is written as a rule for whoever adds the next component kind,
and as phrased it asks them to preserve a property the code does not have.
Restate it as what actually holds: every fallible operation, including the
ones inside the commit, completes before the first write.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test: verify the physical optimizer rule docstring example
The `+SKIP` block in `PhysicalOptimizerRuleExportable` named
`test_ffi_physical_optimizer_rule_runs_during_planning` as the test that
runs it for real, but that test never reads the docstring. It is a
separately written test that happens to call the same two APIs, so it
catches a renamed method or module only by coincidence, and cannot see an
edit to the docstring at all.
Add the mirror the convention actually asks for, in the shape of
`test_with_extensions_docstring_example_still_runs`: parse the live
docstring, keep only the skipped statements, drop the skip, and run them.
Only `ctx` is supplied, because the skipped statements go on using the
context the runnable block above them opened.
Verified by mutation. Renaming the imported class in the docstring fails
with `NameError: name 'MyPhysicalOptimizerRule' is not defined`, and
deleting the block fails the `assert examples` guard rather than passing
vacuously.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* refactor: keep bundle protocols out of datafusion.context
datafusion.context imported QueryPlannerExportable,
SessionComponentsExportable and SessionPlannerExportable at runtime,
so they were reachable as datafusion.context.* despite
datafusion.extensions being their one home. Move them under
TYPE_CHECKING and route the runtime isinstance checks through a
private _extensions module alias. The protocols are new in 55.0.0,
so no released import path is dropped.
Add a test pinning that all four capsule-getter protocols live only
in datafusion.extensions, and list PhysicalOptimizerRuleExportable
in llms.txt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: pin keyword-only construction; scope the rollback promise
Add a test that SessionExtensionComponents rejects positional
arguments, so dropping kw_only=True fails the suite. Every existing
caller passes keywords and would stay green without it.
Drop the absence assertions from the extension protocol import test.
Re-exporting a name is additive and breaks no caller, so asserting a
name is missing only adds friction for a later deliberate export.
Keep the positive check that each protocol imports from
datafusion.extensions.
The contributor guide promised that a raising bundle leaves the
session as it was without the carve-out for writes a hook makes to
the context it is handed. Add it with a ref to the bundles guide,
which is where the exception is explained.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/source/llms.txt
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@
31
31
- [`datafusion.expr`](https://datafusion.apache.org/python/autoapi/datafusion/expr/index.html): expression tree nodes (`Expr`, `Window`, `WindowFrame`, `GroupingSet`).
32
32
- [`datafusion.functions`](https://datafusion.apache.org/python/autoapi/datafusion/functions/index.html): 290+ scalar, aggregate, and window functions.
33
33
- [`datafusion.context.SessionContext`](https://datafusion.apache.org/python/autoapi/datafusion/context/index.html): session entry point, data loading, SQL execution.
34
-
- [`datafusion.extensions`](https://datafusion.apache.org/python/autoapi/datafusion/extensions/index.html): `SessionExtensionComponents`, `SessionComponentsExportable`, `SessionPlannerExportable`, `QueryPlannerExportable`— the extension-bundle protocol.
34
+
- [`datafusion.extensions`](https://datafusion.apache.org/python/autoapi/datafusion/extensions/index.html): `SessionExtensionComponents`, `SessionComponentsExportable`, `SessionPlannerExportable`, `QueryPlannerExportable`, `PhysicalOptimizerRuleExportable` — the extension-bundle and capsule-getter protocols.
35
35
- [`datafusion.ipc`](https://datafusion.apache.org/python/autoapi/datafusion/ipc/index.html): worker and sender context slots for shipping expressions between processes.
0 commit comments