Skip to content

Commit bb62d46

Browse files
timsaucerclaude
andcommitted
fix: name the declared table when its value will not import
A junk table value fell through to the pyarrow Dataset fallback, whose error names neither the table nor the bundle. The declared name is unique within the call, so wrapping the import error with it points at one declaration — the same repair the rules got, adapted to a component whose value has four legal shapes and so cannot be pre-checked in Python. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent eeea12b commit bb62d46

3 files changed

Lines changed: 31 additions & 5 deletions

File tree

crates/core/src/context.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1785,7 +1785,13 @@ impl PySessionContext {
17851785

17861786
let mut resolved = Vec::with_capacity(tables.len());
17871787
for (name, obj) in tables {
1788-
let provider = PyTable::new(obj, Some(session.clone()))?.table;
1788+
// The name is the culprit's identity: it is unique within the call,
1789+
// so an import failure that carries it points at one declaration.
1790+
// The importer's own message names neither the table nor the
1791+
// bundle, because it never knew them.
1792+
let provider = PyTable::new(obj, Some(session.clone()))
1793+
.map_err(|err| exec_datafusion_err!("Resolving the declared table {name}: {err}"))?
1794+
.table;
17891795
let reference = TableReference::from(name.as_str());
17901796
let table_name = reference.table().to_owned();
17911797
let schema = state.schema_for_ref(reference)?;

python/datafusion/context.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2234,14 +2234,16 @@ def with_extensions(
22342234
a declared function or optimizer rule does not expose its
22352235
capsule getter and is not already a wrapper.
22362236
ValueError: If two codecs claim the same id, if two extensions
2237-
declare a function of one kind under the same name, or if a
2238-
getter returns a capsule of the wrong kind. See
2239-
:py:meth:`with_logical_extension_codec` for how ids are
2240-
assigned.
2237+
declare a function, table, or table function of one kind under
2238+
the same name, or if a getter returns a capsule of the wrong
2239+
kind. See :py:meth:`with_logical_extension_codec` for how ids
2240+
are assigned.
22412241
RuntimeError: If a getter is present but returns something that is
22422242
not a ``PyCapsule`` at all. The message comes from the importer
22432243
and does not name the bundle, because by then the declaration
22442244
has already been accepted as the right shape.
2245+
Exception: If a declared table cannot be resolved — the name is
2246+
taken, the schema unknown, or the value not a table.
22452247
22462248
Examples:
22472249
The returned handle is a different object sharing one session, and

python/tests/test_context.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,24 @@ def test_with_extensions_rejects_a_table_in_an_unknown_schema(ctx):
17531753
ctx.udf("double")
17541754

17551755

1756+
def test_with_extensions_rejects_a_table_that_is_not_a_table_by_name(ctx):
1757+
"""A declaration that is not a table at all is refused under its name.
1758+
1759+
A table value can be any of four shapes, so unlike a rule the junk is only
1760+
discovered by the importer, after the bundle can be named. The declared
1761+
name is unique within the call — that is what identifies the culprit.
1762+
"""
1763+
1764+
with pytest.raises(Exception, match=r"declared table junk"):
1765+
ctx.with_extensions(
1766+
_FunctionExtension(udfs=(_doubler(),)),
1767+
_TableExtension(table_providers=(("junk", object()),)),
1768+
)
1769+
1770+
with pytest.raises(KeyError):
1771+
ctx.udf("double")
1772+
1773+
17561774
def test_session_extension_components_rejects_a_single_optimizer_rule():
17571775
"""The same for rules, naming what that field holds."""
17581776
with pytest.raises(

0 commit comments

Comments
 (0)