diff --git a/CHANGES b/CHANGES index 11b3ca5cded..620b95ea725 100644 --- a/CHANGES +++ b/CHANGES @@ -133,6 +133,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. * Fail to load template file if the parent template is archived Deprecated diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 43b6bac041d..4085d5e1392 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -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 diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 7439b297b50..28ea1a08aa8 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -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] diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index 1ef4d1d5178..d018603e2c6 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -292,6 +292,10 @@ 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 @@ -299,6 +303,10 @@ def missing_reference(app, env, node, contnode): 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]: diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 73766e71816..eb8a7a178df 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -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 @@ -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' @@ -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' diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 86e56fd47a8..33f5ceae2c7 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -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'