-
-
Notifications
You must be signed in to change notification settings - Fork 394
/
__init__.py
273 lines (215 loc) · 10.2 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import os
from unittest import SkipTest
import param
from IPython.core.completer import IPCompleter
from IPython.display import HTML, publish_display_data
from param import ipython as param_ext
import holoviews as hv
from ..core.dimension import LabelledData
from ..core.options import Store
from ..core.tree import AttrTree
from ..element.comparison import ComparisonTestCase
from ..plotting.renderer import Renderer
from ..util import extension
from .display_hooks import display, png_display, pprint_display, svg_display
from .magics import load_magics
AttrTree._disabled_prefixes = ['_repr_','_ipython_canary_method_should_not_exist']
def show_traceback():
"""
Display the full traceback after an abbreviated traceback has occurred.
"""
from .display_hooks import FULL_TRACEBACK
print(FULL_TRACEBACK)
class IPTestCase(ComparisonTestCase):
"""
This class extends ComparisonTestCase to handle IPython specific
objects and support the execution of cells and magic.
"""
def setUp(self):
super().setUp()
try:
import IPython
from IPython.display import HTML, SVG
self.ip = IPython.InteractiveShell()
if self.ip is None:
raise TypeError()
except Exception as e:
raise SkipTest("IPython could not be started") from e
self.ip.displayhook.flush = lambda: None # To avoid gc.collect called in it
self.addTypeEqualityFunc(HTML, self.skip_comparison)
self.addTypeEqualityFunc(SVG, self.skip_comparison)
def skip_comparison(self, obj1, obj2, msg): pass
def get_object(self, name):
obj = self.ip._object_find(name).obj
if obj is None:
raise self.failureException(f"Could not find object {name}")
return obj
def cell(self, line):
"Run an IPython cell"
self.ip.run_cell(line, silent=True)
def cell_magic(self, *args, **kwargs):
"Run an IPython cell magic"
self.ip.run_cell_magic(*args, **kwargs)
def line_magic(self, *args, **kwargs):
"Run an IPython line magic"
self.ip.run_line_magic(*args, **kwargs)
class notebook_extension(extension):
"""
Notebook specific extension to hv.extension that offers options for
controlling the notebook environment.
"""
css = param.String(default='', doc="Optional CSS rule set to apply to the notebook.")
logo = param.Boolean(default=True, doc="Toggles display of HoloViews logo")
inline = param.Boolean(default=False, doc="""
Whether to inline JS and CSS resources.
If disabled, resources are loaded from CDN if one is available.""")
width = param.Number(default=None, bounds=(0, 100), doc="""
Width of the notebook as a percentage of the browser screen window width.""")
display_formats = param.List(default=['html'], doc="""
A list of formats that are rendered to the notebook where
multiple formats may be selected at once (although only one
format will be displayed).
Although the 'html' format is supported across backends, other
formats supported by the current backend (e.g. 'png' and 'svg'
using the matplotlib backend) may be used. This may be useful to
export figures to other formats such as PDF with nbconvert.""")
allow_jedi_completion = param.Boolean(default=True, doc="""
Whether to allow jedi tab-completion to be enabled in IPython.
Disabled by default because many HoloViews features rely on
tab-completion machinery not supported when using jedi.""")
case_sensitive_completion = param.Boolean(default=False, doc="""
Whether to monkey patch IPython to use the correct tab-completion
behavior. """)
enable_mathjax = param.Boolean(default=False, doc="""
Whether to load bokeh-mathjax bundle in the notebook.""")
_loaded = False
def __call__(self, *args, **params):
comms = params.pop('comms', None)
super().__call__(*args, **params)
# Abort if IPython not found
try:
ip = params.pop('ip', None) or get_ipython() # noqa (get_ipython)
except Exception:
return
# Notebook archive relies on display hooks being set to work.
try:
import nbformat # noqa: F401
try:
from .archive import notebook_archive
hv.archive = notebook_archive
except AttributeError as e:
if str(e) != "module 'tornado.web' has no attribute 'asynchronous'":
raise
except ImportError:
pass
# Not quite right, should be set when switching backends
if 'matplotlib' in Store.renderers and not notebook_extension._loaded:
svg_exporter = Store.renderers['matplotlib'].instance(holomap=None,fig='svg')
hv.archive.exporters = [svg_exporter] + hv.archive.exporters
p = param.ParamOverrides(self, {k:v for k,v in params.items() if k!='config'})
if p.case_sensitive_completion:
from IPython.core import completer
completer.completions_sorting_key = self.completions_sorting_key
if not p.allow_jedi_completion and hasattr(IPCompleter, 'use_jedi'):
ip.run_line_magic('config', 'IPCompleter.use_jedi = False')
resources = self._get_resources(args, params)
Store.display_formats = p.display_formats
if 'html' not in p.display_formats and len(p.display_formats) > 1:
msg = ('Output magic unable to control displayed format '
'as IPython notebook uses fixed precedence '
f'between {p.display_formats!r}')
display(HTML(f'<b>Warning</b>: {msg}'))
loaded = notebook_extension._loaded
if loaded == False:
param_ext.load_ipython_extension(ip, verbose=False)
load_magics(ip)
Store.output_settings.initialize(list(Store.renderers.keys()))
Store.set_display_hook('html+js', LabelledData, pprint_display)
Store.set_display_hook('png', LabelledData, png_display)
Store.set_display_hook('svg', LabelledData, svg_display)
notebook_extension._loaded = True
css = ''
if p.width is not None:
css += f'<style>div.container {{ width: {p.width}% }}</style>'
if p.css:
css += f'<style>{p.css}</style>'
if css:
display(HTML(css))
resources = list(resources)
if len(resources) == 0: return
from panel import config, extension as panel_extension
if hasattr(config, 'comms') and comms:
config.comms = comms
same_cell_execution = published = getattr(self, '_repeat_execution_in_cell', False)
for r in [r for r in resources if r != 'holoviews']:
Store.renderers[r].load_nb(inline=p.inline)
Renderer.load_nb(inline=p.inline, reloading=same_cell_execution, enable_mathjax=p.enable_mathjax)
if not published and hasattr(panel_extension, "_display_globals"):
panel_extension._display_globals()
if hasattr(ip, 'kernel') and not loaded:
Renderer.comm_manager.get_client_comm(notebook_extension._process_comm_msg,
"hv-extension-comm")
# Create a message for the logo (if shown)
if not same_cell_execution and p.logo:
self.load_logo(logo=p.logo,
bokeh_logo= p.logo and ('bokeh' in resources),
mpl_logo= p.logo and (('matplotlib' in resources)
or resources==['holoviews']),
plotly_logo= p.logo and ('plotly' in resources))
@classmethod
def completions_sorting_key(cls, word):
"Fixed version of IPyton.completer.completions_sorting_key"
prio1, prio2 = 0, 0
if word.startswith('__'): prio1 = 2
elif word.startswith('_'): prio1 = 1
if word.endswith('='): prio1 = -1
if word.startswith('%%'):
if '%' not in word[2:]:
word, prio2 = word[2:], 2
elif word.startswith('%'):
if '%' not in word[1:]:
word, prio2 = word[1:], 1
return prio1, word, prio2
def _get_resources(self, args, params):
"""
Finds the list of resources from the keyword parameters and pops
them out of the params dictionary.
"""
resources = []
disabled = []
for resource in ['holoviews'] + list(Store.renderers.keys()):
if resource in args:
resources.append(resource)
if resource in params:
setting = params.pop(resource)
if setting is True and resource != 'matplotlib':
if resource not in resources:
resources.append(resource)
if setting is False:
disabled.append(resource)
unmatched_args = set(args) - set(resources)
if unmatched_args:
display(HTML("<b>Warning:</b> Unrecognized resources '{}'".format("', '".join(unmatched_args))))
resources = [r for r in resources if r not in disabled]
if ('holoviews' not in disabled) and ('holoviews' not in resources):
resources = ['holoviews'] + resources
return resources
@classmethod
def load_logo(cls, logo=False, bokeh_logo=False, mpl_logo=False, plotly_logo=False):
"""
Allow to display Holoviews' logo and the plotting extensions' logo.
"""
import jinja2
templateLoader = jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
jinjaEnv = jinja2.Environment(loader=templateLoader)
template = jinjaEnv.get_template('load_notebook.html')
html = template.render({'logo': logo,
'bokeh_logo': bokeh_logo,
'mpl_logo': mpl_logo,
'plotly_logo': plotly_logo})
publish_display_data(data={'text/html': html})
notebook_extension.add_delete_action(Renderer._delete_plot)
def load_ipython_extension(ip):
notebook_extension(ip=ip)
def unload_ipython_extension(ip):
notebook_extension._loaded = False