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

Fix #3351: intersphinx does not refers context #3425

Merged
merged 2 commits into from
Apr 23, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Bugs fixed
* C++, properly look up ``any`` references.
* #3624: sphinx.ext.intersphinx couldn't load inventories compressed with gzip
* #3551: PDF information dictionary is lacking author and title data
* #3351: intersphinx does not refers context like ``py:module``, ``py:class``
and so on.

Deprecated
----------
Expand Down
5 changes: 5 additions & 0 deletions sphinx/domains/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,8 @@ def get_type_name(self, type, primary=False):
if primary:
return type.lname
return _('%s %s') % (self.label, type.lname)

def get_full_qualified_name(self, node):
# type: (nodes.Node) -> unicode
"""Return full qualified name for given node."""
return None
10 changes: 10 additions & 0 deletions sphinx/domains/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,16 @@ def get_objects(self):
if type != 'module': # modules are already handled
yield (refname, refname, type, docname, refname, 1)

def get_full_qualified_name(self, node):
# type: (nodes.Node) -> unicode
modname = node.get('py:module')
clsname = node.get('py:class')
target = node.get('reftarget')
if target is None:
return None
else:
return '.'.join(filter(None, [modname, clsname, target]))


def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
Expand Down
8 changes: 8 additions & 0 deletions sphinx/ext/intersphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,21 @@ def missing_reference(app, env, node, contnode):
# until Sphinx-1.6, cmdoptions are stored as std:option
objtypes.append('std:option')
to_try = [(inventories.main_inventory, target)]
if domain:
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
if full_qualified_name:
to_try.append((inventories.main_inventory, full_qualified_name))
in_set = None
if ':' in target:
# first part may be the foreign doc set name
setname, newtarget = target.split(':', 1)
if setname in inventories.named_inventory:
in_set = setname
to_try.append((inventories.named_inventory[setname], newtarget))
if domain:
full_qualified_name = env.get_domain(domain).get_full_qualified_name(node)
if full_qualified_name:
to_try.append((inventories.named_inventory[setname], full_qualified_name))
for inventory, target in to_try:
for objtype in objtypes:
if objtype not in inventory or target not in inventory[objtype]:
Expand Down
34 changes: 32 additions & 2 deletions tests/test_domain_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
"""

import pytest
from mock import Mock
from six import text_type
from docutils import nodes

from sphinx import addnodes
from sphinx.domains.python import py_sig_re, _pseudo_parse_arglist
from sphinx.domains.python import py_sig_re, _pseudo_parse_arglist, PythonDomain

from util import assert_node

Expand All @@ -28,7 +31,6 @@ def parse(sig):


def test_function_signatures():

rv = parse('func(a=1) -> int object')
assert text_type(rv) == u'a=1'

Expand Down Expand Up @@ -165,3 +167,31 @@ def find_obj(modname, prefix, obj_name, obj_type, searchmode=0):
[(u'NestedParentA.NestedChildA.subchild_1', (u'roles', u'method'))])
assert (find_obj(None, u'NestedParentA.NestedChildA', u'subchild_1', u'meth') ==
[(u'NestedParentA.NestedChildA.subchild_1', (u'roles', u'method'))])


def test_get_full_qualified_name():
env = Mock(domaindata={})
domain = PythonDomain(env)

# non-python references
node = nodes.reference()
assert domain.get_full_qualified_name(node) is None

# simple reference
node = nodes.reference(reftarget='func')
assert domain.get_full_qualified_name(node) == 'func'

# with py:module context
kwargs = {'py:module': 'module1'}
node = nodes.reference(reftarget='func', **kwargs)
assert domain.get_full_qualified_name(node) == 'module1.func'

# with py:class context
kwargs = {'py:class': 'Class'}
node = nodes.reference(reftarget='func', **kwargs)
assert domain.get_full_qualified_name(node) == 'Class.func'

# with both py:module and py:class context
kwargs = {'py:module': 'module1', 'py:class': 'Class'}
node = nodes.reference(reftarget='func', **kwargs)
assert domain.get_full_qualified_name(node) == 'module1.Class.func'
12 changes: 12 additions & 0 deletions tests/test_ext_intersphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,18 @@ def reference_check(*args, **kwds):
assert rn is None
assert contnode[0].astext() == 'py3k:unknown'

# no context data
kwargs = {}
node, contnode = fake_node('py', 'func', 'func', 'func()', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
assert rn is None

# context data (like py:module) help to search objects
kwargs = {'py:module': 'module1'}
node, contnode = fake_node('py', 'func', 'func', 'func()', **kwargs)
rn = missing_reference(app, app.env, node, contnode)
assert rn[0].astext() == 'func()'

# check relative paths
rn = reference_check('py', 'mod', 'py3krel:module1', 'foo')
assert rn['refuri'] == 'py3k/foo.html#module-module1'
Expand Down