Skip to content

Commit c41e29e

Browse files
authored
chore: Use pass_through instead of strict in narwhals.from_native, use stable.v1 API more (#3693)
* chore: use `pass_through` instead of `strict` in `narwhals.from_native`, use stable.v1 API more * unrelated(?) ruff fixes * fixup, increase coverage * use to_native method * add flake8-tidy-imports rule * take check out of loop
1 parent 936c0af commit c41e29e

File tree

10 files changed

+49
-27
lines changed

10 files changed

+49
-27
lines changed

altair/_magics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from importlib.util import find_spec
88
from typing import Any
99

10+
import narwhals.stable.v1 as nw
1011
from IPython.core import magic_arguments
11-
from narwhals.dependencies import is_pandas_dataframe as _is_pandas_dataframe
1212

1313
from altair.vegalite import v5 as vegalite_v5
1414

@@ -32,7 +32,7 @@ def _prepare_data(data, data_transformers):
3232
"""Convert input data to data for use within schema."""
3333
if data is None or isinstance(data, dict):
3434
return data
35-
elif _is_pandas_dataframe(data):
35+
elif nw.dependencies.is_pandas_dataframe(data):
3636
if func := data_transformers.get():
3737
data = func(data)
3838
return data

altair/utils/_vegafusion_data.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from typing import TYPE_CHECKING, Any, Callable, Final, TypedDict, Union, overload
66
from weakref import WeakValueDictionary
77

8-
from narwhals.dependencies import is_into_dataframe
8+
import narwhals.stable.v1 as nw
99
from packaging.version import Version
1010

1111
from altair.utils._importers import import_vegafusion
@@ -22,7 +22,7 @@
2222
import sys
2323
from collections.abc import MutableMapping
2424

25-
from narwhals.typing import IntoDataFrame
25+
from narwhals.stable.v1.typing import IntoDataFrame
2626

2727
from vegafusion.runtime import ChartState
2828

@@ -54,7 +54,9 @@
5454
def is_supported_by_vf(data: Any) -> TypeIs[DataFrameLike]:
5555
# Test whether VegaFusion supports the data type
5656
# VegaFusion v2 support narwhals-compatible DataFrames
57-
return isinstance(data, DataFrameLike) or is_into_dataframe(data)
57+
return isinstance(data, DataFrameLike) or nw.dependencies.is_into_dataframe(
58+
data
59+
)
5860

5961
else:
6062

altair/utils/core.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
import jsonschema
1818
import narwhals.stable.v1 as nw
19-
from narwhals.dependencies import get_polars, is_pandas_dataframe
20-
from narwhals.typing import IntoDataFrame
19+
from narwhals.stable.v1.typing import IntoDataFrame
2120

2221
from altair.utils.schemapi import SchemaBase, SchemaLike, Undefined
2322

@@ -35,7 +34,7 @@
3534
import typing as t
3635

3736
import pandas as pd
38-
from narwhals.typing import IntoExpr
37+
from narwhals.stable.v1.typing import IntoExpr
3938

4039
from altair.utils._dfi_types import DataFrame as DfiDataFrame
4140
from altair.vegalite.v5.schema._typing import StandardType_T as InferredVegaLiteType
@@ -470,8 +469,9 @@ def sanitize_narwhals_dataframe(
470469
columns: list[IntoExpr] = []
471470
# See https://github.com/vega/altair/issues/1027 for why this is necessary.
472471
local_iso_fmt_string = "%Y-%m-%dT%H:%M:%S"
472+
is_polars_dataframe = nw.dependencies.is_polars_dataframe(data.to_native())
473473
for name, dtype in schema.items():
474-
if dtype == nw.Date and nw.get_native_namespace(data) is get_polars():
474+
if dtype == nw.Date and is_polars_dataframe:
475475
# Polars doesn't allow formatting `Date` with time directives.
476476
# The date -> datetime cast is extremely fast compared with `to_string`
477477
columns.append(
@@ -673,8 +673,8 @@ def parse_shorthand( # noqa: C901
673673
if schema[unescaped_field] in {
674674
nw.Object,
675675
nw.Unknown,
676-
} and is_pandas_dataframe(nw.to_native(data_nw)):
677-
attrs["type"] = infer_vegalite_type_for_pandas(nw.to_native(column))
676+
} and nw.dependencies.is_pandas_dataframe(data_nw.to_native()):
677+
attrs["type"] = infer_vegalite_type_for_pandas(column.to_native())
678678
else:
679679
attrs["type"] = infer_vegalite_type_for_narwhals(column)
680680
if isinstance(attrs["type"], tuple):

altair/utils/data.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
)
2020

2121
import narwhals.stable.v1 as nw
22-
from narwhals.dependencies import is_pandas_dataframe as _is_pandas_dataframe
23-
from narwhals.typing import IntoDataFrame
22+
from narwhals.stable.v1.typing import IntoDataFrame
2423

2524
from ._importers import import_pyarrow_interchange
2625
from .core import (
@@ -76,7 +75,7 @@ class SupportsGeoInterface(Protocol):
7675

7776
def is_data_type(obj: Any) -> TypeIs[DataType]:
7877
return isinstance(obj, (dict, SupportsGeoInterface)) or isinstance(
79-
nw.from_native(obj, eager_or_interchange_only=True, strict=False),
78+
nw.from_native(obj, eager_or_interchange_only=True, pass_through=True),
8079
nw.DataFrame,
8180
)
8281

@@ -188,7 +187,7 @@ def sample(
188187
if data is None:
189188
return partial(sample, n=n, frac=frac)
190189
check_data_type(data)
191-
if _is_pandas_dataframe(data):
190+
if nw.dependencies.is_pandas_dataframe(data):
192191
return data.sample(n=n, frac=frac)
193192
elif isinstance(data, dict):
194193
if "values" in data:
@@ -210,7 +209,7 @@ def sample(
210209
raise ValueError(msg)
211210
n = int(frac * len(data))
212211
indices = random.sample(range(len(data)), n)
213-
return nw.to_native(data[indices])
212+
return data[indices].to_native()
214213

215214

216215
_FormatType = Literal["csv", "json"]
@@ -319,11 +318,11 @@ def _to_text_kwds(prefix: str, extension: str, filename: str, urlpath: str, /) -
319318
def to_values(data: DataType) -> ToValuesReturnType:
320319
"""Replace a DataFrame by a data model with values."""
321320
check_data_type(data)
322-
# `strict=False` passes `data` through as-is if it is not a Narwhals object.
323-
data_native = nw.to_native(data, strict=False)
321+
# `pass_through=True` passes `data` through as-is if it is not a Narwhals object.
322+
data_native = nw.to_native(data, pass_through=True)
324323
if isinstance(data_native, SupportsGeoInterface):
325324
return {"values": _from_geo_interface(data_native)}
326-
elif _is_pandas_dataframe(data_native):
325+
elif nw.dependencies.is_pandas_dataframe(data_native):
327326
data_native = sanitize_pandas_dataframe(data_native)
328327
return {"values": data_native.to_dict(orient="records")}
329328
elif isinstance(data_native, dict):
@@ -364,7 +363,7 @@ def _from_geo_interface(data: SupportsGeoInterface | Any) -> dict[str, Any]:
364363
- ``typing.TypeGuard``
365364
- ``pd.DataFrame.__getattr__``
366365
"""
367-
if _is_pandas_dataframe(data):
366+
if nw.dependencies.is_pandas_dataframe(data):
368367
data = sanitize_pandas_dataframe(data)
369368
return sanitize_geo_interface(data.__geo_interface__)
370369

@@ -374,7 +373,7 @@ def _data_to_json_string(data: DataType) -> str:
374373
check_data_type(data)
375374
if isinstance(data, SupportsGeoInterface):
376375
return json.dumps(_from_geo_interface(data))
377-
elif _is_pandas_dataframe(data):
376+
elif nw.dependencies.is_pandas_dataframe(data):
378377
data = sanitize_pandas_dataframe(data)
379378
return data.to_json(orient="records", double_precision=15)
380379
elif isinstance(data, dict):
@@ -401,7 +400,7 @@ def _data_to_csv_string(data: DataType) -> str:
401400
f"See https://github.com/vega/altair/issues/3441"
402401
)
403402
raise NotImplementedError(msg)
404-
elif _is_pandas_dataframe(data):
403+
elif nw.dependencies.is_pandas_dataframe(data):
405404
data = sanitize_pandas_dataframe(data)
406405
return data.to_csv(index=False)
407406
elif isinstance(data, dict):

altair/vegalite/v5/api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def _prepare_data(
280280
# convert dataframes or objects with __geo_interface__ to dict
281281
elif not isinstance(data, dict) and _is_data_type(data):
282282
if func := data_transformers.get():
283-
data = func(nw.to_native(data, strict=False))
283+
data = func(nw.to_native(data, pass_through=True))
284284

285285
# convert string input to a URLData
286286
elif isinstance(data, str):

pyproject.toml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ keywords = [
3434
]
3535
requires-python = ">=3.9"
3636
dynamic = ["version"]
37-
license-files = { paths = ["LICENSE"] }
37+
license = {file = "LICENSE"}
3838
classifiers = [
3939
"Development Status :: 5 - Production/Stable",
4040
"Environment :: Console",
@@ -398,6 +398,15 @@ Use `Union[T, None]` instead.
398398
which have a similar but different semantic meaning.
399399
See https://github.com/vega/altair/pull/3449
400400
"""
401+
"narwhals.dependencies".msg = """
402+
Import `dependencies` from `narwhals.stable.v1` instead.
403+
"""
404+
"narwhals.typing".msg = """
405+
Import `typing` from `narwhals.stable.v1` instead.
406+
"""
407+
"narwhals.dtypes".msg = """
408+
Import `dtypes` from `narwhals.stable.v1` instead.
409+
"""
401410

402411
[tool.ruff.lint.per-file-ignores]
403412
# Only enforce type annotation rules on public api

tests/utils/test_schemapi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
if TYPE_CHECKING:
3838
from collections.abc import Iterable, Sequence
3939

40-
from narwhals.typing import IntoDataFrame
40+
from narwhals.stable.v1.typing import IntoDataFrame
4141

4242
_JSON_SCHEMA_DRAFT_URL = load_schema()["$schema"]
4343
# Make tests inherit from _TestSchema, so that when we test from_dict it won't

tests/vegalite/v5/test_api.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,18 @@ def test_polars_with_pandas_nor_pyarrow(monkeypatch: pytest.MonkeyPatch):
17231723
assert "numpy" not in sys.modules
17241724

17251725

1726+
def test_polars_date_32():
1727+
df = pl.DataFrame(
1728+
{"a": [1, 2, 3], "b": [date(2020, 1, 1), date(2020, 1, 2), date(2020, 1, 3)]}
1729+
)
1730+
result = alt.Chart(df).mark_line().encode(x="a", y="b").to_dict()
1731+
assert next(iter(result["datasets"].values())) == [
1732+
{"a": 1, "b": "2020-01-01T00:00:00"},
1733+
{"a": 2, "b": "2020-01-02T00:00:00"},
1734+
{"a": 3, "b": "2020-01-03T00:00:00"},
1735+
]
1736+
1737+
17261738
@skip_requires_pyarrow(requires_tzdata=True)
17271739
def test_interchange_with_date_32():
17281740
# Test that objects which Narwhals only supports at the interchange

tests/vegalite/v5/test_params.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def test_parameter_naming():
107107
# test automatic naming which has the form such as param_5
108108
prm0, prm1, prm2 = (alt.param() for _ in range(3))
109109

110-
res = re.match("param_([0-9]+)", prm0.param.name)
110+
res = re.match(r"param_([0-9]+)", prm0.param.name)
111111

112112
assert res
113113

tools/generate_schema_wrapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ def generate_vegalite_schema_wrapper(fp: Path, /) -> ModuleDef[str]:
751751
"from typing import Any, Literal, Union, Protocol, Sequence, List, Iterator, TYPE_CHECKING",
752752
"import pkgutil",
753753
"import json\n",
754-
"from narwhals.dependencies import is_pandas_dataframe as _is_pandas_dataframe",
754+
"import narwhals.stable.v1 as nw\n",
755755
"from altair.utils.schemapi import SchemaBase, Undefined, UndefinedType, _subclasses # noqa: F401\n",
756756
import_type_checking(
757757
"from datetime import date, datetime",

0 commit comments

Comments
 (0)