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)[source]

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 – string

  • embedded – boolean (default: False)

If embedded is False, then do the replacements in both math_substitutes and nonmath_substitutes. If True, then only do nonmath_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'
>>> from sage.all import *
>>> from sage.misc.sagedoc import detex
>>> detex(r'Some math: `n \geq k`.  A website: \url{sagemath.org}.')
'Some math: n >= k.  A website: sagemath.org.\n'
>>> detex(r'More math: `x \mapsto y`.  {\bf Bold face}.')
'More math: x  |-->  y.  { Bold face}.\n'
>>> detex(r'`a, b, c, \ldots, z`')
'a, b, c, ..., z\n'
>>> detex(r'`a, b, c, \ldots, z`', embedded=True)
'`a, b, c, \\ldots, z`'
>>> detex(r'`\left(\lvert x\ast y \rvert\right]`')
'(| x * y |]\n'
>>> detex(r'`\left(\leq\le\leftarrow \rightarrow\unknownmacro\to`')
'(<=<=<-- -->\\unknownmacro-->\n'
from sage.misc.sagedoc import detex
detex(r'Some math: `n \geq k`.  A website: \url{sagemath.org}.')
detex(r'More math: `x \mapsto y`.  {\bf Bold face}.')
detex(r'`a, b, c, \ldots, z`')
detex(r'`a, b, c, \ldots, z`', embedded=True)
detex(r'`\left(\lvert x\ast y \rvert\right]`')
detex(r'`\left(\leq\le\leftarrow \rightarrow\unknownmacro\to`')
sage.misc.sagedoc.format(s, embedded=False)[source]

noreplace Format Sage documentation s for viewing with IPython.

This calls detex() on s to convert LaTeX commands to plain text, unless the directive nodetex 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 for obj, unless the directive noreplace is given in the first line. If an error occurs under the attempt to find the docstring for obj, then the substring <<<obj>>> is preserved.

Directives must be separated by a comma.

INPUT:

  • s – string

  • embedded – boolean (default: False)

OUTPUT: string

Set embedded equal to True if formatting for use in the notebook; this just gets passed as an argument to detex().

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: format('Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard')
'Let A be an m by n (0,1)-matrix. We identify A with a chessboard\n'
>>> from sage.all import *
>>> from sage.misc.sagedoc import format
>>> format('Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard')
'Let A be an m by n (0,1)-matrix. We identify A with a chessboard\n'
from sage.misc.sagedoc import format
format('Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard')

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`'
>>> from sage.all import *
>>> format("nodetex\n`x \\geq y`")
'`x \\geq y`'
format("nodetex\n`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>>>')                                           # needs sage.modules
'...Definition: identity_matrix(...'
sage: format('<<<identity_matrix>>>')[:28]                                      # needs sphinx
'Definition: identity_matrix('
>>> from sage.all import *
>>> format('<<<identity_matrix')
'<<<identity_matrix\n'
>>> format('identity_matrix>>>')
'identity_matrix>>>\n'
>>> format('<<<identity_matrix>>>')                                           # needs sage.modules
'...Definition: identity_matrix(...'
>>> format('<<<identity_matrix>>>')[:Integer(28)]                                      # needs sphinx
'Definition: identity_matrix('
format('<<<identity_matrix')
format('identity_matrix>>>')
format('<<<identity_matrix>>>')                                           # needs sage.modules
format('<<<identity_matrix>>>')[:28]                                      # needs sphinx
sage.misc.sagedoc.format_search_as_html(what, results, search)[source]

Format the output from search_src, search_def, or search_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 results

  • search – 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 form FILENAME or FILENAME: 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>'
>>> from sage.all import *
>>> from sage.misc.sagedoc import format_search_as_html
>>> 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>'
>>> 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>'
from sage.misc.sagedoc import format_search_as_html
format_search_as_html('Source', 'algebras/steenrod_algebra_element.py:        an antihomomorphism: if we call the antipode `c`, then', 'antipode antihomomorphism')
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')
sage.misc.sagedoc.format_src(s)[source]

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 – string

OUTPUT: string

EXAMPLES:

