Skip to content

fix(python): correct the asof and reader input annotations - #8955

Open
jonasdedden wants to merge 3 commits into
lance-format:mainfrom
jonasdedden:fix/python-structural-optional-types
Open

jonasdedden wants to merge 3 commits into
lance-format:mainfrom
jonasdedden:fix/python-structural-optional-types

Conversation

@jonasdedden

@jonasdedden jonasdedden commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes two wrong type annotations for optional-dependency inputs, each of which hid a runtime bug.

asof

  • ts_types was Union[datetime, pd.Timestamp, str], defined twice. pandas types pd.Timestamp(...) as Timestamp | NaTType, so lance.dataset(uri, asof=pd.Timestamp(...)) failed strict type checking. It is now Union[datetime, NaTType, str], defined once in lance.util.
  • pd.NaT subclasses datetime, so sanitize_ts passed it through and it compared false against every version. It is now rejected with ValueError.
  • The pandas branch for timestamp strings was guarded by _check_for_pandas(ts), which is always false for a str. So asof="2026-01-01" asked you to install pandas even when it was installed. It is now guarded by _PANDAS_AVAILABLE.

ReaderLike

  • It listed pd.Timestamp where a DataFrame belongs and referenced pa.dataset.*, which type checkers can't resolve. It now lists every input _coerce_reader accepts, with the Arrow classes imported directly.
  • Polars frames are detected with _check_for_polars + isinstance instead of matching __module__.
  • The write_dataset docstring now lists the accepted inputs, and test_input_data gains dict and row-dict cases.

test_optional_types_typing.py pins the accepted and rejected asof types under Pyright. ReaderLike can't be checked in CI until pyarrow stubs are added: without them the union accepts anything.

@github-actions github-actions Bot added bug Something isn't working A-python Python bindings labels Sep 2, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 2, 2026
@github-actions github-actions Bot added the A-deps Dependency updates label Sep 2, 2026
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 2, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 2, 2026
@jonasdedden
jonasdedden force-pushed the fix/python-structural-optional-types branch from 8490a06 to 3ccef5f Compare September 2, 2026 20:57
@jonasdedden jonasdedden changed the title fix(python): model optional inputs with protocols fix(python): correct the asof and reader input annotations Sep 2, 2026
@lance-gatekeeper lance-gatekeeper Bot removed K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 2, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 2, 2026
The stubs bundled with pandas declare `Timestamp.__new__` as returning
`Self | NaTType`, so `lance.dataset(asof=pd.Timestamp(...))` was rejected
by strict type checkers. Name `NaTType` in `ts_types`; `pd.Timestamp`
needs no member of its own because it subclasses `datetime`.

`NaT` subclasses `datetime` too, so it previously passed through
`sanitize_ts` untouched and then compared false against every version
timestamp, surfacing as a misleading "earlier than the first version"
error. Reject it at the boundary instead.

The pandas string-parsing branch was guarded by `_check_for_pandas(ts)`,
which inspects the argument's MRO and is therefore always false for a
`str`. That branch had never run: `asof="2026-01-01"` raised "Try
installing Pandas" on machines that had pandas installed. Guard on
`_PANDAS_AVAILABLE` instead.

The new typing regression file joins the pyright target and pins the
accepted and rejected `asof` types in both directions, so the annotation
also fails the type check if it becomes too permissive.
`ReaderLike` listed `pd.Timestamp` rather than a dataframe type, and
reached the Arrow classes through `pa.dataset.Dataset`, which type
checkers cannot resolve because `pyarrow` does not expose `dataset` as an
attribute. The unresolved member made the whole union accept anything, so
neither defect surfaced and the union drifted out of step with
`_coerce_reader`: pandas and Polars dataframes, HuggingFace datasets,
column dicts, row dicts and Pydantic model instances are all coerced at
runtime but were absent from the annotation.

List every input `_coerce_reader` handles, import the Arrow classes
directly, and dispatch on the optional dependencies the way the rest of
the codebase does: `_check_for_polars` plus a real `isinstance` replaces
the duplicated `__module__.startswith("polars")` string matching, which
also lets a type checker narrow the branch. `LanceDataset` moves to a
function-local import because `lance.dataset` names both this module and
a function on the package.

`types.py` cannot join the pyright target yet: without `pyarrow-stubs`,
`isinstance(x, pa.Table)` does not narrow and every branch reports an
error, so that is left for a follow-up along with the stub dependency.
The union members are pinned in the typing regression file instead.
@jonasdedden
jonasdedden force-pushed the fix/python-structural-optional-types branch from 3ccef5f to 9775b51 Compare September 2, 2026 21:46
@lance-gatekeeper lance-gatekeeper Bot removed K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 2, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 2, 2026
ReaderLike accepts anything under the repo's pyright setup (no pyarrow
stubs), so its acceptance checks could not fail. Fold sanitize_ts runtime
tests into parametrized cases and import pydantic only for type checking.
@lance-gatekeeper lance-gatekeeper Bot removed K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk. labels Sep 17, 2026
@jonasdedden

Copy link
Copy Markdown
Contributor Author

@Xuanwo any review? :)

@lance-gatekeeper lance-gatekeeper Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Gate recommendation: approve with a non-blocking risk.

The timestamp contract is aligned between typing and runtime: ordinary pandas timestamps are accepted, while NaT is rejected. The expanded reader union matches the existing reader-dispatch paths, and the latest cleanup correctly removes typing assertions that could not fail in the current environment.

A bounded typing risk remains: Pyright reports missing PyArrow stubs, making ReaderLike effectively permissive and leaving invalid reader inputs without regression-sensitive static coverage. Mapping and Sequence are also broader than the concrete dict and list runtime branches. Resolvable Arrow stubs and tighter container shapes would make that contract enforceable.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 17, 2026
@lance-gatekeeper lance-gatekeeper Bot added the K-risk Latest Gatekeeper recommendation includes a non-blocking risk. label Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-deps Dependency updates A-python Python bindings bug Something isn't working K-approved Latest Gatekeeper recommendation permits acceptance. K-risk Latest Gatekeeper recommendation includes a non-blocking risk.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant