Skip to content
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

[DOC] Use sphinx.ext.linkcode instead of sphinx.ext.viewcode #72

Open
mscheltienne opened this issue Sep 4, 2022 · 0 comments
Open
Labels
📓 doc Improvements or additions to documentation 🌟 enhancement New feature or request

Comments

@mscheltienne
Copy link
Collaborator

mscheltienne commented Sep 4, 2022

I like sphinx.ext.linkcode other sphinx.ext.viewcode because it creates nice links to the function in the source code on GitHub instead of an HTML page with the function code copy/pasted, and because it will work with more objects, e.g. methods!

The downside is that we have to create the function which generates the URL for each object. Here is an example:

import inspect
from importlib import import_nodule


def linkcode_resolve(domain: str, info: Dict[str, str]) -> Optional[str]:
    """Determine the URL corresponding to a Python object.

    Parameters
    ----------
    domain : str
        One of 'py', 'c', 'cpp', 'javascript'.
    info : dict
        With keys "module" and "fullname".

    Returns
    -------
    url : str | None
        The code URL. If None, no link is added.
    """
    if domain != "py":
        return None  # only document python objects

    # retrieve pyobject and file
    try:
        module = import_module(info["module"])
        pyobject = module
        for elt in info["fullname"].split("."):
            pyobject = getattr(pyobject, elt)
        fname = inspect.getsourcefile(pyobject).replace("\\", "/")
    except Exception:
        # Either the object could not be loaded or the file was not found.
        # For instance, properties will raise.
        return None

    # retrieve start/stop lines
    source, start_line = inspect.getsourcelines(pyobject)
    lines = "L%d-L%d" % (start_line, start_line + len(source) - 1)

    # create URL
    if "dev" in release:
        branch = "main"
    else:
        return None  # alternatively, link to a maint/version branch
    fname = fname.split(f"/{package}/")[1]
    url = f"{gh_url}/blob/{branch}/{package}/{fname}#{lines}"
    return URL

As is, it does not work with pycrostates because:

  • the verbose decorator is messing things up. The following code snippet can be used to fix it:
while hasattr(pyobject, '__wrapped__'):
    pyobject = pyobject.__wrapped__
  • some methods are inherited from mne, so we need to figure out if the object is from MNE or pycrostates and build the link accordingly. My best bet is to look at fname. If it's from mne, it will have '/mne/' in the path.
  • splitting the fname (path) at the end to retrieve the relative path to the package folder is not trivial, especially as it has to work on both local build and on readthedocs which has some nasty looking paths ;) What would be super handy is a 'split' from the right function.
@mscheltienne mscheltienne added 📓 doc Improvements or additions to documentation 🌟 enhancement New feature or request labels Sep 30, 2022
@vferat vferat added this to To do in Pycrostates Kanban Apr 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📓 doc Improvements or additions to documentation 🌟 enhancement New feature or request
Projects
Development

No branches or pull requests

1 participant