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

WARNING: py:class reference target not found: gi.repository... #124

Open
ssokolow opened this issue Jan 18, 2020 · 5 comments
Open

WARNING: py:class reference target not found: gi.repository... #124

ssokolow opened this issue Jan 18, 2020 · 5 comments

Comments

@ssokolow
Copy link

ssokolow commented Jan 18, 2020

While trying to get an old codebase switched over to Sphinx, I ran into a confusing problem where my Gtk.thing references were resolving but my Wnck.thing references were not, when both were set up for intersphinx equally well and both had their objects.inv generated by the same generator.

I finally tracked the problem down to referencing Gtk manually with :func: or :class: or what have you, but referencing Wnck through type annotations.

The problem being that sphinx-autodoc-typehints is trying and failing to find gi.repository.Wnck.Window in objects.inv while objects.inv contains Wnck.Window, and then producing un-linked documentation that lists the type as Window (Also not ideal. Is it Wnck.Window, Gtk.Window, Gdk.Window, or perhaps a custom class of my own?) and displaying this warning if nitpicky is set:

docstring of quicktile.commands.workspace_send_window:13: WARNING: py:class reference target not found: gi.repository.Wnck.Window

If you don't have a better idea, I'd suggest a conf.py variable something like this:

intersphinx_mapping = {
    # ...
    'wnck': ('http://lazka.github.io/pgi-docs/Wnck-3.0', None),
}

typehints_ignore_prefix = {
    'wnck': 'gi.repository.'
}

(Taking inspiration from how modindex_common_prefix works.)

For now, I've taken to doing this in my docstrings:

    :param win: The :class:`Wnck.Window` to operate on.
@agronholm
Copy link
Collaborator

Where does gi.repository. come from then?

@ssokolow
Copy link
Author

ssokolow commented Jan 19, 2020

The gi.repository. is an implementation detail for an FFI loader for libraries that expose GObject Introspection interface definitions. (GObject Introspection, or GIR, is an IDL that the GNOME people developed for use by C libraries based on the GLib object system.)

It's used as follows:

import gi
gi.require_version('Gtk', '3.0')

from gi.repository import Gtk

(The gi.require_version is technically optional, but it'll yell at you if you don't pin a version before importing.)

"Gtk" can be anything that has a corresponding file in /usr/lib/x86_64-linux-gnu/girepository-1.0/

Here's the documentation site in question. According to the FAQ, it provides auto-generated API documentation for all libraries with GIR interface definitions available from the Debian Linux testing/unstable package repositories. (260 of them, if my count is correct.)

https://lazka.github.io/pgi-docs/

In theory, because the docs aren't prefixed with gi.repository., they should also be useful for Sphinx-documenting the relevant APIs as seen by other languages with a GIR binding.

(It's my understanding that the handful of gi.overrides. I ran into are the Python-specific adjustments.)

Also, since I also ran into some #38 trouble, I wound up using this solution instead:

# Nitpick every broken reference except ones I whitelist because they *have*
# no intersphinx-compatible documentation.
#
# TODO: Investigate how much work it would be to contribute intersphinx
#       generation to python-xlib's documentation pipeline.
nitpicky = True
nitpick_ignore = [
    ('py:class', 'inspect.FrameInfo'),
    ('py:class', 'tokenize.TokenInfo'),
    ('py:class', 'Xlib.display.Display'),
    ('py:meth', 'Xlib.display.Display.create_resource_object'),
    ('py:meth', 'Xlib.display.Display.keycode_to_keysym'),
    ('py:meth', 'Xlib.display.Display.sync'),
    ('py:class', 'Xlib.error.CatchError'),
    ('py:class', 'Xlib.error.XError'),
    ('py:class', 'Xlib.protocol.event.KeyPress'),
    ('py:mod', 'Xlib.Xatom'),
    ('rst:dir', '.. todo::')
]

# -- Hack to work around sphinx-autodoc-typehints#124 and #38
import inspect, sphinx_autodoc_typehints

qualname_ignored_prefixes = [
    'gi.repository.',
    'gi.overrides.'
]

qualname_overrides = {
    'builtins.frame': ('data', 'types.FrameType'),
    'builtins.traceback': ('class', 'types.TracebackType'),
    'dbus._dbus.SessionBus': ('class', 'dbus.SessionBus'),
    '_io.StringIO': ('class', 'io.StringIO'),
}
fa_orig = sphinx_autodoc_typehints.format_annotation

def format_annotation(annotation, *args, **kwargs):
    if inspect.isclass(annotation):
        full_name = '{}.{}'.format(
            annotation.__module__, annotation.__qualname__)
        for prefix in qualname_ignored_prefixes:
            if full_name.startswith(prefix):
                return ':py:class:`' + full_name[len(prefix):] + '`'
        override = qualname_overrides.get(full_name)
        if override is not None:
            return ':py:{}:`~{}`'.format(*override)
    return fa_orig(annotation, *args, **kwargs)
sphinx_autodoc_typehints.format_annotation = format_annotation

intersphinx_mapping = {
    'cairo': ('https://pycairo.readthedocs.io/en/latest/', None),
    'dbus': ('https://dbus.freedesktop.org/doc/dbus-python/', None),
    'gtk': ('https://lazka.github.io/pgi-docs/Gtk-3.0', None),
    'gdk': ('https://lazka.github.io/pgi-docs/Gdk-3.0', None),
    'gdkx11': ('https://lazka.github.io/pgi-docs/GdkX11-3.0', None),
    'glib': ('https://lazka.github.io/pgi-docs/GLib-2.0', None),
    'python': ('https://docs.python.org/3/', None),
    'wnck': ('https://lazka.github.io/pgi-docs/Wnck-3.0', None),
}

@agronholm
Copy link
Collaborator

Perhaps a mapping could be provided by the user. This isn't the first such case I've seen.

@ssokolow
Copy link
Author

I'd have to see exactly what you have in mind to have a proper opinion but I agree in theory.

@gaborbernat
Copy link
Member

A PR for this would be welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants