diff --git a/altair/utils/core.py b/altair/utils/core.py index 7058f2cf0..7e8340324 100644 --- a/altair/utils/core.py +++ b/altair/utils/core.py @@ -42,7 +42,6 @@ if TYPE_CHECKING: import typing as t - from types import ModuleType import pandas as pd from narwhals.typing import IntoExpr @@ -845,22 +844,6 @@ class _ChannelCache: channel_to_name: dict[type[SchemaBase], str] name_to_channel: dict[str, dict[_ChannelType, type[SchemaBase]]] - @classmethod - def from_channels(cls, channels: ModuleType, /) -> _ChannelCache: - # - This branch is only kept for tests that depend on mocking `channels`. - # - No longer needs to pass around `channels` reference and rebuild every call. - c_to_n = { - c: c._encoding_name - for c in channels.__dict__.values() - if isinstance(c, type) - and issubclass(c, SchemaBase) - and hasattr(c, "_encoding_name") - } - self = cls.__new__(cls) - self.channel_to_name = c_to_n - self.name_to_channel = _invert_group_channels(c_to_n) - return self - @classmethod def from_cache(cls) -> _ChannelCache: global _CHANNEL_CACHE @@ -958,9 +941,7 @@ def _reduce(it: Iterator[tuple[type[Any], str]]) -> Any: return {k: _reduce(chans) for k, chans in grouper} -def infer_encoding_types( - args: tuple[Any, ...], kwargs: dict[str, Any], channels: ModuleType | None = None -): +def infer_encoding_types(args: tuple[Any, ...], kwargs: dict[str, Any]): """ Infer typed keyword arguments for args and kwargs. @@ -970,8 +951,6 @@ def infer_encoding_types( Sequence of function args kwargs : MutableMapping Dict of function kwargs - channels : ModuleType - The module containing all altair encoding channel classes. Returns ------- @@ -979,11 +958,7 @@ def infer_encoding_types( All args and kwargs in a single dict, with keys and types based on the channels mapping. """ - cache = ( - _ChannelCache.from_channels(channels) - if channels - else _ChannelCache.from_cache() - ) + cache = _ChannelCache.from_cache() # First use the mapping to convert args to kwargs based on their types. for arg in args: el = next(iter(arg), None) if isinstance(arg, (list, tuple)) else arg diff --git a/tests/utils/test_core.py b/tests/utils/test_core.py index 295e2b38f..d43f88dd8 100644 --- a/tests/utils/test_core.py +++ b/tests/utils/test_core.py @@ -11,6 +11,7 @@ from pandas.api.types import infer_dtype import altair as alt +from altair.utils import core from altair.utils.core import infer_encoding_types, parse_shorthand, update_nested from tests import skip_requires_pyarrow @@ -267,18 +268,40 @@ def test_update_nested(): @pytest.fixture -def channels(): +def channels() -> types.ModuleType: channels = types.ModuleType("channels") exec(FAKE_CHANNELS_MODULE, channels.__dict__) return channels +@pytest.fixture +def channels_cached(channels) -> core._ChannelCache: + """Previously ``_ChannelCache.from_channels``.""" + cached = core._ChannelCache.__new__(core._ChannelCache) + cached.channel_to_name = { + c: c._encoding_name + for c in channels.__dict__.values() + if isinstance(c, type) + and issubclass(c, alt.SchemaBase) + and hasattr(c, "_encoding_name") + } + cached.name_to_channel = core._invert_group_channels(cached.channel_to_name) + return cached + + def _getargs(*args, **kwargs): return args, kwargs -# NOTE: Dependent on a no longer needed implementation detail -def test_infer_encoding_types(channels): +def test_infer_encoding_types( + monkeypatch: pytest.MonkeyPatch, channels, channels_cached +): + # Indirectly initialize `_CHANNEL_CACHE` + infer_encoding_types((), {}) + # Replace with contents of `FAKE_CHANNELS_MODULE` + # Scoped to only this test + monkeypatch.setattr(core, "_CHANNEL_CACHE", channels_cached) + expected = { "x": channels.X("xval"), "y": channels.YValue("yval"), @@ -289,17 +312,17 @@ def test_infer_encoding_types(channels): args, kwds = _getargs( channels.X("xval"), channels.YValue("yval"), channels.StrokeWidthValue(4) ) - assert infer_encoding_types(args, kwds, channels) == expected + assert infer_encoding_types(args, kwds) == expected # All keyword args args, kwds = _getargs(x="xval", y=alt.value("yval"), strokeWidth=alt.value(4)) - assert infer_encoding_types(args, kwds, channels) == expected + assert infer_encoding_types(args, kwds) == expected # Mixed positional & keyword args, kwds = _getargs( channels.X("xval"), channels.YValue("yval"), strokeWidth=alt.value(4) ) - assert infer_encoding_types(args, kwds, channels) == expected + assert infer_encoding_types(args, kwds) == expected def test_infer_encoding_types_with_condition():