Source code for jyquickhelper.jspy.render_nb_js

# -*- coding: utf-8 -*-
"""
Helpers around JSON


:githublink:`%|py|6`
"""
import uuid
import os
import shutil
import urllib.request as liburl
import urllib.error as liberror
from IPython.display import display_html, display_javascript


[docs]class UrlNotFoundError(Exception): """ Raised when a url does not exist. :githublink:`%|py|17` """
[docs] def __init__(self, url, code): Exception.__init__( self, "Url not found: returned code={0} for '{1}'".format(code, url))
[docs]class JavascriptScriptError(ValueError): """ Raised when the class does not find what it expects. :githublink:`%|py|27` """ pass
[docs]def check_url(url): "Checks urls." try: liburl.urlopen(url) return True except liberror.HTTPError as e: raise UrlNotFoundError(url, e.code) from e except liberror.URLError as e: raise UrlNotFoundError(url, e.reason) from e except Exception as e: raise Exception("Issue with url '{0}'".format(url)) from e
[docs]class RenderJSRaw: """ Adds :epkg:`javascript` into a noteboook. :githublink:`%|py|47` """
[docs] def __init__(self, script, width="100%", height="100%", divid=None, css=None, libs=None, style=None, only_html=False, div_class=None, check_urls=True, local=False): """ :param script: (str) script :param width: (str) width :param height: (str) height :param style: (str) style (added in ``<style>...</style>``) :param divid: (str|None) id of the div :param css: (list) list of css :param libs: (list) list of dependencies :param only_html: (bool) use only function `display_html <http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html? highlight=display_html#IPython.display.display_html>`_ and not `display_javascript <http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html? highlight=display_html#IPython.display.display_javascript>`_ to add javascript to the page. :param div_class: (str) class of the section ``div`` which will host the results of the javascript :param check_urls: (bool) by default, check url exists :param local: (bool|False) use local javascript files :githublink:`%|py|71` """ self.script = script self.uuid = divid if divid else "M" + \ str(uuid.uuid4()).replace("-", "") if style is None: style = '' if width is not None and 'width' not in style: style += "width:{0};".format(width) if height is not None and 'height' not in style: style += "height:{0};".format(height) if not style: style = None else: if width is not None and 'width' not in style: style += "width:{0};".format(width) if height is not None and 'height' not in style: style += "height:{0};".format(height) self.style = style self.only_html = only_html self.div_class = div_class if "__ID__" not in script: raise JavascriptScriptError( "The sript does not contain any string __ID__. It is replaced by the ID value in script:\n{0}".format(script)) self.local = local self.css, self.libs = self._copy_local(css, libs, local) if check_urls and not local: if self.css is not None: for c in self.css: check_url(c) if self.libs is not None: for lib in self.libs: if isinstance(lib, dict): check_url(lib['path']) else: check_url(lib)
[docs] def _copy_local(self, css, libs, local): """ If *self.local*, copies javascript dependencies in the local folder. :param css: list of css :param libs: list of libraries :param local: boolean or new location :return: tuple (css, libs) :githublink:`%|py|115` """ if not self.local: return css, libs to_copy = [] if css: to_copy.extend(css) if libs: for js in libs: if isinstance(js, dict): to_copy.append(js['path']) else: to_copy.append(js) for js in to_copy: if not os.path.exists(js): raise FileNotFoundError("Unable to find '{0}'".format(js)) dest = local if isinstance(local, str) else os.getcwd() shutil.copy(js, dest) if css: css = [os.path.split(c)[-1] for c in css] if libs: def proc(d): "proc" if isinstance(d, dict): d = d.copy() d['path'] = os.path.split(d['path'])[-1] return d else: return os.path.split(d)[-1] libs = [proc(c) for c in libs] return css, libs
[docs] def generate_html(self): """ Overloads method `_ipython_display_ <http://ipython.readthedocs.io/en/stable/config/integrating.html?highlight=Integrating%20>`_. :return: `HTML <http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html#IPython.display.HTML>`_ text, `Javascript <http://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html#IPython.display.Javascript>`_ text :githublink:`%|py|155` """ if self.style: style = ' style="{0}"'.format(self.style) else: style = "" if self.div_class: divcl = ' class="{0}"'.format(self.div_class) else: divcl = "" if self.css: css = "".join( '<link rel="stylesheet" href="{0}" type="text/css" />'.format(c) for c in self.css) ht = '<div id="{uuid}-css">{css}<div{divcl} id="{uuid}"{style}></div></div>'.format( uuid=self.uuid, css=css, style=style, divcl=divcl) else: ht = '<div id="{uuid}-cont"><div{divcl} id="{uuid}"{style}></div></div>'.format( uuid=self.uuid, style=style, divcl=divcl) script = self.script.replace("__ID__", self.uuid) if self.libs: names = [] paths = [] shims = {} args = [] exports = [] for lib in self.libs: if isinstance(lib, dict): name = lib.get("name", None) if "path" in lib: p = lib["path"] if name is None: name = ".".join((p.split("/")[-1]).split(".")[:-1]) path = ".".join(p.split(".")[:-1]) paths.append((name, path)) else: raise KeyError( "unable to find 'path' in {0}".format(lib)) names.append(name) args.append(name) if "exports" in lib: if name not in shims: shims[name] = {} shims[name]["exports"] = lib["exports"] if isinstance(lib["exports"], list): exports.extend(lib["exports"]) else: exports.append(lib["exports"]) if "deps" in lib: if name not in shims: shims[name] = {} shims[name]["deps"] = lib["deps"] else: names.append(lib) if len(names) == 0: raise ValueError( "names is empty.\nlibs={0}\npaths={1}\nshims={2}\nexports={3}".format( self.libs, paths, shims, exports)) require = ",".join("'{0}'".format(na) for na in names) config = ["require.config({"] if len(paths) > 0: config.append("paths:{") for name, path in paths: config.append("'{0}':'{1}',".format(name, path)) config.append("},") if len(shims) > 0: config.append("shim:{") def vd(d): "vd" rows = [] for k, v in sorted(d.items()): rows.append("'{0}':{1}".format( k, v if isinstance(v, list) else "'{0}'".format(v))) return "{%s}" % ",".join(rows) for k, v in sorted(shims.items()): config.append("'{0}':{1},".format(k, vd(v))) config.append("},") config.append("});") if len(config) > 2: prefix = "\n".join(config) + "\n" else: prefix = "" js = prefix + \ """\nrequire([%s], function(%s) { %s });\n""" % ( require, ",".join(args), script) else: js = script if self.only_html: ht += "\n<script>\n%s\n</script>" % js return ht, None return ht, js
[docs]class RenderJSObj(RenderJSRaw): """ Renders JS using :epkg:`javascript`. :githublink:`%|py|252` """
[docs] def _ipython_display_(self): """ overloads method `_ipython_display_ <http://ipython.readthedocs.io/en/stable/config/integrating.html?highlight=Integrating%20>`_. :githublink:`%|py|258` """ ht, js = self.generate_html() if js is None: display_html(ht, raw=True) else: display_html(ht, raw=True) display_javascript(js, raw=True)
[docs]class RenderJS(RenderJSRaw): """ Renders :epkg:`javascript`, only outputs :epkg:`HTML`. :githublink:`%|py|270` """
[docs] def _repr_html_(self): """ Overloads method *_repr_html_*. :githublink:`%|py|275` """ ht, js = self.generate_html() if js is not None: ht += "\n<script>\n{0}\n</script>\n".format(js) return ht