Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8bcf410
Improve module path finder
ProGamerGov Dec 26, 2024
b332cf7
Add tests
ProGamerGov Dec 26, 2024
f6cf7df
add test
ProGamerGov Dec 26, 2024
b926d82
Fix try except issue
ProGamerGov Dec 26, 2024
67c732d
Fix linting errors
ProGamerGov Dec 26, 2024
bf614af
Fix lint
ProGamerGov Dec 26, 2024
bcaec12
remove old NOQA
ProGamerGov Dec 26, 2024
487d4ae
Remove NOQA
ProGamerGov Dec 26, 2024
4f2e401
change test name
ProGamerGov Dec 26, 2024
2b998c3
fix test lint
ProGamerGov Dec 26, 2024
0ae96b1
fix lint quotation marks
ProGamerGov Dec 26, 2024
6e3cfcb
Update authors & changes files
ProGamerGov Dec 26, 2024
dafd181
Merge branch 'master' into master-attempt-2
ProGamerGov Jan 4, 2025
dc4ec10
Fix lint errors
ProGamerGov Jan 5, 2025
761d253
Merge branch 'master' into master-attempt-2
ProGamerGov Jan 5, 2025
8c98620
Update viewcode.py
ProGamerGov Jan 5, 2025
fd52bc1
Update viewcode.py
ProGamerGov Jan 5, 2025
abbadbb
Fix remaining lint issues
ProGamerGov Jan 5, 2025
e91eb2e
fix mistake
ProGamerGov Jan 5, 2025
768145c
Merge branch 'master' into master-attempt-2
ProGamerGov Jan 5, 2025
bcbccd1
fix remaining lint errors
ProGamerGov Jan 5, 2025
49ff6f0
Merge branch 'master-attempt-2' of https://github.com/ProGamerGov/sph…
ProGamerGov Jan 5, 2025
965cc26
fix classes
ProGamerGov Jan 5, 2025
6fa7a43
replace __import__ with find_spec
ProGamerGov Jan 5, 2025
adca233
Merge branch 'master' into master-attempt-2
ProGamerGov Jan 5, 2025
87f01b1
Fix lint errors
ProGamerGov Jan 5, 2025
214ab7b
Merge branch 'master' into master-attempt-2
AA-Turner Jan 5, 2025
a3ff8cb
format
AA-Turner Jan 5, 2025
e06b219
early return
AA-Turner Jan 5, 2025
a7d3d1c
deduplicate
AA-Turner Jan 5, 2025
7e5dc56
Use non-deprecated exec_module
AA-Turner Jan 5, 2025
6849c71
Use module.__name__ instead of parsing the module repr
AA-Turner Jan 5, 2025
eada6e7
module is import_module(module.__name__)
AA-Turner Jan 5, 2025
60f7529
style
AA-Turner Jan 5, 2025
6e435dd
absolute imports
AA-Turner Jan 5, 2025
9dfde4b
unify with the 'import_module' approach
AA-Turner Jan 5, 2025
6ba6460
Credit
AA-Turner Jan 5, 2025
69766d1
remove unused import
AA-Turner Jan 5, 2025
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: 1 addition & 1 deletion AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Contributors
* Antonio Valentino -- qthelp builder, docstring inheritance
* Antti Kaihola -- doctest extension (skipif option)
* Barry Warsaw -- setup command improvements
* Ben Egan -- Napoleon improvements
* Ben Egan -- Napoleon improvements & Viewcode improvements
* Benjamin Peterson -- unittests
* Blaise Laflamme -- pyramid theme
* Brecht Machiels -- builder entry-points
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Bugs fixed
* LaTeX: fix a ``7.4.0`` typo in a default for ``\sphinxboxsetup``
(refs: PR #13152).
Patch by Jean-François B.
* #13195: viewcode: Fix issue where import paths differ from the directory
structure.
* #13096: HTML Search: check that query terms exist as properties in
term indices before accessing them.

Expand Down
47 changes: 34 additions & 13 deletions sphinx/ext/viewcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,41 @@

def _get_full_modname(modname: str, attribute: str) -> str | None:
try:
if modname is None:
# Prevents a TypeError: if the last getattr() call will return None
# then it's better to return it directly
return None
module = import_module(modname)

# Allow an attribute to have multiple parts and incidentally allow
# repeated .s in the attribute.
value = module
for attr in attribute.split('.'):
if attr:
value = getattr(value, attr)
try:
if modname is None:
# Prevents a TypeError: if the last getattr() call will return None
# then it's better to return it directly
return None
module = import_module(modname)

# Allow an attribute to have multiple parts and incidentally allow
# repeated .s in the attribute.
value = module
for attr in attribute.split("."):

Check failure on line 62 in sphinx/ext/viewcode.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

sphinx/ext/viewcode.py:62:41: Q000 Double quotes found but single quotes preferred
if attr:
value = getattr(value, attr)

return getattr(value, "__module__", None)

Check failure on line 66 in sphinx/ext/viewcode.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

sphinx/ext/viewcode.py:66:35: Q000 Double quotes found but single quotes preferred
except ModuleNotFoundError:
# Attempt to find full path of module
module_path = modname.split(".")

Check failure on line 69 in sphinx/ext/viewcode.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

sphinx/ext/viewcode.py:69:41: Q000 Double quotes found but single quotes preferred
actual_path = __import__(module_path[0], globals(), locals(), [], 0)
if len(module_path) > 1:
for mod in module_path[1:]:
actual_path = getattr(actual_path, mod)

# Extract path from module name
actual_path_str = str(actual_path).split("'")[1]

# Load module with exact path
module = import_module(actual_path_str)
value = module
for attr in attribute.split("."):

Check failure on line 81 in sphinx/ext/viewcode.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

sphinx/ext/viewcode.py:81:41: Q000 Double quotes found but single quotes preferred
if attr:
value = getattr(value, attr)

return getattr(value, "__module__", None)

Check failure on line 85 in sphinx/ext/viewcode.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

sphinx/ext/viewcode.py:85:35: Q000 Double quotes found but single quotes preferred

return getattr(value, '__module__', None)
except AttributeError:
# sphinx.ext.viewcode can't follow class instance attribute
# then AttributeError logging output only debug mode.
Expand Down
24 changes: 24 additions & 0 deletions tests/roots/test-ext-viewcode-find-package/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import os
import sys

source_dir = os.path.abspath('.')
if source_dir not in sys.path:
sys.path.insert(0, source_dir)
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
exclude_patterns = ['_build']


if 'test_linkcode' in tags:

Check failure on line 11 in tests/roots/test-ext-viewcode-find-package/conf.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F821)

