diff --git a/pyproject.toml b/pyproject.toml index 97f3af325..8e74dfbb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -468,6 +468,5 @@ ignore=[ "./sphinxext/", "./tests/test_jupyter_chart.py", "./tests/utils/", - "./tests/test_magics.py", "../../../**/Lib", # stdlib ] diff --git a/tests/__init__.py b/tests/__init__.py index 1cda56438..617cfca80 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -59,6 +59,17 @@ def windows_has_tzdata() -> bool: >>> hatch run test-slow --durations=25 # doctest: +SKIP """ +skip_requires_ipython: pytest.MarkDecorator = pytest.mark.skipif( + find_spec("IPython") is None, reason="`IPython` not installed." +) +""" +``pytest.mark.skipif`` decorator. + +Applies when `IPython`_ import would fail. + +.. _IPython: + /~https://github.com/ipython/ipython +""" skip_requires_vl_convert: pytest.MarkDecorator = pytest.mark.skipif( find_spec("vl_convert") is None, reason="`vl_convert` not installed." diff --git a/tests/test_magics.py b/tests/test_magics.py index e1775aaf5..f88c83dbb 100644 --- a/tests/test_magics.py +++ b/tests/test_magics.py @@ -1,68 +1,76 @@ +from __future__ import annotations + import json +from typing import TYPE_CHECKING, Any import pytest -try: - from IPython import InteractiveShell - - IPYTHON_AVAILABLE = True -except ImportError: - IPYTHON_AVAILABLE = False - -from altair.vegalite.v5 import VegaLite - -DATA_RECORDS = [ - {"amount": 28, "category": "A"}, - {"amount": 55, "category": "B"}, - {"amount": 43, "category": "C"}, - {"amount": 91, "category": "D"}, - {"amount": 81, "category": "E"}, - {"amount": 53, "category": "F"}, - {"amount": 19, "category": "G"}, - {"amount": 87, "category": "H"}, -] - -if IPYTHON_AVAILABLE: - _ipshell = InteractiveShell.instance() - _ipshell.run_cell("%load_ext altair") - _ipshell.run_cell( - f""" -import pandas as pd -table = pd.DataFrame.from_records({DATA_RECORDS}) -the_data = table -""" - ) +from altair.vegalite.v5.display import VegaLite +from tests import skip_requires_ipython + +if TYPE_CHECKING: + from IPython.core.interactiveshell import InteractiveShell + + +@pytest.fixture +def records() -> list[dict[str, Any]]: + return [ + {"amount": 28, "category": "A"}, + {"amount": 55, "category": "B"}, + {"amount": 43, "category": "C"}, + {"amount": 91, "category": "D"}, + {"amount": 81, "category": "E"}, + {"amount": 53, "category": "F"}, + {"amount": 19, "category": "G"}, + {"amount": 87, "category": "H"}, + ] -VEGALITE_SPEC = { - "$schema": "https://vega.github.io/schema/vega-lite/v5.json", - "data": {"values": DATA_RECORDS}, - "description": "A simple bar chart with embedded data.", - "encoding": { - "x": {"field": "category", "type": "ordinal"}, - "y": {"field": "amount", "type": "quantitative"}, - }, - "mark": {"type": "bar"}, -} +@pytest.fixture +def vl_spec(records) -> dict[str, Any]: + return { + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "data": {"values": records}, + "description": "A simple bar chart with embedded data.", + "encoding": { + "x": {"field": "category", "type": "ordinal"}, + "y": {"field": "amount", "type": "quantitative"}, + }, + "mark": {"type": "bar"}, + } + + +@pytest.fixture +def ipshell(records) -> InteractiveShell: + from IPython.core.interactiveshell import InteractiveShell + + shell = InteractiveShell.instance() + shell.run_cell("%load_ext altair") + shell.run_cell( + f"import pandas as pd\n" + f"table = pd.DataFrame.from_records({records})\n" + f"the_data = table" + ) + return shell -@pytest.mark.skipif(not IPYTHON_AVAILABLE, reason="requires ipython") -def test_vegalite_magic_data_included(): - result = _ipshell.run_cell("%%vegalite\n" + json.dumps(VEGALITE_SPEC)) +@skip_requires_ipython +def test_vegalite_magic_data_included(ipshell, vl_spec) -> None: + result = ipshell.run_cell("%%vegalite\n" + json.dumps(vl_spec)) assert isinstance(result.result, VegaLite) - assert result.result.spec == VEGALITE_SPEC + assert result.result.spec == vl_spec -@pytest.mark.skipif(not IPYTHON_AVAILABLE, reason="requires ipython") -def test_vegalite_magic_json_flag(): - result = _ipshell.run_cell("%%vegalite --json\n" + json.dumps(VEGALITE_SPEC)) +@skip_requires_ipython +def test_vegalite_magic_json_flag(ipshell, vl_spec) -> None: + result = ipshell.run_cell("%%vegalite --json\n" + json.dumps(vl_spec)) assert isinstance(result.result, VegaLite) - assert result.result.spec == VEGALITE_SPEC + assert result.result.spec == vl_spec -@pytest.mark.skipif(not IPYTHON_AVAILABLE, reason="requires ipython") -def test_vegalite_magic_pandas_data(): - spec = {key: val for key, val in VEGALITE_SPEC.items() if key != "data"} - result = _ipshell.run_cell("%%vegalite table\n" + json.dumps(spec)) +@skip_requires_ipython +def test_vegalite_magic_pandas_data(ipshell, vl_spec) -> None: + spec = {key: val for key, val in vl_spec.items() if key != "data"} + result = ipshell.run_cell("%%vegalite table\n" + json.dumps(spec)) assert isinstance(result.result, VegaLite) - assert result.result.spec == VEGALITE_SPEC + assert result.result.spec == vl_spec