Ticket #5653: docstring.4.patch

File docstring.4.patch, 54.4 KB (added by jhpalmieri, 12 years ago)

Apply only this patch, as it's cumulative. Rebased against 3.4.1.rc4

  • new file doc/introspect/__init__.py

    # HG changeset patch
    # User John H. Palmieri <palmieri@math.washington.edu>
    # Date 1240338630 25200
    # Node ID 0e4cd3a9c85b54538dea576ee67ad0cc57a5ce2b
    # Parent  576345441a28e43ec773c3243233f490b8de2563
    pretty docstrings in notebook
    
    diff -r 576345441a28 -r 0e4cd3a9c85b doc/introspect/__init__.py
    - +  
     1 
  • new file doc/introspect/builder.py

    diff -r 576345441a28 -r 0e4cd3a9c85b doc/introspect/builder.py
    - +  
     1#!/usr/bin/env python
     2import os, sys, subprocess, shutil, glob, optparse
     3
     4#We remove the current directory from sys.path right away
     5#so that we import sage from the proper spot
     6try:
     7    sys.path.remove(os.path.realpath(os.getcwd()))
     8except:
     9    pass
     10
     11from sage.misc.cachefunc import cached_method
     12
     13##########################################
     14#                Options                 #
     15##########################################
     16SAGE_DOC = os.environ['SAGE_DOC']
     17LANGUAGES = ['en', 'fr']
     18SPHINXOPTS  = ""
     19PAPER       = ""
     20
     21if PAPER == "a4":
     22    PAPEROPTS = "-D latex_paper_size=a4"
     23elif PAPER == "letter":
     24    PAPEROPTS = "-D latex_paper_size=letter"
     25else:
     26    PAPEROPTS = ""
     27
     28#Note that this needs to have the doctrees dir   
     29ALLSPHINXOPTS   = SPHINXOPTS + " " + PAPEROPTS + " . "
     30
     31
     32##########################################
     33#          Utility Functions             #
     34##########################################
     35def mkdir(path):
     36    """
     37    Makes the directory at path if it doesn't exist and returns the
     38    string path.
     39
     40    EXAMPLES::
     41
     42        sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     43        sage: d = tmp_filename(); d
     44        '/.../tmp_...'
     45        sage: os.path.exists(d)
     46        False
     47        sage: dd = builder.mkdir(d)
     48        sage: d == dd
     49        True
     50        sage: os.path.exists(d)
     51        True
     52    """
     53    if not os.path.exists(path):
     54        os.makedirs(path)
     55    return path
     56
     57def copytree(src, dst, symlinks=False, ignore_errors=False):
     58    """
     59    Recursively copy a directory tree using copy2().
     60
     61    The destination directory must not already exist.
     62    If exception(s) occur, an Error is raised with a list of reasons.
     63
     64    If the optional symlinks flag is true, symbolic links in the
     65    source tree result in symbolic links in the destination tree; if
     66    it is false, the contents of the files pointed to by symbolic
     67    links are copied.
     68
     69    XXX Consider this example code rather than the ultimate tool.
     70
     71    """
     72    names = os.listdir(src)
     73    mkdir(dst)
     74    errors = []
     75    for name in names:
     76        srcname = os.path.join(src, name)
     77        dstname = os.path.join(dst, name)
     78        try:
     79            if symlinks and os.path.islink(srcname):
     80                linkto = os.readlink(srcname)
     81                os.symlink(linkto, dstname)
     82            elif os.path.isdir(srcname):
     83                copytree(srcname, dstname, symlinks)
     84            else:
     85                shutil.copy2(srcname, dstname)
     86            # XXX What about devices, sockets etc.?
     87        except (IOError, os.error), why:
     88            errors.append((srcname, dstname, str(why)))
     89        # catch the Error from the recursive copytree so that we can
     90        # continue with other files
     91        except shutil.Error, err:
     92            errors.extend(err.args[0])
     93    try:
     94        shutil.copystat(src, dst)
     95    except OSError, why:
     96        errors.extend((src, dst, str(why)))
     97    if errors and not ignore_errors:
     98        raise shutil.Error, errors
     99
     100
     101
     102##########################################
     103#             Builders                   #
     104##########################################
     105def builder_helper(type):
     106    """
     107    Returns a function which builds the documentation for
     108    output type type.
     109    """
     110    def f(self):
     111        output_dir = self._output_dir(type)
     112        os.chdir(self.dir)
     113
     114        build_command = 'sphinx-build'
     115        build_command += ' -b %s -d %s %s %s'%(type, self._doctrees_dir(),
     116                                               ALLSPHINXOPTS, output_dir)
     117        print build_command
     118        subprocess.call(build_command, shell=True)
     119
     120        print "Build finished.  The built documents can be found in %s"%output_dir
     121       
     122    f.is_output_format = True
     123    return f
     124       
     125
     126class DocBuilder(object):
     127    def __init__(self, name, lang='en'):
     128        """
     129        INPUT:
     130           
     131        - ``name`` - the name of a subdirectory in SAGE_DOC, such as
     132          'tutorial' or 'bordeaux_2008'
     133
     134        - ``lang`` - (default "en") the language of the document.
     135        """
     136        if '/' in name:
     137            lang, name = name.split(os.path.sep)
     138        self.name = name
     139        self.lang = lang
     140        self.dir = os.path.join(SAGE_DOC, lang, name)
     141
     142        #Make sure the .static and .templates directories are there
     143        mkdir(os.path.join(self.dir, "static"))
     144        mkdir(os.path.join(self.dir, "templates"))
     145
     146    def _output_dir(self, type):
     147        """
     148        Returns the directory where the output of type type is stored.
     149        If the directory does not exist, then it will automatically be
     150        created.
     151
     152        EXAMPLES::
     153
     154            sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     155            sage: b = builder.DocBuilder('tutorial')
     156            sage: b._output_dir('html')
     157            '.../devel/sage/doc/output/html/en/tutorial'
     158        """
     159        return mkdir(os.path.join(SAGE_DOC, "output", type, self.lang, self.name))
     160
     161    def _doctrees_dir(self):
     162        """
     163        Returns the directory where the doctrees are stored.  If the
     164        directory does not exist, then it will automatically be
     165        created.
     166
     167        EXAMPLES::
     168
     169            sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     170            sage: b = builder.DocBuilder('tutorial')
     171            sage: b._doctrees_dir()
     172            '.../devel/sage/doc/output/doctrees/en/tutorial'
     173        """
     174        return mkdir(os.path.join(SAGE_DOC, "output", 'doctrees', self.lang, self.name))
     175
     176    def _output_formats(self):
     177        """
     178        Returns a list of the possible output formats.
     179
     180        EXAMPLES::
     181
     182            sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     183            sage: b = builder.DocBuilder('tutorial')
     184            sage: b._output_formats()
     185            ['changes', 'html', 'htmlhelp', 'json', 'latex', 'linkcheck', 'pickle', 'web']
     186
     187        """
     188        #Go through all the attributes of self and check to
     189        #see which ones have an 'is_output_format' attribute.  These
     190        #are the ones created with builder_helper.
     191        output_formats = []
     192        for attr in dir(self):
     193            if hasattr(getattr(self, attr), 'is_output_format'):
     194                output_formats.append(attr)
     195        output_formats.sort()
     196        return output_formats
     197
     198    def pdf(self):
     199        """
     200        Builds the PDF files for this document.  This is done by first
     201        (re)-building the LaTeX output, going into that LaTeX
     202        directory, and running 'make all-pdf' there.
     203
     204        EXAMPLES::
     205
     206            sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     207            sage: b = builder.DocBuilder('tutorial')
     208            sage: b.pdf() #not tested
     209        """
     210        self.latex()
     211        os.chdir(self._output_dir('latex'))
     212        subprocess.call('make all-pdf', shell=True)
     213
     214        pdf_dir = self._output_dir('pdf')
     215        for pdf_file in glob.glob('*.pdf'):
     216            shutil.move(pdf_file, os.path.join(pdf_dir, pdf_file))
     217
     218        print "Build finished.  The built documents can be found in %s"%pdf_dir             
     219
     220    def clean(self, *args):
     221        """
     222        """
     223        import shutil
     224        shutil.rmtree(self._doctrees_dir())
     225        output_formats = list(args) if args else self._output_formats()
     226        for format in output_formats:
     227            shutil.rmtree(self._output_dir(format), ignore_errors=True)
     228       
     229    html = builder_helper('html')
     230    pickle = builder_helper('pickle')
     231    web = pickle
     232    json = builder_helper('json')                       
     233    htmlhelp = builder_helper('htmlhelp')
     234    latex = builder_helper('latex')
     235    changes = builder_helper('changes')
     236    linkcheck = builder_helper('linkcheck')
     237
     238class AllBuilder(object):
     239    """
     240    A class used to build all of the documentation.
     241    """
     242    def __getattr__(self, attr):
     243        """
     244        For any attributes not explicitly defined, we just go through
     245        all of the documents and call their attr.  For example,
     246        'AllBuilder().json()' will go through all of the documents
     247        and call the json() method on their builders.
     248        """
     249        from functools import partial
     250        return partial(self._wrapper, attr)
     251
     252    def _wrapper(self, name, *args, **kwds):
     253        """
     254        This is the function which goes through all of the documents
     255        and does the actual building.
     256        """
     257        for document in self.get_all_documents():
     258            getattr(get_builder(document), name)(*args, **kwds)
     259
     260    def get_all_documents(self):
     261        """
     262        Returns a list of all of the documents. A document is a directory within one of
     263        the language subdirectories of SAGE_DOC specified by the global LANGUAGES
     264        variable.
     265
     266        EXAMPLES::
     267
     268            sage: import os, sys; sys.path.append(os.environ['SAGE_DOC']+'/common/'); import builder
     269            sage: documents = builder.AllBuilder().get_all_documents()
     270            sage: 'en/tutorial' in documents
     271            True
     272        """
     273        documents = []
     274        for lang in LANGUAGES:
     275            for document in os.listdir(os.path.join(SAGE_DOC, lang)):
     276                documents.append(os.path.join(lang, document))
     277        return documents
     278
     279class WebsiteBuilder(DocBuilder):
     280    def html(self):
     281        """
     282        After we've finished building the website index page, we copy
     283        everything one directory up.
     284        """
     285        DocBuilder.html(self)
     286        html_output_dir = self._output_dir('html')
     287        copytree(html_output_dir,
     288                 os.path.realpath(os.path.join(html_output_dir, '..')),
     289                 ignore_errors=False)
     290
     291    def clean(self):
     292        """
     293        When we clean the output for the website index, we need to
     294        remove all of the HTML that were placed in the parent
     295        directory.
     296        """
     297        html_output_dir = self._output_dir('html')
     298        parent_dir = os.path.realpath(os.path.join(html_output_dir, '..'))
     299        for filename in os.listdir(html_output_dir):
     300            parent_filename = os.path.join(parent_dir, filename)
     301            if not os.path.exists(parent_filename):
     302                continue
     303            if os.path.isdir(parent_filename):
     304                shutil.rmtree(parent_filename, ignore_errors=True)
     305            else:
     306                os.unlink(parent_filename)
     307
     308        DocBuilder.clean(self)
     309
     310class ReferenceBuilder(DocBuilder):
     311    """
     312    This the class used to build the reference manual.  It is
     313    resposible for making sure the auto generated ReST files for the
     314    Sage library are up to date.
     315
     316    When building any output, we must first go through and check
     317    to see if we need to update any of the autogenerated ReST
     318    files.  There are two cases where this would happen:
     319
     320    1. A new module gets added to one of the toctrees.
     321   
     322    2. The actual module gets updated and possibly contains a new
     323       title.
     324    """
     325    def __init__(self, *args, **kwds):
     326        DocBuilder.__init__(self, *args, **kwds)
     327        self._wrap_builder_helpers()
     328
     329    def _wrap_builder_helpers(self):
     330        from functools import partial, update_wrapper
     331        for attr in dir(self):
     332            if hasattr(getattr(self, attr), 'is_output_format'):
     333                f = partial(self._wrapper, attr)
     334                f.is_output_format = True
     335                update_wrapper(f, getattr(self, attr))
     336                setattr(self, attr, f)
     337   
     338    def _wrapper(self, build_type, *args, **kwds):
     339        """
     340        This is the wrapper around the builder_helper methods that
     341        goes through and makes sure things are up to date.
     342        """
     343        #Write the .rst files for newly included modules
     344        for module_name in self.get_newly_included_modules(save=True):
     345            self.write_auto_rest_file(module_name)
     346
     347        #Update the .rst files for modified Python modules
     348        for module_name in self.get_modified_modules():
     349            self.write_auto_rest_file(module_name.replace(os.path.sep, '.'))
     350
     351        #Copy over the custom .rst files from _sage
     352        _sage = os.path.join(self.dir, '_sage')
     353        if os.path.exists(_sage):
     354            copytree(_sage, os.path.join(self.dir, 'sage'))
     355               
     356        getattr(DocBuilder, build_type)(self, *args, **kwds)
     357   
     358    def cache_filename(self):
     359        """
     360        Returns the filename where the pickle of the dictionary of
     361        already generated .rst files is stored.
     362        """
     363        return os.path.join(self._doctrees_dir(), 'reference.pickle')
     364
     365    @cached_method
     366    def get_cache(self):
     367        """
     368        Retreive the cache of already generated .rst files.  If it
     369        doesn't exist, then we just return an empty dictionary.
     370        """
     371        filename = self.cache_filename()
     372        if not os.path.exists(filename):
     373            return {}
     374
     375        import cPickle
     376        file = open(self.cache_filename(), 'rb')
     377        cache = cPickle.load(file)
     378        file.close()
     379        return cache
     380       
     381
     382    def save_cache(self):
     383        """
     384        Save the cache of already generated .rst files.
     385        """
     386        import cPickle
     387        file = open(self.cache_filename(), 'wb')
     388        cPickle.dump(self.get_cache(), file)
     389        file.close()
     390
     391    def get_sphinx_environment(self):
     392        """
     393        Returns the Sphinx environment for this project.
     394        """
     395        from sphinx.environment import BuildEnvironment
     396        class Foo(object):
     397            pass
     398        config = Foo()
     399        config.values = []
     400
     401        env_pickle = os.path.join(self._doctrees_dir(), 'environment.pickle')
     402        try:
     403            return BuildEnvironment.frompickle(config, env_pickle)
     404        except IOError:
     405            pass
     406                                           
     407    def get_modified_modules(self):
     408        """
     409        Returns an iterator for all the modules that have been modified
     410        since the docuementation was last built.
     411        """
     412        env = self.get_sphinx_environment()
     413        if env is None:
     414            return
     415        added, changed, removed = env.get_outdated_files(False)
     416        for name in changed:
     417            if name.startswith('sage'):
     418                yield name
     419
     420    def print_modified_modules(self):
     421        """
     422        Prints a list of all the modules that have been modified since
     423        the documentation was last built.
     424        """
     425        for module_name in self.get_modified_modules():
     426            print module_name
     427
     428    def get_all_rst_files(self, exclude_sage=True):
     429        """
     430        Returns an iterator for all rst files which are not
     431        autogenerated.
     432        """
     433        for directory, subdirs, files in os.walk(self.dir):
     434            if exclude_sage and directory.startswith(os.path.join(self.dir, 'sage')):
     435                continue
     436            for filename in files:
     437                if not filename.endswith('.rst'):
     438                    continue
     439                yield os.path.join(directory, filename)
     440
     441    def get_all_included_modules(self):
     442        """
     443        Returns an iterator for all modules which are included in the
     444        reference manual.
     445        """
     446        for filename in self.get_all_rst_files():
     447            for module in self.get_modules(filename):
     448                yield module
     449
     450    def get_newly_included_modules(self, save=False):
     451        """
     452        Returns an iterator for all modules that appear in the
     453        toctrees that don't appear in the cache.
     454        """
     455        cache = self.get_cache()
     456        new_modules = []
     457        for module in self.get_all_included_modules():
     458            if module not in cache:
     459                cache[module] = True
     460                yield module
     461        if save:
     462            self.save_cache()
     463
     464    def print_newly_included_modules(self):
     465        """
     466        Prints all of the modules that appear in the toctrees that
     467        don't appear in the cache.
     468        """
     469        for module_name in self.get_newly_included_modules():
     470            print module_name
     471
     472    def get_modules(self, filename):
     473        """
     474        Given a filename for a .rst file, return an iterator for
     475        all of the autogenerated rst files that it includes.
     476        """
     477        #Create the regular expression used to detect an autogenerated file
     478        import re
     479        auto_re = re.compile('^\s*(..\/)*(sage\/[\w\/]*)\s*$')
     480
     481        #Read the lines
     482        f = open(filename)
     483        lines = f.readlines()
     484        f.close()
     485
     486        for line in lines:
     487            match = auto_re.match(line)
     488            if match:
     489                yield match.group(2).replace(os.path.sep, '.')
     490               
     491    def get_module_docstring_title(self, module_name):
     492        """
     493        Returns the title of the module from its docstring.
     494        """
     495        #Try to import the module
     496        try:
     497            import sage.all
     498            __import__(module_name)
     499        except ImportError, err:
     500            raise
     501            print "Warning: could not import %s"%module_name
     502            print err
     503            return "UNABLE TO IMPORT MODULE"
     504        module = sys.modules[module_name]
     505
     506        #Get the docstring
     507        doc = module.__doc__
     508        if doc is None:
     509            doc = module.doc if hasattr(module, 'doc') else ""
     510
     511        #Extract the title
     512        i = doc.find('\n')
     513        if i != -1:
     514            return doc[i+1:].lstrip().splitlines()[0]
     515        else:
     516            return doc
     517
     518    def write_auto_rest_file(self, module_name):
     519        """
     520        Writes the autogenerated .rst file for module_name.
     521        """
     522        if not module_name.startswith('sage'):
     523            return
     524        filename = self.dir + os.path.sep + module_name.replace('.',os.path.sep) + '.rst'
     525        mkdir(os.path.dirname(filename))
     526       
     527        outfile = open(filename, 'w')
     528
     529        title = self.get_module_docstring_title(module_name)
     530
     531        if title == '':
     532            print "WARNING: Missing title for", module_name
     533            title = "MISSING TITLE"
     534
     535        outfile.write(title + '\n')
     536        outfile.write('='*len(title) + "\n\n")
     537        outfile.write('.. This file has been autogenerated.\n\n')
     538        automodule = '.. automodule:: %s\n   :members:\n   :undoc-members:\n\n'
     539        outfile.write(automodule%module_name)
     540
     541        outfile.close()
     542
     543    def clean_auto(self):
     544        """
     545        Remove the cache file for the autogenerated files as well as
     546        the files themselves.
     547        """
     548        if os.path.exists(self.cache_filename()):
     549            os.unlink(self.cache_filename())
     550
     551        import shutil
     552        shutil.rmtree(self.dir + '/sage')
     553
     554    def get_unincluded_modules(self):
     555        """
     556        Returns an iterator for all the modules in the Sage library
     557        which are not included in the reference manual.
     558        """
     559        #Make a dictionary of the included modules
     560        included_modules = {}
     561        for module_name in self.get_all_included_modules():
     562            included_modules[module_name] = True
     563       
     564        base_path = os.path.join(os.environ['SAGE_ROOT'], 'devel', 'sage', 'sage')
     565        for directory, subdirs, files in os.walk(base_path):
     566            for filename in files:
     567                if not (filename.endswith('.py') or
     568                        filename.endswith('.pyx')):
     569                    continue
     570               
     571                path = os.path.join(directory, filename)
     572
     573                #Create the module name
     574                module_name = path[len(base_path):].replace(os.path.sep, '.')
     575                module_name = 'sage' + module_name
     576                module_name = module_name[:-4] if module_name.endswith('pyx') else module_name[:-3]
     577
     578                #Exclude some ones  -- we don't want init the manual
     579                if module_name.endswith('__init__') or module_name.endswith('all'):
     580                    continue
     581
     582                if module_name not in included_modules:
     583                    yield module_name
     584               
     585    def print_unincluded_modules(self):
     586        """
     587        Prints all of the modules which are not included in the Sage
     588        reference manual.
     589        """
     590        for module_name in self.get_unincluded_modules():
     591            print module_name
     592
     593    def print_included_modules(self):
     594        """
     595        Prints all of the modules that are included in the Sage reference
     596        manual.
     597        """
     598        for module_name in self.get_all_included_modules():
     599            print module_name
     600
     601       
     602
     603def get_builder(name):
     604    """
     605    Returns a either a AllBuilder or DocBuilder object depending
     606    on whether ``name`` is 'all' or not.  These are the objects
     607    which do all the real work in building the documentation.
     608    """
     609    if name == 'all':
     610        return AllBuilder()
     611    elif name.endswith('reference'):
     612        return ReferenceBuilder(name)
     613    elif name.endswith('website'):
     614        return WebsiteBuilder(name)
     615    else:
     616        return DocBuilder(name)
     617             
     618
     619def help_message():
     620    """
     621    Returns the help message.
     622    """
     623    all_b = AllBuilder()
     624    docs = all_b.get_all_documents()
     625    docs = [(d[3:] if d[0:3] == 'en/' else d) for d in docs]
     626    tut_b = DocBuilder('en/tutorial')
     627    formats = tut_b._output_formats()
     628    formats.remove('html')
     629    help = "Usage: sage -docbuild {document} {format}\n"
     630    help += "Where {document} is one of:\n    "
     631    help += "\n    ".join(docs)
     632    help += "\nor 'all' for all documents, and {format} is one of:\n    "
     633    help += 'html, pdf, ' + ', '.join(formats)
     634    help += "\n"
     635    help += "When building the reference manual, there are several additional\n"
     636    help += "values for {format}:\n"
     637    help += "    print_modified_modules: list modules modified since the documentation\n"
     638    help += "         was last built\n"
     639    help += "    print_newly_included_modules: list modules added to the\n"
     640    help += "         documentation since it was last built\n"
     641    help += "    print_unincluded_modules: list modules not included in the documentation\n"
     642    help += "    print_included_modules: list modules included in the documentation\n"
     643    print help
     644
     645
     646parser = optparse.OptionParser(usage="usage: sage -docbuild [options] name type")
     647parser.add_option("--jsmath", action="store_true",
     648                  help="render math using jsMath")
     649parser.print_help = help_message
     650
     651if __name__ == '__main__':
     652    options, args = parser.parse_args()
     653
     654    if options.jsmath:
     655        os.environ['SAGE_DOC_JSMATH'] = "True"
     656
     657    #Get the name of the document we are trying to build
     658    try:
     659        name, type = args
     660    except ValueError:
     661        print "You must specify the document name and the output format"
     662        sys.exit(0)
     663   
     664    #Make sure common/static exists
     665    mkdir(os.path.join(SAGE_DOC, 'common', 'static'))
     666
     667    #Get the builder and build
     668    getattr(get_builder(name), type)()
  • new file doc/introspect/conf.py

    diff -r 576345441a28 -r 0e4cd3a9c85b doc/introspect/conf.py
    - +  
     1import sys, os
     2SAGE_DOC = os.environ['SAGE_ROOT'] + '/devel/sage/doc'
     3
     4# If your extensions are in another directory, add it here. If the directory
     5# is relative to the documentation root, use os.path.abspath to make it
     6# absolute, like shown here.
     7#sys.path.append(os.path.abspath('.'))
     8
     9# General configuration
     10# ---------------------
     11
     12# Add any Sphinx extension module names here, as strings. They can be extensions
     13# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
     14extensions = ['sphinx.ext.autodoc', 'sphinx.ext.jsmath']
     15
     16jsmath_path = '/javascript_local/jsmath/easy/load.js'
     17
     18# Add any paths that contain templates here, relative to this directory.
     19templates_path = [SAGE_DOC + '/introspect/templates', 'templates']
     20
     21# The suffix of source filenames.
     22source_suffix = '.rst'
     23
     24# The master toctree document.
     25master_doc = 'index'
     26
     27# General information about the project.
     28project = u""
     29copyright = u'2008, The Sage Group'
     30
     31# The version info for the project you're documenting, acts as replacement for
     32# |version| and |release|, also used in various other places throughout the
     33# built documents.
     34#
     35# The short X.Y version.
     36# from sage.version import version
     37# release = version
     38
     39#version = '3.1.2'
     40# The full version, including alpha/beta/rc tags.
     41#release = '3.1.2'
     42
     43# The language for content autogenerated by Sphinx. Refer to documentation
     44# for a list of supported languages.
     45#language = None
     46
     47# There are two options for replacing |today|: either, you set today to some
     48# non-false value, then it is used:
     49#today = ''
     50# Else, today_fmt is used as the format for a strftime call.
     51#today_fmt = '%B %d, %Y'
     52
     53# List of documents that shouldn't be included in the build.
     54#unused_docs = []
     55
     56# List of directories, relative to source directory, that shouldn't be searched
     57# for source files.
     58exclude_trees = ['.build']
     59
     60# The reST default role (used for this markup: `text`) to use for all documents.
     61default_role = 'math'
     62
     63# If true, '()' will be appended to :func: etc. cross-reference text.
     64#add_function_parentheses = True
     65
     66# If true, the current module name will be prepended to all description
     67# unit titles (such as .. function::).
     68#add_module_names = True
     69
     70# If true, sectionauthor and moduleauthor directives will be shown in the
     71# output. They are ignored by default.
     72#show_authors = False
     73
     74# The name of the Pygments (syntax highlighting) style to use.
     75pygments_style = 'sphinx'
     76
     77
     78# Options for HTML output
     79# -----------------------
     80
     81# The style sheet to use for HTML and HTML Help pages. A file of that name
     82# must exist either in Sphinx' static/ path, or in one of the custom paths
     83# given in html_static_path.
     84html_style = 'default.css'
     85
     86# The name for this set of Sphinx documents.  If None, it defaults to
     87# "<project> v<release> documentation".
     88#html_title = None
     89
     90# A shorter title for the navigation bar.  Default is the same as html_title.
     91#html_short_title = None
     92
     93# The name of an image file (within the static path) to place at the top of
     94# the sidebar.
     95#html_logo = 'sagelogo-word.ico'
     96
     97# The name of an image file (within the static path) to use as favicon of the
     98# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
     99# pixels large.
     100# html_favicon = 'sageicon.png'
     101
     102# Add any paths that contain custom static files (such as style sheets) here,
     103# relative to this directory. They are copied after the builtin static files,
     104# so a file named "default.css" will overwrite the builtin "default.css".
     105html_static_path = [SAGE_DOC +'/introspect/static', 'static']
     106
     107# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
     108# using the given strftime format.
     109#html_last_updated_fmt = '%b %d, %Y'
     110
     111# If true, SmartyPants will be used to convert quotes and dashes to
     112# typographically correct entities.
     113#html_use_smartypants = True
     114
     115# Custom sidebar templates, maps document names to template names.
     116#html_sidebars = {}
     117
     118# Additional templates that should be rendered to pages, maps page names to
     119# template names.
     120#html_additional_pages = {}
     121
     122# If false, no module index is generated.
     123html_use_modindex = False
     124
     125# If false, no index is generated.
     126html_use_index = False
     127
     128# If true, the index is split into individual pages for each letter.
     129#html_split_index = True
     130
     131# If true, the reST sources are included in the HTML build as _sources/<name>.
     132html_copy_source = False
     133
     134# If true, an OpenSearch description file will be output, and all pages will
     135# contain a <link> tag referring to it.  The value of this option must be the
     136# base URL from which the finished HTML is served.
     137#html_use_opensearch = ''
     138
     139# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
     140#html_file_suffix = ''
     141
     142# Output file base name for HTML help builder.
     143#htmlhelp_basename = ''
     144
     145
     146# Options for LaTeX output
     147# ------------------------
     148
     149# The paper size ('letter' or 'a4').
     150#latex_paper_size = 'letter'
     151
     152# The font size ('10pt', '11pt' or '12pt').
     153#latex_font_size = '10pt'
     154
     155# Grouping the document tree into LaTeX files. List of tuples
     156# (source start file, target name, title, author, document class [howto/manual]).
     157#latex_documents = []
     158
     159# The name of an image file (relative to this directory) to place at the top of
     160# the title page.
     161#latex_logo = 'sagelogo-word.png'
     162
     163# For "manual" documents, if this is true, then toplevel headings are parts,
     164# not chapters.
     165#latex_use_parts = False
     166
     167# Additional stuff for the LaTeX preamble.
     168#latex_preamble = ''
     169#latex_preamble = '\usepackage{amsmath}\n\usepackage{amsfonts}\n'
     170
     171# Documents to append as an appendix to all manuals.
     172#latex_appendices = []
     173
     174# If false, no module index is generated.
     175#latex_use_modindex = True
     176
     177
     178#####################################################
     179
     180def process_docstring_aliases(app, what, name, obj, options, docstringlines):
     181    """
     182    Change the docstrings for aliases to point to the original object.
     183    """
     184    basename = name.rpartition('.')[2]
     185    if hasattr(obj, '__name__') and obj.__name__ != basename:
     186        docstringlines[:] = ['See :obj:`%s`.' % name]
     187
     188def process_docstring_cython(app, what, name, obj, options, docstringlines):
     189    """
     190    Remove Cython's filename and location embedding.
     191    """
     192    if len(docstringlines) <= 1:
     193        return
     194
     195    first_line = docstringlines[0]
     196    if first_line.startswith('File:') and '(starting at' in first_line:
     197        #Remove the first two lines
     198        docstringlines.pop(0)
     199        docstringlines.pop(0)
     200
     201def process_docstring_module_title(app, what, name, obj, options, docstringlines):
     202    """
     203    Removes the first line from the beginning of the module's docstring.  This
     204    corresponds to the title of the module's documentation page.
     205    """
     206    if what != "module":
     207        return
     208
     209    #Remove any additional blank lines at the beginning
     210    title_removed = False
     211    while len(docstringlines) > 1 and not title_removed:
     212        if docstringlines[0].strip() != "":
     213            title_removed = True
     214        docstringlines.pop(0)
     215
     216    #Remove any additional blank lines at the beginning
     217    while len(docstringlines) > 1:
     218        if docstringlines[0].strip() == "":
     219            docstringlines.pop(0)
     220        else:
     221            break
     222
     223       
     224def setup(app):
     225    app.connect('autodoc-process-docstring', process_docstring_cython)
     226    app.connect('autodoc-process-docstring', process_docstring_module_title)
  • new file doc/introspect/static/.empty

    diff -r 576345441a28 -r 0e4cd3a9c85b doc/introspect/static/.empty
    - +  
     1 
     2 No newline at end of file
  • new file doc/introspect/templates/layout.html

    diff -r 576345441a28 -r 0e4cd3a9c85b doc/introspect/templates/layout.html
    - +  
     1<div class="docstring">
     2    {% block body %} {% endblock %}
     3</div>
  • sage/misc/sagedoc.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/misc/sagedoc.py
    a b  
    2020#*****************************************************************************
    2121
    2222import 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.
     26math_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', '...')]
     38nonmath_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: ')]
    4655
    4756def _rmcmd(s, cmd, left='', right=''):
    4857    """
     
    112121itempattern = re.compile(r"\\item\[?([^]]*)\]? *(.*)")
    113122itemreplace = r"* \1 \2"
    114123
    115 def detex(s):
     124def detex(s, embedded=False):
    116125    """nodetex
    117126    This strips LaTeX commands from a string; it is used by the
    118127    ``format`` function to process docstrings for display from the
    119128    command line interface.
    120129
    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``.
    122138
    123139    OUTPUT: string
    124140
     
    129145        'Some math: `n >= k`.  A website: sagemath.org.'
    130146        sage: detex(r'More math: `x \mapsto y`.  {\bf Bold face}.')
    131147        '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`'
    134152    """
    135153    s = _rmcmd(s, 'url')
    136154    s = _rmcmd(s, 'code')
     
    142160    s = _rmcmd(s, 'subsubsection')
    143161    s = _rmcmd(s, 'note', 'NOTE: ', '')
    144162    s = _rmcmd(s, 'emph', '*', '*')
     163    s = _rmcmd(s, 'textbf', '*', '*')
    145164
    146165    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:
    149175        s = s.replace(a,b)
    150176    return s
    151177
    152 def format(s):
     178def format(s, embedded=False):
    153179    """
    154180    Format Sage documentation ``s`` for viewing with IPython.
    155181
     
    157183    text, and if ``s`` contains a string of the form "<<<obj>>>",
    158184    then it replaces it with the docstring for "obj".
    159185
    160     INPUT: ``s`` - string
     186    INPUT:
     187
     188    - ``s`` - string
     189    - ``embedded`` - boolean (optional, default False)
    161190
    162191    OUTPUT: string
    163192
     193    Set ``embedded`` equal to True if formatting for use in the
     194    notebook; this just gets passed as an argument to ``detex``.
     195
    164196    EXAMPLES::
    165197
    166198        sage: from sage.misc.sagedoc import format
     
    216248            t = 'Definition: ' + t0 + '\n\n' + t1
    217249            docs.add(obj)
    218250        s = s[:i] + '\n' + t + s[i+6+j:]
    219            
     251
    220252    if 'nodetex' not in directives:
    221         s = detex(s)
     253        s = detex(s, embedded=embedded)
    222254    return s
    223255
    224256def format_src(s):
  • sage/misc/sageinspect.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/misc/sageinspect.py
    a b  
    114114
    115115import inspect
    116116import os
     117EMBEDDED_MODE = False
    117118
    118119def isclassinstance(obj):
    119120    r"""
     
    400401        if s[:4] == 'self':
    401402            s = s[4:]
    402403        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
    403431        return obj_name + '(' + s + ')'
    404432    except (AttributeError, TypeError, ValueError):
    405433        return '%s( [noargspec] )'%obj_name
     
    439467
    440468    if r is None:
    441469        return ''
    442     s = sage.misc.sagedoc.format(str(r))
     470
     471    s = sage.misc.sagedoc.format(str(r), embedded=EMBEDDED_MODE)
    443472
    444473    # If there is a Cython embedded position, it needs to be stripped
    445474    pos = _extract_embedded_position(s)
  • sage/server/notebook/cell.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/server/notebook/cell.py
    a b  
    3434
    3535import os, shutil
    3636
    37 from   sage.misc.misc import word_wrap
     37from   sage.misc.misc import word_wrap, SAGE_ROOT
    3838from   sage.misc.html import math_parse
    3939from   sage.misc.preparser import strip_string_literals
    4040from   sage.misc.package   import is_package_installed
     
    4646else:
    4747    JEDITABLE_TINYMCE = False
    4848
     49# Introspection.  The cache directory is a module-scope variable set
     50# in the first call to Cell.set_introspect_html().
     51_SAGE_INTROSPECT = None
     52import errno, hashlib, time
     53from sphinx.application import Sphinx
     54
    4955
    5056class Cell_generic:
    5157    def is_interactive_cell(self):
     
    14311437    # Introspection #
    14321438    #################
    14331439    def set_introspect_html(self, html, completing=False):
    1434         if completing:
     1440        if html == "" or completing:
    14351441            self.__introspect_html = html
     1442        elif html.find("`") == -1 and html.find("::") == -1:
     1443            # html doesn't seem to be in ReST format so use docutils
     1444            # to process the preamble ("**File:**" etc.)  and put
     1445            # everything else in a <pre> block.
     1446            i = html.find("**Docstring:**")
     1447            if i != -1:
     1448                preamble = html[:i+14]
     1449                from docutils.core import publish_parts
     1450                preamble = publish_parts(html[:i+14], writer_name='html')['body']
     1451                html = html[i+14:]
     1452            else:
     1453                preamble = ""
     1454            self.__introspect_html = '<div class="docstring">' + preamble + '<pre>' + html + '</pre></div>'
    14361455        else:
    1437             html = escape(html).strip()
    1438             self.__introspect_html = '<pre class="introspection">'+html+'</pre>'
     1456            # html is in ReST format, so use Sphinx to process it
     1457           
     1458            # Set the location of the introspection cache, "permanent"
     1459            # or temporary.  The former, DOT_SAGE/sage_notebook/doc,
     1460            # can pool queries from multiple worksheet processes.  The
     1461            # latter is exclusive to a worksheet's process.  The Sage
     1462            # cleaner should delete the temporary directory (or
     1463            # directories) after the notebook server exits.
     1464            global _SAGE_INTROSPECT
     1465            if _SAGE_INTROSPECT is None:
     1466                from sage.misc.misc import DOT_SAGE, tmp_dir
     1467                # It's important to use os.path.join, instead of +,
     1468                # because Sphinx counts on normalized paths.  It's also
     1469                # more portable.
     1470                std_doc_dir = os.path.join(DOT_SAGE, 'sage_notebook/doc')
     1471                try:
     1472                    os.makedirs(std_doc_dir)
     1473                    _SAGE_INTROSPECT = std_doc_dir
     1474                except OSError, error:
     1475                    if error.errno == errno.EEXIST:
     1476                        if os.access(std_doc_dir, os.R_OK | os.W_OK | os.X_OK):
     1477                            _SAGE_INTROSPECT = std_doc_dir
     1478                        else:
     1479                            _SAGE_INTROSPECT = tmp_dir()
     1480                    else:
     1481                        _SAGE_INTROSPECT = tmp_dir()
     1482                print 'Introspection cache: ', _SAGE_INTROSPECT
     1483                       
     1484            # We get a quick checksum of the input.  MD5 admits
     1485            # collisions, but we're not concerned about such security
     1486            # issues here.  Of course, if performance permits, we can
     1487            # choose a more robust hash function.
     1488            hash = hashlib.md5(html).hexdigest()
     1489            base_name = os.path.join(_SAGE_INTROSPECT, hash)
     1490            html_name = base_name + '.html'
     1491
     1492            # Multiple processes might try to read/write the target
     1493            # HTML file simultaneously.  We use a file-based lock.
     1494            # Since we care only about the target's contents, and
     1495            # we've configured Sphinx accordingly, we allow multiple
     1496            # simultaneous instances of Sphinx, as long as their
     1497            # targets are different.  Systems which don't properly
     1498            # implement os.O_EXCL may require coarser locking.
     1499
     1500            # The Pythonic cross-platform file lock below is adapted
     1501            # from
     1502            # http://www.evanfosmark.com/2009/01/cross-platform-file-locking-support-in-python/
     1503            lock_name = base_name + '.lock'
     1504
     1505            # Try to acquire the lock, periodically.  If we time out,
     1506            # we fall back to plainly formatted documentation.
     1507            timeout = 0.5
     1508            delay = 0.05
     1509            start_time = time.time()
     1510
     1511            while True:
     1512                try:
     1513                    # This operation is atomic on platforms which
     1514                    # properly implement os.O_EXCL:
     1515                    fd_lock = os.open(lock_name, os.O_CREAT | os.O_EXCL | os.O_RDWR)
     1516                    break;
     1517                except OSError, err:
     1518                    if (err.errno != errno.EEXIST) or (time.time() - start_time >= timeout):
     1519                        plain_html = escape(html).strip()
     1520                        self.__introspect_html = '<pre class="introspection">' + plain_html + '</pre>'
     1521                        return
     1522                    time.sleep(delay)
     1523
     1524            # We've acquired the lock.  Use cached HTML or run Sphinx.
     1525            try:
     1526                open(html_name, 'r')
     1527                print 'Found: %s' % html_name
     1528            except IOError:
     1529                html = html.replace('\\\\', '\\')
     1530                rst_name = base_name + '.rst'
     1531                fd_rst = open(rst_name, 'w')
     1532                fd_rst.write(html)
     1533                fd_rst.close()
     1534
     1535                # Sphinx setup.  The constructor is Sphinx(srcdir,
     1536                # confdir, outdir, doctreedir, buildername,
     1537                # confoverrides, status, warning, freshenv).
     1538                srcdir = os.path.normpath(_SAGE_INTROSPECT)
     1539
     1540                # Note: It's crucial that confdir* contains a
     1541                # customized conf.py and layout.html.  In particular,
     1542                # we've disabled index generation and told Sphinx to
     1543                # output almost exactly the HTML we display.  Sphinx
     1544                # also pickles its environment in doctreedir, but we
     1545                # force Sphinx never to load this pickle with
     1546                # freshenv=True.
     1547                confdir = os.path.join(SAGE_ROOT, 'devel/sage/doc/introspect')
     1548                doctreedir = os.path.normpath(base_name)
     1549                confoverrides = {'html_context' : {}, 'master_doc' : hash}
     1550
     1551                # To suppress output, use this:
     1552#                sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, None, None, True)
     1553
     1554                # For verbose output, use these instead:
     1555                import sys
     1556                sphinx_app = Sphinx(srcdir, confdir, srcdir, doctreedir, 'html', confoverrides, sys.stdout, sys.stderr, True)
     1557
     1558                # Run Sphinx. The first argument corresponds to
     1559                # sphinx-build's "write all files" -a flag, which we
     1560                # set to None.
     1561                sphinx_app.build(None, [rst_name])
     1562
     1563                # We delete .rst files, so future Sphinx runs don't
     1564                # keep track of them.  We also delete doctrees.
     1565                try:
     1566                    os.unlink(rst_name)
     1567                except OSError:
     1568                    pass
     1569                try:
     1570                    shutil.rmtree(doctreedir)
     1571                    os.unlink(doctreedir)
     1572                except OSError:
     1573                    pass
     1574
     1575                print 'Built: %s' % html_name
     1576            finally:
     1577                # Contents should be flushed on close().
     1578                fd_html = open(html_name, 'r')
     1579                new_html = fd_html.read()
     1580                fd_html.close()
     1581
     1582                # We release the lock and delete the lock file.
     1583                os.close(fd_lock)
     1584                os.unlink(lock_name)
     1585
     1586                new_html = new_html.replace('<pre>', '<pre class="literal-block">')
     1587                self.__introspect_html = new_html
     1588                return
    14391589
    14401590    def introspect_html(self):
    14411591        if not self.introspect():
  • sage/server/notebook/css.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/server/notebook/css.py
    a b  
    293293div.introspection {
    294294}
    295295
     296div.docstring {
     297  font-family:arial;
     298  background-color: #f1f1f1;
     299  color: blue;
     300  border: solid 1px black;
     301  padding:8px;
     302  margin:8px;
     303}
     304
     305pre.literal-block {
     306  background-color: #efc;
     307  color: blue;   
     308}
     309
    296310pre.introspection {
    297311  font-family: monospace;
    298312  font-size:15px;
    299   background-color: #efefef;
     313  background-color: #f1f1f1;
     314  color: blue;
    300315  border: solid 1px black;
    301316  padding:8px;
    302317  margin:8px;
     
    16351650   background-color: #990000;   
    16361651}
    16371652
     1653
     1654
     1655.hll { background-color: #ffffcc }
     1656.c { color: #408090; font-style: italic } /* Comment */
     1657.err { border: 1px solid #FF0000 } /* Error */
     1658.k { color: #007020; font-weight: bold } /* Keyword */
     1659.o { color: #666666 } /* Operator */
     1660.cm { color: #408090; font-style: italic } /* Comment.Multiline */
     1661.cp { color: #007020 } /* Comment.Preproc */
     1662.c1 { color: #408090; font-style: italic } /* Comment.Single */
     1663.cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
     1664.gd { color: #A00000 } /* Generic.Deleted */
     1665.ge { font-style: italic } /* Generic.Emph */
     1666.gr { color: #FF0000 } /* Generic.Error */
     1667.gh { color: #000080; font-weight: bold } /* Generic.Heading */
     1668.gi { color: #00A000 } /* Generic.Inserted */
     1669.go { color: #303030 } /* Generic.Output */
     1670.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
     1671.gs { font-weight: bold } /* Generic.Strong */
     1672.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
     1673.gt { color: #0040D0 } /* Generic.Traceback */
     1674.kc { color: #007020; font-weight: bold } /* Keyword.Constant */
     1675.kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
     1676.kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
     1677.kp { color: #007020 } /* Keyword.Pseudo */
     1678.kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
     1679.kt { color: #902000 } /* Keyword.Type */
     1680.m { color: #208050 } /* Literal.Number */
     1681.s { color: #4070a0 } /* Literal.String */
     1682.na { color: #4070a0 } /* Name.Attribute */
     1683.nb { color: #007020 } /* Name.Builtin */
     1684.nc { color: #0e84b5; font-weight: bold } /* Name.Class */
     1685.no { color: #60add5 } /* Name.Constant */
     1686.nd { color: #555555; font-weight: bold } /* Name.Decorator */
     1687.ni { color: #d55537; font-weight: bold } /* Name.Entity */
     1688.ne { color: #007020 } /* Name.Exception */
     1689.nf { color: #06287e } /* Name.Function */
     1690.nl { color: #002070; font-weight: bold } /* Name.Label */
     1691.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
     1692.nt { color: #062873; font-weight: bold } /* Name.Tag */
     1693.nv { color: #bb60d5 } /* Name.Variable */
     1694.ow { color: #007020; font-weight: bold } /* Operator.Word */
     1695.w { color: #bbbbbb } /* Text.Whitespace */
     1696.mf { color: #208050 } /* Literal.Number.Float */
     1697.mh { color: #208050 } /* Literal.Number.Hex */
     1698.mi { color: #208050 } /* Literal.Number.Integer */
     1699.mo { color: #208050 } /* Literal.Number.Oct */
     1700.sb { color: #4070a0 } /* Literal.String.Backtick */
     1701.sc { color: #4070a0 } /* Literal.String.Char */
     1702.sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
     1703.s2 { color: #4070a0 } /* Literal.String.Double */
     1704.se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
     1705.sh { color: #4070a0 } /* Literal.String.Heredoc */
     1706.si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
     1707.sx { color: #c65d09 } /* Literal.String.Other */
     1708.sr { color: #235388 } /* Literal.String.Regex */
     1709.s1 { color: #4070a0 } /* Literal.String.Single */
     1710.ss { color: #517918 } /* Literal.String.Symbol */
     1711.bp { color: #007020 } /* Name.Builtin.Pseudo */
     1712.vc { color: #bb60d5 } /* Name.Variable.Class */
     1713.vg { color: #bb60d5 } /* Name.Variable.Global */
     1714.vi { color: #bb60d5 } /* Name.Variable.Instance */
     1715.il { color: #208050 } /* Literal.Number.Integer.Long */
     1716
     1717
     1718
    16381719"""
    16391720    if color == 'gmail':
    16401721        color1 = '#c3d9ff'
  • sage/server/notebook/js.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/server/notebook/js.py
    a b  
    10171017            halt_introspection();
    10181018            return;
    10191019        }
     1020
    10201021        d.innerHTML = introspection_text;
     1022
     1023        if (contains_jsmath(introspection_text)) {
     1024            try {
     1025                jsMath.ProcessBeforeShowing(d);
     1026            } catch(e) {
     1027                text_cell.innerHTML = jsmath_font_msg + d.innerHTML;
     1028            }
     1029        }
     1030
    10211031        if(replacing)
    10221032            select_replacement_element();
    10231033    } else {
     
    29933003        cell_output.innerHTML = '';
    29943004        cell_output_nowrap.innerHTML = '';
    29953005        cell_output_html.innerHTML = introspect_html;
     3006        if (contains_jsmath(introspect_html)) {
     3007            try {
     3008                jsMath.ProcessBeforeShowing(cell_output_html);
     3009            } catch(e) {
     3010                cell_output.innerHTML = jsmath_font_msg + cell_output_html.innerHTML;
     3011            }
     3012        }
     3013
    29963014    }
    29973015}
    29983016
  • sage/server/support.py

    diff -r 576345441a28 -r 0e4cd3a9c85b sage/server/support.py
    a b  
    5353        sage.structure.sage_object.base=object_directory
    5454    sage.misc.latex.EMBEDDED_MODE = True
    5555    sage.misc.pager.EMBEDDED_MODE = True
     56    sage.misc.sageinspect.EMBEDDED_MODE = True
    5657
    5758    setup_systems(globs)
    5859    sage.misc.session.init(globs)
     
    188189    except (AttributeError, NameError, SyntaxError):
    189190        return "No object '%s' currently defined."%obj_name
    190191    s  = ''
     192    newline = "\n\n"  # blank line to start new paragraph
    191193    try:
    192194        filename = sageinspect.sage_getfile(obj)
    193195        #i = filename.find('site-packages/sage/')
    194196        #if i == -1:
    195         s += 'File:        %s\n'%filename
     197        s += '**File:** %s'%filename
     198        s += newline
    196199        #else:
    197200        #    file = filename[i+len('site-packages/sage/'):]
    198201        #    s += 'File:        <html><a href="src_browser?%s">%s</a></html>\n'%(file,file)
    199202    except TypeError:
    200203        pass
    201     s += 'Type:        %s\n'%type(obj)
    202     s += 'Definition:  %s\n'%sageinspect.sage_getdef(obj, obj_name)
    203     s += 'Docstring: \n%s\n'%sageinspect.sage_getdoc(obj, obj_name)
     204    s += '**Type:** %s'%type(obj)
     205    s += newline
     206    s += '**Definition:** %s'%sageinspect.sage_getdef(obj, obj_name)
     207    s += newline
     208    s += '**Docstring:**'
     209    s += newline
     210    s += sageinspect.sage_getdoc(obj, obj_name)
    204211    return s.rstrip()
    205212
    206213def source_code(s, globs, system='sage'):
     
    226233            return obj._sage_src_()
    227234        except:
    228235            pass
     236        newline = "\n\n"  # blank line to start new paragraph
     237        indent = "    "   # indent source code to mark it as a code block
     238
    229239        filename = sageinspect.sage_getfile(obj)
    230240        lines, lineno = sageinspect.sage_getsourcelines(obj, is_binary=False)
    231         src = ''.join(lines)
    232         src = sagedoc.format_src(src)
     241        src = indent.join(lines)
     242        src = indent + sagedoc.format_src(src)
    233243        if not lineno is None:
    234             src = "File: %s\nSource Code (starting at line %s):\n%s"%(filename, lineno, src)
    235         return src
     244            output = "**File:** %s"%filename
     245            output += newline
     246            output += "**Source Code** (starting at line %s)::"%lineno
     247            output += newline
     248            output += src
     249        return output
    236250   
    237251    except (TypeError, IndexError), msg:
    238252        print msg