Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for passing in parameter instances as streams #3616

Merged
merged 2 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions holoviews/streams.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,30 +166,42 @@ def trigger(cls, streams):
def _on_trigger(self):
"""Called when a stream has been triggered"""


@classmethod
def _process_streams(cls, streams):
"""
Processes a list of streams promoting Parameterized objects and
methods to Param based streams.
"""
param_watch_support = util.param_version >= '1.8.0'
parameterizeds = [s.parameterized for s in streams if isinstance(s, Params)]
parameterizeds = defaultdict(set)
valid, invalid = [], []
for s in streams:
if not isinstance(s, Stream):
if isinstance(s, param.Parameterized) and param_watch_support:
if s not in parameterizeds:
s = Params(s)
else:
continue
elif util.is_param_method(s) and param_watch_support:
if not hasattr(s, "_dinfo") or util.get_method_owner(s) in parameterizeds:
continue
else:
s = ParamMethod(s)
else:
invalid.append(s)
if isinstance(s, Stream):
pass
elif isinstance(s, param.Parameter):
s = Params(s.owner, [s.name])
elif isinstance(s, param.Parameterized):
s = Params(s)
elif util.is_param_method(s):
if not hasattr(s, "_dinfo"):
continue
s = ParamMethod(s)
else:
invalid.append(s)
continue
if isinstance(s, Params):
pid = id(s.parameterized)
overlap = (set(s.parameters) & parameterizeds[pid])
if overlap:
pname = type(s.parameterized).__name__
param.main.param.warning(
'The %s parameter(s) on the %s object have '
'already been supplied in another stream. '
'Ensure that the supplied streams only specify '
'each parameter once, otherwise multiple '
'events will be triggered when the parameter '
'changes.' % (sorted(overlap), pname))
parameterizeds[pid] |= set(s.parameters)
valid.append(s)
return valid, invalid

Expand Down
43 changes: 39 additions & 4 deletions holoviews/tests/teststreams.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from holoviews.streams import * # noqa (Test all available streams)
from holoviews.util import Dynamic

from .utils import LoggingComparisonTestCase


def test_all_stream_parameters_constant():
all_stream_cls = [v for v in globals().values() if
isinstance(v, type) and issubclass(v, Stream)]
Expand Down Expand Up @@ -178,12 +181,9 @@ def test_class_value_update(self):



class TestParamsStream(ComparisonTestCase):
class TestParamsStream(LoggingComparisonTestCase):

def setUp(self):
if LooseVersion(param.__version__) < '1.8.0':
raise SkipTest('Params stream requires param >= 1.8.0')

class Inner(param.Parameterized):

x = param.Number(default = 0)
Expand Down Expand Up @@ -223,6 +223,41 @@ def subscriber(**kwargs):
inner.y = 2
self.assertEqual(values, [{'x': 2, 'y': 2}])

def test_param_stream_instance_separate_parameters(self):
inner = self.inner()

xparam = Params(inner, ['x'])
yparam = Params(inner, ['y'])

valid, invalid = Stream._process_streams([xparam, yparam])
self.assertEqual(len(valid), 2)
self.assertEqual(len(invalid), 0)

def test_param_stream_instance_overlapping_parameters(self):
inner = self.inner()

params1 = Params(inner)
params2 = Params(inner)

Stream._process_streams([params1, params2])
self.log_handler.assertContains('WARNING', "['x', 'y']")

def test_param_parameter_instance_separate_parameters(self):
inner = self.inner()

valid, invalid = Stream._process_streams([inner.param.x, inner.param.y])
xparam, yparam = valid

self.assertIs(xparam.parameterized, inner)
self.assertEqual(xparam.parameters, ['x'])
self.assertIs(yparam.parameterized, inner)
self.assertEqual(yparam.parameters, ['y'])

def test_param_parameter_instance_overlapping_parameters(self):
inner = self.inner()
Stream._process_streams([inner.param.x, inner.param.x])
self.log_handler.assertContains('WARNING', "['x']")

def test_param_stream_parameter_override(self):
inner = self.inner(x=2)
stream = Params(inner, parameters=['x'])
Expand Down