Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make a default global location for custom user templates #1028

Merged
merged 13 commits into from
Jul 28, 2019
48 changes: 46 additions & 2 deletions docs/source/customizing.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,44 @@
"!jupyter nbconvert --to python 'example.ipynb' --stdout --template=simplepython.tpl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Saving Custom Templates\n",
"\n",
"By default, nbconvert finds templates from a few locations.\n",
"\n",
"The recommended place to save custom templates, so that they are globally accessible to nbconvert, is your jupyter configuration directory:\n",
"\n",
"- ~./jupyter\n",
" - nbconvert\n",
" - templates\n",
" - html\n",
" - latex\n",
"\n",
"The HTML and LaTeX/PDF exporters will search the html and latex subdirectories for templates, respectively.\n",
"\n",
"To find your jupyter configuration directory you can use:\n",
"\n",
"```python\n",
"from jupyter_core.paths import jupyter_config_dir\n",
"print(jupyter_config_dir())\n",
"```\n",
"\n",
"Additionally,\n",
"\n",
"```python\n",
"TemplateExporter.template_path=['.']\n",
"```\n",
"\n",
"defines an additional list of paths that nbconvert can look for user defined templates. It defaults to searching for custom templates in the current working directory and can be changed through configuration options.\n",
"\n",
"### Packaging Custom Templates\n",
"\n",
"nbconvert will, by default, search the paths given by ```jupyter_core.paths.jupyter_path('nbconvert','templates')``` for additional templates. The HTML and LaTeX/PDF exporters will search html and latex subdirectories for templates respectively, just like from the configuration directory. These are the recommended locations to save nbconvert templates too when shipping a python package. nbconvert does not by default store any templates there."
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -376,7 +414,13 @@
"source": [
"### A few gotchas\n",
"\n",
"Jinja blocks use `{% %}` by default which does not play nicely with LaTeX, so those are replaced by `((* *))` in LaTeX templates."
"Jinja uses `%`, `{`, and `}` for syntax by default which does not play nicely with LaTeX. In LaTeX, we have the following replacements:\n",
"\n",
"| Syntax | Default | LaTeX |\n",
"|----------|---------|---------|\n",
"| block | {% %} | ((* *)) |\n",
"| variable | {{ }} | ((( ))) |\n",
"| comment | {# #} | ((= =)) |"
]
},
{
Expand Down Expand Up @@ -24921,7 +24965,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.1"
"version": "3.6.8"
}
},
"nbformat": 4,
Expand Down
9 changes: 9 additions & 0 deletions nbconvert/exporters/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from traitlets import default, Unicode
from traitlets.config import Config
from jupyter_core.paths import jupyter_config_dir, jupyter_path
from jinja2 import contextfilter

from nbconvert.filters.highlight import Highlight2HTML
Expand Down Expand Up @@ -35,6 +36,14 @@ def _file_extension_default(self):
@default('default_template_path')
def _default_template_path_default(self):
return os.path.join("..", "templates", "html")

@default('user_config_template_path')
def _user_config_template_path_default(self):
return os.path.join(jupyter_config_dir(), "nbconvert", "templates", "html")

@default('template_data_paths')
def _template_data_paths_default(self):
return jupyter_path("nbconvert", "templates", "html")

@default('template_file')
def _template_file_default(self):
Expand Down
9 changes: 9 additions & 0 deletions nbconvert/exporters/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from traitlets import Unicode, default
from traitlets.config import Config
from jupyter_core.paths import jupyter_config_dir, jupyter_path

from nbconvert.filters.highlight import Highlight2Latex
from nbconvert.filters.filter_links import resolve_references
Expand Down Expand Up @@ -39,6 +40,14 @@ def _default_template_path_default(self):
@default('template_skeleton_path')
def _template_skeleton_path_default(self):
return os.path.join("..", "templates", "latex", "skeleton")

@default('user_config_template_path')
def _user_config_template_path_default(self):
return os.path.join(jupyter_config_dir(), "nbconvert", "templates", "latex")

@default('template_data_paths')
def _template_data_paths_default(self):
return jupyter_path("nbconvert", "templates", "latex")

#Extension that the template files use.
template_extension = Unicode(".tplx").tag(config=True)
Expand Down
20 changes: 20 additions & 0 deletions nbconvert/exporters/templateexporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from traitlets.config import Config
from traitlets.utils.importstring import import_item
from ipython_genutils import py3compat
from jupyter_core.paths import jupyter_config_dir, jupyter_path
from jupyter_core.utils import ensure_dir_exists
from jinja2 import (
TemplateNotFound, Environment, ChoiceLoader, FileSystemLoader, BaseLoader,
DictLoader
Expand Down Expand Up @@ -184,6 +186,16 @@ def _raw_template_changed(self, change):
help="Path where the template skeleton files are located.",
).tag(affects_environment=True)

user_config_template_path = Unicode(
os.path.join(jupyter_config_dir(), "nbconvert","templates"),
help="Path where users can save templates."
).tag(affects_environment=True)

template_data_paths = List(
jupyter_path('nbconvert','templates'),
help="Path where templates can be installed too."
).tag(affects_environment=True)

#Extension that the template files use.
template_extension = Unicode(".tpl").tag(config=True, affects_environment=True)

Expand Down Expand Up @@ -391,7 +403,15 @@ def _create_environment(self):
"""
here = os.path.dirname(os.path.realpath(__file__))

additional_paths = [self.user_config_template_path]+self.template_data_paths
for path in additional_paths:
try:
ensure_dir_exists(path, mode=0o700)
except OSError:
pass

paths = self.template_path + \
additional_paths + \
[os.path.join(here, self.default_template_path),
os.path.join(here, self.template_skeleton_path)]

Expand Down