"""
A module containing testing utilities and fixtures.
"""
import os
import re
import shutil
import tempfile
import pytest
from contextlib import contextmanager
from bokeh.document import Document
from bokeh.client import pull_session
from pyviz_comms import Comm
from panel import config
from panel.pane import HTML, Markdown
from panel.io import state
from panel import serve
@pytest.fixture
def document():
return Document()
@pytest.fixture
def comm():
return Comm()
@pytest.fixture
def dataframe():
import pandas as pd
return pd.DataFrame({
'int': [1, 2, 3],
'float': [3.14, 6.28, 9.42],
'str': ['A', 'B', 'C']
}, index=[1, 2, 3], columns=['int', 'float', 'str'])
@pytest.fixture
def hv_bokeh():
import holoviews as hv
hv.renderer('bokeh')
prev_backend = hv.Store.current_backend
hv.Store.current_backend = 'bokeh'
yield
hv.Store.current_backend = prev_backend
@pytest.fixture
def get_display_handle():
cleanup = []
def display_handle(model):
cleanup.append(model.ref['id'])
handle = {}
state._handles[model.ref['id']] = (handle, [])
return handle
yield display_handle
for ref in cleanup:
if ref in state._handles:
del state._handles[ref]
@pytest.fixture
def hv_mpl():
import holoviews as hv
hv.renderer('matplotlib')
prev_backend = hv.Store.current_backend
hv.Store.current_backend = 'matplotlib'
yield
hv.Store.current_backend = prev_backend
@pytest.fixture
def tmpdir(request, tmpdir_factory):
name = request.node.name
name = re.sub(r"[\W]", "_", name)
MAXVAL = 30
if len(name) > MAXVAL:
name = name[:MAXVAL]
tmp_dir = tmpdir_factory.mktemp(name, numbered=True)
yield tmp_dir
shutil.rmtree(str(tmp_dir))
@pytest.fixture()
def html_server_session():
html = HTML('
Title
')
server = serve(html, port=6000, show=False, start=False)
session = pull_session(
session_id='Test',
url="http://localhost:{:d}/".format(server.port),
io_loop=server.io_loop
)
yield html, server, session
try:
server.stop()
except AssertionError:
pass # tests may already close this
@pytest.fixture()
def markdown_server_session():
html = Markdown('#Title')
server = serve(html, port=6001, show=False, start=False)
session = pull_session(
session_id='Test',
url="http://localhost:{:d}/".format(server.port),
io_loop=server.io_loop
)
yield html, server, session
try:
server.stop()
except AssertionError:
pass # tests may already close this
@pytest.fixture
def multiple_apps_server_sessions():
"""Serve multiple apps and yield a factory to allow
parameterizing the slugs and the titles."""
servers = []
def create_sessions(slugs, titles):
app1_slug, app2_slug = slugs
apps = {
app1_slug: Markdown('First app'),
app2_slug: Markdown('Second app')
}
server = serve(apps, port=5008, title=titles, show=False, start=False)
servers.append(server)
session1 = pull_session(
url=f"http://localhost:{server.port:d}/app1",
io_loop=server.io_loop
)
session2 = pull_session(
url=f"http://localhost:{server.port:d}/app2",
io_loop=server.io_loop
)
return session1, session2
yield create_sessions
for server in servers:
try:
server.stop()
except AssertionError:
continue # tests may already close this
@pytest.fixture
def with_curdoc():
old_curdoc = state.curdoc
state.curdoc = Document()
try:
yield
finally:
state.curdoc = old_curdoc
@contextmanager
def set_env_var(env_var, value):
old_value = os.environ.get(env_var)
os.environ[env_var] = value
yield
if old_value is None:
del os.environ[env_var]
else:
os.environ[env_var] = old_value
@pytest.fixture(autouse=True)
def server_cleanup():
"""
Clean up after test fails
"""
try:
yield
finally:
state.kill_all_servers()
state._indicators.clear()
state._locations.clear()
state._curdoc = None
state.cache.clear()
state._scheduled.clear()
if state._thread_pool is not None:
state._thread_pool.shutdown(wait=False)
state._thread_pool = None
@pytest.fixture
def py_file():
tf = tempfile.NamedTemporaryFile(mode='w', suffix='.py')
try:
yield tf
finally:
tf.close()
@pytest.fixture
def threads():
config.nthreads = 4
try:
yield 4
finally:
config.nthreads = None