Skip to content

Commit cc3ff0c

Browse files
timsaucerclaude
andcommitted
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>
1 parent e1cdb64 commit cc3ff0c

3 files changed

Lines changed: 18 additions & 5 deletions

File tree

‎docs/source/contributor-guide/ffi-internals.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ prefer `with_extensions` — is documented at {ref}`planner_codec_rebinding`.
116116
## Why `with_extensions` commits last
117117

118118
`with_extensions` promises that a bundle which raises leaves the session as it
119-
was. Keeping that promise is an ordering constraint on the implementation, not
119+
was, apart from anything a hook writes to the context it is handed
120+
({ref}`extension_bundles_transaction`). Keeping that promise is an ordering constraint on the implementation, not
120121
a property of any one step, because the planner is bound on the shared
121122
`SessionState` rather than on the returned handle.
122123

‎python/tests/test_context.py‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,21 @@ def test_session_extension_components_rejects_a_single_codec(field):
10861086
SessionExtensionComponents(**{field: codec})
10871087

10881088

1089+
def test_session_extension_components_is_keyword_only():
1090+
codecs = (
1091+
_NamedCodec(
1092+
SessionContext().__datafusion_logical_extension_codec__(),
1093+
"my_library.logical",
1094+
),
1095+
)
1096+
1097+
with pytest.raises(TypeError, match=r"positional argument"):
1098+
SessionExtensionComponents(codecs)
1099+
1100+
components = SessionExtensionComponents(logical_extension_codecs=codecs)
1101+
assert components.logical_extension_codecs == codecs
1102+
1103+
10891104
def test_session_extension_components_rejects_a_string():
10901105
"""A str is iterable, so it needs refusing on its own.
10911106

‎python/tests/test_imports.py‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,10 @@ def test_import_from_functions_submodule():
201201
"SessionPlannerExportable",
202202
],
203203
)
204-
def test_extension_protocols_live_only_in_extensions(name):
205-
import datafusion.context
204+
def test_extension_protocols_import_from_extensions(name):
206205
import datafusion.extensions
207206

208207
assert getattr(datafusion.extensions, name).__module__ == "datafusion.extensions"
209-
assert not hasattr(datafusion.context, name)
210-
assert not hasattr(datafusion, name)
211208

212209

213210
def test_classes_are_inheritable():

0 commit comments

Comments
 (0)