##// END OF EJS Templates
Post code-review, extended refactor.
Post code-review, extended refactor.

File last commit:

r10485:1de3574b
r10485:1de3574b
Show More
sphinx.py
287 lines | 10.4 KiB | text/x-python | PythonLexer
"""Module that allows custom Sphinx parameters to be set on the notebook and
on the 'other' object passed into Jinja.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2013, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function, absolute_import
# Stdlib imports
# Used to find Sphinx package location
import sphinx
import os.path
# Used to determine python version
import sys
# Used to set the default date to today's date
from datetime import date
# Third-party imports
# Needed for Pygments latex definitions.
from pygments.formatters import LatexFormatter
# Our own imports
# Configurable traitlets
from IPython.utils.traitlets import Unicode, Bool
# Needed to override transformer
from .transformers import (ActivatableTransformer) #TODO
#-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
class SphinxTransformer(ActivatableTransformer):
"""
Sphinx utility transformer.
This transformer is used to set variables needed by the latex to build
Sphinx stylized templates.
"""
interactive = Bool(True, config=True, help="""
Allows you to define whether or not the Sphinx exporter will prompt
you for input during the conversion process. If this is set to false,
the author, version, release, date, and chapter_style traits should
be set.
""")
author = Unicode("Unknown Author", config=True, help="Author name")
version = Unicode("", config=True, help="""Version number
You can leave this blank if you do not want to render a version number.
Example: "1.0.0"
""")
release = Unicode("", config=True, help="""Release name
You can leave this blank if you do not want to render a release name.
Example: "Rough Draft"
""")
publish_date = Unicode("", config=True, help="""Publish date
This is the date to render on the document as the publish date.
Leave this blank to default to todays date.
Example: "June 12, 1990"
""")
chapter_style = Unicode("Bjarne", config=True, help="""Sphinx chapter style
This is the style to use for the chapter headers in the document.
You may choose one of the following:
"Bjarne" (default)
"Lenny"
"Glenn"
"Conny"
"Rejne"
"Sonny" (used for international documents)
""")
output_style = Unicode("notebook", config=True, help="""Nbconvert Ipython
notebook input/output formatting style.
You may choose one of the following:
"simple (recommended for long code segments)"
"notebook" (default)
""")
center_output = Bool(False, config=True, help="""
Optional attempt to center all output. If this is false, no additional
formatting is applied.
""")
use_headers = Bool(True, config=True, help="""
Whether not a header should be added to the document.
""")
overridetitle = Unicode("", config=True, help="")
def __call__(self, nb, other):
"""
Entry
Since we are not interested in any additional manipulation on a cell
by cell basis, we do not call the base implementation.
"""
if self.enabled:
return self.transform(nb, other)
else:
return nb,other
def transform(self, nb, other):
"""
Sphinx transformation to apply on each notebook.
"""
# TODO: Add versatile method of additional notebook metadata. Include
# handling of multiple files. For now use a temporay namespace,
# '_draft' to signify that this needs to change.
if not "_draft" in nb.metadata:
nb.metadata._draft = {}
if not "sphinx" in other:
other["sphinx"] = {}
if self.interactive:
# Prompt the user for additional meta data that doesn't exist currently
# but would be usefull for Sphinx.
nb.metadata._draft["author"] = self._prompt_author()
nb.metadata._draft["version"] = self._prompt_version()
nb.metadata._draft["release"] = self._prompt_release()
nb.metadata._draft["date"] = self._prompt_date()
# Prompt the user for the document style.
other["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style()
other["sphinx"]["outputstyle"] = self._prompt_output_style()
# Small options
other["sphinx"]["centeroutput"] = self._prompt_boolean("Do you want to center the output? (false)", False)
other["sphinx"]["header"] = self._prompt_boolean("Should a Sphinx document header be used? (true)", True)
else:
# Try to use the traitlets.
nb.metadata._draft["author"] = self.author
nb.metadata._draft["version"] = self.version
nb.metadata._draft["release"] = self.release
# Use todays date if none is provided.
if len(self.publish_date.strip()) == 0:
nb.metadata._draft["date"] = date.today().strftime("%B %-d, %Y")
else:
nb.metadata._draft["date"] = self.publish_date
# Sphinx traitlets.
other["sphinx"]["chapterstyle"] = self.chapter_style
other["sphinx"]["outputstyle"] = self.output_style
other["sphinx"]["centeroutput"] = self.center_output
other["sphinx"]["header"] = self.use_headers
# Find and pass in the path to the Sphinx dependencies.
other["sphinx"]["texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs")
# Generate Pygments definitions for Latex
other["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def()
if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0):
nb.metadata.name = self.overridetitle
# End
return nb, other
def _generate_pygments_latex_def(self):
return LatexFormatter().get_style_defs()
def _prompt_author(self):
return self._input("Author name: ")
def _prompt_version(self):
return self._input("Version (ie ""1.0.0""): ")
def _prompt_release(self):
return self._input("Release Name (ie ""Rough draft""): ")
def _prompt_date(self):
default_date = date.today().strftime("%B %-d, %Y")
user_date = self._input("Date (deafults to \"" + default_date + "\"): ")
if len(user_date.strip()) == 0:
user_date = default_date
return user_date
def _prompt_boolean(self, prompt, default=False):
response = self._input(prompt)
response = response.strip().lower()
#Catch 1, true, yes as True
if len(response) > 0 and (response == "1" or response[0] == "t" or response[0] == "y"):
return True
#Catch 0, false, no as False
elif len(response) > 0 and (response == "0" or response[0] == "f" or response[0] == "n"):
return False
else:
return default
def _prompt_output_style(self):
# Dictionary of available output styles
styles = {1: "simple",
2: "notebook"}
#Append comments to the menu when displaying it to the user.
comments = {1: "(recommended for long code segments)",
2: "(default)"}
return self._prompt_dictionary(styles, default_style=2, menu_comments=comments)
def _prompt_chapter_title_style(self):
# Dictionary of available Sphinx styles
styles = {1: "Bjarne",
2: "Lenny",
3: "Glenn",
4: "Conny",
5: "Rejne",
6: "Sonny"}
#Append comments to the menu when displaying it to the user.
comments = {1: "(default)",
6: "(for international documents)"}
return self._prompt_dictionary(styles, menu_comments=comments)
def _prompt_dictionary(self, choices, default_style=1, menu_comments={}):
# Build the menu that will be displayed to the user with
# all of the options available.
prompt = ""
for key, value in choices.iteritems():
prompt += "%d %s " % (key, value)
if key in menu_comments:
prompt += menu_comments[key]
prompt += "\n"
# Continue to ask the user for a style until an appropriate
# one is specified.
response = -1
while (not response in choices):
try:
text_response = self._input(prompt)
# Use default option if no input.
if len(text_response.strip()) == 0:
response = default_style
else:
response = int(text_response)
except:
print("Error: Value is not an available option. 0 selects the default.\n")
return choices[response]
def _input(self, prompt_text):
"""
Prompt the user for input.
The input command will change depending on the version of python
installed. To maintain support for 2 and earlier, we must use
raw_input in that case. Else use input.
"""
# Try to get the python version. This command is only available in
# python 2 and later, so it's important that we catch the exception
# if the command isn't found.
try:
majorversion = sys.version_info[0]
except:
majorversion = 1
# Use the correct function to prompt the user for input depending on
# what python version the code is running in.
if majorversion >= 3:
return input(prompt_text)
else:
return raw_input(prompt_text)