r"""
Sphinx build configuration
This file contains configuration needed to customize Sphinx input and output
behavior.
"""
import importlib
import os
import re
import sys
import dateutil.parser
from IPython.lib.lexers import IPyLexer, IPythonConsoleLexer
from sphinx import highlighting
from sphinx.ext import intersphinx
from sphinx.transforms import SphinxTransform
from sphinx.util.docutils import SphinxDirective
import sage.version
from sage.env import MATHJAX_DIR, PPLPY_DOCS, SAGE_DOC, SAGE_DOC_SRC
from sage.features.sphinx import JupyterSphinx
from sage.misc.latex_macros import sage_mathjax_macros
from sage.misc.sagedoc import extlinks as extlinks
from sage.misc.sagedoc_conf import *
SAGE_LIVE_DOC = os.environ.get('SAGE_LIVE_DOC', 'no')
SAGE_PREPARSED_DOC = os.environ.get('SAGE_PREPARSED_DOC', 'yes')
extensions = [
'sage_docbuild.ext.inventory_builder',
'sage_docbuild.ext.multidocs',
'sage_docbuild.ext.sage_autodoc',
'sphinx.ext.todo',
'sphinx.ext.extlinks',
'sphinx.ext.mathjax',
'sphinx.ext.linkcode',
'sphinx_copybutton',
'sphinx_inline_tabs',
'IPython.sphinxext.ipython_directive',
'matplotlib.sphinxext.plot_directive',
]
if JupyterSphinx().is_present():
extensions.append('jupyter_sphinx')
jupyter_execute_default_kernel = 'sagemath'
if SAGE_LIVE_DOC == 'yes':
JupyterSphinx().require()
SAGE_JUPYTER_SERVER = os.environ.get('SAGE_JUPYTER_SERVER', 'binder')
if SAGE_JUPYTER_SERVER.startswith('binder'):
if SAGE_JUPYTER_SERVER == 'binder':
binder_repo = "sagemath/sage-binder-env/master"
else:
binder_repo = SAGE_JUPYTER_SERVER[7:]
s = binder_repo.split('/', 2)
if len(s) > 2:
binder_options = {
'repo': s[0] + '/' + s[1],
'ref': s[2]
}
else:
binder_options = {
'repo': binder_repo
}
jupyter_sphinx_thebelab_config = {
'requestKernel': False,
'binderOptions': binder_options,
'kernelOptions': {
'name': "sagemath",
'kernelName': "sagemath",
'path': ".",
},
'selector': "div.live-doc"
}
else:
SAGE_JUPYTER_SERVER_TOKEN = os.environ.get('SAGE_JUPYTER_SERVER_TOKEN', 'secret')
jupyter_sphinx_thebelab_config = {
'requestKernel': False,
'kernelOptions': {
'name': "sagemath",
'kernelName': "sagemath",
'path': ".",
'serverSettings': {
'baseUrl': SAGE_JUPYTER_SERVER,
'token': SAGE_JUPYTER_SERVER_TOKEN
},
},
'selector': "div.live-doc"
}
jupyter_sphinx_thebelab_config.update({
'codeMirrorConfig': {
'lineNumbers': True,
}
})
plot_html_show_source_link = False
plot_pre_code = r"""
# Set locale to prevent having commas in decimal numbers
# in tachyon input (see https://github.com/sagemath/sage/issues/28971)
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
def sphinx_plot(graphics, **kwds):
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from sage.misc.temporary_file import tmp_filename
from sage.plot.graphics import _parse_figsize
if os.environ.get('SAGE_SKIP_PLOT_DIRECTIVE', 'no') != 'yes':
## Option handling is taken from Graphics.save
options = dict()
if isinstance(graphics, sage.plot.graphics.Graphics):
options.update(sage.plot.graphics.Graphics.SHOW_OPTIONS)
options.update(graphics._extra_kwds)
options.update(kwds)
elif isinstance(graphics, sage.plot.multigraphics.MultiGraphics):
options.update(kwds)
else:
graphics = graphics.plot(**kwds)
dpi = options.pop('dpi', None)
transparent = options.pop('transparent', None)
fig_tight = options.pop('fig_tight', None)
figsize = options.pop('figsize', None)
if figsize is not None:
figsize = _parse_figsize(figsize)
plt.figure(figsize=figsize)
figure = plt.gcf()
if isinstance(graphics, (sage.plot.graphics.Graphics,
sage.plot.multigraphics.MultiGraphics)):
graphics.matplotlib(figure=figure, figsize=figsize, **options)
if isinstance(graphics, (sage.plot.graphics.Graphics,
sage.plot.multigraphics.GraphicsArray)):
# for Graphics and GraphicsArray, tight_layout adjusts the
# *subplot* parameters so ticks aren't cut off, etc.
figure.tight_layout()
else:
# 3d graphics via png
import matplotlib as mpl
mpl.rcParams['image.interpolation'] = 'bilinear'
mpl.rcParams['image.resample'] = False
mpl.rcParams['figure.figsize'] = [8.0, 6.0]
mpl.rcParams['figure.dpi'] = 80
mpl.rcParams['savefig.dpi'] = 100
fn = tmp_filename(ext=".png")
graphics.save(fn)
img = mpimg.imread(fn)
plt.imshow(img)
plt.axis("off")
plt.margins(0)
if not isinstance(graphics, sage.plot.multigraphics.MultiGraphics):
plt.tight_layout(pad=0)
from sage.all_cmdline import *
"""
plot_html_show_formats = False
plot_formats = ['svg', 'pdf', 'png']
templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates'), 'templates']
master_doc = 'index'
project = ""
copyright = "2005--{}, The Sage Development Team".format(dateutil.parser.parse(sage.version.date).year)
version = sage.version.version
release = sage.version.version
source_repository = 'https://github.com/sagemath/sage/'
source_branch = 'develop'
latex_engine = 'lualatex'
exclude_patterns = ['.build']
show_authors = True
highlighting.lexers['ipycon'] = IPythonConsoleLexer(in1_regex=r'(sage:|>>>)', in2_regex=r'([.][.][.][.]:|[.][.][.])')
highlighting.lexers['ipython'] = IPyLexer()
highlight_language = 'ipycon'
toc_object_entries = True
toc_object_entries_show_parents = 'hide'
todo_include_todos = True
SAGE_DOC_REMOTE_INVENTORIES = os.environ.get('SAGE_DOC_REMOTE_INVENTORIES', 'no') == 'yes'
_vendored_inventories_dir = os.path.join(SAGE_DOC_SRC, "common", "_vendor")
_intersphinx_targets = {
'cvxopt': ['https://cvxopt.org/userguide/'],
'cvxpy': ['https://www.cvxpy.org/'],
'cypari2': ['https://cypari2.readthedocs.io/en/latest/'],
'cysignals': ['https://cysignals.readthedocs.io/en/latest/'],
'flint': ['https://flintlib.org/doc/'],
'fpylll': ['https://fpylll.readthedocs.io/en/latest/'],
'gmpy2': ['https://gmpy2.readthedocs.io/en/latest/'],
'ipywidgets': ['https://ipywidgets.readthedocs.io/en/stable/'],
'matplotlib': ['https://matplotlib.org/stable/'],
'mpmath': ['https://mpmath.org/doc/current/'],
'networkx': ['https://networkx.org/documentation/stable/'],
'numpy': ['https://numpy.org/doc/stable/'],
'pplpy': [PPLPY_DOCS, 'https://www.sagemath.org/pplpy/'],
'python': ['https://docs.python.org/'],
'rpy2': ['https://rpy2.github.io/doc/latest/html/'],
'scipy': ['https://docs.scipy.org/doc/scipy/'],
'sympy': ['https://docs.sympy.org/latest/'],
}
def _intersphinx_mapping(key):
inventories = []
link_target = None
for target in _intersphinx_targets[key]:
if not target:
pass
elif target.startswith('http'):
if not link_target:
link_target = target
if SAGE_DOC_REMOTE_INVENTORIES:
inventories.append(None)
elif os.path.exists(target):
if not link_target:
link_target = target
inventory = os.path.join(target, 'objects.inv')
if os.path.exists(inventory):
inventories.append(inventory)
break
else:
vendored_inventory = os.path.join(_vendored_inventories_dir, key + '.inv')
if os.path.exists(vendored_inventory):
inventories.append(vendored_inventory)
else:
python_inventory_file = os.path.join(_vendored_inventories_dir, "python.inv")
inventories.append(python_inventory_file)
assert link_target
if len(inventories) == 1:
return link_target, inventories[0]
return link_target, tuple(inventories)
def set_intersphinx_mappings(app, config):
"""
Add precompiled inventory (the objects.inv)
"""
app.config.intersphinx_mapping = {}
refpath = os.path.join(SAGE_DOC, "html", "en", "reference")
invpath = os.path.join(SAGE_DOC, "inventory", "en", "reference")
if app.config.multidoc_first_pass == 1 or \
not (os.path.exists(refpath) and os.path.exists(invpath)):
return
app.config.intersphinx_mapping = {key: _intersphinx_mapping(key)
for key in _intersphinx_targets}
dst = os.path.join(invpath, 'objects.inv')
app.config.intersphinx_mapping['sagemath'] = (refpath, dst)
for directory in os.listdir(os.path.join(invpath)):
if directory == 'jupyter_execute':
continue
if os.path.isdir(os.path.join(invpath, directory)):
src = os.path.join(refpath, directory)
dst = os.path.join(invpath, directory, 'objects.inv')
app.config.intersphinx_mapping[directory] = (src, dst)
intersphinx.normalize_intersphinx_mapping(app, config)
multidocs_is_master = True
copybutton_prompt_text = r"sage: |[.][.][.][.]: |>>> |[.][.][.] |\$ "
copybutton_prompt_is_regexp = True
copybutton_exclude = '.linenos, .c1'
copybutton_only_copy_prompt_lines = True
def linkcode_resolve(domain, info):
from urllib.parse import quote
from sage.misc.sageinspect import sage_getsourcelines
if domain != 'py':
return None
if info['module']:
m = importlib.import_module(info['module'])
filename = quote(info['module'].replace('.', '/'))
if m.__file__.endswith('py'):
filename += '.py'
else:
filename += '.pyx'
if 'fullname' in info:
fullname = info['fullname']
obj = m
try:
for attr in fullname.split('.'):
obj = getattr(obj, attr)
lineno = sage_getsourcelines(obj)[-1]
except Exception:
return None
anchor = f'#L{lineno}'
else:
anchor = ''
return f"{source_repository}blob/develop/src/{filename}{anchor}"
return None
html_theme_path = [os.path.join(SAGE_DOC_SRC, "common", "themes")]
html_theme = "furo"
html_theme_options = {
"light_css_variables": {
"color-brand-primary": "#0f0fff",
"color-brand-content": "#0f0fff",
},
"light_logo": "logo_sagemath_black.svg",
"dark_logo": "logo_sagemath_white.svg",
"source_repository": source_repository,
"source_branch": source_branch,
}
github_ref = os.environ.get('GITHUB_REF', '')
if github_ref:
match = re.search(r'refs/pull/(\d+)/merge', github_ref)
if match:
pr_number = match.group(1)
is_for_develop = github_ref.startswith('refs/heads/develop')
is_for_github_pr = github_ref and match and pr_number
is_stable_release = version.split('.')[-1].isnumeric()
if is_for_develop or is_for_github_pr or not is_stable_release:
ver = f'<a href="https://doc-develop--sagemath.netlify.app/html/en/index.html">{version}</a>'
if is_for_github_pr:
pr_url = f'https://github.com/sagemath/sage/pull/{pr_number}'
pr_sha = os.environ.get('PR_SHA', '')
pr_commit = pr_url + f'/commits/{pr_sha}'
ver += f' built with GitHub PR <a href="{pr_url}">#{pr_number}</a>' \
f' on <a href="{pr_commit}">{pr_sha[:7]}</a>' \
f' [<a href="/changes.html">changes</a>]'
banner = f'This is documentation for Sage version {ver} for development purpose.'
html_theme_options.update({ "announcement": banner })
pygments_style = "sphinx"
pygments_dark_style = "monokai"
html_sidebars = {
"**": [
"sidebar/scroll-start.html",
"sidebar/brand.html",
"sidebar/version-selector.html",
"sidebar/search.html",
"sidebar/home.html",
"sidebar/navigation.html",
"sidebar/ethical-ads.html",
"sidebar/scroll-end.html",
"sidebar/variant-selector.html",
]
}
html_css_files = [
'custom-furo.css',
'custom-jupyter-sphinx.css',
'custom-codemirror-monokai.css',
'custom-tabs.css',
]
html_js_files = [
'jupyter-sphinx-furo.js',
]
templates_path = [os.path.join(SAGE_DOC_SRC, 'common', 'templates-furo')] + templates_path
html_favicon = 'favicon.ico'
html_common_static_path = [os.path.join(SAGE_DOC_SRC, 'common', 'static'), 'static']
mathjax3_config = {
"tex": {
"macros": sage_mathjax_macros(),
"inlineMath": [["$", "$"], ["\\(", "\\)"]],
"maxBuffer": 50 * 1024,
"autoload": {"color": [], "colorv2": ["color"]},
},
}
if os.environ.get('SAGE_USE_CDNS', 'no') == 'yes':
mathjax_path = "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"
else:
mathjax_path = os.path.join(MATHJAX_DIR, 'tex-chtml.js')
exclude_patterns = []
modindex_common_prefix = ['sage.']
html_split_index = True
latex_elements = {}
latex_documents = []
latex_elements['preamble'] = r"""
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{textcomp}
\usepackage{mathrsfs}
\usepackage{iftex}
\let\textLaTeX\LaTeX
\AtBeginDocument{\renewcommand*{\LaTeX}{\hbox{\textLaTeX}}}
% Workaround for a LaTeX bug -- see Issue #31397 and
% https://tex.stackexchange.com/questions/583391/mactex-2020-error-with-report-hyperref-mathbf-in-chapter.
\makeatletter
\pdfstringdefDisableCommands{%
\let\mathbf\@firstofone
}
\makeatother
"""
latex_elements['sphinxsetup'] = "verbatimforcewraps=true"
from sage.misc.latex_macros import sage_latex_macros
try:
pngmath_latex_preamble
except NameError:
pngmath_latex_preamble = ""
for macro in sage_latex_macros():
latex_elements['preamble'] += macro + '\n'
pngmath_latex_preamble += macro + '\n'
def add_page_context(app, pagename, templatename, context, doctree):
path1 = os.path.dirname(app.builder.get_outfilename(pagename))
path2 = os.path.join(SAGE_DOC, 'html', 'en')
relpath = os.path.relpath(path2, path1)
context['release'] = release
context['documentation_title'] = f'Version {release} Documentation'
context['documentation_root'] = os.path.join(relpath, 'index.html')
if 'website' in path1:
context['title'] = 'Documentation'
context['website'] = True
context['documentation_root'] = 'index.html'
if 'reference' in path1 and not path1.endswith('reference'):
path2 = os.path.join(SAGE_DOC, 'html', 'en', 'reference')
relpath = os.path.relpath(path2, path1)
context['reference_title'] = f'Version {release} Reference Manual'
context['reference_root'] = os.path.join(relpath, 'index.html')
context['refsub'] = True
if pagename.startswith('sage/'):
suffix = '.py' if importlib.import_module(pagename.replace('/','.')).__file__.endswith('.py') else '.pyx'
context['page_source_suffix'] = suffix
context['theme_source_view_link'] = os.path.join(source_repository, 'blob/develop/src', '{filename}')
context['theme_source_edit_link'] = os.path.join(source_repository, 'edit/develop/src', '{filename}')
dangling_debug = False
def debug_inf(app, message):
if dangling_debug:
app.info(message)
def call_intersphinx(app, env, node, contnode):
r"""
Call intersphinx and make links between Sage manuals relative.
TESTS:
Check that the link from the thematic tutorials to the reference
manual is relative, see :issue:`20118`::
sage: from sage.env import SAGE_DOC
sage: thematic_index = os.path.join(SAGE_DOC, "html", "en", "thematic_tutorials", "index.html")
sage: for line in open(thematic_index).readlines(): # optional - sagemath_doc_html
....: if "padics" in line:
....: _ = sys.stdout.write(line)
<li><p><a class="reference external" href="../reference/padics/sage/rings/padics/tutorial.html#sage-rings-padics-tutorial" title="(in $p$-adics v...)"><span>Introduction to the p-adics</span></a></p></li>
"""
debug_inf(app, "???? Trying intersphinx for %s" % node['reftarget'])
builder = app.builder
res = intersphinx.missing_reference(
app, env, node, contnode)
if res:
if res['refuri'].startswith(SAGE_DOC):
here = os.path.dirname(os.path.join(builder.outdir,
node['refdoc']))
res['refuri'] = os.path.relpath(res['refuri'], here)
debug_inf(app, "++++ Found at %s" % res['refuri'])
else:
debug_inf(app, "---- Intersphinx: %s not Found" % node['reftarget'])
return res
def find_sage_dangling_links(app, env, node, contnode):
r"""
Try to find dangling link in local module imports or all.py.
"""
debug_inf(app, "==================== find_sage_dangling_links ")
reftype = node['reftype']
reftarget = node['reftarget']
try:
doc = node['refdoc']
except KeyError:
debug_inf(app, "-- no refdoc in node %s" % node)
return None
debug_inf(app, "Searching %s from %s" % (reftarget, doc))
if reftarget in base_class_as_func and reftype == 'class':
node['reftype'] = 'func'
res = call_intersphinx(app, env, node, contnode)
if res:
debug_inf(app, "++ DONE %s" % (res['refuri']))
return res
if node.get('refdomain') != 'py':
return None
try:
module = node['py:module']
cls = node['py:class']
except KeyError:
debug_inf(app, "-- no module or class for :%s:%s" % (reftype,
reftarget))
return None
basename = reftarget.split(".")[0]
try:
target_module = getattr(sys.modules['sage.all'], basename).__module__
debug_inf(app, "++ found %s using sage.all in %s" % (basename, target_module))
except AttributeError:
try:
target_module = getattr(sys.modules[node['py:module']], basename).__module__
debug_inf(app, "++ found %s in this module" % (basename,))
except AttributeError:
debug_inf(app, "-- %s not found in sage.all or this module" % (basename))
return None
except KeyError:
target_module = None
if target_module is None:
target_module = ""
debug_inf(app, "?? found in None !!!")
newtarget = target_module+'.'+reftarget
node['reftarget'] = newtarget
builder = app.builder
searchmode = node.hasattr('refspecific') and 1 or 0
matches = builder.env.domains['py'].find_obj(
builder.env, module, cls, newtarget, reftype, searchmode)
if not matches:
debug_inf(app, "?? no matching doc for %s" % newtarget)
return call_intersphinx(app, env, node, contnode)
elif len(matches) > 1:
env.warn(target_module,
'more than one target found for cross-reference '
'%r: %s' % (newtarget,
', '.join(match[0] for match in matches)),
node.line)
name, obj = matches[0]
debug_inf(app, "++ match = %s %s" % (name, obj))
from docutils import nodes
newnode = nodes.reference('', '', internal=True)
if name == target_module:
newnode['refid'] = name
else:
newnode['refuri'] = builder.get_relative_uri(node['refdoc'], obj[0])
newnode['refuri'] += '#' + name
debug_inf(app, "++ DONE at URI %s" % (newnode['refuri']))
newnode['reftitle'] = name
newnode.append(contnode)
return newnode
base_class_as_func = [
'bool', 'complex', 'dict', 'file', 'float',
'frozenset', 'int', 'list', 'long', 'object',
'set', 'slice', 'str', 'tuple', 'type', 'unicode', 'xrange']
nitpick_ignore = [
('py:class', 'twisted.web2.resource.Resource'),
('py:class', 'twisted.web2.resource.PostableResource')]
skip_picklability_check_modules = [
'sage.misc.latex',
'sage.misc.explain_pickle',
'__builtin__',
]
def check_nested_class_picklability(app, what, name, obj, skip, options):
"""
Print a warning if pickling is broken for nested classes.
"""
if hasattr(obj, '__dict__') and hasattr(obj, '__module__'):
module = sys.modules[obj.__module__]
for (nm, v) in obj.__dict__.items():
if (isinstance(v, type) and
v.__name__ == nm and
v.__module__ == module.__name__ and
getattr(module, nm, None) is not v and
v.__module__ not in skip_picklability_check_modules):
app.warn('Pickling of nested class %r is probably broken. '
'Please set the metaclass of the parent class to '
'sage.misc.nested_class.NestedClassMetaclass.' % (
v.__module__ + '.' + name + '.' + nm))
def skip_member(app, what, name, obj, skip, options):
"""
To suppress Sphinx warnings / errors, we
- Don't include [aliases of] builtins.
- Don't include the docstring for any nested class which has been
inserted into its module by
:class:`sage.misc.NestedClassMetaclass` only for pickling. The
class will be properly documented inside its surrounding class.
- Optionally, check whether pickling is broken for nested classes.
- Optionally, include objects whose name begins with an underscore
('_'), i.e., "private" or "hidden" attributes, methods, etc.
Otherwise, we abide by Sphinx's decision. Note: The object
``obj`` is excluded (included) if this handler returns True
(False).
"""
if 'SAGE_CHECK_NESTED' in os.environ:
check_nested_class_picklability(app, what, name, obj, skip, options)
if getattr(obj, '__module__', None) == '__builtin__':
return True
objname = getattr(obj, "__name__", None)
if objname is not None:
if name.find('.') != -1 and objname.find('.') != -1:
if objname.split('.')[-1] == name.split('.')[-1]:
return True
if 'SAGE_DOC_UNDERSCORE' in os.environ:
if name.split('.')[-1].startswith('_'):
return False
return skip
class SagecodeTransform(SphinxTransform):
"""
Transform a code block to a live code block enabled by jupyter-sphinx.
Effectively a code block like::
EXAMPLE::
sage: 1 + 1
2
is transformed into::
EXAMPLE::
sage: 1 + 1
2
.. ONLY:: html
.. JUPYTER-EXECUTE::
:hide-code:
:hide-output:
:raises:
:stderr:
1 + 1
enabling live execution of the code.
"""
default_priority = 170
def apply(self):
if self.app.builder.tags.has('html') or self.app.builder.tags.has('inventory'):
for node in list(self.document.findall(nodes.literal_block)):
if node.get('language') is None and node.astext().startswith('sage:'):
from docutils.nodes import Text
from docutils.nodes import container as Container
from docutils.nodes import label as Label
from docutils.nodes import literal_block as LiteralBlock
from sphinx_inline_tabs._impl import TabContainer
parent = node.parent
index = parent.index(node)
prev_node = node.previous_sibling()
if isinstance(prev_node, TabContainer):
parent.insert(index, nodes.paragraph())
prev_node = parent[index]
index += 1
parent.remove(node)
container = TabContainer("", type="tab", new_set=False)
textnodes = [Text('Sage')]
label = Label("", "", *textnodes)
container += label
content = Container("", is_div=True, classes=["tab-content"])
content += node
container += content
parent.insert(index, container)
index += 1
if isinstance(prev_node, nodes.paragraph):
prev_node['classes'].append('with-sage-tab')
if SAGE_PREPARSED_DOC == 'yes':
from sage.repl.preparse import preparse
container = TabContainer("", type="tab", new_set=False)
textnodes = [Text('Python')]
label = Label("", "", *textnodes)
container += label
content = Container("", is_div=True, classes=["tab-content"])
example_lines = []
preparsed_lines = ['>>> from sage.all import *']
for line in node.rawsource.splitlines() + ['']:
newline = line.lstrip()
if newline.startswith('....: '):
example_lines.append(newline[6:])
else:
if example_lines:
preparsed_example = preparse('\n'.join(example_lines))
prompt = '>>> '
for preparsed_line in preparsed_example.splitlines():
preparsed_lines.append(prompt + preparsed_line)
prompt = '... '
example_lines = []
if newline.startswith('sage: '):
example_lines.append(newline[6:])
else:
preparsed_lines.append(line)
preparsed = '\n'.join(preparsed_lines)
preparsed_node = LiteralBlock(preparsed, preparsed, language='ipycon')
content += preparsed_node
container += content
parent.insert(index, container)
index += 1
if isinstance(prev_node, nodes.paragraph):
prev_node['classes'].append('with-python-tab')
if SAGE_LIVE_DOC == 'yes':
from jupyter_sphinx.ast import CellInputNode, JupyterCellNode
source = node.rawsource
lines = []
for line in source.splitlines():
newline = line.lstrip()
if newline.startswith('sage: ') or newline.startswith('....: '):
lines.append(newline[6:])
cell_node = JupyterCellNode(
execute=False,
hide_code=False,
hide_output=True,
emphasize_lines=[],
raises=False,
stderr=True,
code_below=False,
classes=["jupyter_cell"])
cell_input = CellInputNode(classes=['cell_input','live-doc'])
cell_input += nodes.literal_block(
text='\n'.join(lines),
linenos=False,
linenostart=1)
cell_node += cell_input
container = TabContainer("", type="tab", new_set=False)
textnodes = [Text('Sage Live')]
label = Label("", "", *textnodes)
container += label
content = Container("", is_div=True, classes=["tab-content"])
content += cell_node
container += content
parent.insert(index, container)
index += 1
if isinstance(prev_node, nodes.paragraph):
prev_node['classes'].append('with-sage-live-tab')
class Ignore(SphinxDirective):
has_content = True
def run(self):
return []
def setup(app):
app.connect('autodoc-process-docstring', process_docstring_cython)
app.connect('autodoc-process-docstring', process_directives)
app.connect('autodoc-process-docstring', process_docstring_module_title)
app.connect('autodoc-process-docstring', process_dollars)
app.connect('autodoc-process-docstring', process_inherited)
if os.environ.get('SAGE_SKIP_TESTS_BLOCKS', False):
app.connect('autodoc-process-docstring', skip_TESTS_block)
app.connect('autodoc-skip-member', skip_member)
app.add_transform(SagemathTransform)
if SAGE_LIVE_DOC == 'yes' or SAGE_PREPARSED_DOC == 'yes':
app.add_transform(SagecodeTransform)
if not JupyterSphinx().is_present():
app.add_directive("jupyter-execute", Ignore)
app.add_directive("jupyter-kernel", Ignore)
app.add_directive("jupyter-input", Ignore)
app.add_directive("jupyter-output", Ignore)
app.add_directive("thebe-button", Ignore)
if app.srcdir.is_relative_to(SAGE_DOC_SRC):
app.add_config_value('intersphinx_resolve_self', 'sagemath', False)
app.add_config_value('intersphinx_mapping', {}, False)
app.add_config_value('intersphinx_cache_limit', 5, False)
app.add_config_value('intersphinx_disabled_reftypes', [], False)
app.add_config_value('intersphinx_timeout', None, False)
app.connect('config-inited', set_intersphinx_mappings)
app.connect('builder-inited', intersphinx.load_mappings)
app.connect('missing-reference', find_sage_dangling_links)
app.connect('html-page-context', add_page_context)