23

I am using Sphinx to document a webservice that will be deployed in different servers. The documentation is full of URL examples for the user to click and they should just work. My problem is that the host, port and deployment root will vary and the documentation will have to be re-generated for every deployment.

I tried defining substitutions like this:

|base_url|/path
.. |base_url| replace:: http://localhost:8080

But the generated HTML is not what I want (doesn't include "/path" in the generated link):

<a href="http://localhost:8080">http://localhost:8080</a>/path

Does anybody know how to work around this?

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Martin Blech
  • 13,135
  • 6
  • 31
  • 35

4 Answers4

30

New in Sphinx v1.0:

sphinx.ext.extlinks – Markup to shorten external links

https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html

The extension adds one new config value:

extlinks

This config value must be a dictionary of external sites, mapping unique short alias names to a base URL and a prefix. For example, to create an alias for the above mentioned issues, you would add

extlinks = {'issue': 
    ('http://bitbucket.org/birkenfeld/sphinx/issue/%s', 'issue ')}

Now, you can use the alias name as a new role, e.g. :issue:`123`. This then inserts a link to http://bitbucket.org/birkenfeld/sphinx/issue/123. As you can see, the target given in the role is substituted in the base URL in the place of %s.

The link caption depends on the second item in the tuple, the prefix:

If the prefix is None, the link caption is the full URL. If the prefix is the empty string, the link caption is the partial URL given in the role content (123 in this case.) If the prefix is a non-empty string, the link caption is the partial URL, prepended by the prefix – in the above example, the link caption would be issue 123. You can also use the usual “explicit title” syntax supported by other roles that generate links, i.e. :issue:`this issue <123>`. In this case, the prefix is not relevant.

bad_coder
  • 11,289
  • 20
  • 44
  • 72
dpeifer717
  • 316
  • 3
  • 2
  • That's a great addition to Sphinx. Thanks for the heads up! – Martin Blech Apr 28 '11 at 09:00
  • 6
    At the risk of stating the obvious, you'll need to add this to your extensions `conf.py` `extensions = ['sphinx.ext.extlinks']`. Had to find someone elses `conf.py` to figure it out. – ideasman42 Jun 13 '15 at 13:42
  • 1
    Note that this isn't suitable for the general case of including a general URL that isn't parameterized, especially if that URL coincidentally happens to contain the character sequence `%s`. – shadowtalker Apr 16 '20 at 23:46
5

I had a similar problem where I needed to substitute also URLs in image targets. The extlinks do not expand when used as a value of image :target: attribute. Eventually I wrote a custom sphinx transformation that rewrites URLs that start with a given prefix, in my case, http://mybase/. Here is a relevant code for conf.py:

from sphinx.transforms import SphinxTransform

class ReplaceMyBase(SphinxTransform):

    default_priority = 750
    prefix = 'http://mybase/'

    def apply(self):
        from docutils.nodes import reference, Text
        baseref = lambda o: (
            isinstance(o, reference) and
            o.get('refuri', '').startswith(self.prefix))
        basetext = lambda o: (
            isinstance(o, Text) and o.startswith(self.prefix))
        base = self.config.mybase.rstrip('/') + '/'
        for node in self.document.traverse(baseref):
            target = node['refuri'].replace(self.prefix, base, 1)
            node.replace_attr('refuri', target)
            for t in node.traverse(basetext):
                t1 = Text(t.replace(self.prefix, base, 1), t.rawsource)
                t.parent.replace(t, t1)
        return

# end of class

def setup(app):
    app.add_config_value('mybase', 'https://en.wikipedia.org/wiki', 'env')
    app.add_transform(ReplaceMyBase)
    return

This expands the following rst source to point to English wikipedia. When conf.py sets mybase="https://es.wikipedia.org/wiki" the links would point to the Spanish wiki.

* inline link http://mybase/Helianthus
* `link with text <http://mybase/Helianthus>`_
* `link with separate definition`_
* image link |flowerimage|

.. _link with separate definition: http://mybase/Helianthus

.. |flowerimage| image:: https://upload.wikimedia.org/wikipedia/commons/f/f1/Tournesol.png
   :target: http://mybase/Helianthus
Pavol Juhas
  • 51
  • 1
  • 3
  • Thank you, interesting approach, I am playing with it to handle custom links as replacements in indirect references (can't find a way to use extlinks in sth like .. _some_link: mylink:/some/where ) – Mekk Jan 31 '19 at 10:13
4

Ok, here's how I did it. First, apilinks.py (the Sphinx extension):

from docutils import nodes, utils

def setup(app):
    def api_link_role(role, rawtext, text, lineno, inliner, options={},
                      content=[]):
        ref = app.config.apilinks_base + text
        node = nodes.reference(rawtext, utils.unescape(ref), refuri=ref,
                               **options)
        return [node], []
    app.add_config_value('apilinks_base', 'http://localhost/', False)
    app.add_role('apilink', api_link_role)

Now, in conf.py, add 'apilinks' to the extensions list and set an appropriate value for 'apilinks_base' (otherwise, it will default to 'http://localhost/'). My file looks like this:

extensions = ['sphinx.ext.autodoc', 'apilinks']
# lots of other stuff
apilinks_base = 'http://host:88/base/'

Usage:

:apilink:`path`

Output:

<a href="http://host:88/base/path">http://host:88/base/path</a>
Martin Blech
  • 13,135
  • 6
  • 31
  • 35
1

You can write a Sphinx extension that creates a role like

:apilink:`path` 

and generates the link from that. I never did this, so I can't help more than giving this pointer, sorry. You should try to look at how the various roles are implemented. Many are very similar to what you need, I think.

tsg
  • 2,007
  • 13
  • 12
  • @thoriann: thanks for the pointer and check my answer to see the complete implementation. – Martin Blech Aug 05 '09 at 13:04
  • 11 years later. Dead links. Dead answer (?) – keepAlive Feb 19 '20 at 08:02
  • 1
    @keepAlive You can easily find the moved documents, for example, see https://sphinx.readthedocs.io/en/2.0/usage/extensions/index.html for the first link and https://www.sphinx-doc.org/en/2.0/usage/restructuredtext/roles.html for the second. – Yaroslav Nikitenko Apr 16 '20 at 10:09
  • "easily" is relative. Thank you for finding those documents (that I never would have been able to find). – shadowtalker Apr 16 '20 at 23:44