Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support datetime.(date|datetime) as a SchemaBase parameter #3653

Merged
merged 18 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
30057a0
feat: Support `datetime.(date|datetime)` as a `SchemaBase` parameter
dangotbanned Oct 22, 2024
8ce69ce
test: Adds `test_to_dict_datetime`
dangotbanned Oct 22, 2024
59bc8d8
feat: Reject non-UTC timezones
dangotbanned Oct 22, 2024
62ba4ef
test(typing): Adds `test_to_dict_datetime_typing`
dangotbanned Oct 22, 2024
5fb8f73
fix(typing): Remove unused ignore
dangotbanned Oct 22, 2024
8e27a38
feat(typing): Adds `Temporal` alias
dangotbanned Oct 22, 2024
b6711c7
build: run `generate-schema-wrapper`
dangotbanned Oct 22, 2024
29c500c
fix(typing): Remove unused ignores
dangotbanned Oct 22, 2024
33b6868
fix: Use object identity for `utc` test instead of name
dangotbanned Oct 22, 2024
30b5a3c
refactor(typing): Narrow `selection_(interval|point)(value=...)` types
dangotbanned Oct 23, 2024
a3c465e
Merge branch 'main' into support-datetime-schemabase
dangotbanned Oct 23, 2024
1986932
Merge remote-tracking branch 'upstream/main' into support-datetime-sc…
dangotbanned Oct 23, 2024
063fee9
refactor(typing): Utilize `PrimitiveValue_T`
dangotbanned Oct 23, 2024
23f7a70
refactor(typing): Factor out `_LiteralValue` alias
dangotbanned Oct 23, 2024
30aa4ba
feat(typing): Accurately type `selection_(interval|point)(value=...)`
dangotbanned Oct 24, 2024
8c66420
test(typing): Add (failing) `test_selection_interval_value_typing`
dangotbanned Oct 24, 2024
901e9b3
fix(typing): Correct failing `selection_interval` typing
dangotbanned Oct 24, 2024
2882d5e
test(typing): Improve coverage for `test_selection_interval_value_typ…
dangotbanned Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions altair/utils/schemapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import contextlib
import copy
import datetime as dt
import inspect
import json
import sys
Expand Down Expand Up @@ -502,6 +503,34 @@ def _from_array_like(obj: Iterable[Any], /) -> list[Any]:
return list(obj)


def _from_date_datetime(obj: dt.date | dt.datetime, /) -> dict[str, Any]:
"""
Parse native `datetime.(date|datetime)` into a `DateTime`_ schema.

.. _DateTime:
https://vega.github.io/vega-lite/docs/datetime.html
"""
result: dict[str, Any] = {"year": obj.year, "month": obj.month, "date": obj.day}
if isinstance(obj, dt.datetime):
if obj.time() != dt.time.min:
us = obj.microsecond
ms = us if us == 0 else us // 1_000
result.update(
hours=obj.hour, minutes=obj.minute, seconds=obj.second, milliseconds=ms
)
if tzinfo := obj.tzinfo:
if tzinfo is dt.timezone.utc:
result["utc"] = True
else:
msg = (
f"Unsupported timezone {tzinfo!r}.\n"
"Only `'UTC'` or naive (local) datetimes are permitted.\n"
"See https://altair-viz.github.io/user_guide/generated/core/altair.DateTime.html"
)
raise TypeError(msg)
return result


def _todict(obj: Any, context: dict[str, Any] | None, np_opt: Any, pd_opt: Any) -> Any: # noqa: C901
"""Convert an object to a dict representation."""
if np_opt is not None:
Expand Down Expand Up @@ -532,6 +561,8 @@ def _todict(obj: Any, context: dict[str, Any] | None, np_opt: Any, pd_opt: Any)
return pd_opt.Timestamp(obj).isoformat()
elif _is_iterable(obj, exclude=(str, bytes)):
return _todict(_from_array_like(obj), context, np_opt, pd_opt)
elif isinstance(obj, dt.date):
return _from_date_datetime(obj)
else:
return obj

Expand Down
17 changes: 10 additions & 7 deletions altair/vegalite/v5/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from .data import data_transformers
from .display import VEGA_VERSION, VEGAEMBED_VERSION, VEGALITE_VERSION, renderers
from .schema import SCHEMA_URL, channels, core, mixins
from .schema._typing import Map
from .schema._typing import Map, PrimitiveValue_T
from .theme import themes

if sys.version_info >= (3, 14):
Expand Down Expand Up @@ -88,6 +88,7 @@
SingleDefUnitChannel_T,
SingleTimeUnit_T,
StackOffset_T,
Temporal,
)
from .schema.channels import Column, Facet, Row
from .schema.core import (
Expand Down Expand Up @@ -539,10 +540,8 @@ def check_fields_and_encodings(parameter: Parameter, field_name: str) -> bool:
```
"""

_LiteralValue: TypeAlias = Union[str, bool, float, int]
"""Primitive python value types."""

_FieldEqualType: TypeAlias = Union[_LiteralValue, Map, Parameter, SchemaBase]
_FieldEqualType: TypeAlias = Union[PrimitiveValue_T, Map, Parameter, SchemaBase]
"""Permitted types for equality checks on field values:

