Ticket #5653: docstring.6.patch
File docstring.6.patch, 24.6 KB (added by , 12 years ago) |
---|
-
new file doc/en/introspect/__init__.py
# HG changeset patch # User Mitesh Patel <qed777@gmail.com> # Date 1245514036 25200 # Node ID 4c12b491fcadc745872d6d185ac53a518ff863c3 # Parent f8ed298153dd45b69542e91acd2bd44d2e47a8ca #5653, pretty docstrings diff --git a/doc/en/introspect/__init__.py b/doc/en/introspect/__init__.py new file mode 100644
- + 1 -
new file doc/en/introspect/conf.py
diff --git a/doc/en/introspect/conf.py b/doc/en/introspect/conf.py new file mode 100644
- + 1 # -*- coding: utf-8 -*- 2 # Sage introspection build configuration file. 3 # See sage.server.notebook.cell.set_introspect_html() for details. 4 5 import sys, os 6 sys.path.append(os.environ['SAGE_DOC']) 7 from common.conf import * 8 9 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath'] 10 11 templates_path = ['templates'] 12 html_static_path = ['static'] 13 14 html_use_modindex = False 15 html_use_index = False 16 html_split_index = False 17 html_copy_source = False -
new file doc/en/introspect/static/empty
diff --git a/doc/en/introspect/static/empty b/doc/en/introspect/static/empty new file mode 100644
- + 1 -
new file doc/en/introspect/templates/layout.html
diff --git a/doc/en/introspect/templates/layout.html b/doc/en/introspect/templates/layout.html new file mode 100644
- + 1 <div class="docstring"> 2 {% block body %} {% endblock %} 3 </div> -
sage/misc/sagedoc.py
diff --git a/sage/misc/sagedoc.py b/sage/misc/sagedoc.py
a b 20 20 #***************************************************************************** 21 21 22 22 import os 23 #('\\item', '*'), \ 24 substitutes = [('\\_','_'),\ 25 ('\\item', '* '), \ 26 ('\\to', '-->'), \ 27 ('<BLANKLINE>',''), \ 28 ('\\leq', '<='), \ 29 ('\\geq', '>='), \ 30 ('\\le', '<='), \ 31 ('\\ge', '>='), \ 32 ('\\bf', ''),\ 33 ('\\sage', 'SAGE'), \ 34 ('\\SAGE', 'SAGE'), \ 35 ('\\rm', ''), \ 36 ('cdots', '...'), \ 37 ('\\cdot', ' *'), \ 38 ('$',''), ('\\',''), ('backslash','\\'), \ 39 ('begin{enumerate}',''), ('end{enumerate}',''), \ 40 ('begin{description}',''), ('end{description}',''), \ 41 ('begin{itemize}',''), ('end{itemize}',''), \ 42 ('begin{verbatim}',''), ('end{verbatim}',''), \ 43 ('mapsto', ' |--> '), \ 44 ('ldots', '...'), ('note{','NOTE: ')] 45 23 # two kinds of substitutions: math, which should only be done on the 24 # command line -- in the notebook, these should instead by taken care 25 # of by jsMath -- and nonmath, which should be done always. 26 math_substitutes = [('\\to', '-->'), 27 ('\\leq', '<='), 28 ('\\geq', '>='), 29 ('\\le', '<='), 30 ('\\ge', '>='), 31 ('cdots', '...'), 32 ('\\cdot', ' *'), 33 (' \\times', ' x'), 34 ('\\times', ' x'), 35 ('backslash','\\'), 36 ('mapsto', ' |--> '), 37 ('ldots', '...')] 38 nonmath_substitutes = [('\\_','_'), 39 ('\\item', '* '), 40 ('<BLANKLINE>',''), 41 ('\\bf', ''), 42 ('\\sage', 'SAGE'), 43 ('\\SAGE', 'SAGE'), 44 ('\\rm', ''), 45 ('backslash','\\'), 46 ('begin{enumerate}',''), 47 ('end{enumerate}',''), 48 ('begin{description}',''), 49 ('end{description}',''), 50 ('begin{itemize}',''), 51 ('end{itemize}',''), 52 ('begin{verbatim}',''), 53 ('end{verbatim}',''), 54 ('note{','NOTE: ')] 46 55 47 56 def _rmcmd(s, cmd, left='', right=''): 48 57 """ … … 112 121 itempattern = re.compile(r"\\item\[?([^]]*)\]? *(.*)") 113 122 itemreplace = r"* \1 \2" 114 123 115 def detex(s ):124 def detex(s, embedded=False): 116 125 """nodetex 117 126 This strips LaTeX commands from a string; it is used by the 118 127 ``format`` function to process docstrings for display from the 119 128 command line interface. 120 129 121 INPUT: ``s``, a string. 130 INPUT: 131 132 - ``s`` - string 133 - ``embedded`` - boolean (optional, default False) 134 135 If ``embedded`` is False, then do the replacements in both 136 ``math_substitutes`` and ``nonmath_substitutes``. If True, then 137 only do ``nonmath_substitutes``. 122 138 123 139 OUTPUT: string 124 140 … … 129 145 'Some math: `n >= k`. A website: sagemath.org.' 130 146 sage: detex(r'More math: `x \mapsto y`. {\bf Bold face}.') 131 147 'More math: `x |--> y`. { Bold face}.' 132 sage: detex(r'$a, b, c, \ldots, z$') 133 'a, b, c, ..., z' 148 sage: detex(r'`a, b, c, \ldots, z`') 149 '`a, b, c, ..., z`' 150 sage: detex(r'`a, b, c, \ldots, z`', embedded=True) 151 '`a, b, c, \\\\ldots, z`' 134 152 """ 135 153 s = _rmcmd(s, 'url') 136 154 s = _rmcmd(s, 'code') … … 142 160 s = _rmcmd(s, 'subsubsection') 143 161 s = _rmcmd(s, 'note', 'NOTE: ', '') 144 162 s = _rmcmd(s, 'emph', '*', '*') 163 s = _rmcmd(s, 'textbf', '*', '*') 145 164 146 165 s = re.sub(itempattern, itemreplace, s) 147 148 for a,b in substitutes: 166 167 if not embedded: # not in the notebook 168 for a,b in math_substitutes: # do math substitutions 169 s = s.replace(a,b) 170 s = s.replace('\\','') # nuke backslashes 171 s = s.replace('.. math::\n', '') # get rid of .. math:: directives 172 else: 173 s = s.replace('\\','\\\\') # double up backslashes for jsMath 174 for a,b in nonmath_substitutes: 149 175 s = s.replace(a,b) 150 176 return s 151 177 152 def format(s ):178 def format(s, embedded=False): 153 179 """ 154 180 Format Sage documentation ``s`` for viewing with IPython. 155 181 … … 157 183 text, and if ``s`` contains a string of the form "<<<obj>>>", 158 184 then it replaces it with the docstring for "obj". 159 185 160 INPUT: ``s`` - string 186 INPUT: 187 188 - ``s`` - string 189 - ``embedded`` - boolean (optional, default False) 161 190 162 191 OUTPUT: string 163 192 193 Set ``embedded`` equal to True if formatting for use in the 194 notebook; this just gets passed as an argument to ``detex``. 195 164 196 EXAMPLES:: 165 197 166 198 sage: from sage.misc.sagedoc import format … … 218 250 s = s[:i] + '\n' + t + s[i+6+j:] 219 251 220 252 if 'nodetex' not in directives: 221 s = detex(s )253 s = detex(s, embedded=embedded) 222 254 else: 223 255 # strip the 'nodetex' directive from s 224 256 s = s.replace('nodetex', '', 1) -
sage/misc/sageinspect.py
diff --git a/sage/misc/sageinspect.py b/sage/misc/sageinspect.py
a b 114 114 115 115 import inspect 116 116 import os 117 EMBEDDED_MODE = False 117 118 118 119 def isclassinstance(obj): 119 120 r""" … … 400 401 if s[:4] == 'self': 401 402 s = s[4:] 402 403 s = s.lstrip(',').strip() 404 # for use with typesetting the definition with the notebook: 405 # sometimes s contains "*args" or "**keywds", and the 406 # asterisks confuse ReST/sphinx/docutils, so escape them: 407 # change * to \*, and change ** to \**. 408 if EMBEDDED_MODE: 409 s = s.replace('**', '\\**') # replace ** with \** 410 t = '' 411 while True: # replace * with \* 412 i = s.find('*') 413 if i == -1: 414 break 415 elif i > 0 and s[i-1] == '\\': 416 if s[i+1] == "*": 417 t += s[:i+2] 418 s = s[i+2:] 419 else: 420 t += s[:i+1] 421 s = s[i+1:] 422 continue 423 elif i > 0 and s[i-1] == '*': 424 t += s[:i+1] 425 s = s[i+1:] 426 continue 427 else: 428 t += s[:i] + '\\*' 429 s = s[i+1:] 430 s = t + s 403 431 return obj_name + '(' + s + ')' 404 432 except (AttributeError, TypeError, ValueError): 405 433 return '%s( [noargspec] )'%obj_name … … 439 467 440 468 if r is None: 441 469 return '' 442 s = sage.misc.sagedoc.format(str(r)) 470 471 s = sage.misc.sagedoc.format(str(r), embedded=EMBEDDED_MODE) 443 472 444 473 # If there is a Cython embedded position, it needs to be stripped 445 474 pos = _extract_embedded_position(s) -
sage/server/notebook/cell.py
diff --git a/sage/server/notebook/cell.py b/sage/server/notebook/cell.py
a b 34 34 35 35 import os, shutil 36 36 37 from sage.misc.misc import word_wrap 37 from sage.misc.misc import word_wrap, SAGE_DOC 38 38 from sage.misc.html import math_parse 39 39 from sage.misc.preparser import strip_string_literals 40 40 from sage.misc.package import is_package_installed … … 46 46 else: 47 47 JEDITABLE_TINYMCE = False 48 48 49 # Introspection. The cache directory is a module-scope variable set 50 # in the first call to Cell.set_introspect_html(). 51 import errno, hashlib, time 52 from sphinx.application import Sphinx 53 _SAGE_INTROSPECT = None 49 54 50 55 class Cell_generic: 51 56 def is_interactive_cell(self): … … 1430 1435 ################# 1431 1436 # Introspection # 1432 1437 ################# 1433 def set_introspect_html(self, html, completing=False): 1434 if completing: 1438 def set_introspect_html(self, html, completing=False, verbose=False): 1439 """ 1440 If ``verbose`` is True, print verbose output about notebook 1441 introspection to the command-line. However, the argument 1442 ``verbose`` is not easily accessible now -- if you need to 1443 debug, you have to edit this file, changing its value to True, 1444 and run 'sage -b'. 1445 """ 1446 if html == "" or completing: 1435 1447 self.__introspect_html = html 1448 elif html.find("`") == -1 and html.find("::") == -1: 1449 # html doesn't seem to be in ReST format so use docutils 1450 # to process the preamble ("**File:**" etc.) and put 1451 # everything else in a <pre> block. 1452 i = html.find("**Docstring:**") 1453 if i != -1: 1454 preamble = html[:i+14] 1455 from docutils.core import publish_parts 1456 preamble = publish_parts(html[:i+14], writer_name='html')['body'] 1457 html = html[i+14:] 1458 else: 1459 preamble = "" 1460 self.__introspect_html = '<div class="docstring">' + preamble + '<pre>' + html + '</pre></div>' 1436 1461 else: 1437 html = escape(html).strip() 1438 self.__introspect_html = '<pre class="introspection">'+html+'</pre>' 1462 # html is in ReST format, so use Sphinx to process it 1463 1464 # Set the location of the introspection cache, "permanent" 1465 # or temporary. The former, DOT_SAGE/sage_notebook/doc, 1466 # can pool queries from multiple worksheet processes. The 1467 # latter is exclusive to a worksheet's process. The Sage 1468 # cleaner should delete the temporary directory (or 1469 # directories) after the notebook server exits. 1470 global _SAGE_INTROSPECT 1471 1472 if _SAGE_INTROSPECT is None: 1473 from sage.misc.misc import DOT_SAGE, tmp_dir 1474 # It's important to use os.path.join, instead of +, 1475 # because Sphinx counts on normalized paths. It's also 1476 # more portable. 1477 std_doc_dir = os.path.join(DOT_SAGE, 'sage_notebook/doc') 1478 try: 1479 os.makedirs(std_doc_dir) 1480 _SAGE_INTROSPECT = std_doc_dir 1481 except OSError, error: 1482 if error.errno == errno.EEXIST: 1483 if os.access(std_doc_dir, os.R_OK | os.W_OK | os.X_OK): 1484 _SAGE_INTROSPECT = std_doc_dir 1485 else: 1486 _SAGE_INTROSPECT = tmp_dir() 1487 else: 1488 _SAGE_INTROSPECT = tmp_dir() 1489 if verbose: 1490 print 'Introspection cache: ', _SAGE_INTROSPECT 1491 1492 # We get a quick checksum of the input. MD5 admits 1493 # collisions, but we're not concerned about such security 1494 # issues here. Of course, if performance permits, we can 1495 # choose a more robust hash function. 1496 hash = hashlib.md5(html).hexdigest() 1497 base_name = os.path.join(_SAGE_INTROSPECT, hash) 1498 html_name = base_name + '.html' 1499 1500 # Multiple processes might try to read/write the target 1501 # HTML file simultaneously. We use a file-based lock. 1502 # Since we care only about the target's contents, and 1503 # we've configured Sphinx accordingly, we allow multiple 1504 # simultaneous instances of Sphinx, as long as their 1505 # targets are different. Systems which don't properly 1506 # implement os.O_EXCL may require coarser locking. 1507 1508 # The Pythonic cross-platform file lock below is adapted 1509 # from 1510 # http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-python/ 1511 lock_name = base_name + '.lock' 1512 1513 # Try to acquire the lock, periodically. If we time out, 1514 # we fall back to plainly formatted documentation. 1515 timeout = 0.5 1516 delay = 0.05 1517 start_time = time.time() 1518 1519 while True: 1520 try: 1521 # This operation is atomic on platforms which 1522 # properly implement os.O_EXCL: 1523 fd_lock = os.open(lock_name, os.O_CREAT | os.O_EXCL | os.O_RDWR) 1524 break; 1525 except OSError, err: 1526 if (err.errno != errno.EEXIST) or (time.time() - start_time >= timeout): 1527 plain_html = escape(html).strip() 1528 self.__introspect_html = '<pre class="introspection">' + plain_html + '</pre>' 1529 return 1530 time.sleep(delay) 1531 1532 # We've acquired the lock. Use cached HTML or run Sphinx. 1533 try: 1534 open(html_name, 'r') 1535 if verbose: 1536 print 'Found: %s' % html_name 1537 except IOError: 1538 html = html.replace('\\\\', '\\') 1539 rst_name = base_name + '.rst' 1540 fd_rst = open(rst_name, 'w') 1541 fd_rst.write(html) 1542 fd_rst.close() 1543 1544 # Sphinx setup. The constructor is Sphinx(srcdir, 1545 # confdir, outdir, doctreedir, buildername, 1546 # confoverrides, status, warning, freshenv). 1547 srcdir = os.path.normpath(_SAGE_INTROSPECT) 1548 1549 # Note: It's crucial that confdir* contains a 1550 # customized conf.py and layout.html. In particular, 1551 # we've disabled index generation and told Sphinx to 1552 # output almost exactly the HTML we display. Sphinx 1553 # also pickles its environment in doctreedir, but we 1554 # force Sphinx never to load this pickle with 1555 # freshenv=True. 1556 confdir = os.path.join(SAGE_DOC, 'en/introspect') 1557 doctreedir = os.path.normpath(base_name) 1558 confoverrides = {'html_context' : {}, 'master_doc' : hash} 1559 1560 # To suppress output, use this: 1561 1562 if verbose: 1563 import sys 1564 sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, sys.stdout, sys.stderr, True) 1565 else: 1566 sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, None, None, True) 1567 1568 # Run Sphinx. The first argument corresponds to 1569 # sphinx-build's "write all files" -a flag, which we 1570 # set to None. 1571 sphinx_app.build(None, [rst_name]) 1572 1573 # We delete .rst files, so future Sphinx runs don't 1574 # keep track of them. We also delete doctrees. 1575 try: 1576 os.unlink(rst_name) 1577 except OSError: 1578 pass 1579 try: 1580 shutil.rmtree(doctreedir) 1581 os.unlink(doctreedir) 1582 except OSError: 1583 pass 1584 1585 if verbose: 1586 print 'Built: %s' % html_name 1587 finally: 1588 # Contents should be flushed on close(). 1589 fd_html = open(html_name, 'r') 1590 new_html = fd_html.read() 1591 fd_html.close() 1592 1593 # We release the lock and delete the lock file. 1594 os.close(fd_lock) 1595 os.unlink(lock_name) 1596 1597 new_html = new_html.replace('<pre>', '<pre class="literal-block">') 1598 self.__introspect_html = new_html 1599 return 1439 1600 1440 1601 def introspect_html(self): 1441 1602 if not self.introspect(): -
sage/server/notebook/css.py
diff --git a/sage/server/notebook/css.py b/sage/server/notebook/css.py
a b 293 293 div.introspection { 294 294 } 295 295 296 div.docstring { 297 font-family:arial; 298 background-color: #fafafa; 299 color: black; 300 border: solid 1px black; 301 padding:8px; 302 margin:8px; 303 } 304 305 pre.literal-block { 306 background-color: #ffffff; 307 color: black; 308 padding: 0 0 0 5px; 309 border-left: 2px solid #c0c0c0; 310 } 311 296 312 pre.introspection { 297 313 font-family: monospace; 298 314 font-size:15px; 299 background-color: #efefef; 315 background-color: #f1f1f1; 316 color: blue; 300 317 border: solid 1px black; 301 318 padding:8px; 302 319 margin:8px; … … 1664 1681 background-color: #990000; 1665 1682 } 1666 1683 1684 1685 1686 /* These have been scraped directly from pygment. */ 1687 1688 .hll { background-color: #ffffcc } 1689 .c { color: #408090; font-style: italic } /* Comment */ 1690 .err { border: 1px solid #FF0000 } /* Error */ 1691 .k { color: #007020; font-weight: bold } /* Keyword */ 1692 .o { color: #666666 } /* Operator */ 1693 .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 1694 .cp { color: #007020 } /* Comment.Preproc */ 1695 .c1 { color: #408090; font-style: italic } /* Comment.Single */ 1696 .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 1697 .gd { color: #A00000 } /* Generic.Deleted */ 1698 .ge { font-style: italic } /* Generic.Emph */ 1699 .gr { color: #FF0000 } /* Generic.Error */ 1700 .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 1701 .gi { color: #00A000 } /* Generic.Inserted */ 1702 .go { color: #0000aa } /* Generic.Output */ 1703 .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 1704 .gs { font-weight: bold } /* Generic.Strong */ 1705 .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 1706 .gt { color: #0040D0 } /* Generic.Traceback */ 1707 .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 1708 .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 1709 .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 1710 .kp { color: #007020 } /* Keyword.Pseudo */ 1711 .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 1712 .kt { color: #902000 } /* Keyword.Type */ 1713 .m { color: #208050 } /* Literal.Number */ 1714 .s { color: #4070a0 } /* Literal.String */ 1715 .na { color: #4070a0 } /* Name.Attribute */ 1716 .nb { color: #007020 } /* Name.Builtin */ 1717 .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 1718 .no { color: #60add5 } /* Name.Constant */ 1719 .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 1720 .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 1721 .ne { color: #007020 } /* Name.Exception */ 1722 .nf { color: #06287e } /* Name.Function */ 1723 .nl { color: #002070; font-weight: bold } /* Name.Label */ 1724 .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 1725 .nt { color: #062873; font-weight: bold } /* Name.Tag */ 1726 .nv { color: #bb60d5 } /* Name.Variable */ 1727 .ow { color: #007020; font-weight: bold } /* Operator.Word */ 1728 .w { color: #bbbbbb } /* Text.Whitespace */ 1729 .mf { color: #208050 } /* Literal.Number.Float */ 1730 .mh { color: #208050 } /* Literal.Number.Hex */ 1731 .mi { color: #208050 } /* Literal.Number.Integer */ 1732 .mo { color: #208050 } /* Literal.Number.Oct */ 1733 .sb { color: #4070a0 } /* Literal.String.Backtick */ 1734 .sc { color: #4070a0 } /* Literal.String.Char */ 1735 .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 1736 .s2 { color: #4070a0 } /* Literal.String.Double */ 1737 .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 1738 .sh { color: #4070a0 } /* Literal.String.Heredoc */ 1739 .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 1740 .sx { color: #c65d09 } /* Literal.String.Other */ 1741 .sr { color: #235388 } /* Literal.String.Regex */ 1742 .s1 { color: #4070a0 } /* Literal.String.Single */ 1743 .ss { color: #517918 } /* Literal.String.Symbol */ 1744 .bp { color: #007020 } /* Name.Builtin.Pseudo */ 1745 .vc { color: #bb60d5 } /* Name.Variable.Class */ 1746 .vg { color: #bb60d5 } /* Name.Variable.Global */ 1747 .vi { color: #bb60d5 } /* Name.Variable.Instance */ 1748 .il { color: #208050 } /* Literal.Number.Integer.Long */ 1749 1750 /* end stuff scraped from pygment */ 1751 1667 1752 """ 1668 1753 if color == 'gmail': 1669 1754 color1 = '#c3d9ff' -
sage/server/notebook/templates/notebook_lib.js
diff --git a/sage/server/notebook/templates/notebook_lib.js b/sage/server/notebook/templates/notebook_lib.js
a b 892 892 halt_introspection(); 893 893 return; 894 894 } 895 895 896 d.innerHTML = introspection_text; 897 898 if (contains_jsmath(introspection_text)) { 899 try { 900 jsMath.ProcessBeforeShowing(d); 901 } catch(e) { 902 text_cell.innerHTML = jsmath_font_msg + d.innerHTML; 903 } 904 } 905 896 906 if(replacing) 897 907 select_replacement_element(); 898 908 } else { … … 2891 2901 cell_output.innerHTML = ''; 2892 2902 cell_output_nowrap.innerHTML = ''; 2893 2903 cell_output_html.innerHTML = introspect_html; 2904 if (contains_jsmath(introspect_html)) { 2905 try { 2906 jsMath.ProcessBeforeShowing(cell_output_html); 2907 } catch(e) { 2908 cell_output.innerHTML = jsmath_font_msg + cell_output_html.innerHTML; 2909 } 2910 } 2894 2911 } 2895 2912 } 2896 2913 -
sage/server/support.py
diff --git a/sage/server/support.py b/sage/server/support.py
a b 53 53 sage.structure.sage_object.base=object_directory 54 54 sage.misc.latex.EMBEDDED_MODE = True 55 55 sage.misc.pager.EMBEDDED_MODE = True 56 sage.misc.sageinspect.EMBEDDED_MODE = True 56 57 57 58 setup_systems(globs) 58 59 sage.misc.session.init(globs) … … 191 192 except (AttributeError, NameError, SyntaxError): 192 193 return "No object '%s' currently defined."%obj_name 193 194 s = '' 195 newline = "\n\n" # blank line to start new paragraph 194 196 try: 195 197 filename = sageinspect.sage_getfile(obj) 196 198 #i = filename.find('site-packages/sage/') 197 199 #if i == -1: 198 s += 'File: %s\n'%filename 200 s += '**File:** %s'%filename 201 s += newline 199 202 #else: 200 203 # file = filename[i+len('site-packages/sage/'):] 201 204 # s += 'File: <html><a href="src_browser?%s">%s</a></html>\n'%(file,file) 202 205 except TypeError: 203 206 pass 204 s += 'Type: %s\n'%type(obj) 205 s += 'Definition: %s\n'%sageinspect.sage_getdef(obj, obj_name) 206 s += 'Docstring: \n%s\n'%sageinspect.sage_getdoc(obj, obj_name) 207 s += '**Type:** %s'%type(obj) 208 s += newline 209 s += '**Definition:** %s'%sageinspect.sage_getdef(obj, obj_name) 210 s += newline 211 s += '**Docstring:**' 212 s += newline 213 s += sageinspect.sage_getdoc(obj, obj_name) 207 214 return s.rstrip() 208 215 209 216 def source_code(s, globs, system='sage'): … … 229 236 return obj._sage_src_() 230 237 except: 231 238 pass 239 newline = "\n\n" # blank line to start new paragraph 240 indent = " " # indent source code to mark it as a code block 241 232 242 filename = sageinspect.sage_getfile(obj) 233 243 lines, lineno = sageinspect.sage_getsourcelines(obj, is_binary=False) 234 src = ''.join(lines)235 src = sagedoc.format_src(src)244 src = indent.join(lines) 245 src = indent + sagedoc.format_src(src) 236 246 if not lineno is None: 237 src = "File: %s\nSource Code (starting at line %s):\n%s"%(filename, lineno, src) 238 return src 247 output = "**File:** %s"%filename 248 output += newline 249 output += "**Source Code** (starting at line %s)::"%lineno 250 output += newline 251 output += src 252 return output 239 253 240 254 except (TypeError, IndexError), msg: 241 255 print msg