Skip to content
This repository has been archived by the owner on Nov 29, 2019. It is now read-only.

Fix param.Action (#9). #32

Merged
merged 5 commits into from
Dec 19, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 4 additions & 4 deletions examples/user_guide/Bokeh_App.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@
"\n",
"import param\n",
"import datetime as dt\n",
"\n",
"def hello(x, **kwargs):\n",
" print(\"Hello %s\" % x)\n",
" \n",
"class Example(param.Parameterized):\n",
" \"\"\"An example Parameterized class\"\"\"\n",
" timestamps = []\n",
" \n",
" x = param.Parameter(default=3.14,doc=\"X position\")\n",
" y = param.Parameter(default=\"Not editable\",constant=True)\n",
" string_value = param.String(default=\"str\",doc=\"A string\")\n",
Expand All @@ -46,7 +45,8 @@
" int_list = param.ListSelector(default=[3,5], objects=[1,3,5,7,9],precedence=0.5)\n",
" single_file = param.FileSelector(path='../../*/*.py*',precedence=0.5)\n",
" multiple_files = param.MultiFileSelector(path='../../*/*.py?',precedence=0.5)\n",
" #msg = param.Action(hello, doc=\"\"\"Print a message.\"\"\",precedence=0.7)\n"
" record_timestamp = param.Action(lambda x: x.timestamps.append(dt.datetime.now()), \n",
" doc=\"\"\"Record timestamp.\"\"\",precedence=0.7)\n"
]
},
{
Expand Down
24 changes: 20 additions & 4 deletions examples/user_guide/Introduction.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@
"import param\n",
"import datetime as dt\n",
"\n",
"def hello(x, **kwargs):\n",
" print(\"Hello %s\" % x)\n",
" \n",
"class BaseClass(param.Parameterized):\n",
" x = param.Parameter(default=3.14,doc=\"X position\")\n",
" y = param.Parameter(default=\"Not editable\",constant=True)\n",
Expand All @@ -39,6 +36,8 @@
" \n",
"class Example(BaseClass):\n",
" \"\"\"An example Parameterized class\"\"\"\n",
" timestamps = []\n",
"\n",
" boolean = param.Boolean(True, doc=\"A sample Boolean parameter\")\n",
" color = param.Color(default='#FFFFFF')\n",
" date = param.Date(dt.datetime(2017, 1, 1),\n",
Expand All @@ -48,7 +47,8 @@
" int_list = param.ListSelector(default=[3,5], objects=[1,3,5,7,9],precedence=0.5)\n",
" single_file = param.FileSelector(path='../../*/*.py*',precedence=0.5)\n",
" multiple_files = param.MultiFileSelector(path='../../*/*.py?',precedence=0.5)\n",
" #msg = param.Action(hello, doc=\"\"\"Print a message.\"\"\",precedence=0.7)\n",
" record_timestamp = param.Action(lambda x: x.timestamps.append(dt.datetime.now()), \n",
" doc=\"\"\"Record timestamp.\"\"\",precedence=0.7)\n",
" \n",
"Example.num_int"
]
Expand Down Expand Up @@ -124,6 +124,22 @@
"Example.num_int"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Example.timestamps records the times you pressed the \"record timestamp\" button."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good example, thanks.

]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Example.timestamps"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down
14 changes: 9 additions & 5 deletions parambokeh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ def __call__(self, parameterized, doc=None, plots=[], **params):
def on_msg(self, msg):
p_name = msg['p_name']
p_obj = self.parameterized.params(p_name)
if isinstance(p_obj, param.Action):
getattr(self.parameterized, p_name)(self.parameterized)
return
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other widgets won't be refreshed - is that a problem? What if the callback alters another parameter value? (I decided not to get into this now, deferring it to 'dependencies between parameters and code'...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deferring it to 'dependencies between parameters and code'

+1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds fine.

w = self._widgets[p_name]
self._queue.append((w, p_obj, p_name, None, None, msg['value']))
self.change_event()
Expand Down Expand Up @@ -258,10 +261,6 @@ def _make_widget(self, p_name):
value = getattr(self.parameterized, p_name)

kw = dict(value=value)
if isinstance(p_obj, param.Action):
def action_cb(button):
getattr(self.parameterized, p_name)(self.parameterized)
kw['value'] = action_cb

kw['title'] = p_name

Expand Down Expand Up @@ -289,12 +288,17 @@ def action_cb(button):

if hasattr(p_obj, 'callbacks'):
p_obj.callbacks[id(self.parameterized)] = functools.partial(self._update_trait, p_name)
elif isinstance(w, (Button, Toggle)):
elif isinstance(w, Toggle):
if self.p.mode in ['server', 'raw']:
w.on_change('active', functools.partial(self.on_change, w, p_obj, p_name))
else:
js_callback = self._get_customjs('active', p_name)
w.js_on_change('active', js_callback)
elif isinstance(w, Button):
if self.p.mode in ['server', 'raw']:
w.on_click(functools.partial(value,self.parameterized))
else:
w.js_on_click(self._get_customjs('active', p_name))
elif not p_obj.constant:
if self.p.mode in ['server', 'raw']:
cb = functools.partial(self.on_change, w, p_obj, p_name)
Expand Down
4 changes: 4 additions & 0 deletions parambokeh/comms.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ def _handle_msg(self, msg):
with StandardOutput() as stdout:
self._on_msg(msg)
except Exception as e:
# TODO: isn't this cutting out info needed to understand what's gone wrong?
# Since it's only going to the js console, maybe we could just show everything
# (error = traceback.format_exc() or something like that)? Separately we do need a mechanism
# to report reasonable messages to users, though.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All true, if we can find a way to make tracebacks readable on the JS console I'd be very happy to change this (and port the change back to holoviews).

frame =traceback.extract_tb(sys.exc_info()[2])[-2]
fname,lineno,fn,text = frame
error_kwargs = dict(type=type(e).__name__, fn=fn, fname=fname,
Expand Down
6 changes: 2 additions & 4 deletions parambokeh/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ def ToggleWidget(*args, **kw):

def ButtonWidget(*args, **kw):
kw['label'] = kw.pop('title')
cb = kw.pop('value')
button = Button(*args, **kw)
button.on_click(cb)
return button
kw.pop('value') # button doesn't have value (value attached as click callback)
return Button(*args, **kw)

# TODO: make a composite box/slider widget; slider only appears if
# there's a range.
Expand Down