Skip to content

Commit

Permalink
Merge branch 'main' into olli_renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
dangotbanned committed Sep 9, 2024
2 parents 290f3ac + 682b169 commit ea4e7b4
Show file tree
Hide file tree
Showing 20 changed files with 5,711 additions and 5,847 deletions.
2 changes: 1 addition & 1 deletion NOTES_FOR_MAINTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@ To cut a new release of Altair, follow the steps outlined in

## Web analytics
We use the privacy-friendly [plausible.io](https://plausible.io/) for tracking usage statistics of our documentation.
It is hosted on [https://views.scientific-python.org](https://views.scientific-python.org). To view the stats, you need an account. Ask another maintainer to invite you.
It is hosted on [https://views.scientific-python.org](https://views.scientific-python.org). You can view the stats [here](https://views.scientific-python.org/altair-viz.github.io). To get an account to edit the settings of the web tracking, ask another maintainer.
1 change: 1 addition & 0 deletions altair/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@
"mixins",
"param",
"parse_shorthand",
"register_theme",
"renderers",
"repeat",
"sample",
Expand Down
91 changes: 62 additions & 29 deletions altair/utils/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@
from copy import deepcopy
from itertools import groupby
from operator import itemgetter
from typing import TYPE_CHECKING, Any, Callable, Iterator, Literal, TypeVar, cast
from typing import (
TYPE_CHECKING,
Any,
Callable,
Iterator,
Literal,
TypeVar,
cast,
overload,
)

import jsonschema
import narwhals.stable.v1 as nw
Expand All @@ -22,13 +31,13 @@
from altair.utils.schemapi import SchemaBase, Undefined

if sys.version_info >= (3, 12):
from typing import Protocol, runtime_checkable
from typing import Protocol, TypeAliasType, runtime_checkable
else:
from typing_extensions import Protocol, runtime_checkable
from typing_extensions import Protocol, TypeAliasType, runtime_checkable
if sys.version_info >= (3, 10):
from typing import ParamSpec
from typing import Concatenate, ParamSpec
else:
from typing_extensions import ParamSpec
from typing_extensions import Concatenate, ParamSpec


if TYPE_CHECKING:
Expand All @@ -40,9 +49,21 @@
from altair.utils._dfi_types import DataFrame as DfiDataFrame
from altair.vegalite.v5.schema._typing import StandardType_T as InferredVegaLiteType

V = TypeVar("V")
P = ParamSpec("P")
TIntoDataFrame = TypeVar("TIntoDataFrame", bound=IntoDataFrame)
T = TypeVar("T")
P = ParamSpec("P")
R = TypeVar("R")

WrapsFunc = TypeAliasType("WrapsFunc", Callable[..., R], type_params=(R,))
WrappedFunc = TypeAliasType("WrappedFunc", Callable[P, R], type_params=(P, R))
# NOTE: Requires stringized form to avoid `< (3, 11)` issues
# See: https://github.com/vega/altair/actions/runs/10667859416/job/29567290871?pr=3565
WrapsMethod = TypeAliasType(
"WrapsMethod", "Callable[Concatenate[T, ...], R]", type_params=(T, R)
)
WrappedMethod = TypeAliasType(
"WrappedMethod", Callable[Concatenate[T, P], R], type_params=(T, P, R)
)


@runtime_checkable
Expand Down Expand Up @@ -708,31 +729,43 @@ def infer_vegalite_type_for_narwhals(
raise ValueError(msg)


def use_signature(obj: Callable[P, Any]): # -> Callable[..., Callable[P, V]]:
"""Apply call signature and documentation of `obj` to the decorated method."""
def use_signature(tp: Callable[P, Any], /):
"""
Use the signature and doc of ``tp`` for the decorated callable ``cb``.
def decorate(func: Callable[..., V]) -> Callable[P, V]:
# call-signature of func is exposed via __wrapped__.
# we want it to mimic obj.__init__
- **Overload 1**: Decorating method
- **Overload 2**: Decorating function
# error: Accessing "__init__" on an instance is unsound,
# since instance.__init__ could be from an incompatible subclass [misc]
wrapped = (
obj.__init__ if (isinstance(obj, type) and issubclass(obj, object)) else obj # type: ignore [misc]
)
func.__wrapped__ = wrapped # type: ignore[attr-defined]
func._uses_signature = obj # type: ignore[attr-defined]

# Supplement the docstring of func with information from obj
if doc_in := obj.__doc__:
doc_lines = doc_in.splitlines(keepends=True)[1:]
# Patch in a reference to the class this docstring is copied from,
# to generate a hyperlink.
line_1 = f"{func.__doc__ or f'Refer to :class:`{obj.__name__}`'}\n"
func.__doc__ = "".join((line_1, *doc_lines))
return func
Returns
-------
**Adding the annotation breaks typing**:
Overload[Callable[[WrapsMethod[T, R]], WrappedMethod[T, P, R]], Callable[[WrapsFunc[R]], WrappedFunc[P, R]]]
"""

@overload
def decorate(cb: WrapsMethod[T, R], /) -> WrappedMethod[T, P, R]: ...

@overload
def decorate(cb: WrapsFunc[R], /) -> WrappedFunc[P, R]: ...

def decorate(cb: WrapsFunc[R], /) -> WrappedMethod[T, P, R] | WrappedFunc[P, R]:
"""
Raises when no doc was found.
Notes
-----
- Reference to ``tp`` is stored in ``cb.__wrapped__``.
- The doc for ``cb`` will have a ``.rst`` link added, referring to ``tp``.
"""
cb.__wrapped__ = getattr(tp, "__init__", tp) # type: ignore[attr-defined]

if doc_in := tp.__doc__:
line_1 = f"{cb.__doc__ or f'Refer to :class:`{tp.__name__}`'}\n"
cb.__doc__ = "".join((line_1, *doc_in.splitlines(keepends=True)[1:]))
return cb
else:
msg = f"Found no doc for {obj!r}"
msg = f"Found no doc for {tp!r}"
raise AttributeError(msg)

return decorate
Expand Down
2 changes: 1 addition & 1 deletion altair/utils/plugin_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def __init__(
self.entry_point_group: str = entry_point_group
self.plugin_type: IsPlugin
if plugin_type is not callable and isinstance(plugin_type, type):
msg = (
msg: Any = (
f"Pass a callable `TypeIs` function to `plugin_type` instead.\n"
f"{type(self).__name__!r}(plugin_type)\n\n"
f"See also:\n"
Expand Down
10 changes: 6 additions & 4 deletions altair/utils/theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
from __future__ import annotations

import sys
from typing import TYPE_CHECKING, Callable
from typing import TYPE_CHECKING, Any, Dict

from .plugin_registry import PluginRegistry
from .plugin_registry import Plugin, PluginRegistry

if sys.version_info >= (3, 11):
from typing import LiteralString
Expand All @@ -16,10 +16,12 @@
from altair.utils.plugin_registry import PluginEnabler
from altair.vegalite.v5.theme import AltairThemes, VegaThemes

ThemeType = Callable[..., dict]
ThemeType = Plugin[Dict[str, Any]]


class ThemeRegistry(PluginRegistry[ThemeType, dict]):
# HACK: See for `LiteralString` requirement in `name`
# https://github.com/vega/altair/pull/3526#discussion_r1743350127
class ThemeRegistry(PluginRegistry[ThemeType, Dict[str, Any]]):
def enable(
self, name: LiteralString | AltairThemes | VegaThemes | None = None, **options
) -> PluginEnabler:
Expand Down
2 changes: 1 addition & 1 deletion altair/vegalite/v5/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
renderers,
)
from .schema import *
from .theme import themes
from .theme import register_theme, themes
34 changes: 25 additions & 9 deletions altair/vegalite/v5/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,26 @@ def to_dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]:


class FacetMapping(core.FacetMapping):
"""
FacetMapping schema wrapper.
Parameters
----------
column : str, :class:`FacetFieldDef`, :class:`Column`
A field definition for the horizontal facet of trellis plots.
row : str, :class:`FacetFieldDef`, :class:`Row`
A field definition for the vertical facet of trellis plots.
"""

_class_is_valid_at_instantiation = False

@utils.use_signature(core.FacetMapping)
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def __init__(
self,
column: Optional[str | FacetFieldDef | Column] = Undefined,
row: Optional[str | FacetFieldDef | Row] = Undefined,
**kwargs: Any,
) -> None:
super().__init__(column=column, row=row, **kwargs) # type: ignore[arg-type]

def to_dict(self, *args: Any, **kwargs: Any) -> dict[str, Any]:
copy = self.copy(deep=False)
Expand Down Expand Up @@ -3606,13 +3621,14 @@ def facet(
self = _top_schema_base(self).copy(deep=False)
data, self.data = self.data, Undefined

if facet_specified:
f: Facet | FacetMapping
if not utils.is_undefined(facet):
f = channels.Facet(facet) if isinstance(facet, str) else facet
else:
r: Any = row
f = FacetMapping(row=r, column=column)

return FacetChart(spec=self, facet=f, data=data, columns=columns, **kwargs)
return FacetChart(spec=self, facet=f, data=data, columns=columns, **kwargs) # pyright: ignore[reportArgumentType]


class Chart(
Expand Down Expand Up @@ -4162,7 +4178,7 @@ def add_selection(self, *selections) -> Self: # noqa: ANN002

def concat(*charts: ConcatType, **kwargs: Any) -> ConcatChart:
"""Concatenate charts horizontally."""
return ConcatChart(concat=charts, **kwargs) # pyright: ignore
return ConcatChart(concat=charts, **kwargs)


class HConcatChart(TopLevelMixin, core.TopLevelHConcatSpec):
Expand Down Expand Up @@ -4266,7 +4282,7 @@ def add_selection(self, *selections) -> Self: # noqa: ANN002

def hconcat(*charts: ConcatType, **kwargs: Any) -> HConcatChart:
"""Concatenate charts horizontally."""
return HConcatChart(hconcat=charts, **kwargs) # pyright: ignore
return HConcatChart(hconcat=charts, **kwargs)


class VConcatChart(TopLevelMixin, core.TopLevelVConcatSpec):
Expand Down Expand Up @@ -4372,7 +4388,7 @@ def add_selection(self, *selections) -> Self: # noqa: ANN002

def vconcat(*charts: ConcatType, **kwargs: Any) -> VConcatChart:
"""Concatenate charts vertically."""
return VConcatChart(vconcat=charts, **kwargs) # pyright: ignore
return VConcatChart(vconcat=charts, **kwargs)


class LayerChart(TopLevelMixin, _EncodingMixin, core.TopLevelLayerSpec):
Expand Down Expand Up @@ -4498,7 +4514,7 @@ def add_selection(self, *selections) -> Self: # noqa: ANN002

def layer(*charts: LayerType, **kwargs: Any) -> LayerChart:
"""Layer multiple charts."""
return LayerChart(layer=charts, **kwargs) # pyright: ignore
return LayerChart(layer=charts, **kwargs)


class FacetChart(TopLevelMixin, core.TopLevelFacetSpec):
Expand Down
Loading

0 comments on commit ea4e7b4

Please sign in to comment.