def test_selenium_mimebundle( name: str, data: Dict[str, Any], mode: str, fmt: str, offline: bool, internet_ok: bool, ) -> None: if not (offline or internet_ok): pytest.xfail("Internet not available") saver = SeleniumSaver(data[mode], mode=mode, offline=offline) if mode == "vega" and fmt == "vega-lite": with pytest.raises(ValueError): saver.mimebundle(fmt) return mimetype, out = saver.mimebundle(fmt).popitem() assert mimetype == fmt_to_mimetype(fmt) if fmt == "png": assert isinstance(out, bytes) im = Image.open(io.BytesIO(out)) assert im.format == "PNG" im_expected = Image.open(io.BytesIO(data[fmt])) assert abs(im.size[0] - im_expected.size[0]) < 5 assert abs(im.size[1] - im_expected.size[1]) < 5 elif fmt == "svg": assert out == data[fmt] else: assert out == data[fmt]
def driver(): try: from altair_saver import SeleniumSaver except (ImportError, ModuleNotFoundError): pytest.skip("altair_saver not importable; cannot run driver tests.") if not SeleniumSaver.enabled(): pytest.skip( "selenium not properly configured; cannot run driver tests.") yield altair_transform.driver SeleniumSaver._stop_serving()
def _extract_data(spec: JSONDict, name: str = "data_0") -> pd.DataFrame: """Extract named data from a Vega-Lite chart spec. Parameters ---------- spec : dict The Vega-Lite specification containing the data to extract name : string The name of the data stream to extract Returns ------- data : pd.DataFrame The extracted data """ # Optional deps from selenium.common.exceptions import NoSuchElementException from altair_saver import SeleniumSaver from altair_viewer import get_bundled_script js_resources = { "vega.js": get_bundled_script("vega", alt.VEGA_VERSION), "vega-lite.js": get_bundled_script("vega-lite", alt.VEGALITE_VERSION), "vega-embed.js": get_bundled_script("vega-embed", alt.VEGAEMBED_VERSION), } html = HTML_TEMPLATE.format( vega_url="/vega.js", vegalite_url="/vega-lite.js", vegaembed_url="/vega-embed.js", ) url = SeleniumSaver._serve(html, js_resources) driver_name = SeleniumSaver._select_webdriver(20) driver = SeleniumSaver._registry.get(driver_name, 20) driver.get("about:blank") driver.get(url) try: driver.find_element_by_id("vis") except NoSuchElementException: raise RuntimeError(f"Could not load {url}") data = driver.execute_async_script(EXTRACT_CODE, spec, name) if "error" in data: raise ValueError(f"Javascript Error: {data['error']}") return pd.DataFrame.from_records(json.loads(data["data"]))
def test_extract_error() -> None: saver = SeleniumSaver({}) with pytest.raises(JavascriptError) as err: saver._extract("png") assert "Invalid specification" in str(err.value) saver = SeleniumSaver({}, mode="vega") with pytest.raises(JavascriptError) as err: saver._extract("xxx") assert "Unrecognized format" in str(err.value)
def test_select_webdriver(monkeypatch: MonkeyPatch, webdriver: str) -> None: def get(driver: str, driver_timeout: int) -> str: if driver == webdriver: return driver else: raise WebDriverException(driver) monkeypatch.setattr(SeleniumSaver._registry, "get", get) assert SeleniumSaver._select_webdriver(20) == webdriver
def get_tz_code() -> str: """Get the timezone code used by chromedriver.""" # Optional deps from selenium.common.exceptions import NoSuchElementException from altair_saver import SeleniumSaver html = """<html><body><div id="vis"></div></body></html>""" script = "arguments[0](Intl.DateTimeFormat().resolvedOptions().timeZone)" url = SeleniumSaver._serve(html, {}) driver_name = SeleniumSaver._select_webdriver(20) driver = SeleniumSaver._registry.get(driver_name, 20) driver.get("about:blank") driver.get(url) try: driver.find_element_by_id("vis") except NoSuchElementException: raise RuntimeError(f"Could not load {url}") return driver.execute_async_script(script)
def test_scale_factor(spec: JSONDict, fmt: str, kwds: Dict[str, Any]) -> None: saver1 = SeleniumSaver(spec) out1 = saver1.save(fmt=fmt) saver2 = SeleniumSaver(spec, **kwds) out2 = saver2.save(fmt=fmt) if fmt == "png": assert isinstance(out1, bytes) im1 = Image.open(io.BytesIO(out1)) assert im1.format == "PNG" assert isinstance(out2, bytes) im2 = Image.open(io.BytesIO(out2)) assert im2.format == "PNG" assert im2.size[0] == 2 * im1.size[0] assert im2.size[1] == 2 * im1.size[1] else: assert isinstance(out1, str) im1 = _SVGImage(out1) assert isinstance(out2, str) im2 = _SVGImage(out2) assert im2.width == 2 * im1.width assert im2.height == 2 * im1.height
def test_stop_and_start(name: str, data: Dict[str, Any]) -> None: saver = SeleniumSaver(data["vega-lite"]) bundle1 = saver.mimebundle("png") saver._stop_serving() assert saver._provider is None bundle2 = saver.mimebundle("png") assert bundle1 == bundle2
def test_enabled(monkeypatch: MonkeyPatch, enabled: bool) -> None: monkeypatch.setattr( SeleniumSaver, "_select_webdriver", lambda d: object() if enabled else None ) assert SeleniumSaver.enabled() is enabled