tests/roots/test-ext-viewcode-find-package/conf.py:11:23: F821 Undefined name `tags`
extensions.remove('sphinx.ext.viewcode')
extensions.append('sphinx.ext.linkcode')

def linkcode_resolve(domain, info):
if domain == 'py':
fn = info['module'].replace('.', '/')
return "http://foobar/source/%s.py" % fn

Check failure on line 18 in tests/roots/test-ext-viewcode-find-package/conf.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

tests/roots/test-ext-viewcode-find-package/conf.py:18:20: Q000 Double quotes found but single quotes preferred
elif domain == "js":

Check failure on line 19 in tests/roots/test-ext-viewcode-find-package/conf.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

tests/roots/test-ext-viewcode-find-package/conf.py:19:24: Q000 Double quotes found but single quotes preferred
return "http://foobar/js/" + info['fullname']

Check failure on line 20 in tests/roots/test-ext-viewcode-find-package/conf.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (Q000)

tests/roots/test-ext-viewcode-find-package/conf.py:20:20: Q000 Double quotes found but single quotes preferred
elif domain in ("c", "cpp"):

Check failure on line 21 in tests/roots/test-ext-viewcode-find-package/conf.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PLR6201)

tests/roots/test-ext-viewcode-find-package/conf.py:21:24: PLR6201 Use a set literal when testing for membership
return "http://foobar/%s/%s" % (domain, "".join(info['names']))
else:
raise AssertionError()
10 changes: 10 additions & 0 deletions tests/roots/test-ext-viewcode-find-package/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
viewcode
========

.. currentmodule:: main_package.subpackage.submodule

.. autofunction:: func1

.. autoclass:: Class1

.. autoclass:: Class3
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import main_package.subpackage as subpackage
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from main_package.subpackage._subpackage2 import submodule

__all__ = ["submodule"]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
submodule
"""
# raise RuntimeError('This module should not get imported')


def decorator(f):
return f


@decorator
def func1(a, b):
"""
this is func1
"""
return a, b


@decorator
class Class1(object):
"""
this is Class1
"""


class Class3(object):
"""
this is Class3
"""
class_attr = 42
"""this is the class attribute class_attr"""
24 changes: 24 additions & 0 deletions tests/test_extensions/test_ext_viewcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,27 @@ def find_source(app, modname):
'This is the class attribute class_attr',
):
assert result.count(needle) == 1


@pytest.mark.sphinx('html', testroot='ext-viewcode-find-package', freshenv=True)
def test_find_local_package_import_path(app, status, warning):
app.builder.build_all()
result = (app.outdir / 'index.html').read_text(encoding='utf8')
assert (
result.count(
'href="_modules/main_package/subpackage/_subpackage2/submodule.html#func1"'
)
== 1
)
assert (
result.count(
'href="_modules/main_package/subpackage/_subpackage2/submodule.html#Class1"'
)
== 1
)
assert (
result.count(
'href="_modules/main_package/subpackage/_subpackage2/submodule.html#Class3"'
)
== 1
)
Loading