Skip to content

Commit

Permalink
fix: Resolve alt.binding signature/docstring issues (vega#3671)
Browse files Browse the repository at this point in the history
  • Loading branch information
dangotbanned authored Nov 3, 2024
1 parent 613b6e4 commit c28dbb9
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 4 deletions.
48 changes: 44 additions & 4 deletions altair/vegalite/v5/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
AnyMark,
BindCheckbox,
Binding,
BindInput,
BindRadioSelect,
BindRange,
BinParams,
Expand Down Expand Up @@ -1751,10 +1752,49 @@ def selection_single(**kwargs: Any) -> Parameter:
return _selection(type="point", **kwargs)


@utils.use_signature(core.Binding)
def binding(input: Any, **kwargs: Any) -> Binding:
"""A generic binding."""
return core.Binding(input=input, **kwargs)
def binding(
input: str,
*,
autocomplete: Optional[str] = Undefined,
debounce: Optional[float] = Undefined,
element: Optional[str] = Undefined,
name: Optional[str] = Undefined,
placeholder: Optional[str] = Undefined,
) -> BindInput:
"""
A generic binding.
Parameters
----------
input : str
The type of input element to use. The valid values are ``"checkbox"``, ``"radio"``,
``"range"``, ``"select"``, and any other legal `HTML form input type
<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input>`__.
autocomplete : str
A hint for form autofill. See the `HTML autocomplete attribute
<https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete>`__ for
additional information.
debounce : float
If defined, delays event handling until the specified milliseconds have elapsed
since the last event was fired.
element : str
An optional CSS selector string indicating the parent element to which the input
element should be added. By default, all input elements are added within the parent
container of the Vega view.
name : str
By default, the signal name is used to label input elements. This ``name`` property
can be used instead to specify a custom label for the bound signal.
placeholder : str
Text that appears in the form control when it has no value set.
"""
return core.BindInput(
autocomplete=autocomplete,
debounce=debounce,
element=element,
input=input,
name=name,
placeholder=placeholder,
)


@utils.use_signature(core.BindCheckbox)
Expand Down
37 changes: 37 additions & 0 deletions tests/vegalite/v5/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@
from packaging.version import Version

import altair as alt
from altair.utils.core import use_signature
from altair.utils.schemapi import Optional, SchemaValidationError, Undefined
from tests import skip_requires_vl_convert, slow

if TYPE_CHECKING:
from typing import Any

from altair.vegalite.v5.api import _Conditional, _Conditions
from altair.vegalite.v5.schema._typing import Map

Expand Down Expand Up @@ -1654,3 +1657,37 @@ def test_ibis_with_vegafusion(monkeypatch: pytest.MonkeyPatch):
{"a": 2, "b": "2020-01-02T00:00:00.000"},
{"a": 3, "b": "2020-01-03T00:00:00.000"},
]


def test_binding() -> None:
@use_signature(alt.Binding)
def old_binding(input: Any, **kwargs: Any) -> alt.Binding:
"""A generic binding."""
return alt.Binding(input=input, **kwargs)

# NOTE: `mypy` doesn't complain, but `pyright` does
old = old_binding(input="search", placeholder="Country", name="Search") # pyright: ignore[reportCallIssue]
old_positional = old_binding("search", placeholder="Country", name="Search")

new = alt.binding(input="search", placeholder="Country", name="Search")
new_positional = alt.binding("search", placeholder="Country", name="Search")

assert (
old.to_dict()
== old_positional.to_dict()
== new.to_dict()
== new_positional.to_dict()
)
assert all(
isinstance(x, alt.Binding) for x in (old, old_positional, new, new_positional)
)

MISSING_INPUT = r"missing 1 required positional argument: 'input"

# NOTE: `mypy` doesn't complain, but `pyright` does (Again)
with pytest.raises(TypeError, match=MISSING_INPUT):
old_binding(placeholder="Country", name="Search") # pyright: ignore[reportCallIssue]

# NOTE: Both type checkers can detect the issue on the new signature
with pytest.raises(TypeError, match=MISSING_INPUT):
alt.binding(placeholder="Country", name="Search") # type: ignore[call-arg]

0 comments on commit c28dbb9

Please sign in to comment.