sphinx.py
287 lines
| 10.4 KiB
| text/x-python
|
PythonLexer
Jonathan Frederic
|
r10436 | """Module that allows custom Sphinx parameters to be set on the notebook and | ||
Jonathan Frederic
|
r9772 | on the 'other' object passed into Jinja. | ||
""" | ||||
Jonathan Frederic
|
r10436 | #----------------------------------------------------------------------------- | ||
# 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 | ||||
Jonathan Frederic
|
r9772 | |||
Jonathan Frederic
|
r10436 | # Stdlib imports | ||
Jonathan Frederic
|
r9772 | # 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 | ||||
Jonathan Frederic
|
r10436 | # Third-party imports | ||
Jonathan Frederic
|
r9780 | # Needed for Pygments latex definitions. | ||
from pygments.formatters import LatexFormatter | ||||
Jonathan Frederic
|
r10436 | # Our own imports | ||
# Configurable traitlets | ||||
from IPython.utils.traitlets import Unicode, Bool | ||||
Jonathan Frederic
|
r9772 | # Needed to override transformer | ||
Jonathan Frederic
|
r10436 | from .transformers import (ActivatableTransformer) #TODO | ||
Jonathan Frederic
|
r9772 | |||
Jonathan Frederic
|
r10436 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
Jonathan Frederic
|
r9775 | class SphinxTransformer(ActivatableTransformer): | ||
Jonathan Frederic
|
r9772 | """ | ||
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, | ||||
Jonathan Frederic
|
r9936 | the author, version, release, date, and chapter_style traits should | ||
Jonathan Frederic
|
r9772 | 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" | ||||
""") | ||||
Jonathan Frederic
|
r9936 | publish_date = Unicode("", config=True, help="""Publish date | ||
Jonathan Frederic
|
r9772 | 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" | ||||
""") | ||||
Jonathan Frederic
|
r9936 | chapter_style = Unicode("Bjarne", config=True, help="""Sphinx chapter style | ||
Jonathan Frederic
|
r9772 | 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) | ||||
""") | ||||
Jonathan Frederic
|
r10037 | output_style = Unicode("notebook", config=True, help="""Nbconvert Ipython | ||
Jonathan Frederic
|
r9939 | notebook input/output formatting style. | ||
You may choose one of the following: | ||||
Jonathan Frederic
|
r10037 | "simple (recommended for long code segments)" | ||
"notebook" (default) | ||||
Jonathan Frederic
|
r9939 | """) | ||
Jonathan Frederic
|
r9949 | center_output = Bool(False, config=True, help=""" | ||
Optional attempt to center all output. If this is false, no additional | ||||
formatting is applied. | ||||
Jonathan Frederic
|
r9951 | """) | ||
Jonathan Frederic
|
r9949 | |||
use_headers = Bool(True, config=True, help=""" | ||||
Whether not a header should be added to the document. | ||||
Jonathan Frederic
|
r9951 | """) | ||
Jonathan Frederic
|
r9949 | |||
Jonathan Frederic
|
r10174 | overridetitle = Unicode("", config=True, help="") | ||
Jonathan Frederic
|
r9772 | def __call__(self, nb, other): | ||
""" | ||||
Jonathan Frederic
|
r9775 | Entry | ||
Jonathan Frederic
|
r9772 | Since we are not interested in any additional manipulation on a cell | ||
by cell basis, we do not call the base implementation. | ||||
Jonathan Frederic
|
r9939 | """ | ||
Jonathan Frederic
|
r9775 | if self.enabled: | ||
Jonathan Frederic
|
r9778 | return self.transform(nb, other) | ||
Matthias BUSSONNIER
|
r9807 | else: | ||
return nb,other | ||||
Jonathan Frederic
|
r9772 | |||
Jonathan Frederic
|
r9778 | def transform(self, nb, other): | ||
Jonathan Frederic
|
r9775 | """ | ||
Sphinx transformation to apply on each notebook. | ||||
""" | ||||
Jonathan Frederic
|
r9918 | |||
# 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. | ||||
Jonathan Frederic
|
r9923 | if not "_draft" in nb.metadata: | ||
nb.metadata._draft = {} | ||||
Jonathan Frederic
|
r9937 | |||
if not "sphinx" in other: | ||||
other["sphinx"] = {} | ||||
Jonathan Frederic
|
r9918 | |||
Jonathan Frederic
|
r9772 | if self.interactive: | ||
# Prompt the user for additional meta data that doesn't exist currently | ||||
# but would be usefull for Sphinx. | ||||
Jonathan Frederic
|
r9918 | 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() | ||||
Jonathan Frederic
|
r9772 | |||
# Prompt the user for the document style. | ||||
Jonathan Frederic
|
r9937 | other["sphinx"]["chapterstyle"] = self._prompt_chapter_title_style() | ||
Jonathan Frederic
|
r9939 | other["sphinx"]["outputstyle"] = self._prompt_output_style() | ||
Jonathan Frederic
|
r9949 | |||
# 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) | ||||
Jonathan Frederic
|
r9772 | else: | ||
# Try to use the traitlets. | ||||
Jonathan Frederic
|
r9918 | nb.metadata._draft["author"] = self.author | ||
nb.metadata._draft["version"] = self.version | ||||
nb.metadata._draft["release"] = self.release | ||||
Jonathan Frederic
|
r9772 | |||
Jonathan Frederic
|
r9949 | # Use todays date if none is provided. | ||
Jonathan Frederic
|
r9936 | if len(self.publish_date.strip()) == 0: | ||
Jonathan Frederic
|
r9918 | nb.metadata._draft["date"] = date.today().strftime("%B %-d, %Y") | ||
Jonathan Frederic
|
r9772 | else: | ||
Jonathan Frederic
|
r9936 | nb.metadata._draft["date"] = self.publish_date | ||
Jonathan Frederic
|
r9949 | |||
# Sphinx traitlets. | ||||
Jonathan Frederic
|
r9937 | other["sphinx"]["chapterstyle"] = self.chapter_style | ||
Jonathan Frederic
|
r9939 | other["sphinx"]["outputstyle"] = self.output_style | ||
Jonathan Frederic
|
r9949 | other["sphinx"]["centeroutput"] = self.center_output | ||
other["sphinx"]["header"] = self.use_headers | ||||
Jonathan Frederic
|
r9772 | |||
# Find and pass in the path to the Sphinx dependencies. | ||||
Jonathan Frederic
|
r9937 | other["sphinx"]["texinputs"] = os.path.abspath(sphinx.__file__ + "/../texinputs") | ||
Jonathan Frederic
|
r9772 | |||
Jonathan Frederic
|
r9780 | # Generate Pygments definitions for Latex | ||
Jonathan Frederic
|
r9937 | other["sphinx"]["pygment_definitions"] = self._generate_pygments_latex_def() | ||
Jonathan Frederic
|
r9780 | |||
Jonathan Frederic
|
r10174 | if not (self.overridetitle == None or len(self.overridetitle.strip()) == 0): | ||
nb.metadata.name = self.overridetitle | ||||
Jonathan Frederic
|
r9772 | # End | ||
Jonathan Frederic
|
r9780 | return nb, other | ||
def _generate_pygments_latex_def(self): | ||||
return LatexFormatter().get_style_defs() | ||||
Jonathan Frederic
|
r9772 | |||
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 | ||||
Jonathan Frederic
|
r9949 | def _prompt_boolean(self, prompt, default=False): | ||
response = self._input(prompt) | ||||
response = response.strip().lower() | ||||
#Catch 1, true, yes as True | ||||
Jonathan Frederic
|
r10038 | if len(response) > 0 and (response == "1" or response[0] == "t" or response[0] == "y"): | ||
Jonathan Frederic
|
r9949 | return True | ||
#Catch 0, false, no as False | ||||
Jonathan Frederic
|
r10038 | elif len(response) > 0 and (response == "0" or response[0] == "f" or response[0] == "n"): | ||
Jonathan Frederic
|
r9949 | return False | ||
else: | ||||
Jonathan Frederic
|
r10038 | return default | ||
Jonathan Frederic
|
r9949 | |||
Jonathan Frederic
|
r9939 | 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. | ||||
Jonathan Frederic
|
r10037 | comments = {1: "(recommended for long code segments)", | ||
2: "(default)"} | ||||
Jonathan Frederic
|
r9939 | |||
Jonathan Frederic
|
r10037 | return self._prompt_dictionary(styles, default_style=2, menu_comments=comments) | ||
Jonathan Frederic
|
r9939 | |||
Jonathan Frederic
|
r9772 | def _prompt_chapter_title_style(self): | ||
# Dictionary of available Sphinx styles | ||||
styles = {1: "Bjarne", | ||||
2: "Lenny", | ||||
3: "Glenn", | ||||
4: "Conny", | ||||
5: "Rejne", | ||||
6: "Sonny"} | ||||
Jonathan Frederic
|
r9938 | #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={}): | ||||
Jonathan Frederic
|
r9772 | # Build the menu that will be displayed to the user with | ||
# all of the options available. | ||||
Jonathan Frederic
|
r9938 | prompt = "" | ||
for key, value in choices.iteritems(): | ||||
prompt += "%d %s " % (key, value) | ||||
if key in menu_comments: | ||||
prompt += menu_comments[key] | ||||
prompt += "\n" | ||||
Jonathan Frederic
|
r9772 | |||
# Continue to ask the user for a style until an appropriate | ||||
# one is specified. | ||||
response = -1 | ||||
Jonathan Frederic
|
r9938 | while (not response in choices): | ||
Jonathan Frederic
|
r9772 | try: | ||
Jonathan Frederic
|
r9938 | text_response = self._input(prompt) | ||
Jonathan Frederic
|
r9772 | |||
# Use default option if no input. | ||||
if len(text_response.strip()) == 0: | ||||
Jonathan Frederic
|
r9938 | response = default_style | ||
Jonathan Frederic
|
r9772 | else: | ||
response = int(text_response) | ||||
except: | ||||
Jonathan Frederic
|
r9938 | print("Error: Value is not an available option. 0 selects the default.\n") | ||
return choices[response] | ||||
Jonathan Frederic
|
r9772 | |||
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) | ||||