##// END OF EJS Templates
Add the unlink method to javascript links to maintain compatibility with traitlet links
Jason Grout -
Show More
@@ -1,54 +1,61 b''
1 """Link and DirectionalLink classes.
1 """Link and DirectionalLink classes.
2
2
3 Represents a button in the frontend using a widget. Allows user to listen for
3 Propagate changes between widgets on the javascript side
4 click events on the button and trigger backend code when the clicks are fired.
5 """
4 """
6 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
7 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2014, the IPython Development Team.
8 #
7 #
9 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
10 #
9 #
11 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
12 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
13
12
14 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
15 # Imports
14 # Imports
16 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
17 from .widget import Widget
16 from .widget import Widget
18 from IPython.utils.traitlets import Unicode, Tuple, Any
17 from IPython.utils.traitlets import Unicode, Tuple, Any
19
18
20 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
21 # Classes
20 # Classes
22 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
23
22
24
23
25 class Link(Widget):
24 class Link(Widget):
26 """Link Widget"""
25 """Link Widget"""
27 _model_name = Unicode('LinkModel', sync=True)
26 _model_name = Unicode('LinkModel', sync=True)
28 widgets = Tuple(sync=True, allow_none=False)
27 widgets = Tuple(sync=True, allow_none=False)
29
28
30 def __init__(self, widgets=(), **kwargs):
29 def __init__(self, widgets=(), **kwargs):
31 kwargs['widgets'] = widgets
30 kwargs['widgets'] = widgets
32 super(Link, self).__init__(**kwargs)
31 super(Link, self).__init__(**kwargs)
33
32
33 # for compatibility with traitlet links
34 def unlink(self):
35 self.close()
36
34
37
35 def link(*args):
38 def link(*args):
36 return Link(widgets=args)
39 return Link(widgets=args)
37
40
38
41
39 class DirectionalLink(Widget):
42 class DirectionalLink(Widget):
40 """Directional Link Widget"""
43 """Directional Link Widget"""
41 _model_name = Unicode('DirectionalLinkModel', sync=True)
44 _model_name = Unicode('DirectionalLinkModel', sync=True)
42 targets = Any(sync=True)
45 targets = Any(sync=True)
43 source = Tuple(sync=True)
46 source = Tuple(sync=True)
44
47
45 # Does not quite behave like other widgets but reproduces
48 # Does not quite behave like other widgets but reproduces
46 # the behavior of IPython.utils.traitlets.directional_link
49 # the behavior of IPython.utils.traitlets.directional_link
47 def __init__(self, source, targets=(), **kwargs):
50 def __init__(self, source, targets=(), **kwargs):
48 kwargs['source'] = source
51 kwargs['source'] = source
49 kwargs['targets'] = targets
52 kwargs['targets'] = targets
50 super(DirectionalLink, self).__init__(**kwargs)
53 super(DirectionalLink, self).__init__(**kwargs)
51
54
55 # for compatibility with traitlet links
56 def unlink(self):
57 self.close()
58
52
59
53 def dlink(source, *targets):
60 def dlink(source, *targets):
54 return DirectionalLink(source, targets)
61 return DirectionalLink(source, targets)
@@ -1,376 +1,383 b''
1 {
1 {
2 "cells": [
2 "cells": [
3 {
3 {
4 "cell_type": "markdown",
4 "cell_type": "markdown",
5 "metadata": {},
5 "metadata": {},
6 "source": [
6 "source": [
7 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
7 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
8 ]
8 ]
9 },
9 },
10 {
10 {
11 "cell_type": "markdown",
11 "cell_type": "markdown",
12 "metadata": {
12 "metadata": {
13 "slideshow": {
13 "slideshow": {
14 "slide_type": "slide"
14 "slide_type": "slide"
15 }
15 }
16 },
16 },
17 "source": [
17 "source": [
18 "# Widget Events"
18 "# Widget Events"
19 ]
19 ]
20 },
20 },
21 {
21 {
22 "cell_type": "markdown",
22 "cell_type": "markdown",
23 "metadata": {},
23 "metadata": {},
24 "source": [
24 "source": [
25 "## Special events"
25 "## Special events"
26 ]
26 ]
27 },
27 },
28 {
28 {
29 "cell_type": "code",
29 "cell_type": "code",
30 "execution_count": null,
30 "execution_count": null,
31 "metadata": {
31 "metadata": {
32 "collapsed": false
32 "collapsed": false
33 },
33 },
34 "outputs": [],
34 "outputs": [],
35 "source": [
35 "source": [
36 "from __future__ import print_function"
36 "from __future__ import print_function"
37 ]
37 ]
38 },
38 },
39 {
39 {
40 "cell_type": "markdown",
40 "cell_type": "markdown",
41 "metadata": {},
41 "metadata": {},
42 "source": [
42 "source": [
43 "The `Button` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `Button` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
43 "The `Button` is not used to represent a data type. Instead the button widget is used to **handle mouse clicks**. The **`on_click` method** of the `Button` can be used to register function to be called when the button is clicked. The doc string of the `on_click` can be seen below."
44 ]
44 ]
45 },
45 },
46 {
46 {
47 "cell_type": "code",
47 "cell_type": "code",
48 "execution_count": null,
48 "execution_count": null,
49 "metadata": {
49 "metadata": {
50 "collapsed": false
50 "collapsed": false
51 },
51 },
52 "outputs": [],
52 "outputs": [],
53 "source": [
53 "source": [
54 "from IPython.html import widgets\n",
54 "from IPython.html import widgets\n",
55 "print(widgets.Button.on_click.__doc__)"
55 "print(widgets.Button.on_click.__doc__)"
56 ]
56 ]
57 },
57 },
58 {
58 {
59 "cell_type": "markdown",
59 "cell_type": "markdown",
60 "metadata": {
60 "metadata": {
61 "slideshow": {
61 "slideshow": {
62 "slide_type": "slide"
62 "slide_type": "slide"
63 }
63 }
64 },
64 },
65 "source": [
65 "source": [
66 "### Example"
66 "### Example"
67 ]
67 ]
68 },
68 },
69 {
69 {
70 "cell_type": "markdown",
70 "cell_type": "markdown",
71 "metadata": {},
71 "metadata": {},
72 "source": [
72 "source": [
73 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
73 "Since button clicks are **stateless**, they are **transmitted from the front-end to the back-end using custom messages**. By using the `on_click` method, a button that prints a message when it has been clicked is shown below."
74 ]
74 ]
75 },
75 },
76 {
76 {
77 "cell_type": "code",
77 "cell_type": "code",
78 "execution_count": null,
78 "execution_count": null,
79 "metadata": {
79 "metadata": {
80 "collapsed": false
80 "collapsed": false
81 },
81 },
82 "outputs": [],
82 "outputs": [],
83 "source": [
83 "source": [
84 "from IPython.display import display\n",
84 "from IPython.display import display\n",
85 "button = widgets.Button(description=\"Click Me!\")\n",
85 "button = widgets.Button(description=\"Click Me!\")\n",
86 "display(button)\n",
86 "display(button)\n",
87 "\n",
87 "\n",
88 "def on_button_clicked(b):\n",
88 "def on_button_clicked(b):\n",
89 " print(\"Button clicked.\")\n",
89 " print(\"Button clicked.\")\n",
90 "\n",
90 "\n",
91 "button.on_click(on_button_clicked)"
91 "button.on_click(on_button_clicked)"
92 ]
92 ]
93 },
93 },
94 {
94 {
95 "cell_type": "markdown",
95 "cell_type": "markdown",
96 "metadata": {
96 "metadata": {
97 "slideshow": {
97 "slideshow": {
98 "slide_type": "slide"
98 "slide_type": "slide"
99 }
99 }
100 },
100 },
101 "source": [
101 "source": [
102 "### on_sumbit"
102 "### on_sumbit"
103 ]
103 ]
104 },
104 },
105 {
105 {
106 "cell_type": "markdown",
106 "cell_type": "markdown",
107 "metadata": {},
107 "metadata": {},
108 "source": [
108 "source": [
109 "The **`Text`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
109 "The **`Text`** also has a special **`on_submit` event**. The `on_submit` event **fires when the user hits return**."
110 ]
110 ]
111 },
111 },
112 {
112 {
113 "cell_type": "code",
113 "cell_type": "code",
114 "execution_count": null,
114 "execution_count": null,
115 "metadata": {
115 "metadata": {
116 "collapsed": false
116 "collapsed": false
117 },
117 },
118 "outputs": [],
118 "outputs": [],
119 "source": [
119 "source": [
120 "text = widgets.Text()\n",
120 "text = widgets.Text()\n",
121 "display(text)\n",
121 "display(text)\n",
122 "\n",
122 "\n",
123 "def handle_submit(sender):\n",
123 "def handle_submit(sender):\n",
124 " print(text.value)\n",
124 " print(text.value)\n",
125 "\n",
125 "\n",
126 "text.on_submit(handle_submit)"
126 "text.on_submit(handle_submit)"
127 ]
127 ]
128 },
128 },
129 {
129 {
130 "cell_type": "markdown",
130 "cell_type": "markdown",
131 "metadata": {
131 "metadata": {
132 "slideshow": {
132 "slideshow": {
133 "slide_type": "slide"
133 "slide_type": "slide"
134 }
134 }
135 },
135 },
136 "source": [
136 "source": [
137 "## Traitlet events"
137 "## Traitlet events"
138 ]
138 ]
139 },
139 },
140 {
140 {
141 "cell_type": "markdown",
141 "cell_type": "markdown",
142 "metadata": {},
142 "metadata": {},
143 "source": [
143 "source": [
144 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
144 "**Widget properties are IPython traitlets** and **traitlets are eventful**. To handle changes, the **`on_trait_change` method** of the widget can be used to **register a callback**. The doc string for `on_trait_change` can be seen below."
145 ]
145 ]
146 },
146 },
147 {
147 {
148 "cell_type": "code",
148 "cell_type": "code",
149 "execution_count": null,
149 "execution_count": null,
150 "metadata": {
150 "metadata": {
151 "collapsed": false
151 "collapsed": false
152 },
152 },
153 "outputs": [],
153 "outputs": [],
154 "source": [
154 "source": [
155 "print(widgets.Widget.on_trait_change.__doc__)"
155 "print(widgets.Widget.on_trait_change.__doc__)"
156 ]
156 ]
157 },
157 },
158 {
158 {
159 "cell_type": "markdown",
159 "cell_type": "markdown",
160 "metadata": {
160 "metadata": {
161 "slideshow": {
161 "slideshow": {
162 "slide_type": "slide"
162 "slide_type": "slide"
163 }
163 }
164 },
164 },
165 "source": [
165 "source": [
166 "### Signatures"
166 "### Signatures"
167 ]
167 ]
168 },
168 },
169 {
169 {
170 "cell_type": "markdown",
170 "cell_type": "markdown",
171 "metadata": {},
171 "metadata": {},
172 "source": [
172 "source": [
173 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
173 "Mentioned in the doc string, the callback registered can have **4 possible signatures**:\n",
174 "\n",
174 "\n",
175 "- callback()\n",
175 "- callback()\n",
176 "- callback(trait_name)\n",
176 "- callback(trait_name)\n",
177 "- callback(trait_name, new_value)\n",
177 "- callback(trait_name, new_value)\n",
178 "- callback(trait_name, old_value, new_value)\n",
178 "- callback(trait_name, old_value, new_value)\n",
179 "\n",
179 "\n",
180 "Using this method, an example of how to output an `IntSlider`'s value as it is changed can be seen below."
180 "Using this method, an example of how to output an `IntSlider`'s value as it is changed can be seen below."
181 ]
181 ]
182 },
182 },
183 {
183 {
184 "cell_type": "code",
184 "cell_type": "code",
185 "execution_count": null,
185 "execution_count": null,
186 "metadata": {
186 "metadata": {
187 "collapsed": false
187 "collapsed": false
188 },
188 },
189 "outputs": [],
189 "outputs": [],
190 "source": [
190 "source": [
191 "int_range = widgets.IntSlider()\n",
191 "int_range = widgets.IntSlider()\n",
192 "display(int_range)\n",
192 "display(int_range)\n",
193 "\n",
193 "\n",
194 "def on_value_change(name, value):\n",
194 "def on_value_change(name, value):\n",
195 " print(value)\n",
195 " print(value)\n",
196 "\n",
196 "\n",
197 "int_range.on_trait_change(on_value_change, 'value')"
197 "int_range.on_trait_change(on_value_change, 'value')"
198 ]
198 ]
199 },
199 },
200 {
200 {
201 "cell_type": "markdown",
201 "cell_type": "markdown",
202 "metadata": {},
202 "metadata": {},
203 "source": [
203 "source": [
204 "# Linking Widgets"
204 "# Linking Widgets"
205 ]
205 ]
206 },
206 },
207 {
207 {
208 "cell_type": "markdown",
208 "cell_type": "markdown",
209 "metadata": {},
209 "metadata": {},
210 "source": [
210 "source": [
211 "Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. \n",
211 "Often, you may want to simply link widget attributes together. Synchronization of attributes can be done in a simpler way than by using bare traitlets events. \n",
212 "\n",
212 "\n",
213 "The first method is to use the `link` and `directional_link` functions from the `traitlets` module. "
213 "The first method is to use the `link` and `directional_link` functions from the `traitlets` module. "
214 ]
214 ]
215 },
215 },
216 {
216 {
217 "cell_type": "markdown",
217 "cell_type": "markdown",
218 "metadata": {},
218 "metadata": {},
219 "source": [
219 "source": [
220 "## Linking traitlets attributes from the server side"
220 "## Linking traitlets attributes from the server side"
221 ]
221 ]
222 },
222 },
223 {
223 {
224 "cell_type": "code",
224 "cell_type": "code",
225 "execution_count": null,
225 "execution_count": null,
226 "metadata": {
226 "metadata": {
227 "collapsed": false
227 "collapsed": false
228 },
228 },
229 "outputs": [],
229 "outputs": [],
230 "source": [
230 "source": [
231 "from IPython.utils import traitlets"
231 "from IPython.utils import traitlets"
232 ]
232 ]
233 },
233 },
234 {
234 {
235 "cell_type": "code",
235 "cell_type": "code",
236 "execution_count": null,
236 "execution_count": null,
237 "metadata": {
237 "metadata": {
238 "collapsed": false
238 "collapsed": false
239 },
239 },
240 "outputs": [],
240 "outputs": [],
241 "source": [
241 "source": [
242 "caption = widgets.Latex(value = 'The values of slider1, slider2 and slider3 are synchronized')\n",
242 "caption = widgets.Latex(value = 'The values of slider1, slider2 and slider3 are synchronized')\n",
243 "sliders1, slider2, slider3 = widgets.IntSlider(description='Slider 1'),\\\n",
243 "sliders1, slider2, slider3 = widgets.IntSlider(description='Slider 1'),\\\n",
244 " widgets.IntSlider(description='Slider 2'),\\\n",
244 " widgets.IntSlider(description='Slider 2'),\\\n",
245 " widgets.IntSlider(description='Slider 3')\n",
245 " widgets.IntSlider(description='Slider 3')\n",
246 "l = traitlets.link((sliders1, 'value'), (slider2, 'value'), (slider3, 'value'))\n",
246 "l = traitlets.link((sliders1, 'value'), (slider2, 'value'), (slider3, 'value'))\n",
247 "display(caption, sliders1, slider2, slider3)"
247 "display(caption, sliders1, slider2, slider3)"
248 ]
248 ]
249 },
249 },
250 {
250 {
251 "cell_type": "code",
251 "cell_type": "code",
252 "execution_count": null,
252 "execution_count": null,
253 "metadata": {
253 "metadata": {
254 "collapsed": false
254 "collapsed": false
255 },
255 },
256 "outputs": [],
256 "outputs": [],
257 "source": [
257 "source": [
258 "caption = widgets.Latex(value = 'Changes in source values are reflected in target1 and target2')\n",
258 "caption = widgets.Latex(value = 'Changes in source values are reflected in target1 and target2')\n",
259 "source, target1, target2 = widgets.IntSlider(description='Source'),\\\n",
259 "source, target1, target2 = widgets.IntSlider(description='Source'),\\\n",
260 " widgets.IntSlider(description='Target 1'),\\\n",
260 " widgets.IntSlider(description='Target 1'),\\\n",
261 " widgets.IntSlider(description='Target 2')\n",
261 " widgets.IntSlider(description='Target 2')\n",
262 "traitlets.dlink((source, 'value'), (target1, 'value'), (target2, 'value'))\n",
262 "traitlets.dlink((source, 'value'), (target1, 'value'), (target2, 'value'))\n",
263 "display(caption, source, target1, target2)"
263 "display(caption, source, target1, target2)"
264 ]
264 ]
265 },
265 },
266 {
266 {
267 "cell_type": "markdown",
267 "cell_type": "markdown",
268 "metadata": {},
268 "metadata": {},
269 "source": [
269 "source": [
270 "Function `traitlets.link` returns a `Link` object. The link can be broken by calling the `unlink` method."
270 "Function `traitlets.link` returns a `Link` object. The link can be broken by calling the `unlink` method."
271 ]
271 ]
272 },
272 },
273 {
273 {
274 "cell_type": "code",
274 "cell_type": "code",
275 "execution_count": null,
275 "execution_count": null,
276 "metadata": {
276 "metadata": {
277 "collapsed": false
277 "collapsed": false
278 },
278 },
279 "outputs": [],
279 "outputs": [],
280 "source": [
280 "source": [
281 "# l.unlink()"
281 "# l.unlink()"
282 ]
282 ]
283 },
283 },
284 {
284 {
285 "cell_type": "markdown",
285 "cell_type": "markdown",
286 "metadata": {},
286 "metadata": {},
287 "source": [
287 "source": [
288 "## Linking widgets attributes from the client side"
288 "## Linking widgets attributes from the client side"
289 ]
289 ]
290 },
290 },
291 {
291 {
292 "cell_type": "markdown",
292 "cell_type": "markdown",
293 "metadata": {},
293 "metadata": {},
294 "source": [
294 "source": [
295 "When synchronizing traitlets attributes, you may experience a lag because of the latency dues to the rountrip to the server side. You can also directly link widgets attributes, either in a unidirectional or a bidirectional fashion using the link widgets. "
295 "When synchronizing traitlets attributes, you may experience a lag because of the latency dues to the rountrip to the server side. You can also directly link widgets attributes, either in a unidirectional or a bidirectional fashion using the link widgets. "
296 ]
296 ]
297 },
297 },
298 {
298 {
299 "cell_type": "code",
299 "cell_type": "code",
300 "execution_count": null,
300 "execution_count": null,
301 "metadata": {
301 "metadata": {
302 "collapsed": false
302 "collapsed": false
303 },
303 },
304 "outputs": [],
304 "outputs": [],
305 "source": [
305 "source": [
306 "caption = widgets.Latex(value = 'The values of range1, range2 and range3 are synchronized')\n",
306 "caption = widgets.Latex(value = 'The values of range1, range2 and range3 are synchronized')\n",
307 "range1, range2, range3 = widgets.IntSlider(description='Range 1'),\\\n",
307 "range1, range2, range3 = widgets.IntSlider(description='Range 1'),\\\n",
308 " widgets.IntSlider(description='Range 2'),\\\n",
308 " widgets.IntSlider(description='Range 2'),\\\n",
309 " widgets.IntSlider(description='Range 3')\n",
309 " widgets.IntSlider(description='Range 3')\n",
310 "l = widgets.link((range1, 'value'), (range2, 'value'), (range3, 'value'))\n",
310 "l = widgets.link((range1, 'value'), (range2, 'value'), (range3, 'value'))\n",
311 "display(caption, range1, range2, range3)"
311 "display(caption, range1, range2, range3)"
312 ]
312 ]
313 },
313 },
314 {
314 {
315 "cell_type": "code",
315 "cell_type": "code",
316 "execution_count": null,
316 "execution_count": null,
317 "metadata": {
317 "metadata": {
318 "collapsed": false
318 "collapsed": false
319 },
319 },
320 "outputs": [],
320 "outputs": [],
321 "source": [
321 "source": [
322 "caption = widgets.Latex(value = 'Changes in source_range values are reflected in target_range1 and target_range2')\n",
322 "caption = widgets.Latex(value = 'Changes in source_range values are reflected in target_range1 and target_range2')\n",
323 "source_range, target_range1, target_range2 = widgets.IntSlider(description='Source range'),\\\n",
323 "source_range, target_range1, target_range2 = widgets.IntSlider(description='Source range'),\\\n",
324 " widgets.IntSlider(description='Target range 1'),\\\n",
324 " widgets.IntSlider(description='Target range 1'),\\\n",
325 " widgets.IntSlider(description='Target range 2')\n",
325 " widgets.IntSlider(description='Target range 2')\n",
326 "widgets.dlink((source_range, 'value'), (target_range1, 'value'), (target_range2, 'value'))\n",
326 "widgets.dlink((source_range, 'value'), (target_range1, 'value'), (target_range2, 'value'))\n",
327 "display(caption, source_range, target_range1, target_range2)"
327 "display(caption, source_range, target_range1, target_range2)"
328 ]
328 ]
329 },
329 },
330 {
330 {
331 "cell_type": "markdown",
331 "cell_type": "markdown",
332 "metadata": {},
332 "metadata": {},
333 "source": [
333 "source": [
334 "Function `widgets.link` returns a `Link` widget. The link can be broken by calling the `close` method."
334 "Function `widgets.link` returns a `Link` widget. The link can be broken by calling the `unlink` method."
335 ]
335 ]
336 },
336 },
337 {
337 {
338 "cell_type": "code",
338 "cell_type": "code",
339 "execution_count": null,
339 "execution_count": null,
340 "metadata": {
340 "metadata": {
341 "collapsed": false
341 "collapsed": false
342 },
342 },
343 "outputs": [],
343 "outputs": [],
344 "source": [
344 "source": [
345 "# l.close()"
345 "# l.unlink()"
346 ]
346 ]
347 },
347 },
348 {
348 {
349 "cell_type": "markdown",
349 "cell_type": "markdown",
350 "metadata": {},
350 "metadata": {},
351 "source": [
351 "source": [
352 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
352 "[Index](Index.ipynb) - [Back](Widget List.ipynb) - [Next](Widget Styling.ipynb)"
353 ]
353 ]
354 }
354 }
355 ],
355 ],
356 "metadata": {
356 "metadata": {
357 "cell_tags": [
357 "cell_tags": [
358 [
358 [
359 "<None>",
359 "<None>",
360 null
360 null
361 ]
361 ]
362 ],
362 ],
363 "kernelspec": {
363 "kernelspec": {
364 "display_name": "Python 2",
365 "name": "python2"
366 },
367 "language_info": {
364 "codemirror_mode": {
368 "codemirror_mode": {
365 "name": "python",
369 "name": "ipython",
366 "version": 2
370 "version": 2
367 },
371 },
368 "display_name": "Python 2",
372 "file_extension": ".py",
369 "language": "python",
373 "mimetype": "text/x-python",
370 "name": "python2"
374 "name": "python",
375 "nbconvert_exporter": "python",
376 "pygments_lexer": "ipython2",
377 "version": "2.7.8"
371 },
378 },
372 "signature": "sha256:05a3e92089b37f68e3134587ffef6ef73830e5f8b3c515ba24640d7c803820c3"
379 "signature": "sha256:b6eadc174d0d9c1907518d9f37760eb3dca3aec0ef1f3746e6f0537a36e99919"
373 },
380 },
374 "nbformat": 4,
381 "nbformat": 4,
375 "nbformat_minor": 0
382 "nbformat_minor": 0
376 } No newline at end of file
383 }
General Comments 0
You need to be logged in to leave comments. Login now