Format Sage documentation for viewing with IPython and the notebook¶
AUTHORS:
William Stein (2005): initial version.
Nick Alexander (2007): nodetex functions
Nick Alexander (2008): search_src, search_def improvements
Martin Albrecht (2008-03-21): parse LaTeX description environments in sagedoc
John Palmieri (2009-04-11): fix for #5754 plus doctests
Dan Drake (2009-05-21): refactor search_* functions, use system ‘find’ instead of sage -grep
John Palmieri (2009-06-28): don’t use ‘find’ – use Python (os.walk, re.search) instead.
Simon King (2011-09): Use os.linesep, avoid destruction of embedding information, enable nodetex in a docstring. Consequently use sage_getdoc.
- sage.misc.sagedoc.detex(s, embedded=False)¶
This strips LaTeX commands from a string; it is used by the
format
function to process docstrings for display from the command line interface.INPUT:
s
- stringembedded
- boolean (optional, default False)
If
embedded
is False, then do the replacements in bothmath_substitutes
andnonmath_substitutes
. If True, then only dononmath_substitutes
.OUTPUT:
string
EXAMPLES:
sage: from sage.misc.sagedoc import detex sage: detex(r'Some math: `n \geq k`. A website: \url{sagemath.org}.') 'Some math: n >= k. A website: sagemath.org.\n' sage: detex(r'More math: `x \mapsto y`. {\bf Bold face}.') 'More math: x |--> y. { Bold face}.\n' sage: detex(r'`a, b, c, \ldots, z`') 'a, b, c, ..., z\n' sage: detex(r'`a, b, c, \ldots, z`', embedded=True) '`a, b, c, \\ldots, z`' sage: detex(r'`\left(\lvert x\ast y \rvert\right]`') '(| x * y |]\n' sage: detex(r'`\left(\leq\le\leftarrow \rightarrow\unknownmacro\to`') '(<=<=<-- -->\\unknownmacro-->\n'
- sage.misc.sagedoc.format(s, embedded=False)¶
noreplace Format Sage documentation
s
for viewing with IPython.This calls
detex
ons
to convert LaTeX commands to plain text, unless the directivenodetex
is given in the first line of the string.Also, if
s
contains a string of the form<<<obj>>>
, then it replaces it with the docstring forobj
, unless the directivenoreplace
is given in the first line. If an error occurs under the attempt to find the docstring forobj
, then the substring<<<obj>>>
is preserved.Directives must be separated by a comma.
INPUT:
s
- stringembedded
- boolean (optional, default False)
OUTPUT: string
Set
embedded
equal to True if formatting for use in the notebook; this just gets passed as an argument todetex
.See also
sage.misc.sageinspect.sage_getdoc()
to get the formatted documentation of a given object.EXAMPLES:
sage: from sage.misc.sagedoc import format sage: identity_matrix(2).rook_vector.__doc__[202:274] 'Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard' sage: format(identity_matrix(2).rook_vector.__doc__[202:274]) 'Let A be an m by n (0,1)-matrix. We identify A with a chessboard\n'
If the first line of the string is ‘nodetex’, remove ‘nodetex’ but don’t modify any TeX commands:
sage: format("nodetex\n`x \\geq y`") '`x \\geq y`'
Testing a string enclosed in triple angle brackets:
sage: format('<<<identity_matrix') '<<<identity_matrix\n' sage: format('identity_matrix>>>') 'identity_matrix>>>\n' sage: format('<<<identity_matrix>>>')[:28] 'Definition: identity_matrix('
- sage.misc.sagedoc.format_search_as_html(what, results, search)¶
Format the output from
search_src
,search_def
, orsearch_doc
as html, for use in the notebook.INPUT:
what
- (string) what was searched (source code or documentation)results
- (string or list) the results of the search as a string or list of search resultssearch
- (string or list) what was being searched for, either as a string which is taken verbatim, or a list of multiple search terms if there were more than one
This function parses
results
: each line should have either the formFILENAME
orFILENAME: string
where FILENAME is the file in which the string that matched the search was found. If FILENAME ends in ‘.html’, then this is part of the documentation; otherwise, it is in the source code. In either case, an appropriate link is created.EXAMPLES:
sage: from sage.misc.sagedoc import format_search_as_html sage: format_search_as_html('Source', 'algebras/steenrod_algebra_element.py: an antihomomorphism: if we call the antipode `c`, then', 'antipode antihomomorphism') '<html><font color="black"><h2>Search Source: "antipode antihomomorphism"</h2></font><font color="darkpurple"><ol><li><a href="/src/algebras/steenrod_algebra_element.py" target="_blank"><tt>algebras/steenrod_algebra_element.py</tt></a>\n</ol></font></html>' sage: format_search_as_html('Other', 'html/en/reference/sage/algebras/steenrod_algebra_element.html:an antihomomorphism: if we call the antipode <span class="math">c</span>, then', 'antipode antihomomorphism') '<html><font color="black"><h2>Search Other: "antipode antihomomorphism"</h2></font><font color="darkpurple"><ol><li><a href="/doc/live/reference/sage/algebras/steenrod_algebra_element.html" target="_blank"><tt>reference/sage/algebras/steenrod_algebra_element.html</tt></a>\n</ol></font></html>'
- sage.misc.sagedoc.format_src(s)¶
Format Sage source code
s
for viewing with IPython.If
s
contains a string of the form “<<<obj>>>”, then it replaces it with the source code for “obj”.INPUT:
s
- stringOUTPUT: string
EXAMPLES:
sage: from sage.misc.sagedoc import format_src sage: format_src('unladen swallow') 'unladen swallow' sage: format_src('<<<Sq>>>')[5:15] 'Sq(*nums):'
- sage.misc.sagedoc.help(module=None)¶
If there is an argument
module
, print the Python help message formodule
. With no argument, print a help message about getting help in Sage.EXAMPLES:
sage: help() Welcome to Sage ...
- sage.misc.sagedoc.my_getsource(obj, oname='')¶
Retrieve the source code for
obj
.INPUT:
obj
– a Sage object, function, etc.oname
– str (optional). A name under which the object is known. Currently ignored by Sage.
OUTPUT:
Its documentation (string)
EXAMPLES:
sage: from sage.misc.sagedoc import my_getsource sage: s = my_getsource(identity_matrix) sage: s[15:34] 'def identity_matrix'
- sage.misc.sagedoc.process_dollars(s)¶
Replace dollar signs with backticks.
More precisely, do a regular expression search. Replace a plain dollar sign ($) by a backtick (`). Replace an escaped dollar sign (\$) by a dollar sign ($). Don’t change a dollar sign preceded or followed by a backtick (`$ or $`), because of strings like “
$HOME
”. Don’t make any changes on lines starting with more spaces than the first nonempty line ins
, because those are indented and hence part of a block of code or examples.This also doesn’t replaces dollar signs enclosed in curly braces, to avoid nested math environments.
EXAMPLES:
sage: from sage.misc.sagedoc import process_dollars sage: process_dollars('hello') 'hello' sage: process_dollars('some math: $x=y$') 'some math: `x=y`'
Replace \$ with $, and don’t do anything when backticks are involved:
sage: process_dollars(r'a ``$REAL`` dollar sign: \$') 'a ``$REAL`` dollar sign: $'
Don’t make any changes on lines indented more than the first nonempty line:
sage: s = '\n first line\n indented $x=y$' sage: s == process_dollars(s) True
Don’t replace dollar signs enclosed in curly braces:
sage: process_dollars(r'f(n) = 0 \text{ if $n$ is prime}') 'f(n) = 0 \\text{ if $n$ is prime}'
This is not perfect:
sage: process_dollars(r'$f(n) = 0 \text{ if $n$ is prime}$') '`f(n) = 0 \\text{ if $n$ is prime}$'
The regular expression search doesn’t find the last $. Fortunately, there don’t seem to be any instances of this kind of expression in the Sage library, as of this writing.
- sage.misc.sagedoc.process_extlinks(s, embedded=False)¶
In docstrings at the command line, process markup related to the Sphinx extlinks extension. For example, replace
:trac:`NUM`
withhttps://trac.sagemath.org/NUM
, and similarly with:python:TEXT
and:wikipedia:TEXT
, looking up the url from the dictionaryextlinks
insage.docs.conf
. IfTEXT
is of the formblah <LINK>
, then it usesLINK
rather thanTEXT
to construct the url.In the notebook, don’t do anything: let sphinxify take care of it.
INPUT:
s
– string, in practice a docstringembedded
– boolean (optional, default False)
This function is called by
format()
, and if in the notebook, it setsembedded
to beTrue
, otherwiseFalse
.EXAMPLES:
sage: from sage.misc.sagedoc import process_extlinks sage: process_extlinks('See :trac:`1234`, :wikipedia:`Wikipedia <Sage_(mathematics_software)>`, and :trac:`4321` ...') 'See https://trac.sagemath.org/1234, https://en.wikipedia.org/wiki/Sage_(mathematics_software), and https://trac.sagemath.org/4321 ...' sage: process_extlinks('See :trac:`1234` for more information.', embedded=True) 'See :trac:`1234` for more information.' sage: process_extlinks('see :python:`Implementing Descriptors <reference/datamodel.html#implementing-descriptors>` ...') 'see https://docs.python.org/release/.../reference/datamodel.html#implementing-descriptors ...'
- sage.misc.sagedoc.process_mathtt(s)¶
Replace \mathtt{BLAH} with BLAH in the command line.
INPUT:
s
- string, in practice a docstring
This function is called by
format()
.EXAMPLES:
sage: from sage.misc.sagedoc import process_mathtt sage: process_mathtt(r'e^\mathtt{self}') 'e^self'
- sage.misc.sagedoc.search_def(name, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)¶
Search Sage library source code for function definitions containing
name
. The search is case-insensitive by default.INPUT: same as for
search_src()
.OUTPUT: same as for
search_src()
.Note
The regular expression used by this function only finds function definitions that are preceded by spaces, so if you use tabs on a “def” line, this function will not find it. As tabs are not allowed in Sage library code, this should not be a problem.
EXAMPLES:
See the documentation for
search_src()
for more examples.sage: print(search_def("fetch", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): matrix/matrix0.pxd: cdef fetch(self, key) sage: print(search_def("fetch", path_re="pyx", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key):
- sage.misc.sagedoc.search_doc(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)¶
Search Sage HTML documentation for lines containing
string
. The search is case-insensitive by default.The file paths in the output are relative to
$SAGE_DOC
.INPUT: same as for
search_src()
.OUTPUT: same as for
search_src()
.EXAMPLES:
See the documentation for
search_src()
for more examples.sage: search_doc('creates a polynomial', path_re='tutorial', interact=False) # random html/en/tutorial/tour_polynomial.html:<p>This creates a polynomial ring and tells Sage to use (the string)
If you search the documentation for ‘tree’, then you will get too many results, because many lines in the documentation contain the word ‘toctree’. If you use the
whole_word
option, though, you can search for ‘tree’ without returning all of the instances of ‘toctree’. In the following, sincesearch_doc('tree', interact=False)
returns a string with one line for each match, counting the length ofsearch_doc('tree', interact=False).splitlines()
gives the number of matches.sage: N = len(search_doc('tree', interact=False).splitlines()) # optional - dochtml, long time sage: L = search_doc('tree', whole_word=True, interact=False).splitlines() # optional - dochtml, long time sage: len(L) < N # optional - dochtml, long time True sage: import re sage: tree_re = re.compile(r'(^|\W)tree(\W|$)', re.I) sage: all(tree_re.search(l) for l in L) # optional - dochtml, long time True
- sage.misc.sagedoc.search_src(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)¶
Search Sage library source code for lines containing
string
. The search is case-insensitive by default.INPUT:
string
- a string to find in the Sage source code.extra1
, …,extra5
- additional strings to require when searching. Lines must match all of these, as well asstring
.whole_word
(optional, default False) - if True, search forstring
andextra1
(etc.) as whole words only. This assumes that each of these arguments is a single word, not a regular expression, and it might have unexpected results if used with regular expressions.ignore_case
(optional, default True) - if False, perform a case-sensitive searchmultiline
(optional, default False) - if True, search more than one line at a time. In this case, print any matching file names, but don’t print line numbers.interact
(optional, defaultTrue
) - ifFalse
, return a string with all the matches. Otherwise, this function returnsNone
, and the results are displayed appropriately, according to whether you are using the notebook or the command-line interface. You should not ordinarily need to use this.path_re
(optional, default ‘’) - regular expression which the filename (including the path) must match.module
(optional, default ‘sage’) - the module in which to search. The default is ‘sage’, the entire Sage library. Ifmodule
doesn’t start with “sage”, then the links in the notebook output may not function.
OUTPUT: If
interact
is False, then return a string with all of the matches, separated by newlines. On the other hand, ifinteract
is True (the default), there is no output. Instead: at the command line, the search results are printed on the screen in the formfilename:line_number:line of text
, showing the filename in which each match occurs, the line number where it occurs, and the actual matching line. (Ifmultiline
is True, then only the filename is printed for each match.) The file paths in the output are relative to$SAGE_SRC
. In the notebook, each match produces a link to the actual file in which it occurs.The
string
andextraN
arguments are treated as regular expressions, as ispath_re
, and errors will be raised if they are invalid. The matches will be case-insensitive unlessignore_case
is False.Note
The
extraN
parameters are present only becausesearch_src(string, *extras, interact=False)
is not parsed correctly by Python 2.6; see http://bugs.python.org/issue1909.EXAMPLES:
First note that without using
interact=False
, this function produces no output, while withinteract=False
, the output is a string. These examples almost all use this option, so that they have something to which to compare their output.You can search for “matrix” by typing
search_src("matrix")
. This particular search will produce many results:sage: len(search_src("matrix", interact=False).splitlines()) # random # long time 9522
You can restrict to the Sage calculus code with
search_src("matrix", module="sage.calculus")
, and this produces many fewer results:sage: len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random 26
Note that you can do tab completion on the
module
string. Another way to accomplish a similar search:sage: len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 True
The following produces an error because the string ‘fetch(’ is a malformed regular expression:
sage: print(search_src(" fetch(", "def", interact=False)) # py2 Traceback (most recent call last): ... error: unbalanced parenthesis sage: print(search_src(" fetch(", "def", interact=False)) # py3 Traceback (most recent call last): ... error: missing ), unterminated subpattern at position 6
To fix this, escape the parenthesis with a backslash:
sage: print(search_src(r" fetch\(", "def", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key): matrix/matrix0.pxd: cdef fetch(self, key) sage: print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time matrix/matrix0.pyx: cdef fetch(self, key):
As noted above, the search is case-insensitive, but you can make it case-sensitive with the ‘ignore_case’ key word:
sage: s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0 True sage: s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0 True sage: s = search_src('MatRiX', path_re='matrix', interact=False, ignore_case=False); s.find('x') > 0 False
Searches are by default restricted to single lines, but this can be changed by setting
multiline
to be True. In the following, sincesearch_src(string, interact=False)
returns a string with one line for each match, counting the length ofsearch_src(string, interact=False).splitlines()
gives the number of matches.sage: len(search_src('log', 'derivative', interact=False).splitlines()) < 40 True sage: len(search_src('log', 'derivative', interact=False, multiline=True).splitlines()) > 70 True
A little recursive narcissism: let’s do a doctest that searches for this function’s doctests. Note that you can’t put “sage:” in the doctest string because it will get replaced by the Python “>>>” prompt.
sage: print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) # random # long time misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random misc/sagedoc.py:... len(search_src("matrix", path_re="calc", interact=False).splitlines()) > 15 misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py2 misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False)) # py3 misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False)) # random # long time misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0 misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0 misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False, ignore_case=False); s.find('x') > 0 misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40 misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False, multiline=True).splitlines()) > 70 misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000 # long time misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub', 'start', 'index', interact=False)) # random # long time misc/sagedoc.py:... sage: results = search_src('format_search_as_html', # long time
- sage.misc.sagedoc.skip_TESTS_block(docstring)¶
Remove blocks labeled “TESTS:” from
docstring
.INPUT:
docstring
, a string
A “TESTS” block is a block starting “TESTS:” (or the same with two colons), on a line on its own, and ending either with a line indented less than “TESTS”, or with a line with the same level of indentation – not more – matching one of the following:
a Sphinx directive of the form “.. foo:”, optionally followed by other text.
text of the form “UPPERCASE:”, optionally followed by other text.
lines which look like a reST header: one line containing anything, followed by a line consisting only of a string of hyphens, equal signs, or other characters which are valid markers for reST headers:
- = ` : ' " ~ _ ^ * + # < >
. However, lines only containing double colons \(::\) do not end “TESTS” blocks.
Return the string obtained from
docstring
by removing these blocks.EXAMPLES:
sage: from sage.misc.sagedoc import skip_TESTS_block sage: start = ' Docstring\n\n' sage: test = ' TESTS: \n\n Here is a test::\n sage: 2+2 \n 5 \n\n' sage: test2 = ' TESTS:: \n\n sage: 2+2 \n 6 \n\n'
Test lines starting with “REFERENCES:”:
sage: refs = ' REFERENCES: \n text text \n' sage: skip_TESTS_block(start + test + refs).rstrip() == (start + refs).rstrip() True sage: skip_TESTS_block(start + test + test2 + refs).rstrip() == (start + refs).rstrip() True sage: skip_TESTS_block(start + test + refs + test2).rstrip() == (start + refs).rstrip() True
Test Sphinx directives:
sage: directive = ' .. todo:: \n do some stuff \n' sage: skip_TESTS_block(start + test + refs + test2 + directive).rstrip() == (start + refs + directive).rstrip() True
Test unindented lines:
sage: unindented = 'NOT INDENTED\n' sage: skip_TESTS_block(start + test + unindented).rstrip() == (start + unindented).rstrip() True sage: skip_TESTS_block(start + test + unindented + test2 + unindented).rstrip() == (start + unindented + unindented).rstrip() True
Test headers:
sage: header = ' Header:\n ~~~~~~~~' sage: skip_TESTS_block(start + test + header) == start + header True
Not a header because the characters on the second line must all be the same:
sage: fake_header = ' Header:\n -=-=-=-=-=' sage: skip_TESTS_block(start + test + fake_header).rstrip() == start.rstrip() True
Not a header because it’s indented compared to ‘TEST’ in the string
test
:sage: another_fake = '\n blah\n ----' sage: skip_TESTS_block(start + test + another_fake).rstrip() == start.rstrip() True
Double colons
::
are also not considered as headers (trac ticket #27896):sage: colons = ' ::\n\n sage: 2+2\n 4\n\n' sage: skip_TESTS_block(start + test2 + colons).rstrip() == start.rstrip() True