diff --git a/altair/__init__.py b/altair/__init__.py index c9b0da123..d6c03f48a 100644 --- a/altair/__init__.py +++ b/altair/__init__.py @@ -653,7 +653,7 @@ def __dir__(): from altair.vegalite.v5.schema.core import Dict from altair.jupyter import JupyterChart from altair.expr import expr -from altair.utils import AltairDeprecationWarning +from altair.utils import AltairDeprecationWarning, parse_shorthand, Optional, Undefined def load_ipython_extension(ipython): diff --git a/altair/vegalite/__init__.py b/altair/vegalite/__init__.py index 690d64e63..8fa78644e 100644 --- a/altair/vegalite/__init__.py +++ b/altair/vegalite/__init__.py @@ -1,2 +1,2 @@ -# ruff: noqa +# ruff: noqa: F403 from .v5 import * diff --git a/altair/vegalite/schema.py b/altair/vegalite/schema.py index 3807f3767..d3ee42222 100644 --- a/altair/vegalite/schema.py +++ b/altair/vegalite/schema.py @@ -1,4 +1,4 @@ """Altair schema wrappers""" -# ruff: noqa +# ruff: noqa: F403 from .v5.schema import * diff --git a/altair/vegalite/v5/__init__.py b/altair/vegalite/v5/__init__.py index 2801df33c..be8d802fb 100644 --- a/altair/vegalite/v5/__init__.py +++ b/altair/vegalite/v5/__init__.py @@ -1,10 +1,16 @@ -# ruff: noqa +# ruff: noqa: F401, F403 from .schema import * from .api import * from altair.expr.core import datum -from .display import VegaLite, renderers +from .display import ( + VegaLite, + renderers, + VEGALITE_VERSION, + VEGAEMBED_VERSION, + VEGA_VERSION, +) from .compiler import vegalite_compilers from .data import ( @@ -17,3 +23,4 @@ default_data_transformer, data_transformers, ) +from .theme import themes diff --git a/altair/vegalite/v5/api.py b/altair/vegalite/v5/api.py index 58820e5fa..55fb4110b 100644 --- a/altair/vegalite/v5/api.py +++ b/altair/vegalite/v5/api.py @@ -21,9 +21,10 @@ import functools import operator from copy import deepcopy as _deepcopy -from .schema import core, channels, mixins, Undefined, SCHEMA_URL -from altair.utils import Optional +from .schema import core, channels, mixins, SCHEMA_URL + +from altair.utils import Optional, Undefined from .data import data_transformers from ... import utils from ...expr import core as _expr_core @@ -123,6 +124,58 @@ OneOrSeq, ) +__all__ = [ + "TOPLEVEL_ONLY_KEYS", + "Bin", + "ChainedWhen", + "Chart", + "ChartDataType", + "ChartType", + "ConcatChart", + "DataType", + "FacetChart", + "FacetMapping", + "HConcatChart", + "Impute", + "LayerChart", + "LookupData", + "Parameter", + "ParameterExpression", + "RepeatChart", + "SelectionExpression", + "SelectionPredicateComposition", + "Then", + "Title", + "TopLevelMixin", + "VConcatChart", + "When", + "binding", + "binding_checkbox", + "binding_radio", + "binding_range", + "binding_select", + "check_fields_and_encodings", + "concat", + "condition", + "graticule", + "hconcat", + "is_chart_type", + "layer", + "mixins", + "param", + "repeat", + "selection", + "selection_interval", + "selection_multi", + "selection_point", + "selection_single", + "sequence", + "sphere", + "topo_feature", + "value", + "vconcat", + "when", +] ChartDataType: TypeAlias = Optional[Union[DataType, core.Data, str, core.Generator]] _TSchemaBase = TypeVar("_TSchemaBase", bound=core.SchemaBase) diff --git a/altair/vegalite/v5/schema/channels.py b/altair/vegalite/v5/schema/channels.py index 07ba8c099..5e0fc2658 100644 --- a/altair/vegalite/v5/schema/channels.py +++ b/altair/vegalite/v5/schema/channels.py @@ -31,6 +31,113 @@ from ._typing import * # noqa: F403 +__all__ = [ + "X2", + "Y2", + "Angle", + "AngleDatum", + "AngleValue", + "Color", + "ColorDatum", + "ColorValue", + "Column", + "DatumChannelMixin", + "Description", + "DescriptionValue", + "Detail", + "Facet", + "FieldChannelMixin", + "Fill", + "FillDatum", + "FillOpacity", + "FillOpacityDatum", + "FillOpacityValue", + "FillValue", + "Href", + "HrefValue", + "Key", + "Latitude", + "Latitude2", + "Latitude2Datum", + "Latitude2Value", + "LatitudeDatum", + "Longitude", + "Longitude2", + "Longitude2Datum", + "Longitude2Value", + "LongitudeDatum", + "Opacity", + "OpacityDatum", + "OpacityValue", + "Order", + "OrderValue", + "Radius", + "Radius2", + "Radius2Datum", + "Radius2Value", + "RadiusDatum", + "RadiusValue", + "Row", + "Shape", + "ShapeDatum", + "ShapeValue", + "Size", + "SizeDatum", + "SizeValue", + "Stroke", + "StrokeDash", + "StrokeDashDatum", + "StrokeDashValue", + "StrokeDatum", + "StrokeOpacity", + "StrokeOpacityDatum", + "StrokeOpacityValue", + "StrokeValue", + "StrokeWidth", + "StrokeWidthDatum", + "StrokeWidthValue", + "Text", + "TextDatum", + "TextValue", + "Theta", + "Theta2", + "Theta2Datum", + "Theta2Value", + "ThetaDatum", + "ThetaValue", + "Tooltip", + "TooltipValue", + "Url", + "UrlValue", + "ValueChannelMixin", + "X", + "X2Datum", + "X2Value", + "XDatum", + "XError", + "XError2", + "XError2Value", + "XErrorValue", + "XOffset", + "XOffsetDatum", + "XOffsetValue", + "XValue", + "Y", + "Y2Datum", + "Y2Value", + "YDatum", + "YError", + "YError2", + "YError2Value", + "YErrorValue", + "YOffset", + "YOffsetDatum", + "YOffsetValue", + "YValue", + "with_property_setters", +] + + class FieldChannelMixin: _encoding_name: str diff --git a/tests/vegalite/v5/test_api.py b/tests/vegalite/v5/test_api.py index 92441f955..9ebd29ac2 100644 --- a/tests/vegalite/v5/test_api.py +++ b/tests/vegalite/v5/test_api.py @@ -23,6 +23,7 @@ import polars as pl import altair as alt +from altair.utils.schemapi import Undefined try: import vl_convert as vlc @@ -1351,14 +1352,14 @@ def test_subcharts_with_same_data(method, data): text = point.mark_text() chart1 = func(point, line, text) - assert chart1.data is not alt.Undefined - assert all(c.data is alt.Undefined for c in getattr(chart1, method)) + assert chart1.data is not Undefined + assert all(c.data is Undefined for c in getattr(chart1, method)) if method != "concat": op = OP_DICT[method] chart2 = op(op(point, line), text) - assert chart2.data is not alt.Undefined - assert all(c.data is alt.Undefined for c in getattr(chart2, method)) + assert chart2.data is not Undefined + assert all(c.data is Undefined for c in getattr(chart2, method)) @pytest.mark.parametrize("method", ["layer", "hconcat", "vconcat", "concat"]) @@ -1373,20 +1374,20 @@ def test_subcharts_different_data(method, data): nodata = alt.Chart().mark_point().encode(x="x:Q", y="y:Q") chart1 = func(point, otherdata) - assert chart1.data is alt.Undefined + assert chart1.data is Undefined assert getattr(chart1, method)[0].data is data chart2 = func(point, nodata) - assert chart2.data is alt.Undefined + assert chart2.data is Undefined assert getattr(chart2, method)[0].data is data def test_layer_facet(basic_chart): chart = (basic_chart + basic_chart).facet(row="row:Q") - assert chart.data is not alt.Undefined - assert chart.spec.data is alt.Undefined + assert chart.data is not Undefined + assert chart.spec.data is Undefined for layer in chart.spec.layer: - assert layer.data is alt.Undefined + assert layer.data is Undefined dct = chart.to_dict() assert "data" in dct diff --git a/tests/vegalite/v5/test_params.py b/tests/vegalite/v5/test_params.py index b88d3fb36..890682708 100644 --- a/tests/vegalite/v5/test_params.py +++ b/tests/vegalite/v5/test_params.py @@ -8,6 +8,7 @@ import re import altair.vegalite.v5 as alt +from altair.utils.deprecation import AltairDeprecationWarning def test_variable_param(): @@ -82,9 +83,9 @@ def test_selection_deprecation(): alt.selection_interval() # this v4 syntax is deprecated - with pytest.warns(alt.utils.deprecation.AltairDeprecationWarning): + with pytest.warns(AltairDeprecationWarning): alt.selection_single() - with pytest.warns(alt.utils.deprecation.AltairDeprecationWarning): + with pytest.warns(AltairDeprecationWarning): alt.selection_multi() # new syntax @@ -95,7 +96,7 @@ def test_selection_deprecation(): # this v4 syntax is deprecated brush = alt.selection_interval() c = alt.Chart().mark_point() - with pytest.warns(alt.utils.deprecation.AltairDeprecationWarning): + with pytest.warns(AltairDeprecationWarning): c.add_selection(brush) diff --git a/tools/generate_schema_wrapper.py b/tools/generate_schema_wrapper.py index 545cc4083..8569e1588 100644 --- a/tools/generate_schema_wrapper.py +++ b/tools/generate_schema_wrapper.py @@ -9,7 +9,8 @@ import sys import textwrap from dataclasses import dataclass -from typing import Final, Iterable, Literal +from typing import Final, Iterable, Literal, Iterator +from itertools import chain from urllib import request import m2r @@ -572,41 +573,29 @@ class ChannelInfo: datum_class_name: str | None = None value_class_name: str | None = None + @property + def all_names(self) -> Iterator[str]: + if self.field_class_name: + yield self.field_class_name + if self.datum_class_name: + yield self.datum_class_name + if self.value_class_name: + yield self.value_class_name + def generate_vegalite_channel_wrappers( schemafile: Path, version: str, imports: list[str] | None = None ) -> str: - # TODO: generate __all__ for top of file schema = load_schema_with_shorthand_properties(schemafile) - imports = imports or [ - "from __future__ import annotations\n", - "from typing import Any, overload, Sequence, List, Literal, Union, TYPE_CHECKING", - "from narwhals.dependencies import is_pandas_dataframe as _is_pandas_dataframe", - "from altair.utils.schemapi import Undefined, with_property_setters", - "from altair.utils import infer_encoding_types as _infer_encoding_types", - "from altair.utils import parse_shorthand", - "from . import core", - ] - contents = [ - HEADER, - CHANNEL_MYPY_IGNORE_STATEMENTS, - *imports, - _type_checking_only_imports( - "from altair import Parameter, SchemaBase", - "from altair.utils.schemapi import Optional", - "from ._typing import * # noqa: F403", - "from typing_extensions import Self", - ), - CHANNEL_MIXINS, - ] - encoding_def = "FacetedEncoding" encoding = SchemaInfo(schema["definitions"][encoding_def], rootschema=schema) channel_infos: dict[str, ChannelInfo] = {} + class_defs = [] + for prop, propschema in encoding.properties.items(): def_dict = get_field_datum_value_defs(propschema, schema) @@ -657,10 +646,45 @@ def generate_vegalite_channel_wrappers( haspropsetters=True, altair_classes_prefix="core", ) - contents.append(gen.schema_class()) + class_defs.append(gen.schema_class()) channel_infos[prop] = channel_info + # NOTE: See https://github.com/vega/altair/pull/3482#issuecomment-2241577342 + COMPAT_EXPORTS = ( + "DatumChannelMixin", + "FieldChannelMixin", + "ValueChannelMixin", + "with_property_setters", + ) + + it = chain.from_iterable(info.all_names for info in channel_infos.values()) + all_ = list(chain(it, COMPAT_EXPORTS)) + + imports = imports or [ + "from __future__ import annotations\n", + "from typing import Any, overload, Sequence, List, Literal, Union, TYPE_CHECKING", + "from narwhals.dependencies import is_pandas_dataframe as _is_pandas_dataframe", + "from altair.utils.schemapi import Undefined, with_property_setters", + "from altair.utils import infer_encoding_types as _infer_encoding_types", + "from altair.utils import parse_shorthand", + "from . import core", + ] + contents = [ + HEADER, + CHANNEL_MYPY_IGNORE_STATEMENTS, + *imports, + _type_checking_only_imports( + "from altair import Parameter, SchemaBase", + "from altair.utils.schemapi import Optional", + "from ._typing import * # noqa: F403", + "from typing_extensions import Self", + ), + "\n" f"__all__ = {sorted(all_)}\n", + CHANNEL_MIXINS, + *class_defs, + ] + # Generate the type signature for the encode method encode_signature = _create_encode_signature(channel_infos) contents.append(encode_signature)