Skip to content

Allow extensions to define the keys returned by linkcode ext #11824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Features added

* #11701: HTML Search: Adopt the new `<search>`_ element.
Patch by Bénédikt Tran.
* #11824: linkcode: Allow extensions to add support for a domain by defining
the keys that should be present.
Patch by Nicolas Peugnet.

.. _`<search>`: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/search

Expand Down
2 changes: 2 additions & 0 deletions doc/extdev/appapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ package.

.. automethod:: Sphinx.add_autodoc_attrgetter

.. automethod:: Sphinx.add_linkcode_domain

.. automethod:: Sphinx.add_search_language

.. automethod:: Sphinx.add_source_suffix
Expand Down
3 changes: 3 additions & 0 deletions doc/usage/extensions/linkcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ Configuration
- ``javascript``: ``object`` (name of the object), ``fullname``
(name of the item)

Support for other domains can be added with
:py:meth:`.Sphinx.add_linkcode_domain()`.

Example:

.. code-block:: python
Expand Down
9 changes: 9 additions & 0 deletions sphinx/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,15 @@ def add_autodoc_attrgetter(self, typ: type, getter: Callable[[Any, str, Any], An
logger.debug('[app] adding autodoc attrgetter: %r', (typ, getter))
self.registry.add_autodoc_attrgetter(typ, getter)

def add_linkcode_domain(self, domain: str, keys: list[str]) -> None:
"""Register a new list of keys to use for a domain by the
:mod:`sphinx.ext.linkcode` extension.

.. versionadded:: 7.3
"""
from sphinx.ext.linkcode import domain_keys
domain_keys[domain] = keys
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering but what happens if two extensions do the same? should extend the keys and removing duplicates?

Also, you should probably say (in the doc) that the keys an extension defines overrides whatever keys were previously defined if we go with the current implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering but what happens if two extensions do the same? should extend the keys and removing duplicates?

I don't think so, the idea is that an extension that provides support for a new domain, for instance sphinxcontrib-phpdomain, can now add the php domain to the list of domains supported by linkcode. I don't think that anybody uses two extensions adding support for the same domain, so I don't see any chances of conflict here.

Another possibility I see would be to completely forbid overriding an existing key, or maybe add a warning when a key is overridden. But I thought overriding the existing keys could also be useful in a way.

Maybe we should wait for another opinion? I'm not in a hurry for this feature.

Also, you should probably say (in the doc) that the keys an extension defines overrides whatever keys were previously defined if we go with the current implementation.

I will add a more descriptive explanation when we settle on the preferred behaviour.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like the opinion of another maintainer/contributor. Since we are in a holiday period, it might take a while though. When we release new versions, we create an issue and you can ask at that moment if we didn't decide on anything.


def add_search_language(self, cls: Any) -> None:
"""Register a new language for the HTML search index.

Expand Down
15 changes: 8 additions & 7 deletions sphinx/ext/linkcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
from sphinx.application import Sphinx


domain_keys = {
'py': ['module', 'fullname'],
'c': ['names'],
'cpp': ['names'],
'js': ['object', 'fullname'],
}


class LinkcodeError(SphinxError):
category = "linkcode error"

Expand All @@ -30,13 +38,6 @@ def doctree_read(app: Sphinx, doctree: Node) -> None:
raise LinkcodeError(msg)
assert resolve_target is not None # for mypy

domain_keys = {
'py': ['module', 'fullname'],
'c': ['names'],
'cpp': ['names'],
'js': ['object', 'fullname'],
}

for objnode in list(doctree.findall(addnodes.desc)):
domain = objnode.get('domain')
uris: set[str] = set()
Expand Down
5 changes: 5 additions & 0 deletions tests/roots/test-ext-viewcode/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ def linkcode_resolve(domain, info):
return "http://foobar/js/" + info['fullname']
elif domain in ("c", "cpp"):
return f"http://foobar/{domain}/{''.join(info['names'])}"
elif domain == "rst":
return "http://foobar/rst/{fullname}".format(**info)
else:
raise AssertionError()

def setup(app):
app.add_linkcode_domain("rst", ["fullname"])
7 changes: 7 additions & 0 deletions tests/roots/test-ext-viewcode/objects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,10 @@ CPP domain

.. cpp:function:: T& operator[]( unsigned j )
const T& operator[]( unsigned j ) const

rST domain
==========

.. rst:role:: foo

Foo description.
1 change: 1 addition & 0 deletions tests/test_ext_viewcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def test_linkcode(app, status, warning):
assert 'http://foobar/js/' in stuff
assert 'http://foobar/c/' in stuff
assert 'http://foobar/cpp/' in stuff
assert 'http://foobar/rst/' in stuff


@pytest.mark.sphinx(testroot='ext-viewcode-find', freshenv=True)
Expand Down