You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

83 lines
3.9 KiB

#############################################################################
# Copyright (c) 2018, Voila Contributors #
# Copyright (c) 2018, QuantStack #
# #
# Distributed under the terms of the BSD 3-Clause License. #
# #
# The full license is in the file LICENSE, distributed with this software. #
#############################################################################
import os
import json
from jupyter_core.paths import jupyter_path
ROOT = os.path.dirname(__file__)
STATIC_ROOT = os.path.join(ROOT, 'static')
# if the directory above us contains the following paths, it means we are installed in dev mode (pip install -e .)
DEV_MODE = os.path.exists(os.path.join(ROOT, '../setup.py')) and os.path.exists(os.path.join(ROOT, '../share'))
def collect_template_paths(
nbconvert_template_paths,
static_paths,
tornado_template_paths,
template_name='default'):
"""
Voila supports custom templates for rendering notebooks.
For a specified template name, `collect_template_paths` collects
- nbconvert template paths,
- static paths,
- tornado template paths,
by looking in the standard Jupyter data directories (PREFIX/share/jupyter/voila/templates)
with different prefix values (user directory, sys prefix, and then system prefix) which
allows users to override templates locally.
The function will recursively load the base templates upon which the specified template
may be based.
"""
# We look at the usual jupyter locations, and for development purposes also
# relative to the package directory (first entry, meaning with highest precedence)
search_directories = []
if DEV_MODE:
search_directories.append(os.path.abspath(os.path.join(ROOT, '..', 'share', 'jupyter', 'voila', 'templates')))
search_directories.extend(jupyter_path('voila', 'templates'))
found_at_least_one = False
for search_directory in search_directories:
template_directory = os.path.join(search_directory, template_name)
if os.path.exists(template_directory):
found_at_least_one = True
conf = {}
conf_file = os.path.join(template_directory, 'conf.json')
if os.path.exists(conf_file):
with open(conf_file) as f:
conf = json.load(f)
# For templates that are not named 'default', we assume the default base_template is 'default'
# that means that even the default template could have a base_template when explicitly given.
if template_name != 'default' or 'base_template' in conf:
collect_template_paths(
nbconvert_template_paths,
static_paths,
tornado_template_paths,
conf.get('base_template', 'default'))
extra_nbconvert_path = os.path.join(template_directory, 'nbconvert_templates')
nbconvert_template_paths.insert(0, extra_nbconvert_path)
extra_static_path = os.path.join(template_directory, 'static')
static_paths.insert(0, extra_static_path)
extra_template_path = os.path.join(template_directory, 'templates')
tornado_template_paths.insert(0, extra_template_path)
# We don't look at multiple directories, once a directory with a given name is found at a
# given level of precedence (for instance user directory), we don't look further (for instance
# in sys.prefix)
break
if not found_at_least_one:
paths = "\n\t".join(search_directories)
raise ValueError('No template sub-directory with name %r found in the following paths:\n\t%s' % (template_name, paths))