- `datum.field == ...`
Expand Down Expand Up @@ -633,7 +632,7 @@ class _ConditionExtra(TypedDict, closed=True, total=False): # type: ignore[call
param: Parameter | str
test: _TestPredicateType
value: Any
__extra_items__: _StatementType | OneOrSeq[_LiteralValue]
__extra_items__: _StatementType | OneOrSeq[PrimitiveValue_T]


_Condition: TypeAlias = _ConditionExtra
Expand Down Expand Up @@ -1438,7 +1437,9 @@ def selection(type: Optional[SelectionType_T] = Undefined, **kwds: Any) -> Param

def selection_interval(
name: str | None = None,
value: Optional[Any] = Undefined,
value: Optional[
PrimitiveValue_T | Temporal | SchemaBase | Sequence[SchemaBase | Map] | Map
] = Undefined,
dangotbanned marked this conversation as resolved.
Show resolved Hide resolved
bind: Optional[Binding | str] = Undefined,
empty: Optional[bool] = Undefined,
expr: Optional[str | Expr | Expression] = Undefined,
Expand Down Expand Up @@ -1551,7 +1552,9 @@ def selection_interval(

def selection_point(
name: str | None = None,
value: Optional[Any] = Undefined,
value: Optional[
PrimitiveValue_T | Temporal | SchemaBase | Sequence[SchemaBase | Map] | Map
] = Undefined,
dangotbanned marked this conversation as resolved.
Show resolved Hide resolved
bind: Optional[Binding | str] = Undefined,
empty: Optional[bool] = Undefined,
expr: Optional[Expr] = Undefined,
Expand Down
4 changes: 4 additions & 0 deletions altair/vegalite/v5/schema/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import re
import sys
from collections.abc import Mapping, Sequence
from datetime import date, datetime
from typing import Annotated, Any, Generic, Literal, TypeVar, Union, get_args

if sys.version_info >= (3, 14): # https://peps.python.org/pep-0728/
Expand Down Expand Up @@ -87,6 +88,7 @@
"StepFor_T",
"StrokeCap_T",
"StrokeJoin_T",
"Temporal",
"TextBaseline_T",
"TextDirection_T",
"TimeInterval_T",
Expand Down Expand Up @@ -198,6 +200,8 @@ class PaddingKwds(TypedDict, total=False):
top: float


Temporal: TypeAlias = Union[date, datetime]

dangotbanned marked this conversation as resolved.
Show resolved Hide resolved
VegaThemes: TypeAlias = Literal[
"carbong10",
"carbong100",
Expand Down
Loading