passagemath-repl 10.4.62__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_repl-10.4.62.data/scripts/sage-cachegrind +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-callgrind +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-cleaner +230 -0
- passagemath_repl-10.4.62.data/scripts/sage-coverage +327 -0
- passagemath_repl-10.4.62.data/scripts/sage-eval +14 -0
- passagemath_repl-10.4.62.data/scripts/sage-fixdoctests +708 -0
- passagemath_repl-10.4.62.data/scripts/sage-inline-fortran +12 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipynb2rst +50 -0
- passagemath_repl-10.4.62.data/scripts/sage-ipython +16 -0
- passagemath_repl-10.4.62.data/scripts/sage-massif +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-notebook +267 -0
- passagemath_repl-10.4.62.data/scripts/sage-omega +25 -0
- passagemath_repl-10.4.62.data/scripts/sage-preparse +302 -0
- passagemath_repl-10.4.62.data/scripts/sage-run +27 -0
- passagemath_repl-10.4.62.data/scripts/sage-run-cython +10 -0
- passagemath_repl-10.4.62.data/scripts/sage-runtests +9 -0
- passagemath_repl-10.4.62.data/scripts/sage-startuptime.py +163 -0
- passagemath_repl-10.4.62.data/scripts/sage-valgrind +34 -0
- passagemath_repl-10.4.62.dist-info/METADATA +77 -0
- passagemath_repl-10.4.62.dist-info/RECORD +162 -0
- passagemath_repl-10.4.62.dist-info/WHEEL +5 -0
- passagemath_repl-10.4.62.dist-info/top_level.txt +1 -0
- sage/all__sagemath_repl.py +119 -0
- sage/doctest/__init__.py +4 -0
- sage/doctest/__main__.py +236 -0
- sage/doctest/all.py +4 -0
- sage/doctest/check_tolerance.py +261 -0
- sage/doctest/control.py +1727 -0
- sage/doctest/external.py +534 -0
- sage/doctest/fixtures.py +383 -0
- sage/doctest/forker.py +2665 -0
- sage/doctest/marked_output.py +102 -0
- sage/doctest/parsing.py +1708 -0
- sage/doctest/parsing_test.py +79 -0
- sage/doctest/reporting.py +733 -0
- sage/doctest/rif_tol.py +124 -0
- sage/doctest/sources.py +1657 -0
- sage/doctest/test.py +584 -0
- sage/doctest/tests/1second.rst +4 -0
- sage/doctest/tests/99seconds.rst +4 -0
- sage/doctest/tests/abort.rst +5 -0
- sage/doctest/tests/atexit.rst +7 -0
- sage/doctest/tests/fail_and_die.rst +6 -0
- sage/doctest/tests/initial.rst +15 -0
- sage/doctest/tests/interrupt.rst +7 -0
- sage/doctest/tests/interrupt_diehard.rst +14 -0
- sage/doctest/tests/keyboardinterrupt.rst +11 -0
- sage/doctest/tests/longtime.rst +5 -0
- sage/doctest/tests/nodoctest +5 -0
- sage/doctest/tests/random_seed.rst +4 -0
- sage/doctest/tests/show_skipped.rst +18 -0
- sage/doctest/tests/sig_on.rst +9 -0
- sage/doctest/tests/simple_failure.rst +8 -0
- sage/doctest/tests/sleep_and_raise.rst +106 -0
- sage/doctest/tests/tolerance.rst +31 -0
- sage/doctest/util.py +750 -0
- sage/interfaces/cleaner.py +48 -0
- sage/interfaces/quit.py +163 -0
- sage/misc/all__sagemath_repl.py +51 -0
- sage/misc/banner.py +235 -0
- sage/misc/benchmark.py +221 -0
- sage/misc/classgraph.py +131 -0
- sage/misc/copying.py +22 -0
- sage/misc/cython.py +694 -0
- sage/misc/dev_tools.py +745 -0
- sage/misc/edit_module.py +304 -0
- sage/misc/explain_pickle.py +3079 -0
- sage/misc/gperftools.py +361 -0
- sage/misc/inline_fortran.py +212 -0
- sage/misc/messaging.py +86 -0
- sage/misc/pager.py +21 -0
- sage/misc/profiler.py +179 -0
- sage/misc/python.py +70 -0
- sage/misc/remote_file.py +53 -0
- sage/misc/sage_eval.py +246 -0
- sage/misc/sage_input.py +3621 -0
- sage/misc/sagedoc.py +1742 -0
- sage/misc/sh.py +38 -0
- sage/misc/trace.py +90 -0
- sage/repl/__init__.py +16 -0
- sage/repl/all.py +15 -0
- sage/repl/attach.py +625 -0
- sage/repl/configuration.py +186 -0
- sage/repl/display/__init__.py +1 -0
- sage/repl/display/fancy_repr.py +354 -0
- sage/repl/display/formatter.py +318 -0
- sage/repl/display/jsmol_iframe.py +290 -0
- sage/repl/display/pretty_print.py +153 -0
- sage/repl/display/util.py +163 -0
- sage/repl/image.py +302 -0
- sage/repl/inputhook.py +91 -0
- sage/repl/interface_magic.py +298 -0
- sage/repl/interpreter.py +854 -0
- sage/repl/ipython_extension.py +593 -0
- sage/repl/ipython_kernel/__init__.py +1 -0
- sage/repl/ipython_kernel/__main__.py +4 -0
- sage/repl/ipython_kernel/all_jupyter.py +10 -0
- sage/repl/ipython_kernel/install.py +301 -0
- sage/repl/ipython_kernel/interact.py +278 -0
- sage/repl/ipython_kernel/kernel.py +217 -0
- sage/repl/ipython_kernel/widgets.py +466 -0
- sage/repl/ipython_kernel/widgets_sagenb.py +587 -0
- sage/repl/ipython_tests.py +163 -0
- sage/repl/load.py +326 -0
- sage/repl/preparse.py +2218 -0
- sage/repl/prompts.py +90 -0
- sage/repl/rich_output/__init__.py +4 -0
- sage/repl/rich_output/backend_base.py +648 -0
- sage/repl/rich_output/backend_doctest.py +316 -0
- sage/repl/rich_output/backend_emacs.py +151 -0
- sage/repl/rich_output/backend_ipython.py +596 -0
- sage/repl/rich_output/buffer.py +311 -0
- sage/repl/rich_output/display_manager.py +829 -0
- sage/repl/rich_output/example.avi +0 -0
- sage/repl/rich_output/example.canvas3d +1 -0
- sage/repl/rich_output/example.dvi +0 -0
- sage/repl/rich_output/example.flv +0 -0
- sage/repl/rich_output/example.gif +0 -0
- sage/repl/rich_output/example.jpg +0 -0
- sage/repl/rich_output/example.mkv +0 -0
- sage/repl/rich_output/example.mov +0 -0
- sage/repl/rich_output/example.mp4 +0 -0
- sage/repl/rich_output/example.ogv +0 -0
- sage/repl/rich_output/example.pdf +0 -0
- sage/repl/rich_output/example.png +0 -0
- sage/repl/rich_output/example.svg +54 -0
- sage/repl/rich_output/example.webm +0 -0
- sage/repl/rich_output/example.wmv +0 -0
- sage/repl/rich_output/example_jmol.spt.zip +0 -0
- sage/repl/rich_output/example_wavefront_scene.mtl +7 -0
- sage/repl/rich_output/example_wavefront_scene.obj +17 -0
- sage/repl/rich_output/output_basic.py +391 -0
- sage/repl/rich_output/output_browser.py +103 -0
- sage/repl/rich_output/output_catalog.py +54 -0
- sage/repl/rich_output/output_graphics.py +320 -0
- sage/repl/rich_output/output_graphics3d.py +345 -0
- sage/repl/rich_output/output_video.py +231 -0
- sage/repl/rich_output/preferences.py +432 -0
- sage/repl/rich_output/pretty_print.py +339 -0
- sage/repl/rich_output/test_backend.py +201 -0
- sage/repl/user_globals.py +214 -0
- sage/tests/__init__.py +1 -0
- sage/tests/all.py +3 -0
- sage/tests/article_heuberger_krenn_kropf_fsm-in-sage.py +630 -0
- sage/tests/arxiv_0812_2725.py +351 -0
- sage/tests/benchmark.py +1923 -0
- sage/tests/book_schilling_zabrocki_kschur_primer.py +795 -0
- sage/tests/book_stein_ent.py +651 -0
- sage/tests/book_stein_modform.py +558 -0
- sage/tests/cmdline.py +790 -0
- sage/tests/combinatorial_hopf_algebras.py +52 -0
- sage/tests/finite_poset.py +623 -0
- sage/tests/functools_partial_src.py +27 -0
- sage/tests/gosper-sum.py +218 -0
- sage/tests/lazy_imports.py +28 -0
- sage/tests/modular_group_cohomology.py +80 -0
- sage/tests/numpy.py +21 -0
- sage/tests/parigp.py +76 -0
- sage/tests/startup.py +27 -0
- sage/tests/symbolic-series.py +76 -0
- sage/tests/sympy.py +16 -0
- sage/tests/test_deprecation.py +31 -0
sage/misc/sagedoc.py
ADDED
@@ -0,0 +1,1742 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-repl
|
2
|
+
r"""
|
3
|
+
Format Sage documentation for viewing with IPython and the notebook
|
4
|
+
|
5
|
+
AUTHORS:
|
6
|
+
|
7
|
+
- William Stein (2005): initial version.
|
8
|
+
- Nick Alexander (2007): nodetex functions
|
9
|
+
- Nick Alexander (2008): search_src, search_def improvements
|
10
|
+
- Martin Albrecht (2008-03-21): parse LaTeX description environments in sagedoc
|
11
|
+
- John Palmieri (2009-04-11): fix for #5754 plus doctests
|
12
|
+
- Dan Drake (2009-05-21): refactor search_* functions, use system 'find' instead of sage -grep
|
13
|
+
- John Palmieri (2009-06-28): don't use 'find' -- use Python (os.walk, re.search) instead.
|
14
|
+
- Simon King (2011-09): Use os.linesep, avoid destruction of embedding information,
|
15
|
+
enable nodetex in a docstring. Consequently use sage_getdoc.
|
16
|
+
|
17
|
+
TESTS:
|
18
|
+
|
19
|
+
Check that argspecs of extension function/methods appear correctly,
|
20
|
+
see :issue:`12849`::
|
21
|
+
|
22
|
+
sage: from sage.env import SAGE_DOC
|
23
|
+
sage: docfilename = os.path.join(SAGE_DOC, 'html', 'en', 'reference', 'calculus', 'sage', 'symbolic', 'expression.html')
|
24
|
+
sage: with open(docfilename) as fobj: # needs sagemath_doc_html
|
25
|
+
....: for line in fobj:
|
26
|
+
....: if "#sage.symbolic.expression.Expression.numerical_approx" in line:
|
27
|
+
....: print(line)
|
28
|
+
<span class="sig-name descname"><span class="pre">numerical_approx</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">prec</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">digits</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">algorithm</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span>...
|
29
|
+
|
30
|
+
Check that sphinx is not imported at Sage start-up::
|
31
|
+
|
32
|
+
sage: os.system("sage -c \"if 'sphinx' in sys.modules: sys.exit(1)\"") # needs sage.all
|
33
|
+
0
|
34
|
+
"""
|
35
|
+
# ****************************************************************************
|
36
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
37
|
+
#
|
38
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
39
|
+
# as published by the Free Software Foundation; either version 2 of
|
40
|
+
# the License, or (at your option) any later version.
|
41
|
+
# https://www.gnu.org/licenses/
|
42
|
+
# ****************************************************************************
|
43
|
+
import os
|
44
|
+
import re
|
45
|
+
import shutil
|
46
|
+
import sys
|
47
|
+
import pydoc
|
48
|
+
from sage.misc.temporary_file import tmp_dir
|
49
|
+
from sage.misc.viewer import browser
|
50
|
+
from sage.misc import sageinspect
|
51
|
+
import sage.version
|
52
|
+
from sage.env import SAGE_DOC, SAGE_SRC
|
53
|
+
|
54
|
+
# The detex function does two kinds of substitutions: math, which
|
55
|
+
# should only be done on the command line -- in the notebook, these
|
56
|
+
# should instead by taken care of by MathJax -- and nonmath, which
|
57
|
+
# should be done always.
|
58
|
+
|
59
|
+
# Math substitutions: don't forget the leading backslash '\\'. These
|
60
|
+
# are done using regular expressions, so it works best to also make
|
61
|
+
# the strings raw: r'\\blah'.
|
62
|
+
math_substitutes = [
|
63
|
+
(r'\\to', '-->'),
|
64
|
+
(r'\\rightarrow', '-->'),
|
65
|
+
(r'\\leftarrow', '<--'),
|
66
|
+
(r'\\leftrightarrow', '<->'),
|
67
|
+
(r'\\longrightarrow', '--->'),
|
68
|
+
(r'\\longleftarrow', '<---'),
|
69
|
+
(r'\\longleftrightarrow', '<-->'),
|
70
|
+
(r'\\Rightarrow', '==>'),
|
71
|
+
(r'\\Leftarrow', '<=='),
|
72
|
+
(r'\\Leftrightarrow', '<=>'),
|
73
|
+
(r'\\Longrightarrow', '===>'),
|
74
|
+
(r'\\Longleftarrow', '<==='),
|
75
|
+
(r'\\Longleftrightarrow', '<==>'),
|
76
|
+
(r'\\colon', ':'),
|
77
|
+
(r'\\left', ''),
|
78
|
+
(r'\\right', ''),
|
79
|
+
(r'\\bigl', ''),
|
80
|
+
(r'\\bigr', ''),
|
81
|
+
(r'\\leq', '<='),
|
82
|
+
(r'\\geq', '>='),
|
83
|
+
(r'\\le', '<='),
|
84
|
+
(r'\\ge', '>='),
|
85
|
+
(r'\\cdots', '...'),
|
86
|
+
(r'\\ldots', '...'),
|
87
|
+
(r'\\dots', '...'),
|
88
|
+
(r'\\cdot', ' *'),
|
89
|
+
(r'\\ast', ' *'),
|
90
|
+
(r' \\times', ' x'),
|
91
|
+
(r'\\times', ' x'),
|
92
|
+
(r'\\backslash', '\\'),
|
93
|
+
(r'\\mapsto', ' |--> '),
|
94
|
+
(r'\\longmapsto', ' |---> '),
|
95
|
+
(r'\\lvert', '|'),
|
96
|
+
(r'\\rvert', '|'),
|
97
|
+
(r'\\mid', '|'),
|
98
|
+
(r' \\circ', ' o'),
|
99
|
+
(r'\\circ', ' o')
|
100
|
+
]
|
101
|
+
nonmath_substitutes = [
|
102
|
+
('\\_', '_'),
|
103
|
+
('\\item', '* '),
|
104
|
+
('<BLANKLINE>', ''),
|
105
|
+
('\\bf', ''),
|
106
|
+
('\\sage', 'Sage'),
|
107
|
+
('\\SAGE', 'Sage'),
|
108
|
+
('\\Sage', 'Sage'),
|
109
|
+
('\\rm', ''),
|
110
|
+
('backslash', '\\'),
|
111
|
+
('begin{enumerate}', ''),
|
112
|
+
('end{enumerate}', ''),
|
113
|
+
('begin{description}', ''),
|
114
|
+
('end{description}', ''),
|
115
|
+
('begin{itemize}', ''),
|
116
|
+
('end{itemize}', ''),
|
117
|
+
('begin{verbatim}', ''),
|
118
|
+
('end{verbatim}', ''),
|
119
|
+
('note{', 'NOTE: '),
|
120
|
+
]
|
121
|
+
|
122
|
+
|
123
|
+
def _rmcmd(s, cmd, left='', right=''):
|
124
|
+
"""
|
125
|
+
Remove the LaTeX command ``cmd`` from the string ``s``. This
|
126
|
+
function is used by ``detex``.
|
127
|
+
|
128
|
+
INPUT:
|
129
|
+
|
130
|
+
- ``s`` -- string; string from which to remove the command
|
131
|
+
|
132
|
+
- ``cmd`` -- string; command to be removed. This should be a
|
133
|
+
command which takes a single argument, like 'emph' or 'url'; the
|
134
|
+
command is removed, but its argument is not.
|
135
|
+
|
136
|
+
- ``left``, ``right`` -- string (default: ``''``); add these
|
137
|
+
strings at the left and right ends of the command. See the
|
138
|
+
examples.
|
139
|
+
|
140
|
+
EXAMPLES::
|
141
|
+
|
142
|
+
sage: from sage.misc.sagedoc import _rmcmd
|
143
|
+
sage: _rmcmd('Check out \\url{http://www.sagemath.org}.', 'url')
|
144
|
+
'Check out http://www.sagemath.org.'
|
145
|
+
sage: _rmcmd('Text in \\emph{italics} looks like this.', 'emph', '*', '*')
|
146
|
+
'Text in *italics* looks like this.'
|
147
|
+
sage: _rmcmd('This is a \\very{silly} example.', 'very', right='!?')
|
148
|
+
'This is a silly!? example.'
|
149
|
+
"""
|
150
|
+
c = '\\%s{' % cmd
|
151
|
+
while True:
|
152
|
+
i = s.find(c)
|
153
|
+
if i == -1:
|
154
|
+
return s
|
155
|
+
nesting = 1
|
156
|
+
j = i + len(c) + 1
|
157
|
+
while j < len(s) and nesting > 0:
|
158
|
+
if s[j] == '{':
|
159
|
+
nesting += 1
|
160
|
+
elif s[j] == '}':
|
161
|
+
nesting -= 1
|
162
|
+
j += 1
|
163
|
+
j -= 1 # j is position of closing '}'
|
164
|
+
if j < len(s):
|
165
|
+
s = s[:i] + left + s[i + len(c):j] + right + s[j + 1:]
|
166
|
+
else:
|
167
|
+
return s
|
168
|
+
|
169
|
+
# I wanted to be cool and use regexp's, but they aren't really
|
170
|
+
# useful, since really this is a parsing problem, because of
|
171
|
+
# nesting of commands, etc. Since it doesn't have to be
|
172
|
+
# super super fast (it's a page of text scrolled to the user),
|
173
|
+
# the above works fine.
|
174
|
+
|
175
|
+
#
|
176
|
+
# import re
|
177
|
+
# def _rmcmd(s, cmd, left='', right=''):
|
178
|
+
# c = '\\%s{.*}'%cmd
|
179
|
+
# r = re.compile(c, re.DOTALL)
|
180
|
+
# while True:
|
181
|
+
# m = r.search(s)
|
182
|
+
# if m is None: break
|
183
|
+
# s = s[:m.start()] + left + s[m.start()+len(cmd)+1:m.end()-1] \
|
184
|
+
# + right + s[m.end():]
|
185
|
+
# return s
|
186
|
+
|
187
|
+
|
188
|
+
itempattern = re.compile(r"\\item\[?([^]]*)\]? *(.*)")
|
189
|
+
itemreplace = r"* \1 \2"
|
190
|
+
|
191
|
+
|
192
|
+
def detex(s, embedded=False):
|
193
|
+
r"""nodetex
|
194
|
+
This strips LaTeX commands from a string; it is used by the
|
195
|
+
``format`` function to process docstrings for display from the
|
196
|
+
command line interface.
|
197
|
+
|
198
|
+
INPUT:
|
199
|
+
|
200
|
+
- ``s`` -- string
|
201
|
+
- ``embedded`` -- boolean (default: ``False``)
|
202
|
+
|
203
|
+
If ``embedded`` is ``False``, then do the replacements in both
|
204
|
+
``math_substitutes`` and ``nonmath_substitutes``. If ``True``, then
|
205
|
+
only do ``nonmath_substitutes``.
|
206
|
+
|
207
|
+
OUTPUT: string
|
208
|
+
|
209
|
+
EXAMPLES::
|
210
|
+
|
211
|
+
sage: from sage.misc.sagedoc import detex
|
212
|
+
sage: detex(r'Some math: `n \geq k`. A website: \url{sagemath.org}.')
|
213
|
+
'Some math: n >= k. A website: sagemath.org.\n'
|
214
|
+
sage: detex(r'More math: `x \mapsto y`. {\bf Bold face}.')
|
215
|
+
'More math: x |--> y. { Bold face}.\n'
|
216
|
+
sage: detex(r'`a, b, c, \ldots, z`')
|
217
|
+
'a, b, c, ..., z\n'
|
218
|
+
sage: detex(r'`a, b, c, \ldots, z`', embedded=True)
|
219
|
+
'`a, b, c, \\ldots, z`'
|
220
|
+
sage: detex(r'`\left(\lvert x\ast y \rvert\right]`')
|
221
|
+
'(| x * y |]\n'
|
222
|
+
sage: detex(r'`\left(\leq\le\leftarrow \rightarrow\unknownmacro\to`')
|
223
|
+
'(<=<=<-- -->\\unknownmacro-->\n'
|
224
|
+
"""
|
225
|
+
s = _rmcmd(s, 'url')
|
226
|
+
s = _rmcmd(s, 'code')
|
227
|
+
s = _rmcmd(s, 'class')
|
228
|
+
s = _rmcmd(s, 'mbox')
|
229
|
+
s = _rmcmd(s, 'text')
|
230
|
+
s = _rmcmd(s, 'section')
|
231
|
+
s = _rmcmd(s, 'subsection')
|
232
|
+
s = _rmcmd(s, 'subsubsection')
|
233
|
+
s = _rmcmd(s, 'note', 'NOTE: ', '')
|
234
|
+
s = _rmcmd(s, 'emph', '*', '*')
|
235
|
+
s = _rmcmd(s, 'textbf', '*', '*')
|
236
|
+
|
237
|
+
s = re.sub(itempattern, itemreplace, s)
|
238
|
+
|
239
|
+
for a, b in nonmath_substitutes:
|
240
|
+
s = s.replace(a, b)
|
241
|
+
if not embedded: # not in the notebook
|
242
|
+
s = _rmcmd(s, 'mathop')
|
243
|
+
s = _rmcmd(s, 'mathrm')
|
244
|
+
try:
|
245
|
+
from .sphinxify import sphinxify
|
246
|
+
except ImportError:
|
247
|
+
s = s.replace('``', '"').replace('`', '') + '\n'
|
248
|
+
else:
|
249
|
+
s = sphinxify(s, format='text')
|
250
|
+
# Do math substitutions. The strings to be replaced should be
|
251
|
+
# TeX commands like "\\blah". Do a regular expression
|
252
|
+
# replacement to replace "\\blah" but not "\\blahxyz", etc.:
|
253
|
+
# test to make sure the next character is not a letter.
|
254
|
+
for a, b in math_substitutes:
|
255
|
+
s = re.sub(a + '([^a-zA-Z])', b + '\\1', s)
|
256
|
+
return s
|
257
|
+
|
258
|
+
|
259
|
+
def skip_TESTS_block(docstring):
|
260
|
+
r"""
|
261
|
+
Remove blocks labeled "TESTS:" from ``docstring``.
|
262
|
+
|
263
|
+
INPUT:
|
264
|
+
|
265
|
+
- ``docstring`` -- string
|
266
|
+
|
267
|
+
A "TESTS" block is a block starting "TESTS:" (or
|
268
|
+
the same with two colons), on a line on its own, and ending either
|
269
|
+
with a line indented less than "TESTS", or with a line with the
|
270
|
+
same level of indentation -- not more -- matching one of the
|
271
|
+
following:
|
272
|
+
|
273
|
+
- a Sphinx directive of the form ".. foo:", optionally followed by
|
274
|
+
other text.
|
275
|
+
|
276
|
+
- text of the form "UPPERCASE:", optionally followed by other
|
277
|
+
text.
|
278
|
+
|
279
|
+
- lines which look like a reST header: one line containing
|
280
|
+
anything, followed by a line consisting only of a string of
|
281
|
+
hyphens, equal signs, or other characters which are valid
|
282
|
+
markers for reST headers: ``- = ` : ' " ~ _ ^ * + # < >``.
|
283
|
+
However, lines only containing double colons `::` do not
|
284
|
+
end "TESTS" blocks.
|
285
|
+
|
286
|
+
Return the string obtained from ``docstring`` by removing these
|
287
|
+
blocks.
|
288
|
+
|
289
|
+
EXAMPLES::
|
290
|
+
|
291
|
+
sage: from sage.misc.sagedoc import skip_TESTS_block
|
292
|
+
sage: start = ' Docstring\n\n'
|
293
|
+
sage: test = ' TESTS: \n\n Here is a test::\n sage: 2+2 \n 5 \n\n'
|
294
|
+
sage: test2 = ' TESTS:: \n\n sage: 2+2 \n 6 \n\n'
|
295
|
+
|
296
|
+
Test lines starting with "REFERENCES:"::
|
297
|
+
|
298
|
+
sage: refs = ' REFERENCES: \n text text \n'
|
299
|
+
sage: skip_TESTS_block(start + test + refs).rstrip() == (start + refs).rstrip()
|
300
|
+
True
|
301
|
+
sage: skip_TESTS_block(start + test + test2 + refs).rstrip() == (start + refs).rstrip()
|
302
|
+
True
|
303
|
+
sage: skip_TESTS_block(start + test + refs + test2).rstrip() == (start + refs).rstrip()
|
304
|
+
True
|
305
|
+
|
306
|
+
Test Sphinx directives::
|
307
|
+
|
308
|
+
sage: directive = ' .. todo:: \n do some stuff \n'
|
309
|
+
sage: skip_TESTS_block(start + test + refs + test2 + directive).rstrip() == (start + refs + directive).rstrip()
|
310
|
+
True
|
311
|
+
|
312
|
+
Test unindented lines::
|
313
|
+
|
314
|
+
sage: unindented = 'NOT INDENTED\n'
|
315
|
+
sage: skip_TESTS_block(start + test + unindented).rstrip() == (start + unindented).rstrip()
|
316
|
+
True
|
317
|
+
sage: skip_TESTS_block(start + test + unindented + test2 + unindented).rstrip() == (start + unindented + unindented).rstrip()
|
318
|
+
True
|
319
|
+
|
320
|
+
Test headers::
|
321
|
+
|
322
|
+
sage: header = ' Header:\n ~~~~~~~~'
|
323
|
+
sage: skip_TESTS_block(start + test + header) == start + header
|
324
|
+
True
|
325
|
+
|
326
|
+
Not a header because the characters on the second line must all be
|
327
|
+
the same::
|
328
|
+
|
329
|
+
sage: fake_header = ' Header:\n -=-=-=-=-='
|
330
|
+
sage: skip_TESTS_block(start + test + fake_header).rstrip() == start.rstrip()
|
331
|
+
True
|
332
|
+
|
333
|
+
Not a header because it's indented compared to 'TEST' in the
|
334
|
+
string ``test``::
|
335
|
+
|
336
|
+
sage: another_fake = '\n blah\n ----'
|
337
|
+
sage: skip_TESTS_block(start + test + another_fake).rstrip() == start.rstrip()
|
338
|
+
True
|
339
|
+
|
340
|
+
Double colons ``::`` are also not considered as headers (:issue:`27896`)::
|
341
|
+
|
342
|
+
sage: colons = ' ::\n\n sage: 2+2\n 4\n\n'
|
343
|
+
sage: skip_TESTS_block(start + test2 + colons).rstrip() == start.rstrip()
|
344
|
+
True
|
345
|
+
"""
|
346
|
+
# tests_block: match a line starting with whitespace, then
|
347
|
+
# "TEST" or "TESTS" followed by ":" or "::", then possibly
|
348
|
+
# more whitespace, then the end of the line.
|
349
|
+
tests_block = re.compile('([ ]*)TEST[S]?:[:]?[ ]*$')
|
350
|
+
# end_of_block: match a line starting with whitespace, then Sphinx
|
351
|
+
# directives of the form ".. foo:". This will match directive
|
352
|
+
# names "foo" containing letters of either case, hyphens,
|
353
|
+
# underscores.
|
354
|
+
# Also match uppercase text followed by a colon, like
|
355
|
+
# "REFERENCES:" or "ALGORITHM:".
|
356
|
+
end_of_block = re.compile(r'[ ]*(\.\.[ ]+[-_A-Za-z]+|[A-Z]+):')
|
357
|
+
# header: match a string of hyphens, or other characters which are
|
358
|
+
# valid markers for reST headers: - = ` : ' " ~ _ ^ * + # < >
|
359
|
+
# except for double colons ::
|
360
|
+
header = re.compile(r'^[ ]*(?:([-=`\'"~_^*+#><])\1+|:|:::+)[ ]*$')
|
361
|
+
s = ''
|
362
|
+
skip = False
|
363
|
+
previous = ''
|
364
|
+
# indentation: amount of indentation at the start of 'TESTS:'.
|
365
|
+
indentation = ''
|
366
|
+
for l in docstring.split('\n'):
|
367
|
+
if not skip:
|
368
|
+
m = tests_block.match(l)
|
369
|
+
if m:
|
370
|
+
skip = True
|
371
|
+
indentation = m.group(1)
|
372
|
+
else:
|
373
|
+
s += "\n"
|
374
|
+
s += l
|
375
|
+
else:
|
376
|
+
if l and not l.isspace() and not l.startswith(indentation):
|
377
|
+
# A non-blank line indented less than 'TESTS:'
|
378
|
+
skip = False
|
379
|
+
s += "\n"
|
380
|
+
s += l
|
381
|
+
elif end_of_block.match(l) and not tests_block.match(l):
|
382
|
+
# A line matching end_of_block and indented the same as 'TESTS:'
|
383
|
+
if l.startswith(indentation + " "):
|
384
|
+
continue
|
385
|
+
skip = False
|
386
|
+
s += "\n"
|
387
|
+
s += l
|
388
|
+
elif header.match(l):
|
389
|
+
# A line matching header.
|
390
|
+
if l.startswith(indentation + " "):
|
391
|
+
continue
|
392
|
+
skip = False
|
393
|
+
if previous:
|
394
|
+
s += "\n"
|
395
|
+
s += previous
|
396
|
+
s += "\n"
|
397
|
+
s += l
|
398
|
+
previous = l
|
399
|
+
return s[1:] # Remove empty line from the beginning.
|
400
|
+
|
401
|
+
|
402
|
+
def process_dollars(s):
|
403
|
+
r"""nodetex
|
404
|
+
Replace dollar signs with backticks.
|
405
|
+
|
406
|
+
More precisely, do a regular expression search. Replace a plain
|
407
|
+
dollar sign ($) by a backtick (`). Replace an escaped dollar sign
|
408
|
+
(\\$) by a dollar sign ($). Don't change a dollar sign preceded or
|
409
|
+
followed by a backtick (\`$ or \$`), because of strings like
|
410
|
+
"``$HOME``". Don't make any changes on lines starting with more
|
411
|
+
spaces than the first nonempty line in ``s``, because those are
|
412
|
+
indented and hence part of a block of code or examples.
|
413
|
+
|
414
|
+
This also doesn't replaces dollar signs enclosed in curly braces,
|
415
|
+
to avoid nested math environments.
|
416
|
+
|
417
|
+
EXAMPLES::
|
418
|
+
|
419
|
+
sage: from sage.misc.sagedoc import process_dollars
|
420
|
+
sage: process_dollars('hello')
|
421
|
+
'hello'
|
422
|
+
sage: process_dollars('some math: $x=y$')
|
423
|
+
doctest:warning...
|
424
|
+
DeprecationWarning: using dollar signs to mark up math in Sage docstrings
|
425
|
+
is deprecated; use backticks instead
|
426
|
+
See https://github.com/sagemath/sage/issues/33973 for details.
|
427
|
+
'some math: `x=y`'
|
428
|
+
|
429
|
+
Replace \\$ with $, and don't do anything when backticks are involved::
|
430
|
+
|
431
|
+
sage: process_dollars(r'a ``$REAL`` dollar sign: \$')
|
432
|
+
'a ``$REAL`` dollar sign: $'
|
433
|
+
|
434
|
+
Don't make any changes on lines indented more than the first
|
435
|
+
nonempty line::
|
436
|
+
|
437
|
+
sage: s = '\n first line\n indented $x=y$'
|
438
|
+
sage: s == process_dollars(s)
|
439
|
+
True
|
440
|
+
|
441
|
+
Don't replace dollar signs enclosed in curly braces::
|
442
|
+
|
443
|
+
sage: process_dollars(r'f(n) = 0 \text{ if $n$ is prime}')
|
444
|
+
'f(n) = 0 \\text{ if $n$ is prime}'
|
445
|
+
|
446
|
+
This is not perfect::
|
447
|
+
|
448
|
+
sage: process_dollars(r'$f(n) = 0 \text{ if $n$ is prime}$')
|
449
|
+
'`f(n) = 0 \\text{ if $n$ is prime}$'
|
450
|
+
|
451
|
+
The regular expression search doesn't find the last $.
|
452
|
+
Fortunately, there don't seem to be any instances of this kind of
|
453
|
+
expression in the Sage library, as of this writing.
|
454
|
+
"""
|
455
|
+
if s.find("$") == -1:
|
456
|
+
return s
|
457
|
+
from sage.misc.superseded import deprecation
|
458
|
+
# find how much leading whitespace s has, for later comparison:
|
459
|
+
# ignore all $ on lines which start with more whitespace.
|
460
|
+
whitespace = re.match(r'\s*\S', s.lstrip('\n'))
|
461
|
+
whitespace = ' ' * (whitespace.end() - 1) # leading whitespace
|
462
|
+
# Indices will be a list of pairs of positions in s, to search between.
|
463
|
+
# If the following search has no matches, then indices will be (0, len(s)).
|
464
|
+
indices = [0]
|
465
|
+
# This searches for "$blah$" inside a pair of curly braces --
|
466
|
+
# don't change these, since they're probably coming from a nested
|
467
|
+
# math environment. So for each match, search to the left of its
|
468
|
+
# start and to the right of its end, but not in between.
|
469
|
+
for m in re.finditer(r"{[^{}$]*\$([^{}$]*)\$[^{}$]*}", s):
|
470
|
+
indices[-1] = (indices[-1], m.start())
|
471
|
+
indices.append(m.end())
|
472
|
+
indices[-1] = (indices[-1], len(s))
|
473
|
+
# regular expression for $ (not \$, `$, $`, and only on a line
|
474
|
+
# with no extra leading whitespace).
|
475
|
+
#
|
476
|
+
# in detail:
|
477
|
+
# re.compile("^" # beginning of line
|
478
|
+
# + "(%s%)?" % whitespace
|
479
|
+
# + r"""(\S # non whitespace
|
480
|
+
# .*?)? # non-greedy match any non-newline characters
|
481
|
+
# (?<!`|\\)\$(?!`) # $ with negative lookbehind and lookahead
|
482
|
+
# """, re.M | re.X)
|
483
|
+
#
|
484
|
+
# except that this doesn't work, so use the equivalent regular
|
485
|
+
# expression without the 're.X' option. Maybe 'whitespace' gets
|
486
|
+
# eaten up by re.X?
|
487
|
+
regexp = "^" + "(%s)?" % whitespace + r"(\S.*?)?(?<!`|\\)\$(?!`)"
|
488
|
+
dollar = re.compile(regexp, re.M)
|
489
|
+
# regular expression for \$
|
490
|
+
slashdollar = re.compile(r"\\\$")
|
491
|
+
for start, end in indices:
|
492
|
+
while dollar.search(s, start, end):
|
493
|
+
m = dollar.search(s, start, end)
|
494
|
+
s = s[:m.end() - 1] + "`" + s[m.end():]
|
495
|
+
deprecation(33973,
|
496
|
+
"using dollar signs to mark up math in Sage docstrings "
|
497
|
+
"is deprecated; use backticks instead")
|
498
|
+
while slashdollar.search(s, start, end):
|
499
|
+
m = slashdollar.search(s, start, end)
|
500
|
+
s = s[:m.start()] + "$" + s[m.end():]
|
501
|
+
return s
|
502
|
+
|
503
|
+
|
504
|
+
# When adding roles here, also add them to SAGE_ROOT/src/tox.ini [flake8]
|
505
|
+
# and document them in SAGE_ROOT/src/doc/en/developer/sage_manuals.rst
|
506
|
+
#
|
507
|
+
# Sage github issue shortcuts. For example, :issue:`7549`.
|
508
|
+
pythonversion = sys.version.split(' ')[0]
|
509
|
+
extlinks = {
|
510
|
+
'python': (f'https://docs.python.org/release/{pythonversion}/%s', None),
|
511
|
+
'issue': ('https://github.com/sagemath/sage/issues/%s', 'Issue #%s'),
|
512
|
+
'sage_root': ('https://github.com/sagemath/sage/tree/develop/%s', 'SAGE_ROOT/%s'),
|
513
|
+
'wikipedia': ('https://en.wikipedia.org/wiki/%s', 'Wikipedia article %s'),
|
514
|
+
'arxiv': ('https://arxiv.org/abs/%s', 'arXiv %s'),
|
515
|
+
'oeis': ('https://oeis.org/%s', 'OEIS sequence %s'),
|
516
|
+
'doi': ('https://doi.org/%s', 'doi:%s'),
|
517
|
+
'pari': ('https://pari.math.u-bordeaux.fr/dochtml/help/%s', 'pari:%s'),
|
518
|
+
'mathscinet': ('https://www.ams.org/mathscinet-getitem?mr=%s', 'MathSciNet %s'),
|
519
|
+
'common_lisp': ('https://www.lispworks.com/documentation/lw50/CLHS/Body/%s.htm', 'Common Lisp: %s'),
|
520
|
+
'ecl': ('https://ecl.common-lisp.dev/static/manual/%s.html', 'ECL: %s'),
|
521
|
+
'gap': ('https://docs.gap-system.org/doc/ref/%s_mj.html', 'GAP: %s'),
|
522
|
+
'gap_package': ('https://docs.gap-system.org/pkg/%s', 'GAP package %s'),
|
523
|
+
'giac_cascmd': ('https://www-fourier.ujf-grenoble.fr/~parisse/giac/doc/en/cascmd_en/%s.html', 'Giac: %s'),
|
524
|
+
'giac_us': ('https://www-fourier.ujf-grenoble.fr/~parisse/giac_us.html#%s', 'Giac API: %s'),
|
525
|
+
'maxima': ('https://maxima.sourceforge.io/docs/manual/maxima_singlepage.html#%s', 'Maxima: %s'),
|
526
|
+
'meson': ('https://mesonbuild.com/%s', 'Meson: %s'),
|
527
|
+
'polymake': ('https://polymake.org/doku.php/documentation/latest/%s', 'polymake: %s'),
|
528
|
+
'ppl': ('https://www.bugseng.com/products/ppl/documentation/user/ppl-user-1.2-html/%s.html', 'PPL: %s'),
|
529
|
+
'qepcad': ('https://www.usna.edu/CS/qepcadweb/B/%s.html', 'QEPCAD: %s'),
|
530
|
+
'scip': ('https://scipopt.org/doc/html/%s.php', 'SCIP: %s'),
|
531
|
+
'singular': ('https://www.singular.uni-kl.de/Manual/4-3-2/%s.htm', 'Singular: %s'),
|
532
|
+
'soplex': ('https://soplex.zib.de/doc/html/%s.php', 'SoPlex: %s'),
|
533
|
+
}
|
534
|
+
|
535
|
+
|
536
|
+
def process_extlinks(s, embedded=False):
|
537
|
+
r"""nodetex
|
538
|
+
|
539
|
+
In docstrings at the command line, process markup related to the
|
540
|
+
Sphinx extlinks extension. For example, replace ``:issue:`NUM```
|
541
|
+
with ``https://github.com/sagemath/sage/issues/NUM``, and similarly with
|
542
|
+
``:python:TEXT`` and ``:wikipedia:TEXT``, looking up the url from
|
543
|
+
the dictionary ``extlinks`` in ``sage_docbuild.conf``.
|
544
|
+
If ``TEXT`` is of the form ``blah <LINK>``, then it uses ``LINK``
|
545
|
+
rather than ``TEXT`` to construct the url.
|
546
|
+
|
547
|
+
In the notebook, don't do anything: let sphinxify take care of it.
|
548
|
+
|
549
|
+
INPUT:
|
550
|
+
|
551
|
+
- ``s`` -- string, in practice a docstring
|
552
|
+
- ``embedded`` -- boolean (default: ``False``)
|
553
|
+
|
554
|
+
This function is called by :func:`format`, and if in the notebook,
|
555
|
+
it sets ``embedded`` to be ``True``, otherwise ``False``.
|
556
|
+
|
557
|
+
EXAMPLES::
|
558
|
+
|
559
|
+
sage: from sage.misc.sagedoc import process_extlinks
|
560
|
+
sage: process_extlinks('See :issue:`1234`, :wikipedia:`Wikipedia <Sage_(mathematics_software)>`, and :issue:`4321` ...')
|
561
|
+
'See https://github.com/sagemath/sage/issues/1234, https://en.wikipedia.org/wiki/Sage_(mathematics_software), and https://github.com/sagemath/sage/issues/4321 ...'
|
562
|
+
sage: process_extlinks('See :issue:`1234` for more information.', embedded=True)
|
563
|
+
'See :issue:`1234` for more information.'
|
564
|
+
sage: process_extlinks('see :python:`Implementing Descriptors <reference/datamodel.html#implementing-descriptors>` ...')
|
565
|
+
'see https://docs.python.org/release/.../reference/datamodel.html#implementing-descriptors ...'
|
566
|
+
"""
|
567
|
+
if embedded:
|
568
|
+
return s
|
569
|
+
for key in extlinks:
|
570
|
+
while True:
|
571
|
+
m = re.search(':%s:`([^`]*)`' % key, s)
|
572
|
+
if not m:
|
573
|
+
break
|
574
|
+
link = m.group(1)
|
575
|
+
m = re.search('.*<([^>]*)>', link)
|
576
|
+
if m:
|
577
|
+
link = m.group(1)
|
578
|
+
s = re.sub(':%s:`([^`]*)`' % key,
|
579
|
+
extlinks[key][0].replace('%s', link),
|
580
|
+
s, count=1)
|
581
|
+
return s
|
582
|
+
|
583
|
+
|
584
|
+
def process_mathtt(s):
|
585
|
+
r"""nodetex
|
586
|
+
Replace \\mathtt{BLAH} with BLAH in the command line.
|
587
|
+
|
588
|
+
INPUT:
|
589
|
+
|
590
|
+
- ``s`` -- string, in practice a docstring
|
591
|
+
|
592
|
+
This function is called by :func:`format`.
|
593
|
+
|
594
|
+
EXAMPLES::
|
595
|
+
|
596
|
+
sage: from sage.misc.sagedoc import process_mathtt
|
597
|
+
sage: process_mathtt(r'e^\mathtt{self}')
|
598
|
+
'e^self'
|
599
|
+
"""
|
600
|
+
while True:
|
601
|
+
start = s.find("\\mathtt{")
|
602
|
+
end = s.find("}", start)
|
603
|
+
if start == -1 or end == -1:
|
604
|
+
break
|
605
|
+
s = s[:start] + s[start + 8:end] + s[end + 1:]
|
606
|
+
return s
|
607
|
+
|
608
|
+
|
609
|
+
def process_optional_doctest_tags(s):
|
610
|
+
r"""
|
611
|
+
Remove ``# optional/needs`` doctest tags for present features from docstring ``s``.
|
612
|
+
|
613
|
+
EXAMPLES:
|
614
|
+
|
615
|
+
sage: from sage.misc.sagedoc import process_optional_doctest_tags
|
616
|
+
sage: process_optional_doctest_tags("sage: # needs sage.rings.finite_rings\nsage: K.<x> = FunctionField(GF(5^2,'a')); K\nRational function field in x over Finite Field in a of size 5^2") # needs sage.rings.finite_rings
|
617
|
+
"sage: K.<x> = FunctionField(GF(5^2,'a')); K\nRational function field in x over Finite Field in a of size 5^2"
|
618
|
+
"""
|
619
|
+
import io
|
620
|
+
from sage.doctest.external import available_software
|
621
|
+
from sage.doctest.parsing import parse_optional_tags, update_optional_tags
|
622
|
+
|
623
|
+
start = 0
|
624
|
+
with io.StringIO() as output:
|
625
|
+
for m in re.finditer('( *sage: *.*#.*)\n', s):
|
626
|
+
output.write(s[start:m.start(0)])
|
627
|
+
line = m.group(1)
|
628
|
+
tags = [tag for tag in parse_optional_tags(line)
|
629
|
+
if tag not in available_software]
|
630
|
+
line = update_optional_tags(line, tags=tags)
|
631
|
+
if not re.fullmatch(' *sage: *', line):
|
632
|
+
print(line, file=output)
|
633
|
+
start = m.end(0)
|
634
|
+
output.write(s[start:])
|
635
|
+
return output.getvalue()
|
636
|
+
|
637
|
+
|
638
|
+
def format(s, embedded=False):
|
639
|
+
r"""noreplace
|
640
|
+
Format Sage documentation ``s`` for viewing with IPython.
|
641
|
+
|
642
|
+
This calls :func:`detex` on ``s`` to convert LaTeX commands to plain
|
643
|
+
text, unless the directive ``nodetex`` is given in the first line
|
644
|
+
of the string.
|
645
|
+
|
646
|
+
Also, if ``s`` contains a string of the form ``<<<obj>>>``, then
|
647
|
+
it replaces it with the docstring for ``obj``, unless the
|
648
|
+
directive ``noreplace`` is given in the first line. If an error
|
649
|
+
occurs under the attempt to find the docstring for ``obj``, then
|
650
|
+
the substring ``<<<obj>>>`` is preserved.
|
651
|
+
|
652
|
+
Directives must be separated by a comma.
|
653
|
+
|
654
|
+
INPUT:
|
655
|
+
|
656
|
+
- ``s`` -- string
|
657
|
+
- ``embedded`` -- boolean (default: ``False``)
|
658
|
+
|
659
|
+
OUTPUT: string
|
660
|
+
|
661
|
+
Set ``embedded`` equal to ``True`` if formatting for use in the
|
662
|
+
notebook; this just gets passed as an argument to :func:`detex`.
|
663
|
+
|
664
|
+
.. SEEALSO::
|
665
|
+
|
666
|
+
:func:`sage.misc.sageinspect.sage_getdoc` to get the formatted
|
667
|
+
documentation of a given object.
|
668
|
+
|
669
|
+
EXAMPLES::
|
670
|
+
|
671
|
+
sage: from sage.misc.sagedoc import format
|
672
|
+
sage: format('Let `A` be an `m` by `n` (0,1)-matrix. We identify `A` with a chessboard')
|
673
|
+
'Let A be an m by n (0,1)-matrix. We identify A with a chessboard\n'
|
674
|
+
|
675
|
+
If the first line of the string is 'nodetex', remove 'nodetex' but
|
676
|
+
don't modify any TeX commands::
|
677
|
+
|
678
|
+
sage: format("nodetex\n`x \\geq y`")
|
679
|
+
'`x \\geq y`'
|
680
|
+
|
681
|
+
Testing a string enclosed in triple angle brackets::
|
682
|
+
|
683
|
+
sage: format('<<<identity_matrix')
|
684
|
+
'<<<identity_matrix\n'
|
685
|
+
sage: format('identity_matrix>>>')
|
686
|
+
'identity_matrix>>>\n'
|
687
|
+
sage: format('<<<identity_matrix>>>') # needs sage.modules
|
688
|
+
'...Definition: identity_matrix(...'
|
689
|
+
sage: format('<<<identity_matrix>>>')[:28] # needs sphinx
|
690
|
+
'Definition: identity_matrix('
|
691
|
+
|
692
|
+
TESTS:
|
693
|
+
|
694
|
+
We check that the todo Sphinx extension is correctly activated::
|
695
|
+
|
696
|
+
sage: sage.misc.sagedoc.format(sage.combinat.ranker.on_fly.__doc__) # needs sphinx
|
697
|
+
" Return ... Todo: add tests as in combinat::rankers\n"
|
698
|
+
|
699
|
+
In the following use case, the ``nodetex`` directive would have been ignored prior
|
700
|
+
to :issue:`11815`::
|
701
|
+
|
702
|
+
sage: cython_code = ["def testfunc(x):",
|
703
|
+
....: " '''",
|
704
|
+
....: " nodetex",
|
705
|
+
....: " This is a doc string with raw latex",
|
706
|
+
....: "",
|
707
|
+
....: " `x \\geq y`",
|
708
|
+
....: " '''",
|
709
|
+
....: " return -x"]
|
710
|
+
sage: cython('\n'.join(cython_code)) # needs sage.misc.cython
|
711
|
+
sage: from sage.misc.sageinspect import sage_getdoc
|
712
|
+
sage: print(sage_getdoc(testfunc)) # needs sage.misc.cython
|
713
|
+
<BLANKLINE>
|
714
|
+
This is a doc string with raw latex
|
715
|
+
<BLANKLINE>
|
716
|
+
`x \geq y`
|
717
|
+
<BLANKLINE>
|
718
|
+
|
719
|
+
We check that the ``noreplace`` directive works, even combined with
|
720
|
+
``nodetex`` (see :issue:`11817`)::
|
721
|
+
|
722
|
+
sage: print(format('''nodetex, noreplace\n<<<identity_matrix>>>`\\not= 0`'''))
|
723
|
+
<<<identity_matrix>>>`\not= 0`
|
724
|
+
|
725
|
+
If replacement is impossible, then no error is raised::
|
726
|
+
|
727
|
+
sage: print(format('<<<bla\n<<<bla>>>\n<<<identity_matrix>>>')) # needs sage.modules
|
728
|
+
<<<bla <<<bla>>>
|
729
|
+
<BLANKLINE>
|
730
|
+
Definition: identity_matrix(ring, n=0, sparse=False)
|
731
|
+
<BLANKLINE>
|
732
|
+
This function is available as identity_matrix(...) and
|
733
|
+
matrix.identity(...).
|
734
|
+
<BLANKLINE>
|
735
|
+
Return the n x n identity matrix over the given ring.
|
736
|
+
...
|
737
|
+
|
738
|
+
Check that backslashes are preserved in code blocks (:issue:`29140`)::
|
739
|
+
|
740
|
+
sage: format('::\n' # needs sphinx
|
741
|
+
....: '\n'
|
742
|
+
....: r' sage: print(r"\\\\.")' '\n'
|
743
|
+
....: r' \\\\.')
|
744
|
+
' sage: print(r"\\\\\\\\.")\n \\\\\\\\.\n'
|
745
|
+
sage: format(r'inline code ``\\\\.``')
|
746
|
+
'inline code "\\\\\\\\."\n'
|
747
|
+
"""
|
748
|
+
if not isinstance(s, str):
|
749
|
+
raise TypeError("s must be a string")
|
750
|
+
|
751
|
+
# Leading empty lines must be removed, since we search for directives
|
752
|
+
# in the first line.
|
753
|
+
s = s.lstrip(os.linesep)
|
754
|
+
|
755
|
+
# parse directives at beginning of docstring
|
756
|
+
# currently, only 'nodetex' and 'noreplace' are supported.
|
757
|
+
# 'no' + 'doctest' may be supported eventually (don't type that as
|
758
|
+
# one word, or the whole file will not be doctested).
|
759
|
+
first_newline = s.find(os.linesep)
|
760
|
+
if first_newline > -1:
|
761
|
+
first_line = s[:first_newline]
|
762
|
+
else:
|
763
|
+
first_line = s
|
764
|
+
# Moreover, we must strip blank space in order to get the directives
|
765
|
+
directives = [d.strip().lower() for d in first_line.split(',')]
|
766
|
+
|
767
|
+
if 'noreplace' in directives or 'nodetex' in directives:
|
768
|
+
s = s[first_newline + len(os.linesep):]
|
769
|
+
|
770
|
+
try:
|
771
|
+
import sage.all as toplevel
|
772
|
+
except ImportError:
|
773
|
+
try:
|
774
|
+
import sage.all__sagemath_polyhedra as toplevel
|
775
|
+
except ImportError:
|
776
|
+
try:
|
777
|
+
import sage.all__sagemath_categories as toplevel
|
778
|
+
except ImportError:
|
779
|
+
import sage.all__sagemath_objects as toplevel
|
780
|
+
|
781
|
+
docs = set()
|
782
|
+
if 'noreplace' not in directives:
|
783
|
+
i_0 = 0
|
784
|
+
while True:
|
785
|
+
i = s[i_0:].find("<<<")
|
786
|
+
if i == -1:
|
787
|
+
break
|
788
|
+
j = s[i_0 + i + 3:].find('>>>')
|
789
|
+
if j == -1:
|
790
|
+
break
|
791
|
+
obj = s[i_0 + i + 3:i_0 + i + 3 + j]
|
792
|
+
if obj in docs:
|
793
|
+
t = ''
|
794
|
+
elif obj.isidentifier():
|
795
|
+
try:
|
796
|
+
x = getattr(toplevel, obj)
|
797
|
+
except AttributeError:
|
798
|
+
# A pair <<<...>>> has been found, but the object not.
|
799
|
+
i_0 += i + 6 + j
|
800
|
+
continue
|
801
|
+
t0 = sage.misc.sageinspect.sage_getdef(x, obj)
|
802
|
+
t1 = sage.misc.sageinspect.sage_getdoc(x)
|
803
|
+
t = 'Definition: ' + t0 + '\n\n' + t1
|
804
|
+
docs.add(obj)
|
805
|
+
else:
|
806
|
+
# This is a simple heuristics to cover the case of
|
807
|
+
# a non-matching set of <<< and >>>
|
808
|
+
i_0 += i + 3
|
809
|
+
continue
|
810
|
+
|
811
|
+
s = s[:i_0 + i] + '\n' + t + s[i_0 + i + 6 + j:]
|
812
|
+
i_0 += i
|
813
|
+
|
814
|
+
if 'nodetex' not in directives:
|
815
|
+
s = process_dollars(s)
|
816
|
+
s = skip_TESTS_block(s)
|
817
|
+
if not embedded:
|
818
|
+
s = process_mathtt(s)
|
819
|
+
s = process_extlinks(s, embedded=embedded)
|
820
|
+
s = detex(s, embedded=embedded)
|
821
|
+
|
822
|
+
if not embedded:
|
823
|
+
s = process_optional_doctest_tags(s)
|
824
|
+
|
825
|
+
return s
|
826
|
+
|
827
|
+
|
828
|
+
def format_src(s):
|
829
|
+
"""
|
830
|
+
Format Sage source code ``s`` for viewing with IPython.
|
831
|
+
|
832
|
+
If ``s`` contains a string of the form "<<<obj>>>", then it
|
833
|
+
replaces it with the source code for "obj".
|
834
|
+
|
835
|
+
INPUT:
|
836
|
+
|
837
|
+
- ``s`` -- string
|
838
|
+
|
839
|
+
OUTPUT: string
|
840
|
+
|
841
|
+
EXAMPLES::
|
842
|
+
|
843
|
+
sage: from sage.misc.sagedoc import format_src
|
844
|
+
sage: format_src('unladen swallow')
|
845
|
+
'unladen swallow'
|
846
|
+
sage: format_src('<<<Sq>>>')[5:15] # needs sage.combinat sage.modules
|
847
|
+
'Sq(*nums):'
|
848
|
+
"""
|
849
|
+
if not isinstance(s, str):
|
850
|
+
raise TypeError("s must be a string")
|
851
|
+
docs = set()
|
852
|
+
|
853
|
+
try:
|
854
|
+
import sage.all
|
855
|
+
except ImportError:
|
856
|
+
pass
|
857
|
+
|
858
|
+
while True:
|
859
|
+
i = s.find("<<<")
|
860
|
+
if i == -1:
|
861
|
+
break
|
862
|
+
j = s[i + 3:].find('>>>')
|
863
|
+
if j == -1:
|
864
|
+
break
|
865
|
+
obj = s[i + 3:i + 3 + j]
|
866
|
+
if obj in docs:
|
867
|
+
t = ''
|
868
|
+
else:
|
869
|
+
x = eval('sage.all.%s' % obj, locals())
|
870
|
+
t = my_getsource(x)
|
871
|
+
docs.add(obj)
|
872
|
+
if t is None:
|
873
|
+
print(x)
|
874
|
+
t = ''
|
875
|
+
s = s[:i] + '\n' + t + s[i + 6 + j:]
|
876
|
+
|
877
|
+
return s
|
878
|
+
|
879
|
+
|
880
|
+
###############################
|
881
|
+
|
882
|
+
def _search_src_or_doc(what, string, extra1='', extra2='', extra3='',
|
883
|
+
extra4='', extra5='', **kwargs):
|
884
|
+
r"""
|
885
|
+
Search the Sage library or documentation for lines containing
|
886
|
+
``string`` and possibly some other terms. This function is used by
|
887
|
+
:func:`search_src`, :func:`search_doc`, and :func:`search_def`.
|
888
|
+
|
889
|
+
INPUT:
|
890
|
+
|
891
|
+
- ``what`` -- either ``'src'`` or ``'doc'``, according to whether you
|
892
|
+
are searching the documentation or source code
|
893
|
+
- the rest of the input is the same as :func:`search_src`,
|
894
|
+
:func:`search_doc`, and :func:`search_def`
|
895
|
+
|
896
|
+
OUTPUT:
|
897
|
+
|
898
|
+
If ``interact`` is ``False``, a string containing the results;
|
899
|
+
otherwise, there is no output and the results are presented
|
900
|
+
according to whether you are using the notebook or command-line
|
901
|
+
interface. In the command-line interface, each line of the results
|
902
|
+
has the form ``filename:num:line of code``, where ``num`` is the
|
903
|
+
line number in ``filename`` and ``line of code`` is the line that
|
904
|
+
matched your search terms.
|
905
|
+
|
906
|
+
EXAMPLES::
|
907
|
+
|
908
|
+
sage: from sage.misc.sagedoc import _search_src_or_doc
|
909
|
+
sage: print(_search_src_or_doc('src', r'matrix\(', # long time random
|
910
|
+
....: 'incidence_structures', 'self',
|
911
|
+
....: '^combinat', interact=False))
|
912
|
+
misc/sagedoc.py: sage: _search_src_or_doc('src', 'matrix(', 'incidence_structures', 'self', '^combinat', interact=False)
|
913
|
+
combinat/designs/incidence_structures.py: M1 = self.incidence_matrix()
|
914
|
+
combinat/designs/incidence_structures.py: A = self.incidence_matrix()
|
915
|
+
combinat/designs/incidence_structures.py: M = transpose(self.incidence_matrix())
|
916
|
+
combinat/designs/incidence_structures.py: def incidence_matrix(self):
|
917
|
+
combinat/designs/incidence_structures.py: A = self.incidence_matrix()
|
918
|
+
combinat/designs/incidence_structures.py: A = self.incidence_matrix()
|
919
|
+
combinat/designs/incidence_structures.py: #A = self.incidence_matrix()
|
920
|
+
|
921
|
+
TESTS:
|
922
|
+
|
923
|
+
The examples are nice, but marking them "random" means we're not
|
924
|
+
really testing if the function works, just that it completes. These
|
925
|
+
tests aren't perfect, but are reasonable.
|
926
|
+
|
927
|
+
::
|
928
|
+
|
929
|
+
sage: from sage.misc.sagedoc import _search_src_or_doc
|
930
|
+
sage: len(_search_src_or_doc('src', r'matrix\(', 'incidence_structures', 'self', 'combinat', interact=False).splitlines()) > 1
|
931
|
+
True
|
932
|
+
sage: 'abvar/homology' in _search_src_or_doc('doc', 'homology', 'variety', interact=False) # long time (4s on sage.math, 2012), needs sagemath_doc_html
|
933
|
+
True
|
934
|
+
sage: 'divisors' in _search_src_or_doc('src', '^ *def prime', interact=False)
|
935
|
+
True
|
936
|
+
|
937
|
+
When passing ``interactive=True``, in a terminal session this will pass the
|
938
|
+
``text/plain`` output to the configured pager, while in a notebook session
|
939
|
+
it will display the ``text/html`` output in the notebook's pager. However,
|
940
|
+
in a non-interactive session (as in the doctests) it should just print the
|
941
|
+
results to stdout::
|
942
|
+
|
943
|
+
sage: from sage.misc.sagedoc import _search_src_or_doc
|
944
|
+
sage: _search_src_or_doc('src', # long time
|
945
|
+
....: r'def _search_src_or_doc\(',
|
946
|
+
....: interact=True)
|
947
|
+
misc/sagedoc.py:...: def _search_src_or_doc(what, string, extra1='', extra2='', extra3='',
|
948
|
+
"""
|
949
|
+
|
950
|
+
# process keyword arguments
|
951
|
+
interact = kwargs.get('interact', True)
|
952
|
+
path_re = kwargs.get('path_re', '')
|
953
|
+
module = kwargs.get('module', 'sage')
|
954
|
+
whole_word = kwargs.get('whole_word', False)
|
955
|
+
ignore_case = kwargs.get('ignore_case', True)
|
956
|
+
multiline = kwargs.get('multiline', False)
|
957
|
+
|
958
|
+
# done processing keywords
|
959
|
+
# define module, exts (file extension), title (title of search),
|
960
|
+
# base_path (top directory in which to search)
|
961
|
+
if what == 'src':
|
962
|
+
base_path = SAGE_SRC
|
963
|
+
if module.find('sage') == 0:
|
964
|
+
module = module[4:].lstrip(".") # remove 'sage' or 'sage.' from module
|
965
|
+
base_path = os.path.join(base_path, 'sage')
|
966
|
+
module = module.replace(".", os.sep)
|
967
|
+
exts = ['py', 'pyx', 'pxd']
|
968
|
+
title = 'Source Code'
|
969
|
+
else:
|
970
|
+
module = ''
|
971
|
+
exts = ['html']
|
972
|
+
title = 'Documentation'
|
973
|
+
base_path = os.path.join(SAGE_DOC, 'html')
|
974
|
+
if not os.path.exists(base_path):
|
975
|
+
print("""Warning: the Sage documentation is not available""")
|
976
|
+
|
977
|
+
strip = len(base_path)
|
978
|
+
results = []
|
979
|
+
# in regular expressions, '\bWORD\b' matches 'WORD' but not
|
980
|
+
# 'SWORD' or 'WORDS'. so if the user requests a whole_word
|
981
|
+
# search, append and prepend '\b' to each string.
|
982
|
+
regexp = string
|
983
|
+
extra_regexps = extras = [extra1, extra2, extra3, extra4, extra5]
|
984
|
+
if whole_word:
|
985
|
+
regexp = r'\b' + regexp + r'\b'
|
986
|
+
extra_regexps = [r'\b%s\b' % e for e in extra_regexps]
|
987
|
+
if ignore_case:
|
988
|
+
# 'flags' is a flag passed to re.search. use bit-wise or "|" to combine flags.
|
989
|
+
flags = re.IGNORECASE
|
990
|
+
else:
|
991
|
+
flags = 0
|
992
|
+
|
993
|
+
# done with preparation; ready to start search
|
994
|
+
for dirpath, dirs, files in os.walk(os.path.join(base_path, module)):
|
995
|
+
try:
|
996
|
+
dirs.remove('_static')
|
997
|
+
except ValueError:
|
998
|
+
pass
|
999
|
+
for f in files:
|
1000
|
+
if not f.startswith('.') and re.search(r"\.(" + "|".join(exts) + ")$", f):
|
1001
|
+
filename = os.path.join(dirpath, f)
|
1002
|
+
if re.search(path_re, filename):
|
1003
|
+
if multiline:
|
1004
|
+
with open(filename) as fobj:
|
1005
|
+
line = fobj.read()
|
1006
|
+
if re.search(regexp, line, flags):
|
1007
|
+
match_list = line
|
1008
|
+
else:
|
1009
|
+
match_list = None
|
1010
|
+
for extra in extra_regexps:
|
1011
|
+
if extra and match_list:
|
1012
|
+
if not re.search(extra, match_list):
|
1013
|
+
match_list = None
|
1014
|
+
if match_list:
|
1015
|
+
results.append(filename[strip:].lstrip("/") + '\n')
|
1016
|
+
else:
|
1017
|
+
with open(filename) as fobj:
|
1018
|
+
match_list = [(lineno, line)
|
1019
|
+
for lineno, line in enumerate(fobj)
|
1020
|
+
if re.search(regexp, line, flags)]
|
1021
|
+
for extra in extra_regexps:
|
1022
|
+
if extra:
|
1023
|
+
match_list = [s for s in match_list
|
1024
|
+
if re.search(extra, s[1], re.MULTILINE | flags)]
|
1025
|
+
for num, line in match_list:
|
1026
|
+
results.append('{}:{}:{}'.format(
|
1027
|
+
filename[strip:].lstrip('/'), num + 1, line))
|
1028
|
+
|
1029
|
+
text_results = ''.join(results).rstrip()
|
1030
|
+
|
1031
|
+
if not interact:
|
1032
|
+
return text_results
|
1033
|
+
|
1034
|
+
html_results = format_search_as_html(title, results, [string] + extras)
|
1035
|
+
# potentially used below
|
1036
|
+
|
1037
|
+
# Pass through the IPython pager in a mime bundle
|
1038
|
+
from IPython.core.page import page
|
1039
|
+
if not isinstance(text_results, str):
|
1040
|
+
text_results = text_results.decode('utf-8', 'replace')
|
1041
|
+
|
1042
|
+
page({
|
1043
|
+
'text/plain': text_results,
|
1044
|
+
# 'text/html': html_results
|
1045
|
+
# don't return HTML results since they currently are not
|
1046
|
+
# correctly formatted for Jupyter use
|
1047
|
+
})
|
1048
|
+
|
1049
|
+
|
1050
|
+
def search_src(string, extra1='', extra2='', extra3='', extra4='',
|
1051
|
+
extra5='', **kwds):
|
1052
|
+
r"""
|
1053
|
+
Search Sage library source code for lines containing ``string``.
|
1054
|
+
The search is case-insensitive by default.
|
1055
|
+
|
1056
|
+
INPUT:
|
1057
|
+
|
1058
|
+
- ``string`` -- string to find in the Sage source code
|
1059
|
+
|
1060
|
+
- ``extra1``, ..., ``extra5`` -- additional strings to require when
|
1061
|
+
searching. Lines must match all of these, as well as ``string``
|
1062
|
+
|
1063
|
+
- ``whole_word`` -- (default: ``False``) if ``True``, search for
|
1064
|
+
``string`` and ``extra1`` (etc.) as whole words only. This
|
1065
|
+
assumes that each of these arguments is a single word, not a
|
1066
|
+
regular expression, and it might have unexpected results if used
|
1067
|
+
with regular expressions.
|
1068
|
+
|
1069
|
+
- ``ignore_case`` -- boolean (default: ``True``); if ``False``, perform a
|
1070
|
+
case-sensitive search
|
1071
|
+
|
1072
|
+
- ``multiline`` -- (default: ``False``) if ``True``, search more
|
1073
|
+
than one line at a time. In this case, print any matching file
|
1074
|
+
names, but don't print line numbers.
|
1075
|
+
|
1076
|
+
- ``interact`` -- boolean (default: ``True``); if ``False``, return
|
1077
|
+
a string with all the matches. Otherwise, this function returns
|
1078
|
+
``None``, and the results are displayed appropriately, according
|
1079
|
+
to whether you are using the notebook or the command-line
|
1080
|
+
interface. You should not ordinarily need to use this.
|
1081
|
+
|
1082
|
+
- ``path_re`` -- (default: ``''``) regular expression which
|
1083
|
+
the filename (including the path) must match
|
1084
|
+
|
1085
|
+
- ``module`` -- (default: ``'sage'``) the module in which to
|
1086
|
+
search. The default is 'sage', the entire Sage library. If
|
1087
|
+
``module`` doesn't start with "sage", then the links in the
|
1088
|
+
notebook output may not function.
|
1089
|
+
|
1090
|
+
OUTPUT:
|
1091
|
+
|
1092
|
+
If ``interact`` is ``False``, then return a string with all of
|
1093
|
+
the matches, separated by newlines. On the other hand, if
|
1094
|
+
``interact`` is ``True`` (the default), there is no output. Instead:
|
1095
|
+
at the command line, the search results are printed on the screen
|
1096
|
+
in the form ``filename:line_number:line of text``, showing the
|
1097
|
+
filename in which each match occurs, the line number where it
|
1098
|
+
occurs, and the actual matching line. (If ``multiline`` is ``True``,
|
1099
|
+
then only the filename is printed for each match.) The file paths
|
1100
|
+
in the output are relative to ``$SAGE_SRC``. In the
|
1101
|
+
notebook, each match produces a link to the actual file in which
|
1102
|
+
it occurs.
|
1103
|
+
|
1104
|
+
The ``string`` and ``extraN`` arguments are treated as regular
|
1105
|
+
expressions, as is ``path_re``, and errors will be raised if they
|
1106
|
+
are invalid. The matches will be case-insensitive unless
|
1107
|
+
``ignore_case`` is ``False``.
|
1108
|
+
|
1109
|
+
.. NOTE::
|
1110
|
+
|
1111
|
+
The ``extraN`` parameters are present only because
|
1112
|
+
``search_src(string, *extras, interact=False)``
|
1113
|
+
is not parsed correctly by Python 2.6; see http://bugs.python.org/issue1909.
|
1114
|
+
|
1115
|
+
EXAMPLES:
|
1116
|
+
|
1117
|
+
First note that without using ``interact=False``, this function
|
1118
|
+
produces no output, while with ``interact=False``, the output is a
|
1119
|
+
string. These examples almost all use this option, so that they
|
1120
|
+
have something to which to compare their output.
|
1121
|
+
|
1122
|
+
You can search for "matrix" by typing ``search_src("matrix")``.
|
1123
|
+
This particular search will produce many results::
|
1124
|
+
|
1125
|
+
sage: len(search_src("matrix", interact=False).splitlines()) # random # long time
|
1126
|
+
9522
|
1127
|
+
|
1128
|
+
You can restrict to the Sage calculus code with
|
1129
|
+
``search_src("matrix", module="sage.calculus")``, and this
|
1130
|
+
produces many fewer results::
|
1131
|
+
|
1132
|
+
sage: len(search_src("matrix", module="sage.calculus", interact=False).splitlines()) # random
|
1133
|
+
26
|
1134
|
+
|
1135
|
+
Note that you can do tab completion on the ``module`` string.
|
1136
|
+
Another way to accomplish a similar search::
|
1137
|
+
|
1138
|
+
sage: len(search_src("matrix", path_re="calc", # needs sage.modules
|
1139
|
+
....: interact=False).splitlines()) > 15
|
1140
|
+
True
|
1141
|
+
|
1142
|
+
The following produces an error because the string 'fetch(' is a
|
1143
|
+
malformed regular expression::
|
1144
|
+
|
1145
|
+
sage: print(search_src(" fetch(", "def", interact=False))
|
1146
|
+
Traceback (most recent call last):
|
1147
|
+
...
|
1148
|
+
error: missing ), unterminated subpattern at position 6
|
1149
|
+
|
1150
|
+
To fix this, *escape* the parenthesis with a backslash::
|
1151
|
+
|
1152
|
+
sage: print(search_src(r" fetch\(", "def", interact=False)) # random # long time
|
1153
|
+
matrix/matrix0.pyx: cdef fetch(self, key):
|
1154
|
+
matrix/matrix0.pxd: cdef fetch(self, key)
|
1155
|
+
|
1156
|
+
sage: print(search_src(r" fetch\(", "def", "pyx", interact=False)) # random # long time
|
1157
|
+
matrix/matrix0.pyx: cdef fetch(self, key):
|
1158
|
+
|
1159
|
+
As noted above, the search is case-insensitive, but you can make it
|
1160
|
+
case-sensitive with the 'ignore_case' key word::
|
1161
|
+
|
1162
|
+
sage: s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0
|
1163
|
+
True
|
1164
|
+
|
1165
|
+
sage: s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0
|
1166
|
+
True
|
1167
|
+
|
1168
|
+
sage: s = search_src('MatRiX', path_re='matrix',
|
1169
|
+
....: interact=False, ignore_case=False); s.find('x') > 0
|
1170
|
+
False
|
1171
|
+
|
1172
|
+
Searches are by default restricted to single lines, but this can
|
1173
|
+
be changed by setting ``multiline`` to be True. In the following,
|
1174
|
+
since ``search_src(string, interact=False)`` returns a string with
|
1175
|
+
one line for each match, counting the length of
|
1176
|
+
``search_src(string, interact=False).splitlines()`` gives the
|
1177
|
+
number of matches. ::
|
1178
|
+
|
1179
|
+
sage: len(search_src('log', 'derivative', interact=False).splitlines()) < 40
|
1180
|
+
True
|
1181
|
+
sage: len(search_src('log', 'derivative', # needs sage.all
|
1182
|
+
....: interact=False, multiline=True).splitlines()) > 70
|
1183
|
+
True
|
1184
|
+
|
1185
|
+
A little recursive narcissism: let's do a doctest that searches for
|
1186
|
+
this function's doctests. Note that you can't put "sage:" in the
|
1187
|
+
doctest string because it will get replaced by the Python ">>>"
|
1188
|
+
prompt.
|
1189
|
+
|
1190
|
+
::
|
1191
|
+
|
1192
|
+
sage: print(search_src(r'^ *sage[:] .*search_src\(', interact=False)) # long time
|
1193
|
+
misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines())...
|
1194
|
+
misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines())...
|
1195
|
+
misc/sagedoc.py:... len(search_src("matrix", path_re="calc"...
|
1196
|
+
misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False))...
|
1197
|
+
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False))...
|
1198
|
+
misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False))...
|
1199
|
+
misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0...
|
1200
|
+
misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix', interact=False); s.find('x') > 0...
|
1201
|
+
misc/sagedoc.py:... s = search_src('MatRiX', path_re='matrix',...
|
1202
|
+
misc/sagedoc.py:... len(search_src('log', 'derivative', interact=False).splitlines()) < 40...
|
1203
|
+
misc/sagedoc.py:... len(search_src('log', 'derivative'...
|
1204
|
+
misc/sagedoc.py:... print(search_src(r'^ *sage[:] .*search_src\(', interact=False))...
|
1205
|
+
misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines()) > 9000...
|
1206
|
+
misc/sagedoc.py:... print(search_src('matrix', 'column', 'row', 'sub',...
|
1207
|
+
misc/sagedoc.py:... sage: results = search_src('format_search_as_html',...
|
1208
|
+
|
1209
|
+
TESTS:
|
1210
|
+
|
1211
|
+
As of this writing, there are about 9500 lines in the Sage library that
|
1212
|
+
contain "matrix"; it seems safe to assume we will continue to have
|
1213
|
+
over 9000 such lines::
|
1214
|
+
|
1215
|
+
sage: len(search_src("matrix", interact=False).splitlines()) > 9000 # long time
|
1216
|
+
True
|
1217
|
+
|
1218
|
+
Check that you can pass 5 parameters::
|
1219
|
+
|
1220
|
+
sage: print(search_src('matrix', 'column', 'row', 'sub', 'start', 'index', interact=False)) # random # long time
|
1221
|
+
matrix/matrix0.pyx:598: Get The 2 x 2 submatrix of M, starting at row index and column
|
1222
|
+
matrix/matrix0.pyx:607: Get the 2 x 3 submatrix of M starting at row index and column index
|
1223
|
+
matrix/matrix0.pyx:924: Set the 2 x 2 submatrix of M, starting at row index and column
|
1224
|
+
matrix/matrix0.pyx:933: Set the 2 x 3 submatrix of M starting at row index and column
|
1225
|
+
"""
|
1226
|
+
return _search_src_or_doc('src', string, extra1=extra1, extra2=extra2,
|
1227
|
+
extra3=extra3, extra4=extra4, extra5=extra5,
|
1228
|
+
**kwds)
|
1229
|
+
|
1230
|
+
|
1231
|
+
def search_doc(string, extra1='', extra2='', extra3='', extra4='',
|
1232
|
+
extra5='', **kwds):
|
1233
|
+
r"""
|
1234
|
+
Search Sage HTML documentation for lines containing ``string``. The
|
1235
|
+
search is case-insensitive by default.
|
1236
|
+
|
1237
|
+
The file paths in the output are relative to ``$SAGE_DOC``.
|
1238
|
+
|
1239
|
+
INPUT: same as for :func:`search_src`.
|
1240
|
+
|
1241
|
+
OUTPUT: same as for :func:`search_src`
|
1242
|
+
|
1243
|
+
EXAMPLES:
|
1244
|
+
|
1245
|
+
See the documentation for :func:`search_src` for more examples. ::
|
1246
|
+
|
1247
|
+
sage: search_doc('creates a polynomial', path_re='tutorial', interact=False) # random
|
1248
|
+
html/en/tutorial/tour_polynomial.html:<p>This creates a polynomial ring and tells Sage to use (the string)
|
1249
|
+
|
1250
|
+
If you search the documentation for 'tree', then you will get too
|
1251
|
+
many results, because many lines in the documentation contain the
|
1252
|
+
word 'toctree'. If you use the ``whole_word`` option, though, you
|
1253
|
+
can search for 'tree' without returning all of the instances of
|
1254
|
+
'toctree'. In the following, since ``search_doc('tree',
|
1255
|
+
interact=False)`` returns a string with one line for each match,
|
1256
|
+
counting the length of ``search_doc('tree',
|
1257
|
+
interact=False).splitlines()`` gives the number of matches. ::
|
1258
|
+
|
1259
|
+
sage: # long time, needs sagemath_doc_html
|
1260
|
+
sage: N = len(search_doc('tree', interact=False).splitlines())
|
1261
|
+
sage: L = search_doc('tree', whole_word=True, interact=False).splitlines()
|
1262
|
+
sage: len(L) < N
|
1263
|
+
True
|
1264
|
+
sage: import re
|
1265
|
+
sage: tree_re = re.compile(r'(^|\W)tree(\W|$)', re.I)
|
1266
|
+
sage: all(tree_re.search(l) for l in L)
|
1267
|
+
True
|
1268
|
+
"""
|
1269
|
+
return _search_src_or_doc('doc', string, extra1=extra1, extra2=extra2,
|
1270
|
+
extra3=extra3, extra4=extra4, extra5=extra5,
|
1271
|
+
**kwds)
|
1272
|
+
|
1273
|
+
|
1274
|
+
def search_def(name, extra1='', extra2='', extra3='', extra4='',
|
1275
|
+
extra5='', **kwds):
|
1276
|
+
r"""
|
1277
|
+
Search Sage library source code for function definitions containing
|
1278
|
+
``name``. The search is case-insensitive by default.
|
1279
|
+
|
1280
|
+
INPUT: same as for :func:`search_src`.
|
1281
|
+
|
1282
|
+
OUTPUT: same as for :func:`search_src`
|
1283
|
+
|
1284
|
+
.. NOTE::
|
1285
|
+
|
1286
|
+
The regular expression used by this function only finds function
|
1287
|
+
definitions that are preceded by spaces, so if you use tabs on a
|
1288
|
+
"def" line, this function will not find it. As tabs are not
|
1289
|
+
allowed in Sage library code, this should not be a problem.
|
1290
|
+
|
1291
|
+
EXAMPLES:
|
1292
|
+
|
1293
|
+
See the documentation for :func:`search_src` for more examples. ::
|
1294
|
+
|
1295
|
+
sage: print(search_def("fetch", interact=False)) # random # long time
|
1296
|
+
matrix/matrix0.pyx: cdef fetch(self, key):
|
1297
|
+
matrix/matrix0.pxd: cdef fetch(self, key)
|
1298
|
+
|
1299
|
+
sage: print(search_def("fetch", path_re="pyx", interact=False)) # random # long time
|
1300
|
+
matrix/matrix0.pyx: cdef fetch(self, key):
|
1301
|
+
"""
|
1302
|
+
# since we convert name to a regular expression, we need to do the
|
1303
|
+
# 'whole_word' conversion here, rather than pass it on to
|
1304
|
+
# _search_src_or_doc.
|
1305
|
+
if 'whole_word' in kwds and kwds['whole_word']:
|
1306
|
+
name = r'\b' + name + r'\b'
|
1307
|
+
if extra1:
|
1308
|
+
extra1 = r'\b' + extra1 + r'\b'
|
1309
|
+
if extra2:
|
1310
|
+
extra2 = r'\b' + extra2 + r'\b'
|
1311
|
+
if extra3:
|
1312
|
+
extra3 = r'\b' + extra3 + r'\b'
|
1313
|
+
if extra4:
|
1314
|
+
extra4 = r'\b' + extra4 + r'\b'
|
1315
|
+
if extra5:
|
1316
|
+
extra5 = r'\b' + extra5 + r'\b'
|
1317
|
+
kwds['whole_word'] = False
|
1318
|
+
|
1319
|
+
return _search_src_or_doc('src', '^ *[c]?def.*%s' % name, extra1=extra1,
|
1320
|
+
extra2=extra2, extra3=extra3, extra4=extra4,
|
1321
|
+
extra5=extra5, **kwds)
|
1322
|
+
|
1323
|
+
|
1324
|
+
def format_search_as_html(what, results, search):
|
1325
|
+
r"""
|
1326
|
+
Format the output from ``search_src``, ``search_def``, or
|
1327
|
+
``search_doc`` as html, for use in the notebook.
|
1328
|
+
|
1329
|
+
INPUT:
|
1330
|
+
|
1331
|
+
- ``what`` -- string; what was searched (source code or
|
1332
|
+
documentation)
|
1333
|
+
- ``results`` -- string or list; the results of the search as a string or list of
|
1334
|
+
search results
|
1335
|
+
- ``search`` -- string or list; what was being searched for, either as a
|
1336
|
+
string which is taken verbatim, or a list of multiple search terms if
|
1337
|
+
there were more than one
|
1338
|
+
|
1339
|
+
This function parses ``results``: each line should have either the form
|
1340
|
+
``FILENAME`` or ``FILENAME: string`` where FILENAME is the file in which
|
1341
|
+
the string that matched the search was found. If FILENAME ends in '.html',
|
1342
|
+
then this is part of the documentation; otherwise, it is in the source
|
1343
|
+
code. In either case, an appropriate link is created.
|
1344
|
+
|
1345
|
+
EXAMPLES::
|
1346
|
+
|
1347
|
+
sage: from sage.misc.sagedoc import format_search_as_html
|
1348
|
+
sage: format_search_as_html('Source', 'algebras/steenrod_algebra_element.py: an antihomomorphism: if we call the antipode `c`, then', 'antipode antihomomorphism')
|
1349
|
+
'<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>'
|
1350
|
+
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')
|
1351
|
+
'<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>'
|
1352
|
+
|
1353
|
+
TESTS:
|
1354
|
+
|
1355
|
+
Test that results from a ``search_src`` with ``multiline=True`` works
|
1356
|
+
reasonably::
|
1357
|
+
|
1358
|
+
sage: results = search_src('format_search_as_html', # long time
|
1359
|
+
....: multiline=True, interact=False)
|
1360
|
+
sage: format_search_as_html('Source', results, # long time
|
1361
|
+
....: 'format_search_as_html')
|
1362
|
+
'<html><font color="black"><h2>Search Source: "format_search_as_html"</h2></font><font color="darkpurple"><ol><li><a href="/src/misc/sagedoc.py" target="_blank"><tt>misc/sagedoc.py</tt></a>\n</ol></font></html>'
|
1363
|
+
"""
|
1364
|
+
|
1365
|
+
if not isinstance(search, list):
|
1366
|
+
search = [search]
|
1367
|
+
|
1368
|
+
s = [
|
1369
|
+
'<html>',
|
1370
|
+
'<font color="black">',
|
1371
|
+
'<h2>Search {}: {}</h2>'.format(
|
1372
|
+
what, ', '.join('"{}"'.format(s) for s in search if s.strip())),
|
1373
|
+
'</font>',
|
1374
|
+
'<font color="darkpurple">',
|
1375
|
+
'<ol>'
|
1376
|
+
]
|
1377
|
+
|
1378
|
+
append = s.append
|
1379
|
+
|
1380
|
+
if not isinstance(results, list):
|
1381
|
+
results = results.splitlines()
|
1382
|
+
|
1383
|
+
files = set()
|
1384
|
+
for L in results:
|
1385
|
+
filename = L.strip().split(':', 1)[0]
|
1386
|
+
if filename:
|
1387
|
+
files.add(filename)
|
1388
|
+
files = sorted(files)
|
1389
|
+
for F in files:
|
1390
|
+
if F.endswith('.html'):
|
1391
|
+
F = F.split('/', 2)[2]
|
1392
|
+
url = '/doc/live/' + F
|
1393
|
+
else:
|
1394
|
+
# source code
|
1395
|
+
url = '/src/' + F
|
1396
|
+
append('<li><a href="%s" target="_blank"><tt>%s</tt></a>\n' % (url, F))
|
1397
|
+
append('</ol>')
|
1398
|
+
append('</font>')
|
1399
|
+
append('</html>')
|
1400
|
+
return ''.join(s)
|
1401
|
+
|
1402
|
+
|
1403
|
+
#######################################
|
1404
|
+
# Add detex'ing of documentation
|
1405
|
+
#######################################
|
1406
|
+
|
1407
|
+
|
1408
|
+
def my_getsource(obj, oname=''):
|
1409
|
+
"""
|
1410
|
+
Retrieve the source code for ``obj``.
|
1411
|
+
|
1412
|
+
INPUT:
|
1413
|
+
|
1414
|
+
- ``obj`` -- a Sage object, function, etc.
|
1415
|
+
|
1416
|
+
- ``oname`` -- string (optional); a name under which the object is
|
1417
|
+
known. Currently ignored by Sage
|
1418
|
+
|
1419
|
+
OUTPUT:
|
1420
|
+
|
1421
|
+
Its documentation (string)
|
1422
|
+
|
1423
|
+
EXAMPLES::
|
1424
|
+
|
1425
|
+
sage: from sage.misc.sagedoc import my_getsource
|
1426
|
+
sage: s = my_getsource(identity_matrix) # needs sage.modules
|
1427
|
+
sage: s[15:34] # needs sage.modules
|
1428
|
+
'def identity_matrix'
|
1429
|
+
"""
|
1430
|
+
try:
|
1431
|
+
s = sageinspect.sage_getsource(obj)
|
1432
|
+
return format_src(s)
|
1433
|
+
except Exception as msg:
|
1434
|
+
print('Error getting source:', msg)
|
1435
|
+
return None
|
1436
|
+
|
1437
|
+
|
1438
|
+
class _sage_doc:
|
1439
|
+
"""
|
1440
|
+
Open Sage documentation in a web browser, from either the
|
1441
|
+
command-line or the notebook.
|
1442
|
+
|
1443
|
+
- Type "browse_sage_doc.DOCUMENT()" to open the named document --
|
1444
|
+
for example, "browse_sage_doc.tutorial()" opens the tutorial.
|
1445
|
+
Available documents are
|
1446
|
+
|
1447
|
+
- tutorial: the Sage tutorial
|
1448
|
+
- reference: the Sage reference manual
|
1449
|
+
- constructions: "how do I construct ... in Sage?"
|
1450
|
+
- developer: the Sage developer's guide.
|
1451
|
+
|
1452
|
+
- Type "browse_sage_doc(OBJECT, output=FORMAT, view=BOOL)" to view
|
1453
|
+
the documentation for OBJECT, as in
|
1454
|
+
"browse_sage_doc(identity_matrix, 'html'). ``output`` can be
|
1455
|
+
either 'html' or 'rst': the form of the output. ``view`` is
|
1456
|
+
only relevant if ``output`` is ``html``; in this case, if
|
1457
|
+
``view`` is ``True`` (its default value), then open up the
|
1458
|
+
documentation in a web browser. Otherwise, just output the
|
1459
|
+
documentation as a string.
|
1460
|
+
|
1461
|
+
EXAMPLES::
|
1462
|
+
|
1463
|
+
sage: browse_sage_doc._open("reference", testing=True)[0] # needs sagemath_doc_html
|
1464
|
+
'http://localhost:8000/doc/live/reference/index.html'
|
1465
|
+
sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] # needs sage.modules
|
1466
|
+
'Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring'
|
1467
|
+
"""
|
1468
|
+
def __init__(self):
|
1469
|
+
"""
|
1470
|
+
EXAMPLES::
|
1471
|
+
|
1472
|
+
sage: browse_sage_doc._base_url
|
1473
|
+
'http://localhost:8000/doc/live/'
|
1474
|
+
"""
|
1475
|
+
self._base_url = "http://localhost:8000/doc/live/"
|
1476
|
+
self._base_path = os.path.join(SAGE_DOC, "html", "en")
|
1477
|
+
|
1478
|
+
def __call__(self, obj, output='html', view=True):
|
1479
|
+
r"""
|
1480
|
+
Return the documentation for ``obj``.
|
1481
|
+
|
1482
|
+
INPUT:
|
1483
|
+
|
1484
|
+
- ``obj`` -- a Sage object
|
1485
|
+
- ``output`` -- 'html', 'rst', or 'text': return documentation in this form
|
1486
|
+
- ``view`` -- only has an effect if output is 'html': in this
|
1487
|
+
case, if ``view`` is ``True``, display the documentation in
|
1488
|
+
a web browser. Otherwise, return the documentation as a
|
1489
|
+
string.
|
1490
|
+
|
1491
|
+
EXAMPLES::
|
1492
|
+
|
1493
|
+
sage: browse_sage_doc(identity_matrix, 'rst') # needs sage.modules
|
1494
|
+
"...**File:**...**Type:**...**Definition:** identity_matrix..."
|
1495
|
+
sage: identity_matrix.__doc__ in browse_sage_doc(identity_matrix, 'rst') # needs sage.modules
|
1496
|
+
True
|
1497
|
+
sage: browse_sage_doc(identity_matrix, 'html', False) # needs sagemath_doc_html sphinx
|
1498
|
+
'...div...File:...Type:...Definition:...identity_matrix...'
|
1499
|
+
|
1500
|
+
In the 'text' version, double colons have been replaced with
|
1501
|
+
single ones (among other things)::
|
1502
|
+
|
1503
|
+
sage: '::' in browse_sage_doc(identity_matrix, 'rst') # needs sage.modules
|
1504
|
+
True
|
1505
|
+
sage: '::' in browse_sage_doc(identity_matrix, 'text') # needs sphinx
|
1506
|
+
False
|
1507
|
+
"""
|
1508
|
+
if output != 'html' and view:
|
1509
|
+
view = False
|
1510
|
+
|
1511
|
+
s = ''
|
1512
|
+
newline = "\n\n" # blank line to start new paragraph
|
1513
|
+
|
1514
|
+
try:
|
1515
|
+
filename = sageinspect.sage_getfile(obj)
|
1516
|
+
s += '**File:** %s' % filename
|
1517
|
+
s += newline
|
1518
|
+
except TypeError:
|
1519
|
+
pass
|
1520
|
+
|
1521
|
+
obj_name = ''
|
1522
|
+
locs = sys._getframe(1).f_locals
|
1523
|
+
for var in locs:
|
1524
|
+
if id(locs[var]) == id(obj):
|
1525
|
+
obj_name = var
|
1526
|
+
|
1527
|
+
s += '**Type:** %s' % type(obj)
|
1528
|
+
s += newline
|
1529
|
+
s += '**Definition:** %s' % sageinspect.sage_getdef(obj, obj_name)
|
1530
|
+
s += newline
|
1531
|
+
s += '**Docstring:**'
|
1532
|
+
s += newline
|
1533
|
+
s += sageinspect.sage_getdoc(obj, obj_name, embedded=True)
|
1534
|
+
|
1535
|
+
# now s should be the reST version of the docstring
|
1536
|
+
if output == 'html':
|
1537
|
+
try:
|
1538
|
+
from .sphinxify import sphinxify
|
1539
|
+
except ImportError:
|
1540
|
+
from html import escape
|
1541
|
+
html = escape(s)
|
1542
|
+
else:
|
1543
|
+
html = sphinxify(s)
|
1544
|
+
if view:
|
1545
|
+
path = os.path.join(tmp_dir(), "temp.html")
|
1546
|
+
filed = open(path, 'w')
|
1547
|
+
|
1548
|
+
static_path = os.path.join(SAGE_DOC, "html", "en", "_static")
|
1549
|
+
if os.path.exists(static_path):
|
1550
|
+
title = obj_name + ' - Sage ' + sage.version.version + ' Documentation'
|
1551
|
+
template = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
1552
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
1553
|
+
|
1554
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
1555
|
+
<head>
|
1556
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
1557
|
+
<title>%(title)s</title>
|
1558
|
+
<link rel="stylesheet" href="%(static_path)s/default.css" type="text/css" />
|
1559
|
+
<link rel="stylesheet" href="%(static_path)s/pygments.css" type="text/css" />
|
1560
|
+
<style type="text/css">
|
1561
|
+
<!--
|
1562
|
+
div.body {
|
1563
|
+
margin: 1.0em;
|
1564
|
+
padding: 1.0em;
|
1565
|
+
}
|
1566
|
+
div.bodywrapper {
|
1567
|
+
margin: 0;
|
1568
|
+
}
|
1569
|
+
-->
|
1570
|
+
</style>
|
1571
|
+
<script type="text/javascript">
|
1572
|
+
var DOCUMENTATION_OPTIONS = {
|
1573
|
+
URL_ROOT: '',
|
1574
|
+
VERSION: '%(version)s',
|
1575
|
+
COLLAPSE_MODINDEX: false,
|
1576
|
+
FILE_SUFFIX: '.html',
|
1577
|
+
HAS_SOURCE: false
|
1578
|
+
};
|
1579
|
+
</script>
|
1580
|
+
<script type="text/javascript" src="%(static_path)s/jquery.js"></script>
|
1581
|
+
<script type="text/javascript" src="%(static_path)s/doctools.js"></script>
|
1582
|
+
<link rel="shortcut icon" href="%(static_path)s/favicon.ico" />
|
1583
|
+
<link rel="icon" href="%(static_path)s/sageicon.png" type="image/x-icon" />
|
1584
|
+
</head>
|
1585
|
+
<body>
|
1586
|
+
<div class="document">
|
1587
|
+
<div class="documentwrapper">
|
1588
|
+
<div class="bodywrapper">
|
1589
|
+
<div class="body">
|
1590
|
+
%(html)s
|
1591
|
+
</div>
|
1592
|
+
</div>
|
1593
|
+
</div>
|
1594
|
+
</div>
|
1595
|
+
</body>
|
1596
|
+
</html>"""
|
1597
|
+
html = template % {'html': html,
|
1598
|
+
'static_path': static_path,
|
1599
|
+
'title': title,
|
1600
|
+
'version': sage.version.version}
|
1601
|
+
|
1602
|
+
filed.write(html)
|
1603
|
+
filed.close()
|
1604
|
+
os.system(browser() + " " + path)
|
1605
|
+
else:
|
1606
|
+
return html
|
1607
|
+
elif output == 'rst':
|
1608
|
+
return s
|
1609
|
+
elif output == 'text':
|
1610
|
+
try:
|
1611
|
+
from .sphinxify import sphinxify
|
1612
|
+
except ImportError:
|
1613
|
+
return s
|
1614
|
+
else:
|
1615
|
+
return sphinxify(s, format='text')
|
1616
|
+
else:
|
1617
|
+
raise ValueError("output type {} not recognized".format(output))
|
1618
|
+
|
1619
|
+
def _open(self, name, testing=False):
|
1620
|
+
"""
|
1621
|
+
Open the document ``name`` in a web browser. This constructs
|
1622
|
+
the appropriate URL and/or path name and passes it to the web
|
1623
|
+
browser.
|
1624
|
+
|
1625
|
+
INPUT:
|
1626
|
+
|
1627
|
+
- ``name`` -- string; name of the documentation
|
1628
|
+
|
1629
|
+
- ``testing`` -- boolean (default: ``False``); if ``True``,
|
1630
|
+
then just return the URL and path-name for this document
|
1631
|
+
(don't open the web browser)
|
1632
|
+
|
1633
|
+
EXAMPLES::
|
1634
|
+
|
1635
|
+
sage: browse_sage_doc._open("reference", testing=True)[0] # needs sagemath_doc_html
|
1636
|
+
'http://localhost:8000/doc/live/reference/index.html'
|
1637
|
+
sage: browse_sage_doc._open("tutorial", testing=True)[1] # needs sagemath_doc_html
|
1638
|
+
'.../html/en/tutorial/index.html'
|
1639
|
+
"""
|
1640
|
+
url = self._base_url + os.path.join(name, "index.html")
|
1641
|
+
path = os.path.join(self._base_path, name, "index.html")
|
1642
|
+
if not os.path.exists(path):
|
1643
|
+
raise OSError("""The document '{0}' does not exist. Please build it
|
1644
|
+
with 'sage -docbuild {0} html' and try again.""".format(name))
|
1645
|
+
|
1646
|
+
if testing:
|
1647
|
+
return (url, path)
|
1648
|
+
|
1649
|
+
os.system(browser() + " " + path)
|
1650
|
+
|
1651
|
+
def tutorial(self):
|
1652
|
+
"""
|
1653
|
+
The Sage tutorial. To get started with Sage, start here.
|
1654
|
+
|
1655
|
+
EXAMPLES::
|
1656
|
+
|
1657
|
+
sage: tutorial() # indirect doctest, not tested
|
1658
|
+
"""
|
1659
|
+
self._open("tutorial")
|
1660
|
+
|
1661
|
+
def reference(self):
|
1662
|
+
"""
|
1663
|
+
The Sage reference manual.
|
1664
|
+
|
1665
|
+
EXAMPLES::
|
1666
|
+
|
1667
|
+
sage: reference() # indirect doctest, not tested
|
1668
|
+
sage: manual() # indirect doctest, not tested
|
1669
|
+
"""
|
1670
|
+
self._open("reference")
|
1671
|
+
|
1672
|
+
manual = reference
|
1673
|
+
|
1674
|
+
def developer(self):
|
1675
|
+
"""
|
1676
|
+
The Sage developer's guide. Learn to develop programs for Sage.
|
1677
|
+
|
1678
|
+
EXAMPLES::
|
1679
|
+
|
1680
|
+
sage: developer() # indirect doctest, not tested
|
1681
|
+
"""
|
1682
|
+
self._open("developer")
|
1683
|
+
|
1684
|
+
def constructions(self):
|
1685
|
+
"""
|
1686
|
+
Sage constructions. Attempts to answer the question "How do I
|
1687
|
+
construct ... in Sage?"
|
1688
|
+
|
1689
|
+
EXAMPLES::
|
1690
|
+
|
1691
|
+
sage: constructions() # indirect doctest, not tested
|
1692
|
+
"""
|
1693
|
+
self._open("constructions")
|
1694
|
+
|
1695
|
+
|
1696
|
+
browse_sage_doc = _sage_doc()
|
1697
|
+
tutorial = browse_sage_doc.tutorial
|
1698
|
+
reference = browse_sage_doc.reference
|
1699
|
+
manual = browse_sage_doc.reference
|
1700
|
+
developer = browse_sage_doc.developer
|
1701
|
+
constructions = browse_sage_doc.constructions
|
1702
|
+
|
1703
|
+
python_help = pydoc.help
|
1704
|
+
|
1705
|
+
|
1706
|
+
def help(module=None):
|
1707
|
+
"""
|
1708
|
+
If there is an argument ``module``, print the Python help message
|
1709
|
+
for ``module``. With no argument, print a help message about
|
1710
|
+
getting help in Sage.
|
1711
|
+
|
1712
|
+
EXAMPLES::
|
1713
|
+
|
1714
|
+
sage: help()
|
1715
|
+
Welcome to Sage ...
|
1716
|
+
"""
|
1717
|
+
if module is not None:
|
1718
|
+
python_help(module)
|
1719
|
+
else:
|
1720
|
+
print("""Welcome to Sage {}!
|
1721
|
+
|
1722
|
+
To view the Sage tutorial in your web browser, type "tutorial()", and
|
1723
|
+
to view the (very detailed) Sage reference manual, type "manual()".
|
1724
|
+
For help on any Sage function, for example "matrix_plot", type
|
1725
|
+
"matrix_plot?" to see a help message, type "help(matrix_plot)" to see
|
1726
|
+
a very similar message, type "browse_sage_doc(matrix_plot)" to view a
|
1727
|
+
help message in a web browser, and type "matrix_plot??" to look at the
|
1728
|
+
function's source code.
|
1729
|
+
|
1730
|
+
(When you type something like "matrix_plot?", "help(matrix_plot)", or
|
1731
|
+
"matrix_plot??", Sage may start a paging program to display the
|
1732
|
+
requested message. Type a space to scroll to the next page, type "h"
|
1733
|
+
to get help on the paging program, and type "q" to quit it and return
|
1734
|
+
to the "sage:" prompt.)
|
1735
|
+
|
1736
|
+
For license information for Sage and its components, read the file
|
1737
|
+
"COPYING.txt" in the top-level directory of the Sage installation,
|
1738
|
+
or type "license()".
|
1739
|
+
|
1740
|
+
To enter Python's interactive online help utility, type "python_help()".
|
1741
|
+
To get help on a Python function, module or package, type "help(MODULE)" or
|
1742
|
+
"python_help(MODULE)".""".format(sage.version.version))
|