Skip to content

Commit c4495d0

Browse files
committed
Use _StrPath in sphinx.pycode
1 parent bb6ecbc commit c4495d0

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

sphinx/ext/viewcode.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from sphinx.application import Sphinx
3030
from sphinx.builders import Builder
3131
from sphinx.environment import BuildEnvironment
32+
from sphinx.util._pathlib import _StrPath
3233
from sphinx.util.typing import ExtensionMetadata
3334

3435
logger = logging.getLogger(__name__)
@@ -207,7 +208,7 @@ def remove_viewcode_anchors(self) -> None:
207208
node.parent.remove(node)
208209

209210

210-
def get_module_filename(app: Sphinx, modname: str) -> str | None:
211+
def get_module_filename(app: Sphinx, modname: str) -> _StrPath | None:
211212
"""Get module filename for *modname*."""
212213
source_info = app.emit_firstresult('viewcode-find-source', modname)
213214
if source_info:

sphinx/pycode/__init__.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from __future__ import annotations
44

5-
import os
6-
import os.path
75
import tokenize
86
from importlib import import_module
97
from typing import TYPE_CHECKING, Any, Literal
@@ -13,6 +11,7 @@
1311
from sphinx.util._pathlib import _StrPath
1412

1513
if TYPE_CHECKING:
14+
import os
1615
from inspect import Signature
1716

1817

@@ -28,7 +27,7 @@ class ModuleAnalyzer:
2827
cache: dict[tuple[Literal['file', 'module'], str | _StrPath], Any] = {}
2928

3029
@staticmethod
31-
def get_module_source(modname: str) -> tuple[str | None, str | None]:
30+
def get_module_source(modname: str) -> tuple[_StrPath | None, str | None]:
3231
"""Try to find the source code for a module.
3332
3433
Returns ('filename', 'source'). One of it can be None if
@@ -39,14 +38,15 @@ def get_module_source(modname: str) -> tuple[str | None, str | None]:
3938
except Exception as err:
4039
raise PycodeError('error importing %r' % modname, err) from err
4140
loader = getattr(mod, '__loader__', None)
42-
filename = getattr(mod, '__file__', None)
41+
filename: str | None = getattr(mod, '__file__', None)
4342
if loader and getattr(loader, 'get_source', None):
4443
# prefer Native loader, as it respects #coding directive
4544
try:
4645
source = loader.get_source(modname)
4746
if source:
47+
mod_path = None if filename is None else _StrPath(filename)
4848
# no exception and not None - it must be module source
49-
return filename, source
49+
return mod_path, source
5050
except ImportError:
5151
pass # Try other "source-mining" methods
5252
if filename is None and loader and getattr(loader, 'get_filename', None):
@@ -60,24 +60,28 @@ def get_module_source(modname: str) -> tuple[str | None, str | None]:
6060
if filename is None:
6161
# all methods for getting filename failed, so raise...
6262
raise PycodeError('no source found for module %r' % modname)
63-
filename = os.path.normpath(os.path.abspath(filename))
64-
if filename.lower().endswith(('.pyo', '.pyc')):
65-
filename = filename[:-1]
66-
if not os.path.isfile(filename) and os.path.isfile(filename + 'w'):
67-
filename += 'w'
68-
elif not filename.lower().endswith(('.py', '.pyw')):
69-
raise PycodeError('source is not a .py file: %r' % filename)
70-
71-
if not os.path.isfile(filename):
72-
raise PycodeError('source file is not present: %r' % filename)
73-
return filename, None
63+
mod_path = _StrPath(filename).resolve()
64+
if mod_path.suffix in {'.pyo', '.pyc'}:
65+
mod_path_pyw = mod_path.with_suffix('.pyw')
66+
if not mod_path.is_file() and mod_path_pyw.is_file():
67+
mod_path = mod_path_pyw
68+
else:
69+
mod_path = mod_path.with_suffix('.py')
70+
elif mod_path.suffix not in {'.py', '.pyw'}:
71+
msg = f'source is not a .py file: {mod_path!r}'
72+
raise PycodeError(msg)
73+
74+
if not mod_path.is_file():
75+
msg = f'source file is not present: {mod_path!r}'
76+
raise PycodeError(msg)
77+
return mod_path, None
7478

7579
@classmethod
7680
def for_string(
7781
cls: type[ModuleAnalyzer],
7882
string: str,
7983
modname: str,
80-
srcname: str = '<string>',
84+
srcname: str | os.PathLike[str] = '<string>',
8185
) -> ModuleAnalyzer:
8286
return cls(string, modname, srcname)
8387

0 commit comments

Comments
 (0)