Skip to content

Commit

Permalink
fix(typing): Resolve or ignore all of tests.utils
Browse files Browse the repository at this point in the history
Some common themes:
- Testing with *known* invalid arguments
- Using `PluginRegistry.get()` without checking for `None`
- `SchemaBase.(to|from)_dict` ) allows more than just `dict`
  • Loading branch information
dangotbanned committed Nov 5, 2024
1 parent 9d7aee1 commit d8dcbd8
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 33 deletions.
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,5 @@ ignore=[
"./altair/jupyter/",
"./sphinxext/",
"./tests/test_jupyter_chart.py",
"./tests/utils/",
"../../../**/Lib", # stdlib
]
4 changes: 3 additions & 1 deletion tests/utils/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def assert_is_vega_spec(vega_spec):
@skip_requires_vl_convert
def test_vegalite_compiler(chart):
vegalite_spec = chart.to_dict()
vega_spec = vegalite_compilers.get()(vegalite_spec)
fn = vegalite_compilers.get()
assert fn is not None
vega_spec = fn(vegalite_spec)
assert_is_vega_spec(vega_spec)


Expand Down
2 changes: 1 addition & 1 deletion tests/utils/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def channels_cached(channels) -> core._ChannelCache:
"""Previously ``_ChannelCache.from_channels``."""
cached = core._ChannelCache.__new__(core._ChannelCache)
cached.channel_to_name = {
c: c._encoding_name
c: c._encoding_name # pyright: ignore[reportAttributeAccessIssue]
for c in channels.__dict__.values()
if isinstance(c, type)
and issubclass(c, alt.SchemaBase)
Expand Down
16 changes: 12 additions & 4 deletions tests/utils/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,16 @@ def test_dataframe_to_json():
- make certain the filename is deterministic
- make certain the file contents match the data.
"""
filename = ""
data = _create_dataframe(10)
try:
result1 = _pipe(data, to_json)
result2 = _pipe(data, to_json)
filename = result1["url"]
output = pd.read_json(filename)
finally:
Path(filename).unlink()
if filename:
Path(filename).unlink()

assert result1 == result2
assert output.equals(data)
Expand All @@ -120,14 +122,16 @@ def test_dict_to_json():
- make certain the filename is deterministic
- make certain the file contents match the data.
"""
filename = ""
data = _create_data_with_values(10)
try:
result1 = _pipe(data, to_json)
result2 = _pipe(data, to_json)
filename = result1["url"]
output = pd.read_json(filename).to_dict(orient="records")
finally:
Path(filename).unlink()
if filename:
Path(filename).unlink()

assert result1 == result2
assert data == {"values": output}
Expand All @@ -141,14 +145,16 @@ def test_dataframe_to_csv(tp: type[Any]) -> None:
- make certain the filename is deterministic
- make certain the file contents match the data.
"""
filename: str = ""
data = _create_dataframe(10, tp=tp)
try:
result1 = _pipe(data, to_csv)
result2 = _pipe(data, to_csv)
filename = result1["url"]
output = tp(pd.read_csv(filename))
finally:
Path(filename).unlink()
if filename:
Path(filename).unlink()

assert result1 == result2
assert output.equals(data)
Expand All @@ -161,14 +167,16 @@ def test_dict_to_csv():
- make certain the filename is deterministic
- make certain the file contents match the data.
"""
filename = ""
data = _create_data_with_values(10)
try:
result1 = _pipe(data, to_csv)
result2 = _pipe(data, to_csv)
filename = result1["url"]
output = pd.read_csv(filename).to_dict(orient="records")
finally:
Path(filename).unlink()
if filename:
Path(filename).unlink()

assert result1 == result2
assert data == {"values": output}
4 changes: 2 additions & 2 deletions tests/utils/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def spec():
def test_spec_to_html(requirejs, fullhtml, spec):
# We can't test that the html actually renders, but we'll test aspects of
# it to make certain that the keywords are respected.
vegaembed_version = ("3.12",)
vegalite_version = ("3.0",)
vegaembed_version = "3.12"
vegalite_version = "3.0"
vega_version = "4.0"

html = spec_to_html(
Expand Down
13 changes: 9 additions & 4 deletions tests/utils/test_mimebundle.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from __future__ import annotations

from typing import Any

import pytest

import altair as alt
Expand All @@ -7,7 +11,7 @@


@pytest.fixture
def vegalite_spec():
def vegalite_spec() -> dict[str, Any]:
return {
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple bar chart with embedded data.",
Expand Down Expand Up @@ -187,15 +191,15 @@ def test_spec_to_vegalite_mimebundle(vegalite_spec):
def test_spec_to_vega_mimebundle(vega_spec):
# ValueError: mode must be 'vega-lite'
with pytest.raises(ValueError): # noqa: PT011
spec_to_mimebundle(
spec_to_mimebundle( # pyright: ignore[reportCallIssue]
spec=vega_spec,
mode="vega",
mode="vega", # pyright: ignore[reportArgumentType]
format="vega",
vega_version=alt.VEGA_VERSION,
)


def test_spec_to_json_mimebundle():
def test_spec_to_json_mimebundle(vegalite_spec):
bundle = spec_to_mimebundle(
spec=vegalite_spec,
mode="vega-lite",
Expand Down Expand Up @@ -240,5 +244,6 @@ def test_vegafusion_chart_to_vega_mime_bundle(vegalite_spec):
chart = alt.Chart.from_dict(vegalite_spec)
with alt.data_transformers.enable("vegafusion"), alt.renderers.enable("json"):
bundle = chart._repr_mimebundle_()
assert isinstance(bundle, tuple)
vega_spec = bundle[0]["application/json"]
check_pre_transformed_vega_spec(vega_spec)
16 changes: 12 additions & 4 deletions tests/utils/test_plugin_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def test_plugin_registry():
plugins.enable("new_plugin")
assert plugins.names() == ["new_plugin"]
assert plugins.active == "new_plugin"
assert plugins.get()(3) == 9
fn = plugins.get()
assert fn is not None
assert fn(3) == 9
assert repr(plugins) == (
"TypedCallableRegistry(active='new_plugin', " "registered=['new_plugin'])"
)
Expand All @@ -49,16 +51,22 @@ def test_plugin_registry_extra_options():

plugins.register("metadata_plugin", lambda x, p=2: x**p)
plugins.enable("metadata_plugin")
assert plugins.get()(3) == 9
fn = plugins.get()
assert fn is not None
assert fn(3) == 9

plugins.enable("metadata_plugin", p=3)
assert plugins.active == "metadata_plugin"
assert plugins.get()(3) == 27
fn = plugins.get()
assert fn is not None
assert fn(3) == 27

# enabling without changing name
plugins.enable(p=2)
assert plugins.active == "metadata_plugin"
assert plugins.get()(3) == 9
fn = plugins.get()
assert fn is not None
assert fn(3) == 9


def test_plugin_registry_global_settings():
Expand Down
30 changes: 15 additions & 15 deletions tests/utils/test_schemapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,15 +251,15 @@ def test_simple_type():

def test_simple_array():
assert SimpleArray([4, 5, "six"]).to_dict() == [4, 5, "six"]
assert SimpleArray.from_dict(list("abc")).to_dict() == list("abc")
assert SimpleArray.from_dict(list("abc")).to_dict() == list("abc") # pyright: ignore[reportArgumentType]


def test_definition_union():
obj = DefinitionUnion.from_dict("A")
obj = DefinitionUnion.from_dict("A") # pyright: ignore[reportArgumentType]
assert isinstance(obj, Bar)
assert obj.to_dict() == "A"

obj = DefinitionUnion.from_dict("B")
obj = DefinitionUnion.from_dict("B") # pyright: ignore[reportArgumentType]
assert isinstance(obj, Bar)
assert obj.to_dict() == "B"

Expand Down Expand Up @@ -445,7 +445,7 @@ def chart_error_example__hconcat():
alt.Chart(source)
.mark_text()
.encode(
alt.Text("Horsepower:N", title={"text": "Horsepower", "align": "right"})
alt.Text("Horsepower:N", title={"text": "Horsepower", "align": "right"}) # pyright: ignore[reportArgumentType]
)
)

Expand All @@ -460,7 +460,7 @@ def chart_error_example__invalid_y_option_value_unknown_x_option():
.mark_bar()
.encode(
x=alt.X("variety", unknown=2),
y=alt.Y("sum(yield)", stack="asdf"),
y=alt.Y("sum(yield)", stack="asdf"), # pyright: ignore[reportArgumentType]
)
)

Expand All @@ -472,7 +472,7 @@ def chart_error_example__invalid_y_option_value():
.mark_bar()
.encode(
x=alt.X("variety"),
y=alt.Y("sum(yield)", stack="asdf"),
y=alt.Y("sum(yield)", stack="asdf"), # pyright: ignore[reportArgumentType]
)
)

Expand All @@ -486,15 +486,15 @@ def chart_error_example__invalid_y_option_value_with_condition():
.mark_bar()
.encode(
x="variety",
y=alt.Y("sum(yield)", stack="asdf"),
y=alt.Y("sum(yield)", stack="asdf"), # pyright: ignore[reportArgumentType]
opacity=alt.condition("datum.yield > 0", alt.value(1), alt.value(0.2)),
)
)


def chart_error_example__invalid_timeunit_value():
# Error: Invalid value for Angle.timeUnit
return alt.Chart().encode(alt.Angle().timeUnit("invalid_value"))
return alt.Chart().encode(alt.Angle().timeUnit("invalid_value")) # pyright: ignore[reportArgumentType]


def chart_error_example__invalid_sort_value():
Expand All @@ -507,13 +507,13 @@ def chart_error_example__invalid_bandposition_value():
return (
alt.Chart(data.cars())
.mark_text(align="right")
.encode(alt.Text("Horsepower:N", bandPosition="4"))
.encode(alt.Text("Horsepower:N", bandPosition="4")) # pyright: ignore[reportArgumentType]
)


def chart_error_example__invalid_type():
# Error: Invalid value for type
return alt.Chart().encode(alt.X(type="unknown"))
return alt.Chart().encode(alt.X(type="unknown")) # pyright: ignore[reportArgumentType]


def chart_error_example__additional_datum_argument():
Expand All @@ -539,21 +539,21 @@ def chart_error_example__wrong_tooltip_type_in_faceted_chart():
return (
alt.Chart(pd.DataFrame({"a": [1]}))
.mark_point()
.encode(tooltip=[{"wrong"}])
.encode(tooltip=[{"wrong"}]) # pyright: ignore[reportArgumentType]
.facet()
)


def chart_error_example__wrong_tooltip_type_in_layered_chart():
# Error: Wrong data type to pass to tooltip
return alt.layer(alt.Chart().mark_point().encode(tooltip=[{"wrong"}]))
return alt.layer(alt.Chart().mark_point().encode(tooltip=[{"wrong"}])) # pyright: ignore[reportArgumentType]


def chart_error_example__two_errors_in_layered_chart():
# Error 1: Wrong data type to pass to tooltip
# Error 2: `Color` has no parameter named 'invalidArgument'
return alt.layer(
alt.Chart().mark_point().encode(tooltip=[{"wrong"}]),
alt.Chart().mark_point().encode(tooltip=[{"wrong"}]), # pyright: ignore[reportArgumentType]
alt.Chart().mark_line().encode(alt.Color(invalidArgument="unknown")),
)

Expand Down Expand Up @@ -595,7 +595,7 @@ def chart_error_example__two_errors_with_one_in_nested_layered_chart():

blue_bars = (
alt.Chart(source)
.encode(alt.X("Day:O").scale(invalidOption=10), alt.Y("Value:Q"))
.encode(alt.X("Day:O").scale(invalidOption=10), alt.Y("Value:Q")) # pyright: ignore[reportCallIssue]
.mark_bar()
)
red_bars = (
Expand Down Expand Up @@ -635,7 +635,7 @@ def chart_error_example__four_errors_hide_fourth():
.mark_bar()
.encode(
x=alt.X("variety", unknown=2),
y=alt.Y("sum(yield)", stack="asdf"),
y=alt.Y("sum(yield)", stack="asdf"), # pyright: ignore[reportArgumentType]
color=alt.Color("variety", another_unknown=2),
opacity=alt.Opacity("variety", fourth_error=1),
)
Expand Down
2 changes: 1 addition & 1 deletion tests/utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_sanitize_dataframe():
if str(df[col].dtype).startswith("datetime"):
# astype(datetime) introduces time-zone issues:
# to_datetime() does not.
utc = isinstance(df[col].dtype, pd.core.dtypes.dtypes.DatetimeTZDtype)
utc = isinstance(df[col].dtype, pd.DatetimeTZDtype)
df2[col] = pd.to_datetime(df2[col], utc=utc)
else:
df2[col] = df2[col].astype(df[col].dtype)
Expand Down

0 comments on commit d8dcbd8

Please sign in to comment.