vgplot 0.29.0__tar.gz → 0.30.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {vgplot-0.29.0 → vgplot-0.30.0}/.gitignore +1 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/PKG-INFO +21 -10
- {vgplot-0.29.0 → vgplot-0.30.0}/README.md +19 -9
- {vgplot-0.29.0 → vgplot-0.30.0}/package.json +1 -1
- {vgplot-0.29.0 → vgplot-0.30.0}/pyproject.toml +1 -5
- {vgplot-0.29.0/test → vgplot-0.30.0/tests}/test_full_round_trip.py +2 -10
- {vgplot-0.29.0/test → vgplot-0.30.0/tests}/test_python_api.py +48 -10
- {vgplot-0.29.0/test → vgplot-0.30.0/tests}/test_schema_coverage.py +2 -7
- vgplot-0.30.0/tests/test_unset_sentinel.py +70 -0
- vgplot-0.30.0/vgplot/_compat.py +103 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/_generated/__init__.py +1 -1
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/_generated/encodings.py +6 -6
- vgplot-0.30.0/vgplot/_generated/marks.py +4124 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/_types.py +4 -9
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/data.py +15 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/plot.py +6 -2
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/spec.py +32 -14
- vgplot-0.29.0/vgplot/_generated/marks.py +0 -4124
- {vgplot-0.29.0 → vgplot-0.30.0}/CONTRIBUTING.md +0 -0
- {vgplot-0.29.0/test → vgplot-0.30.0/tests}/__init__.py +0 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/__init__.py +0 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/_generated/attributes.py +0 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/encodings.py +0 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/params.py +0 -0
- {vgplot-0.29.0 → vgplot-0.30.0}/vgplot/util.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vgplot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.30.0
|
|
4
4
|
Summary: A Python API for authoring Mosaic vgplot visualizations
|
|
5
5
|
Project-URL: homepage, https://github.com/uwdata/mosaic
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: narwhals>=2.8.0
|
|
7
8
|
Description-Content-Type: text/markdown
|
|
8
9
|
|
|
9
10
|
# vgplot
|
|
@@ -58,18 +59,30 @@ brush = vg.selection.crossfilter()
|
|
|
58
59
|
|
|
59
60
|
view = vg.vconcat(
|
|
60
61
|
vg.plot(
|
|
61
|
-
vg.rect_y(
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
vg.rect_y(
|
|
63
|
+
flights,
|
|
64
|
+
x=vg.bin("delay"),
|
|
65
|
+
y=vg.count(),
|
|
66
|
+
filter_by=brush,
|
|
67
|
+
fill="steelblue",
|
|
68
|
+
inset_left=0.5,
|
|
69
|
+
inset_right=0.5,
|
|
70
|
+
),
|
|
64
71
|
vg.interval_x(bind=brush),
|
|
65
72
|
vg.x_domain("Fixed"),
|
|
66
73
|
vg.x_label("Arrival Delay (min)"),
|
|
67
74
|
vg.height(200),
|
|
68
75
|
),
|
|
69
76
|
vg.plot(
|
|
70
|
-
vg.rect_y(
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
vg.rect_y(
|
|
78
|
+
flights,
|
|
79
|
+
x=vg.bin("time"),
|
|
80
|
+
y=vg.count(),
|
|
81
|
+
filter_by=brush,
|
|
82
|
+
fill="steelblue",
|
|
83
|
+
inset_left=0.5,
|
|
84
|
+
inset_right=0.5,
|
|
85
|
+
),
|
|
73
86
|
vg.interval_x(bind=brush),
|
|
74
87
|
vg.x_domain("Fixed"),
|
|
75
88
|
vg.x_label("Departure Time (hour)"),
|
|
@@ -93,9 +106,7 @@ bias = vg.param(0)
|
|
|
93
106
|
view = vg.vconcat(
|
|
94
107
|
vg.slider(label="Bias", bind=bias, min=0, max=1000, step=1),
|
|
95
108
|
vg.plot(
|
|
96
|
-
vg.area_y(walk, x="t", y=vg.sql("v + $bias")),
|
|
97
|
-
vg.width(680),
|
|
98
|
-
vg.height(200),
|
|
109
|
+
vg.area_y(walk, x="t", y=vg.sql("v + $bias")), vg.width(680), vg.height(200)
|
|
99
110
|
),
|
|
100
111
|
)
|
|
101
112
|
|
|
@@ -50,18 +50,30 @@ brush = vg.selection.crossfilter()
|
|
|
50
50
|
|
|
51
51
|
view = vg.vconcat(
|
|
52
52
|
vg.plot(
|
|
53
|
-
vg.rect_y(
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
vg.rect_y(
|
|
54
|
+
flights,
|
|
55
|
+
x=vg.bin("delay"),
|
|
56
|
+
y=vg.count(),
|
|
57
|
+
filter_by=brush,
|
|
58
|
+
fill="steelblue",
|
|
59
|
+
inset_left=0.5,
|
|
60
|
+
inset_right=0.5,
|
|
61
|
+
),
|
|
56
62
|
vg.interval_x(bind=brush),
|
|
57
63
|
vg.x_domain("Fixed"),
|
|
58
64
|
vg.x_label("Arrival Delay (min)"),
|
|
59
65
|
vg.height(200),
|
|
60
66
|
),
|
|
61
67
|
vg.plot(
|
|
62
|
-
vg.rect_y(
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
vg.rect_y(
|
|
69
|
+
flights,
|
|
70
|
+
x=vg.bin("time"),
|
|
71
|
+
y=vg.count(),
|
|
72
|
+
filter_by=brush,
|
|
73
|
+
fill="steelblue",
|
|
74
|
+
inset_left=0.5,
|
|
75
|
+
inset_right=0.5,
|
|
76
|
+
),
|
|
65
77
|
vg.interval_x(bind=brush),
|
|
66
78
|
vg.x_domain("Fixed"),
|
|
67
79
|
vg.x_label("Departure Time (hour)"),
|
|
@@ -85,9 +97,7 @@ bias = vg.param(0)
|
|
|
85
97
|
view = vg.vconcat(
|
|
86
98
|
vg.slider(label="Bias", bind=bias, min=0, max=1000, step=1),
|
|
87
99
|
vg.plot(
|
|
88
|
-
vg.area_y(walk, x="t", y=vg.sql("v + $bias")),
|
|
89
|
-
vg.width(680),
|
|
90
|
-
vg.height(200),
|
|
100
|
+
vg.area_y(walk, x="t", y=vg.sql("v + $bias")), vg.width(680), vg.height(200)
|
|
91
101
|
),
|
|
92
102
|
)
|
|
93
103
|
|
|
@@ -4,7 +4,7 @@ dynamic = ["version"]
|
|
|
4
4
|
description = "A Python API for authoring Mosaic vgplot visualizations"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
7
|
-
dependencies = []
|
|
7
|
+
dependencies = ["narwhals>=2.8.0"]
|
|
8
8
|
|
|
9
9
|
[project.urls]
|
|
10
10
|
homepage = "https://github.com/uwdata/mosaic"
|
|
@@ -31,7 +31,3 @@ pattern = "\"version\": \"(?P<version>.+?)\""
|
|
|
31
31
|
|
|
32
32
|
[tool.hatch.build.targets.wheel]
|
|
33
33
|
packages = ["vgplot"]
|
|
34
|
-
|
|
35
|
-
[tool.pyright]
|
|
36
|
-
ignore = ["../**/.venv/"] # Do not display diagnostics in external source code
|
|
37
|
-
typeCheckingMode = "standard"
|
|
@@ -3,26 +3,18 @@
|
|
|
3
3
|
# in specs/json/. Also checks that Python, JSON, and ESM example sets stay
|
|
4
4
|
# in sync (same filenames).
|
|
5
5
|
#
|
|
6
|
-
# Run: pytest packages/vgplot/vgplot-python/
|
|
6
|
+
# Run: pytest packages/vgplot/vgplot-python/tests/test_full_round_trip.py
|
|
7
7
|
import json
|
|
8
|
-
import sys
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
from typing import Any
|
|
11
10
|
|
|
12
11
|
import pytest
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
SPEC_DIR = ROOT / "specs"
|
|
13
|
+
SPEC_DIR = Path(__file__).resolve().parents[4] / "specs"
|
|
16
14
|
JSON_DIR = SPEC_DIR / "json"
|
|
17
15
|
ESM_DIR = SPEC_DIR / "esm"
|
|
18
16
|
PYTHON_DIR = SPEC_DIR / "python"
|
|
19
17
|
|
|
20
|
-
VGPLOT_PKG = ROOT / "packages" / "vgplot" / "vgplot-python"
|
|
21
|
-
|
|
22
|
-
for p in (VGPLOT_PKG, ROOT):
|
|
23
|
-
if str(p) not in sys.path:
|
|
24
|
-
sys.path.insert(0, str(p))
|
|
25
|
-
|
|
26
18
|
|
|
27
19
|
def load_json_fixture(name: str) -> dict:
|
|
28
20
|
return json.loads((JSON_DIR / f"{name}.json").read_text(encoding="utf-8"))
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
# Unit tests for the vgplot Python API, covering behaviors that the
|
|
2
2
|
# generated-spec round-trip suite does not exercise directly.
|
|
3
|
-
import
|
|
4
|
-
from pathlib import Path
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
import pytest
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
for p in (VGPLOT_PKG, ROOT):
|
|
11
|
-
if str(p) not in sys.path:
|
|
12
|
-
sys.path.insert(0, str(p))
|
|
13
|
-
|
|
14
|
-
import vgplot as vg # noqa: E402
|
|
15
|
-
from vgplot.plot import Mark # noqa: E402
|
|
7
|
+
import vgplot as vg
|
|
8
|
+
from vgplot.plot import Mark
|
|
16
9
|
|
|
17
10
|
|
|
18
11
|
class TestGeneratedMarks:
|
|
@@ -79,3 +72,48 @@ class TestAutoNaming:
|
|
|
79
72
|
assert d["params"]["_param0"] == 1
|
|
80
73
|
assert d["params"]["_param1"] == 2
|
|
81
74
|
assert d["plot"][0]["x"] == "$_param1"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class TestDataFrames:
|
|
78
|
+
"""A DataFrame passed directly to a mark is discovered by variable name,
|
|
79
|
+
referenced as a table, and carried in the spec's data section for the host
|
|
80
|
+
(e.g. the widget) to register."""
|
|
81
|
+
|
|
82
|
+
def test_frame_is_referenced_and_named_after_variable(self):
|
|
83
|
+
pytest.importorskip("pyarrow")
|
|
84
|
+
import pyarrow as pa
|
|
85
|
+
|
|
86
|
+
weather = pa.table({"a": [1, 2, 3]})
|
|
87
|
+
view = vg.plot(vg.dot(weather, x="a"))
|
|
88
|
+
d = view.to_dict()
|
|
89
|
+
|
|
90
|
+
assert d["plot"][0]["data"] == {"from": "weather"}
|
|
91
|
+
assert d["data"]["weather"] is weather
|
|
92
|
+
|
|
93
|
+
def test_frame_and_datadef_share_the_data_section(self):
|
|
94
|
+
pytest.importorskip("pyarrow")
|
|
95
|
+
import pyarrow as pa
|
|
96
|
+
|
|
97
|
+
weather = pa.table({"a": [1]})
|
|
98
|
+
athletes = vg.csv("athletes.csv")
|
|
99
|
+
view = vg.plot(vg.dot(weather, x="a"), vg.dot(athletes, x="a"))
|
|
100
|
+
d = view.to_dict()
|
|
101
|
+
|
|
102
|
+
assert d["plot"][0]["data"] == {"from": "weather"}
|
|
103
|
+
assert d["plot"][1]["data"] == {"from": "athletes"}
|
|
104
|
+
assert d["data"]["weather"] is weather
|
|
105
|
+
assert d["data"]["athletes"] == {"type": "csv", "file": "athletes.csv"}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if TYPE_CHECKING:
|
|
109
|
+
|
|
110
|
+
def typing_dunder_all() -> None:
|
|
111
|
+
# Ok
|
|
112
|
+
vg.arrow
|
|
113
|
+
vg.errorbar_x
|
|
114
|
+
vg.mark
|
|
115
|
+
|
|
116
|
+
# TODO @dangotbanned: Get pyright to error on these
|
|
117
|
+
# Error (`_generated` modules)
|
|
118
|
+
vg.attributes # ty: ignore[unresolved-attribute]
|
|
119
|
+
vg.marks # ty: ignore[unresolved-attribute]
|
|
@@ -4,16 +4,11 @@
|
|
|
4
4
|
# schema addition that was never generated or hand-added.
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
-
import sys
|
|
8
7
|
from pathlib import Path
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
for p in (ROOT / "packages" / "vgplot" / "vgplot-python", ROOT):
|
|
12
|
-
if str(p) not in sys.path:
|
|
13
|
-
sys.path.insert(0, str(p))
|
|
14
|
-
|
|
15
|
-
import vgplot as vg # noqa: E402
|
|
9
|
+
import vgplot as vg
|
|
16
10
|
|
|
11
|
+
ROOT = Path(__file__).resolve().parents[4]
|
|
17
12
|
SCHEMA = ROOT / "docs" / "public" / "schema" / "latest.json"
|
|
18
13
|
|
|
19
14
|
# Schema names whose Python export is renamed or intentionally absent.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Union, get_type_hints
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
# NOTE: Don't move this into a runtime import (yet)
|
|
8
|
+
from vgplot._types import UNSET
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _import_unset() -> UNSET:
|
|
12
|
+
# NOTE: A regular import would add:
|
|
13
|
+
# - `vgplot._types` to `sys.modules`
|
|
14
|
+
# - `UNSET` to `globals`
|
|
15
|
+
# And we can't use `importlib.reload`, since that would create a new object
|
|
16
|
+
from vgplot._types import UNSET
|
|
17
|
+
|
|
18
|
+
return UNSET
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_unset_identity() -> None:
|
|
22
|
+
unset_1 = _import_unset()
|
|
23
|
+
unset_2 = _import_unset()
|
|
24
|
+
assert unset_1 is unset_2
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_unset_repr() -> None:
|
|
28
|
+
assert repr(_import_unset()) == "UNSET"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_unset_pickle() -> None:
|
|
32
|
+
import pickle
|
|
33
|
+
|
|
34
|
+
unset = _import_unset()
|
|
35
|
+
assert pickle.loads(pickle.dumps(unset)) is unset # noqa: S301
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_unset_type_expression_union() -> None:
|
|
39
|
+
# Adapted from https://github.com/python/typing_extensions/blob/83400e979b8e3b0b647f9a6a57f0275230e5f19f/src/test_typing_extensions.py#L9694-L9701
|
|
40
|
+
from vgplot._types import UNSET
|
|
41
|
+
|
|
42
|
+
def func1(a: int | UNSET = UNSET) -> None: ...
|
|
43
|
+
def func2(a: UNSET | int = UNSET) -> None: ...
|
|
44
|
+
|
|
45
|
+
assert get_type_hints(func1, localns=locals())["a"] == Union[int, UNSET] # noqa: UP007
|
|
46
|
+
assert get_type_hints(func2, localns=locals())["a"] == Union[UNSET, int] # noqa: UP007
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_unset_copy_identity() -> None:
|
|
50
|
+
# Adapted from https://github.com/python/typing_extensions/blob/83400e979b8e3b0b647f9a6a57f0275230e5f19f/src/test_typing_extensions.py#L9711-L9713
|
|
51
|
+
unset = _import_unset()
|
|
52
|
+
assert unset is copy.copy(unset)
|
|
53
|
+
assert unset is copy.deepcopy(unset)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_unset_union_identity() -> None:
|
|
57
|
+
unset = _import_unset()
|
|
58
|
+
assert (unset | unset) is unset
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if TYPE_CHECKING:
|
|
62
|
+
from typing_extensions import assert_type
|
|
63
|
+
|
|
64
|
+
def typing_unset(
|
|
65
|
+
a: UNSET, b: str | UNSET, c: Any | UNSET, d: int | None | UNSET = UNSET
|
|
66
|
+
) -> None:
|
|
67
|
+
assert_type(a, UNSET)
|
|
68
|
+
assert_type(b, str | UNSET)
|
|
69
|
+
assert_type(c, Any | UNSET)
|
|
70
|
+
assert_type(d, int | None | UNSET)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Backwards compatibility for features not available at our [requires-python][1].
|
|
2
|
+
|
|
3
|
+
Import from here to avoid introducing runtime dependency on [typing_extensions][2].
|
|
4
|
+
|
|
5
|
+
[1]: https://packaging.python.org/en/latest/specifications/pyproject-toml/#requires-python
|
|
6
|
+
[2]: https://github.com/python/typing_extensions
|
|
7
|
+
|
|
8
|
+
## sentinel
|
|
9
|
+
[`sentinel`][3] was introduced in `3.15` (see [PEP 661][4]).
|
|
10
|
+
|
|
11
|
+
We can remove the backport after [3.15 end-of-life][5].
|
|
12
|
+
|
|
13
|
+
[3]: https://docs.python.org/3.15/library/functions.html#sentinel
|
|
14
|
+
[4]: https://peps.python.org/pep-0661/
|
|
15
|
+
[5]: https://peps.python.org/pep-0790/#lifespan
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import typing
|
|
22
|
+
|
|
23
|
+
# ruff: noqa: A002
|
|
24
|
+
from contextlib import suppress
|
|
25
|
+
from importlib.util import find_spec
|
|
26
|
+
from typing import TYPE_CHECKING, Any, ClassVar
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _sentinel_backport_pre_typing_extensions_4_16() -> Any:
|
|
30
|
+
class _sentinel_backport:
|
|
31
|
+
"""Create a unique sentinel object.
|
|
32
|
+
|
|
33
|
+
*name* should be the name of the variable to which the return value shall be assigned.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, name: str, /, *, repr: str | None = None) -> None:
|
|
37
|
+
self.__name__: str = name
|
|
38
|
+
self._repr: str = repr if repr is not None else name
|
|
39
|
+
# TODO @dangotbanned: Figure out why they didn't use the `"__main__"` default here?
|
|
40
|
+
module: str | None = None
|
|
41
|
+
if hasattr(sys, "_getframemodulename"):
|
|
42
|
+
module = sys._getframemodulename(1) or "__main__"
|
|
43
|
+
elif hasattr(sys, "_getframe"):
|
|
44
|
+
with suppress(ValueError):
|
|
45
|
+
module = sys._getframe(1).f_globals.get("__name__", "__main__")
|
|
46
|
+
|
|
47
|
+
# For pickling as a singleton
|
|
48
|
+
self.__module__ = module # pyright: ignore[reportAttributeAccessIssue] # ty: ignore[invalid-assignment]
|
|
49
|
+
|
|
50
|
+
__init_subclass__: ClassVar[None] = None
|
|
51
|
+
|
|
52
|
+
def __repr__(self) -> str:
|
|
53
|
+
return self._repr
|
|
54
|
+
|
|
55
|
+
if sys.version_info < (3, 11):
|
|
56
|
+
# The presence of this method convinces typing._type_check that Sentinels are types.
|
|
57
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
58
|
+
msg = f"{type(self).__name__!r} object is not callable"
|
|
59
|
+
raise TypeError(msg)
|
|
60
|
+
|
|
61
|
+
def __or__(self, other: Any) -> Any:
|
|
62
|
+
return typing.Union[self, other] # noqa: UP007
|
|
63
|
+
|
|
64
|
+
def __ror__(self, other: Any) -> Any:
|
|
65
|
+
return typing.Union[other, self] # noqa: UP007
|
|
66
|
+
|
|
67
|
+
def __reduce__(self) -> str:
|
|
68
|
+
return self.__name__
|
|
69
|
+
|
|
70
|
+
return _sentinel_backport
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _sentinel_backport_pre_py_3_15() -> Any:
|
|
74
|
+
"""Return a [PEP 661]-compatible [`sentinel`](https://docs.python.org/3.15/library/functions.html#sentinel) factory.
|
|
75
|
+
|
|
76
|
+
[PEP 661]: https://peps.python.org/pep-0661/
|
|
77
|
+
|
|
78
|
+
## Notes
|
|
79
|
+
- Does not depend on `typing_extensions`, but will use it if a suitable version is available
|
|
80
|
+
- Fallback is adapted from [`typing_extensions==4.16.0`](https://github.com/python/typing_extensions/blob/f29cd28d8ed7642cafb1d18daf5aa41be6a5c0aa/src/typing_extensions.py#L176-L271)
|
|
81
|
+
"""
|
|
82
|
+
if find_spec("typing_extensions"):
|
|
83
|
+
import typing_extensions
|
|
84
|
+
|
|
85
|
+
# NOTE: In the same release the name changed, this guy landed https://github.com/python/typing_extensions/pull/617
|
|
86
|
+
# `4.14-4.15` is fine for typing, but the runtime changes are too big to rely on
|
|
87
|
+
if hasattr(typing_extensions, "sentinel"):
|
|
88
|
+
return getattr(typing_extensions, "sentinel", typing_extensions.Sentinel)
|
|
89
|
+
|
|
90
|
+
return _sentinel_backport_pre_typing_extensions_4_16()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
if TYPE_CHECKING:
|
|
94
|
+
# Was renamed in https://github.com/python/typing_extensions/releases/tag/4.16.0
|
|
95
|
+
from typing_extensions import Sentinel as sentinel # noqa: N813
|
|
96
|
+
else: # noqa: PLR5501
|
|
97
|
+
if sys.version_info >= (3, 15):
|
|
98
|
+
from builtins import sentinel
|
|
99
|
+
else:
|
|
100
|
+
sentinel = _sentinel_backport_pre_py_3_15()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
__all__ = ("sentinel",)
|
|
@@ -7,4 +7,4 @@ from .attributes import __all__ as _attr_all
|
|
|
7
7
|
from .encodings import __all__ as _enc_all
|
|
8
8
|
from .marks import __all__ as _mark_all
|
|
9
9
|
|
|
10
|
-
__all__ = [*_mark_all, *_attr_all, *_enc_all]
|
|
10
|
+
__all__ = [*_mark_all, *_attr_all, *_enc_all] # pyright: ignore[reportUnsupportedDunderAll]
|
|
@@ -54,7 +54,7 @@ def column(col: TransformArg, **options: Any) -> dict[str, Any]:
|
|
|
54
54
|
return _transform("column", (col,), options)
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
def count(col: TransformArg = UNSET, **options: Any) -> dict[str, Any]:
|
|
57
|
+
def count(col: TransformArg | UNSET = UNSET, **options: Any) -> dict[str, Any]:
|
|
58
58
|
"""Compute the count of records in an aggregation group."""
|
|
59
59
|
return _transform("count", (col,), options)
|
|
60
60
|
|
|
@@ -101,8 +101,8 @@ def geojson(col: TransformArg, **options: Any) -> dict[str, Any]:
|
|
|
101
101
|
|
|
102
102
|
def lag(
|
|
103
103
|
col: TransformArg,
|
|
104
|
-
offset: TransformArg = UNSET,
|
|
105
|
-
default: TransformArg = UNSET,
|
|
104
|
+
offset: TransformArg | UNSET = UNSET,
|
|
105
|
+
default: TransformArg | UNSET = UNSET,
|
|
106
106
|
**options: Any,
|
|
107
107
|
) -> dict[str, Any]:
|
|
108
108
|
"""Compute lagging values in a column."""
|
|
@@ -121,8 +121,8 @@ def last_value(col: TransformArg, **options: Any) -> dict[str, Any]:
|
|
|
121
121
|
|
|
122
122
|
def lead(
|
|
123
123
|
col: TransformArg,
|
|
124
|
-
offset: TransformArg = UNSET,
|
|
125
|
-
default: TransformArg = UNSET,
|
|
124
|
+
offset: TransformArg | UNSET = UNSET,
|
|
125
|
+
default: TransformArg | UNSET = UNSET,
|
|
126
126
|
**options: Any,
|
|
127
127
|
) -> dict[str, Any]:
|
|
128
128
|
"""Compute leading values in a column."""
|
|
@@ -150,7 +150,7 @@ def mode(col: TransformArg, **options: Any) -> dict[str, Any]:
|
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
def nth_value(
|
|
153
|
-
col: TransformArg, offset: TransformArg = UNSET, **options: Any
|
|
153
|
+
col: TransformArg, offset: TransformArg | UNSET = UNSET, **options: Any
|
|
154
154
|
) -> dict[str, Any]:
|
|
155
155
|
"""Get the nth value of the given column in the current window frame, counting from one."""
|
|
156
156
|
return _transform("nth_value", (col, offset), options)
|