sage: from sage.misc.sagedoc import format_src
sage: format_src('unladen swallow')
'unladen swallow'
sage: format_src('<<<Sq>>>')[5:15]                                              # needs sage.combinat sage.modules
'Sq(*nums):'
>>> from sage.all import *
>>> from sage.misc.sagedoc import format_src
>>> format_src('unladen swallow')
'unladen swallow'
>>> format_src('<<<Sq>>>')[Integer(5):Integer(15)]                                              # needs sage.combinat sage.modules
'Sq(*nums):'
from sage.misc.sagedoc import format_src
format_src('unladen swallow')
format_src('<<<Sq>>>')[5:15]                                              # needs sage.combinat sage.modules
sage.misc.sagedoc.help(module=None)[source]

If there is an argument module, print the Python help message for module. With no argument, print a help message about getting help in Sage.

EXAMPLES:

sage: help()
Welcome to Sage ...
>>> from sage.all import *
>>> help()
Welcome to Sage ...
help()
sage.misc.sagedoc.my_getsource(obj, oname='')[source]

Retrieve the source code for obj.

INPUT:

  • obj – a Sage object, function, etc.

  • oname – string (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)                                         # needs sage.modules
sage: s[15:34]                                                                  # needs sage.modules
'def identity_matrix'
>>> from sage.all import *
>>> from sage.misc.sagedoc import my_getsource
>>> s = my_getsource(identity_matrix)                                         # needs sage.modules
>>> s[Integer(15):Integer(34)]                                                                  # needs sage.modules
'def identity_matrix'
from sage.misc.sagedoc import my_getsource
s = my_getsource(identity_matrix)                                         # needs sage.modules
s[15:34]                                                                  # needs sage.modules
sage.misc.sagedoc.process_dollars(s)[source]

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 in s, 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$')
doctest:warning...
DeprecationWarning: using dollar signs to mark up math in Sage docstrings
is deprecated; use backticks instead
See https://github.com/sagemath/sage/issues/33973 for details.
'some math: `x=y`'
>>> from sage.all import *
>>> from sage.misc.sagedoc import process_dollars
>>> process_dollars('hello')
'hello'
>>> process_dollars('some math: $x=y$')
doctest:warning...
DeprecationWarning: using dollar signs to mark up math in Sage docstrings
is deprecated; use backticks instead
See https://github.com/sagemath/sage/issues/33973 for details.
'some math: `x=y`'
from sage.misc.sagedoc import process_dollars
process_dollars('hello')
process_dollars('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: $'
>>> from sage.all import *
>>> process_dollars(r'a ``$REAL`` dollar sign: \$')
'a ``$REAL`` dollar sign: $'
process_dollars(r'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
>>> from sage.all import *
>>> s = '\n first line\n     indented $x=y$'
>>> s == process_dollars(s)
True
s = '\n first line\n     indented $x=y$'
s == process_dollars(s)

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}'
>>> from sage.all import *
>>> process_dollars(r'f(n) = 0 \text{ if $n$ is prime}')
'f(n) = 0 \\text{ if $n$ is prime}'
process_dollars(r'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}$'
>>> from sage.all import *
>>> process_dollars(r'$f(n) = 0 \text{ if $n$ is prime}$')
'`f(n) = 0 \\text{ if $n$ is prime}$'
process_dollars(r'$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.

In docstrings at the command line, process markup related to the Sphinx extlinks extension. For example, replace :issue:`NUM` with https://github.com/sagemath/sage/issues/NUM, and similarly with :python:TEXT and :wikipedia:TEXT, looking up the url from the dictionary extlinks in sage_docbuild.conf. If TEXT is of the form blah <LINK>, then it uses LINK rather than TEXT to construct the url.

In the notebook, don’t do anything: let sphinxify take care of it.

INPUT:

  • s – string, in practice a docstring

  • embedded – boolean (default: False)

This function is called by format(), and if in the notebook, it sets embedded to be True, otherwise False.

EXAMPLES:

sage: from sage.misc.sagedoc import process_extlinks
sage: process_extlinks('See :issue:`1234`, :wikipedia:`Wikipedia <Sage_(mathematics_software)>`, and :issue:`4321` ...')
'See https://github.com/sagemath/sage/issues/1234, https://en.wikipedia.org/wiki/Sage_(mathematics_software), and https://github.com/sagemath/sage/issues/4321 ...'
sage: process_extlinks('See :issue:`1234` for more information.', embedded=True)
'See :issue:`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 ...'
>>> from sage.all import *
>>> from sage.misc.sagedoc import process_extlinks
>>> process_extlinks('See :issue:`1234`, :wikipedia:`Wikipedia <Sage_(mathematics_software)>`, and :issue:`4321` ...')
'See https://github.com/sagemath/sage/issues/1234, https://en.wikipedia.org/wiki/Sage_(mathematics_software), and https://github.com/sagemath/sage/issues/4321 ...'
>>> process_extlinks('See :issue:`1234` for more information.', embedded=True)
'See :issue:`1234` for more information.'
>>> process_extlinks('see :python:`Implementing Descriptors <reference/datamodel.html#implementing-descriptors>` ...')
'see https://docs.python.org/release/.../reference/datamodel.html#implementing-descriptors ...'
from sage.misc.sagedoc import process_extlinks
process_extlinks('See :issue:`1234`, :wikipedia:`Wikipedia <Sage_(mathematics_software)>`, and :issue:`4321` ...')
process_extlinks('See :issue:`1234` for more information.', embedded=True)
process_extlinks('see :python:`Implementing Descriptors <reference/datamodel.html#implementing-descriptors>` ...')
sage.misc.sagedoc.process_mathtt(s)[source]

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'
>>> from sage.all import *
>>> from sage.misc.sagedoc import process_mathtt
>>> process_mathtt(r'e^\mathtt{self}')
'e^self'
from sage.misc.sagedoc import process_mathtt
process_mathtt(r'e^\mathtt{self}')
sage.misc.sagedoc.process_optional_doctest_tags(s)[source]

Remove # optional/needs doctest tags for present features from docstring s.

EXAMPLES:

sage: from sage.misc.sagedoc import process_optional_doctest_tags sage: process_optional_doctest_tags(“sage: # needs sage.rings.finite_ringsnsage: K.<x> = FunctionField(GF(5^2,’a’)); KnRational function field in x over Finite Field in a of size 5^2”) # needs sage.rings.finite_rings “sage: K.<x> = FunctionField(GF(5^2,’a’)); KnRational function field in x over Finite Field in a of size 5^2”

sage.misc.sagedoc.search_def(name, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)[source]

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):
>>> from sage.all import *
>>> print(search_def("fetch", interact=False))  # random # long time
matrix/matrix0.pyx:    cdef fetch(self, key):
matrix/matrix0.pxd:    cdef fetch(self, key)

>>> print(search_def("fetch", path_re="pyx", interact=False))  # random # long time
matrix/matrix0.pyx:    cdef fetch(self, key):
print(search_def("fetch", interact=False))  # random # long time
print(search_def("fetch", path_re="pyx", interact=False))  # random # long time
sage.misc.sagedoc.search_doc(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)[source]

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)
>>> from sage.all import *
>>> 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)
search_doc('creates a polynomial', path_re='tutorial', interact=False) # random

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, since search_doc('tree', interact=False) returns a string with one line for each match, counting the length of search_doc('tree', interact=False).splitlines() gives the number of matches.

sage: # long time, needs sagemath_doc_html
sage: N = len(search_doc('tree', interact=False).splitlines())
sage: L = search_doc('tree', whole_word=True, interact=False).splitlines()
sage: len(L) < N
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)
True
>>> from sage.all import *
>>> # long time, needs sagemath_doc_html
>>> N = len(search_doc('tree', interact=False).splitlines())
>>> L = search_doc('tree', whole_word=True, interact=False).splitlines()
>>> len(L) < N
True
>>> import re
>>> tree_re = re.compile(r'(^|\W)tree(\W|$)', re.I)
>>> all(tree_re.search(l) for l in L)
True
# long time, needs sagemath_doc_html
N = len(search_doc('tree', interact=False).splitlines())
L = search_doc('tree', whole_word=True, interact=False).splitlines()
len(L) < N
import re
tree_re = re.compile(r'(^|\W)tree(\W|$)', re.I)
all(tree_re.search(l) for l in L)
sage.misc.sagedoc.search_src(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds)[source]

