Ticket #9128: trac_9128-sphinx_links_all-fh.patch

File trac_9128-sphinx_links_all-fh.patch, 12.2 KB (added by nthiery, 8 years ago)
  • doc/common/builder.py

    # HG changeset patch
    # User Nicolas M. Thiery <nthiery@users.sf.net>
    # Date 1329758989 -3600
    # Node ID 5d9f4bf13e466489160104c5bea0e54ff792e719
    # Parent  b00ce6df2e4b8e12e712cca66efedc48a06fc9a9
    #9128: sphinx try to resolve links using sage.all and docs.python.orgs
    
    diff --git a/doc/common/builder.py b/doc/common/builder.py
    a b class AllBuilder(object): 
    254254            sage: documents = builder.AllBuilder().get_all_documents()
    255255            sage: 'en/tutorial' in documents
    256256            True
     257            sage: documents[0] == 'en/reference'
     258            True
    257259        """
    258260        documents = []
    259261        for lang in LANGUAGES:
    260262            for document in os.listdir(os.path.join(SAGE_DOC, lang)):
    261263                if document not in OMIT:
    262264                    documents.append(os.path.join(lang, document))
     265
     266        # Ensure that the reference guide is compiled first so that links from
     267        # the other document to it are correctly resolved.
     268        if 'en/reference' in documents:
     269            documents.remove('en/reference')
     270        documents.insert(0, 'en/reference')
     271
    263272        return documents
    264273
    265274class WebsiteBuilder(DocBuilder):
    class ReferenceBuilder(DocBuilder): 
    603612            logger.error("Warning: Missing title for %s", module_name)
    604613            title = "MISSING TITLE"
    605614
     615        outfile.write(".. _%s:\n\n"%module_name)
    606616        outfile.write(title + '\n')
    607617        outfile.write('='*len(title) + "\n\n")
    608618        outfile.write('.. This file has been autogenerated.\n\n')
    def setup_parser(): 
    944954    standard.add_option("--no-pdf-links", dest="no_pdf_links",
    945955                        action="store_true",
    946956                        help="do not include PDF links in DOCUMENT 'website'; FORMATs: html, json, pickle, web")
     957    standard.add_option("--warn-links", dest="warn_links",
     958                        default=False, action="store_true",
     959                        help="issue a warning whenever a link is not properly resolved; equivalent to '--sphinx-opts -n' (sphinx option: nitpicky)")
    947960    standard.add_option("--check-nested", dest="check_nested",
    948961                        action="store_true",
    949962                        help="check picklability of nested classes in DOCUMENT 'reference'")
    if __name__ == '__main__': 
    10571070    if options.sphinx_opts:
    10581071        ALLSPHINXOPTS += options.sphinx_opts.replace(',', ' ') + " "
    10591072    if options.no_pdf_links:
    1060         ALLSPHINXOPTS += "-A hide_pdf_links=1"
     1073        ALLSPHINXOPTS += "-A hide_pdf_links=1 "
     1074    if options.warn_links:
     1075        ALLSPHINXOPTS += "-n "
     1076
    10611077
    10621078    # Make sure common/static exists.
    10631079    mkdir(os.path.join(SAGE_DOC, 'common', 'static'))
  • doc/common/conf.py

    diff --git a/doc/common/conf.py b/doc/common/conf.py
    a b  
    1 import sys, os, re
     1import sys, os, sphinx
     2
    23SAGE_ROOT = os.environ['SAGE_ROOT']
    34SAGE_DOC = os.path.join(SAGE_ROOT, 'devel/sage/doc')
    45
     6def get_doc_abspath(path):
     7    """
     8    return the absolute path from a SAGE_DOC relative path
     9    """
     10    return os.path.abspath(os.path.join(SAGE_DOC, path))
     11
    512# If your extensions are in another directory, add it here. If the directory
    6 # is relative to the documentation root, use os.path.abspath to make it
     13# is relative to the documentation root, use get_doc_abspath to make it
    714# absolute, like shown here.
    8 #sys.path.append(os.path.abspath('.'))
    9 sys.path.append(os.path.abspath(os.path.join(SAGE_DOC, 'common')))
     15sys.path.append(get_doc_abspath('common'))
    1016
    1117# General configuration
    1218# ---------------------
    sys.path.append(os.path.abspath(os.path. 
    1622extensions = ['sage_autodoc',  'sphinx.ext.graphviz',
    1723              'sphinx.ext.inheritance_diagram', 'sphinx.ext.todo',
    1824              'sphinx.ext.extlinks']
     25# We do *not* fully initialize intersphinx since we call it by hand
     26# in find_sage_dangling_links.
    1927#, 'sphinx.ext.intersphinx']
    2028
    2129
    inheritance_edge_attrs = {} 
    98106todo_include_todos = True
    99107
    100108
     109# Cross-links to other project's online documentation.
     110# intersphinx_mapping = {'http://docs.python.org/': None}
     111#intersphinx_mapping = {'python': ('http://docs.python.org/',
     112#                                  'python-inv.txt')}
     113intersphinx_mapping = {
     114    'http://docs.python.org/': get_doc_abspath('common/python.inv')}
     115
     116def set_intersphinx_mappings(app):
     117    """
     118    Add reference's objects.inv to intersphinx if not compiling reference
     119    """
     120    app.config.intersphinx_mapping = intersphinx_mapping
     121    refpath = 'output/html/en/reference/'
     122    if not app.srcdir.endswith('reference'):
     123        app.config.intersphinx_mapping[get_doc_abspath(refpath)] = get_doc_abspath(refpath+'objects.inv')
     124pythonversion = sys.version.split(' ')[0]
     125# Python and Sage trac ticket shortcuts. For example, :trac:`7549` .
     126
    101127# Sage trac ticket shortcuts. For example, :trac:`7549` .
    102128extlinks = {
     129    'python': ('http://docs.python.org/release/'+pythonversion+'/%s', ''),
    103130    'trac': ('http://trac.sagemath.org/sage_trac/ticket/%s', 'trac ticket #'),
    104131    'wikipedia': ('http://en.wikipedia.org/wiki/%s', 'Wikipedia article ')}
    105132
    html_split_index = True 
    199226# Output file base name for HTML help builder.
    200227#htmlhelp_basename = ''
    201228
    202 # Cross-links to other project's online documentation.
    203 #intersphinx_mapping = {'http://docs.python.org/dev': None}
    204 
    205229
    206230# Options for LaTeX output
    207231# ------------------------
    def process_inherited(app, what, name, o 
    440464    for i in xrange(len(docstringlines)):
    441465        docstringlines.pop()
    442466
    443 from sage.misc.sageinspect import sage_getargspec
    444 autodoc_builtin_argspec = sage_getargspec
     467dangling_debug = False
     468
     469def debug_inf(app, message):
     470    if dangling_debug: app.info(message)
     471
     472def call_intersphinx(app, env, node, contnode):
     473    """
     474    Call intersphinx and work around its misshandling of relative links
     475    """
     476    debug_inf(app, "???? Trying intersphinx for %s"%node['reftarget'])
     477    builder = app.builder
     478    res =  sphinx.ext.intersphinx.missing_reference(
     479        app, env, node, contnode)
     480    if res: #workaround intersphinx misshandling of relative links
     481        # useful for debugging
     482        # import pdb
     483        # pdb.set_trace()
     484        if res['refuri'].startswith(SAGE_DOC):
     485            here = os.path.dirname(os.path.join(builder.outdir,
     486                                                node['refdoc']))
     487            res['refuri'] = os.path.relpath(res['refuri'], here)
     488            debug_inf(app, "++++ Found at %s"%res['refuri'])
     489    else:
     490        debug_inf(app, "---- Intersphinx: %s not Found"%node['reftarget'])
     491    return res
     492
     493# lists of basic Python class which are documented as functions
     494base_class_as_func = [
     495    'bool', 'complex', 'dict', 'file', 'float',
     496    'frozenset', 'int', 'list', 'long', 'object',
     497    'set', 'slice', 'str', 'tuple', 'type', 'unicode', 'xrange']
     498
     499def find_sage_dangling_links(app, env, node, contnode):
     500    """
     501    Try to find dangling link in local module imports or all.py.
     502    """
     503    debug_inf(app, "==================== find_sage_dangling_links ")
     504
     505    reftype = node['reftype']
     506    reftarget  = node['reftarget']
     507    try:
     508        doc = node['refdoc']
     509    except KeyError:
     510        debug_inf(app, "-- no refdoc in node %s"%node)
     511        return None
     512
     513    debug_inf(app, "Searching %s from %s"%(reftarget, doc))
     514
     515    # Workaround: in Python's doc 'object', 'list', ... are documented as a
     516    # function rather than a class
     517    if reftarget in base_class_as_func and reftype == 'class':
     518        node['reftype'] = 'func'
     519
     520    res = call_intersphinx(app, env, node, contnode)
     521    if res:
     522        debug_inf(app, "++ DONE %s"%(res['refuri']))
     523        return res
     524
     525    if node.get('refdomain') != 'py': # not a python file
     526       return None
     527
     528    try:
     529        module = node['py:module']
     530        cls    = node['py:class']
     531    except KeyError:
     532        debug_inf(app, "-- no module or class for :%s:%s"%(reftype, reftarget))
     533        return None
     534
     535    basename = reftarget.split(".")[0]
     536    try:
     537        target_module = getattr(sys.modules['sage.all'], basename).__module__
     538    except AttributeError:
     539        debug_inf(app, "-- %s not found in sage.all"%(basename))
     540        return None
     541    if target_module is None:
     542        target_module = ""
     543        debug_inf(app, "?? found in None !!!")
     544
     545    debug_inf(app, "++ found %s using sage.all in %s"%(basename, target_module))
     546
     547    newtarget = target_module+'.'+reftarget
     548    node['reftarget'] = newtarget
     549
     550    # adapted  from sphinx/domains/python.py
     551    builder = app.builder
     552    searchmode = node.hasattr('refspecific') and 1 or 0
     553    matches =  builder.env.domains['py'].find_obj(
     554        builder.env, module, cls, newtarget, reftype, searchmode)
     555    if not matches:
     556        debug_inf(app, "?? no matching doc for %s"%newtarget)
     557        return call_intersphinx(app, env, node, contnode)
     558    elif len(matches) > 1:
     559        env.warn(target_module,
     560                 'more than one target found for cross-reference '
     561                 '%r: %s' % (newtarget,
     562                             ', '.join(match[0] for match in matches)),
     563                 node.line)
     564    name, obj = matches[0]
     565    debug_inf(app, "++ match = %s %s"%(name, obj))
     566
     567    from docutils import nodes
     568    newnode = nodes.reference('', '', internal=True)
     569    if name == target_module:
     570        newnode['refid'] = name
     571    else:
     572        newnode['refuri'] = builder.get_relative_uri(node['refdoc'], obj[0])
     573        newnode['refuri'] += '#' + name
     574        debug_inf(app, "++ DONE at URI %s"%(newnode['refuri']))
     575    newnode['reftitle'] = name
     576    newnode.append(contnode)
     577    return newnode
     578
    445579
    446580def setup(app):
    447581    app.connect('autodoc-process-docstring', process_docstring_cython)
    def setup(app): 
    451585    app.connect('autodoc-process-docstring', process_mathtt)
    452586    app.connect('autodoc-process-docstring', process_inherited)
    453587    app.connect('autodoc-skip-member', skip_member)
     588
     589    app.add_config_value('intersphinx_mapping', {}, True)
     590    app.add_config_value('intersphinx_cache_limit', 5, False)
     591    # We do *not* fully initialize intersphinx since we call it by hand
     592    # in find_sage_dangling_links.
     593    #   app.connect('missing-reference', missing_reference)
     594    app.connect('missing-reference', find_sage_dangling_links)
     595    import sphinx.ext.intersphinx
     596    app.connect('builder-inited', set_intersphinx_mappings)
     597    app.connect('builder-inited', sphinx.ext.intersphinx.load_mappings)
     598
  • doc/en/developer/sage_manuals.rst

    diff --git a/doc/en/developer/sage_manuals.rst b/doc/en/developer/sage_manuals.rst
    a b name. For example, in the huge link 
    137137only ``".to_dyck_word()"`` will appear. Note that the parentheses in
    138138the link are autogenerated.
    139139
    140 Finally, local names are handled. That is, for example, in the
     140Local names are handled. That is, for example, in the
    141141definition of a class (and any of its members or methods), you can
    142142link to any member or method of the same class by simply giving the
    143143name of it prepended by a dot ``"."``. You do not need to give its
    link produced and also without any error 
    154154the prepended dot, the object is searched starting from the top-level
    155155to the innermost module or class.
    156156
     157You can also link, without giving the full path, to objects imported in a
     158local module or imported by default in Sage. For example, the two following
     159are equivalent, as :class:`Parent` is imported by default in Sage (using the
     160``all.py`` files)::
     161
     162    :class:`Parent`
     163    :class:`~sage.structure.parent.Parent`
     164
    157165Sage adds a special role to link to trac ticket. The code ``:trac:`12490```
    158166link to the :trac:`12490`. When fixing a bug, you should add the link to the
    159167corresponding trac ticket in the ``TEST`` section. Here is an example::
    If the same vein you can also add links  
    170178``:wikipedia:`Sage_(mathematics_software)``` add the following link to the
    171179:wikipedia:`Sage_(mathematics_software)`
    172180
     181.. note::
     182
     183    Finally, you can check that all links are properly resolved by adding the
     184    argument ``--warn-links`` to the documentation build command as in::
     185
     186        sage -docbuild --warn-links reference html
     187
     188    In this case, when a link is not resolved Sphinx will issue a warning.
     189
    173190
    174191Adding a new file
    175192-----------------