Search Sage library source code for lines containing string. The search is case-insensitive by default.

INPUT:

  • string – string to find in the Sage source code

  • extra1, …, extra5 – additional strings to require when searching. Lines must match all of these, as well as string

  • whole_word – (default: False) if True, search for string and extra1 (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 – boolean (default: True); if False, perform a case-sensitive search

  • multiline – (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 – boolean (default: True); if False, return a string with all the matches. Otherwise, this function returns None, 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 – (default: '') regular expression which the filename (including the path) must match

  • module – (default: 'sage') the module in which to search. The default is ‘sage’, the entire Sage library. If module 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, if interact is True (the default), there is no output. Instead: at the command line, the search results are printed on the screen in the form filename:line_number:line of text, showing the filename in which each match occurs, the line number where it occurs, and the actual matching line. (If multiline 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 and extraN arguments are treated as regular expressions, as is path_re, and errors will be raised if they are invalid. The matches will be case-insensitive unless ignore_case is False.

Note

The extraN parameters are present only because search_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 with interact=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
>>> from sage.all import *
>>> len(search_src("matrix", interact=False).splitlines())  # random # long time
9522
len(search_src("matrix", interact=False).splitlines())  # random # long time

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
>>> from sage.all import *
>>> len(search_src("matrix", module="sage.calculus", interact=False).splitlines())  # random
26
len(search_src("matrix", module="sage.calculus", interact=False).splitlines())  # random

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",                                  # needs sage.modules
....:                interact=False).splitlines()) > 15
True
>>> from sage.all import *
>>> len(search_src("matrix", path_re="calc",                                  # needs sage.modules
...                interact=False).splitlines()) > Integer(15)
True
len(search_src("matrix", path_re="calc",                                  # needs sage.modules
               interact=False).splitlines()) > 15

The following produces an error because the string ‘fetch(’ is a malformed regular expression:

sage: print(search_src(" fetch(", "def", interact=False))
Traceback (most recent call last):
...
error: missing ), unterminated subpattern at position 6
>>> from sage.all import *
>>> print(search_src(" fetch(", "def", interact=False))
Traceback (most recent call last):
...
error: missing ), unterminated subpattern at position 6
print(search_src(" fetch(", "def", interact=False))

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):
>>> from sage.all import *
>>> 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)

>>> print(search_src(r" fetch\(", "def", "pyx", interact=False))  # random # long time
matrix/matrix0.pyx:    cdef fetch(self, key):
print(search_src(r" fetch\(", "def", interact=False))  # random # long time
print(search_src(r" fetch\(", "def", "pyx", interact=False))  # random # long time

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
>>> from sage.all import *
>>> s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > Integer(0)
True

>>> s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > Integer(0)
True

>>> s = search_src('MatRiX', path_re='matrix',
...                interact=False, ignore_case=False); s.find('x') > Integer(0)
False
s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0
s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0
s = search_src('MatRiX', path_re='matrix',
               interact=False, ignore_case=False); s.find('x') > 0

Searches are by default restricted to single lines, but this can be changed by setting multiline to be True. In the following, since search_src(string, interact=False) returns a string with one line for each match, counting the length of search_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
>>> from sage.all import *
>>> len(search_src('log', 'derivative', interact=False).splitlines()) < Integer(40)
True
>>> len(search_src('log', 'derivative',
...                interact=False, multiline=True).splitlines()) > Integer(70)
True
len(search_src('log', 'derivative', interact=False).splitlines()) < 40
len(search_src('log', 'derivative',
               interact=False, multiline=True).splitlines()) > 70

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())...
misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines())...
misc/sagedoc.py:... len(search_src("matrix", path_re="calc"...
misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False))...
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False))...
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False))...
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',...
misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40...
misc/sagedoc.py:... len(search_src('log', 'derivative'...
misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False))...
misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000...
misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub',...
misc/sagedoc.py:... sage: results = search_src('format_search_as_html',...
>>> from sage.all import *
>>> print(search_src(r'^ *sage[:] .*search_src\(', interact=False))  # long time
misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines())...
misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines())...
misc/sagedoc.py:... len(search_src("matrix", path_re="calc"...
misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False))...
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False))...
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False))...
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',...
misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40...
misc/sagedoc.py:... len(search_src('log', 'derivative'...
misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False))...
misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000...
misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub',...
misc/sagedoc.py:... sage: results = search_src('format_search_as_html',...
print(search_src(r'^ *sage[:] .*search_src\(', interact=False))  # long time
sage.misc.sagedoc.skip_TESTS_block(docstring)[source]

Remove blocks labeled “TESTS:” from docstring.

INPUT:

  • docstring – 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'
>>> from sage.all import *
>>> from sage.misc.sagedoc import skip_TESTS_block
>>> start = ' Docstring\n\n'
>>> test = ' TESTS: \n\n Here is a test::\n     sage: 2+2 \n     5 \n\n'
>>> test2 = ' TESTS:: \n\n     sage: 2+2 \n     6 \n\n'
from sage.misc.sagedoc import skip_TESTS_block
start = ' Docstring\n\n'
test = ' TESTS: \n\n Here is a test::\n     sage: 2+2 \n     5 \n\n'
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
>>> from sage.all import *
>>> refs = ' REFERENCES: \n text text \n'
>>> skip_TESTS_block(start + test + refs).rstrip() == (start + refs).rstrip()
True
>>> skip_TESTS_block(start + test + test2 + refs).rstrip() == (start + refs).rstrip()
True
>>> skip_TESTS_block(start + test + refs + test2).rstrip() == (start + refs).rstrip()
True
refs = ' REFERENCES: \n text text \n'
skip_TESTS_block(start + test + refs).rstrip() == (start + refs).rstrip()
skip_TESTS_block(start + test + test2 + refs).rstrip() == (start + refs).rstrip()
skip_TESTS_block(start + test + refs + test2).rstrip() == (start + refs).rstrip()

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
>>> from sage.all import *
>>> directive = ' .. todo:: \n     do some stuff \n'
>>> skip_TESTS_block(start + test + refs + test2 + directive).rstrip() == (start + refs + directive).rstrip()
True
directive = ' .. todo:: \n     do some stuff \n'
skip_TESTS_block(start + test + refs + test2 + directive).rstrip() == (start + refs + directive).rstrip()

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
>>> from sage.all import *
>>> unindented = 'NOT INDENTED\n'
>>> skip_TESTS_block(start + test + unindented).rstrip() == (start + unindented).rstrip()
True
>>> skip_TESTS_block(start + test + unindented + test2 + unindented).rstrip() == (start + unindented + unindented).rstrip()
True
unindented = 'NOT INDENTED\n'
skip_TESTS_block(start + test + unindented).rstrip() == (start + unindented).rstrip()
skip_TESTS_block(start + test + unindented + test2 + unindented).rstrip() == (start + unindented + unindented).rstrip()

Test headers:

sage: header = ' Header:\n ~~~~~~~~'
sage: skip_TESTS_block(start + test + header) == start + header
True
>>> from sage.all import *
>>> header = ' Header:\n ~~~~~~~~'
>>> skip_TESTS_block(start + test + header) == start + header
True
header = ' Header:\n ~~~~~~~~'
skip_TESTS_block(start + test + header) == start + header

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
>>> from sage.all import *
>>> fake_header = ' Header:\n -=-=-=-=-='
>>> skip_TESTS_block(start + test + fake_header).rstrip() == start.rstrip()
True
fake_header = ' Header:\n -=-=-=-=-='
skip_TESTS_block(start + test + fake_header).rstrip() == start.rstrip()

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
>>> from sage.all import *
>>> another_fake = '\n    blah\n    ----'
>>> skip_TESTS_block(start + test + another_fake).rstrip() == start.rstrip()
True
another_fake = '\n    blah\n    ----'
skip_TESTS_block(start + test + another_fake).rstrip() == start.rstrip()

Double colons :: are also not considered as headers (Issue #27896):

sage: colons = ' ::\n\n     sage: 2+2\n     4\n\n'
sage: skip_TESTS_block(start + test2 + colons).rstrip() == start.rstrip()
True
>>> from sage.all import *
>>> colons = ' ::\n\n     sage: 2+2\n     4\n\n'
>>> skip_TESTS_block(start + test2 + colons).rstrip() == start.rstrip()
True
colons = ' ::\n\n     sage: 2+2\n     4\n\n'
skip_TESTS_block(start + test2 + colons).rstrip() == start.rstrip()