Skip to content

Commit

Permalink
improve pyi file import (#732)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhils committed Aug 27, 2024
1 parent da0c1cd commit 2544fdd
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 74 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Fix a bug where entire modules would be excluded by `--no-include-undocumented`.
To exclude modules, see https://pdoc.dev/docs/pdoc.html#exclude-submodules-from-being-documented.
([#728](https://github.com/mitmproxy/pdoc/pull/728), @mhils)
- Fix a bug where pdoc would crash when importing pyi files.
([#732](https://github.com/mitmproxy/pdoc/pull/732), @mhils)
- Fix a bug where subclasses of TypedDict subclasses would not render correctly.
([#729](https://github.com/mitmproxy/pdoc/pull/729), @mhils)

Expand Down
28 changes: 22 additions & 6 deletions pdoc/doc_pyi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from __future__ import annotations

import importlib.util
from pathlib import Path
import sys
import traceback
Expand Down Expand Up @@ -45,13 +46,28 @@ def find_stub_file(module_name: str) -> Path | None:


def _import_stub_file(module_name: str, stub_file: Path) -> types.ModuleType:
"""Import the type stub outside of the normal import machinery."""
code = compile(stub_file.read_text(), str(stub_file), "exec")
m = types.ModuleType(module_name)
m.__file__ = str(stub_file)
eval(code, m.__dict__, m.__dict__)
"""
Import the type stub outside of the normal import machinery.
return m
Note that currently, for objects imported by the stub file, the _original_ module
is used and not the corresponding stub file.
"""
sys.path_hooks.append(
importlib.machinery.FileFinder.path_hook(
(importlib.machinery.SourceFileLoader, [".pyi"])
)
)
try:
loader = importlib.machinery.SourceFileLoader(module_name, str(stub_file))
spec = importlib.util.spec_from_file_location(
module_name, stub_file, loader=loader
)
assert spec is not None
m = importlib.util.module_from_spec(spec)
loader.exec_module(m)
return m
finally:
sys.path_hooks.pop()


def _prepare_module(ns: doc.Namespace) -> None:
Expand Down
2 changes: 1 addition & 1 deletion test/test_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def outfile(self, format: str) -> Path:
Snapshot("pyo3_sample_library", specs=["pdoc_pyo3_sample_library"]),
Snapshot("top_level_reimports", ["top_level_reimports"]),
Snapshot("type_checking_imports", ["type_checking_imports.main"]),
Snapshot("type_stub", min_version=(3, 10)),
Snapshot("type_stubs", ["type_stubs"], min_version=(3, 10)),
Snapshot(
"visibility",
render_options={
Expand Down
171 changes: 104 additions & 67 deletions test/testdata/type_stub.html → test/testdata/type_stubs.html

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions test/testdata/type_stubs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<module type_stubs # This module has an a…
<function def func(x: str, y: Any, z: Iterable[str]) -> int: ... # A simple function.>
<var var: list[str] = [] # Docstring override f…>
<class type_stubs.Class
<method def __init__(): ...>
<var attr: int = 42 # An attribute>
<method def meth(self, y: bool) -> bool: ... # A simple method.>
<class type_stubs.Class.Subclass
<method def __init__(): ...>
<var attr: str = '42' # An attribute>
<method def meth(self, y: bool) -> bool: ... # A simple method.>
>
<method def no_type_annotation(self, z): ... # A method not present…>
<method def overloaded(*args, **kwds): ... # An overloaded method…>
>
<class type_stubs.ImportedClass # inherited from type_stubs._utils.ImportedClass, Docstring from impor…
<method def __init__(): ... # inherited from type_stubs._utils.ImportedClass.__init__>
>
>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
This module has an accompanying .pyi file with type stubs.
"""

from ._utils import ImportedClass


def func(x, y):
"""A simple function."""
Expand Down Expand Up @@ -30,3 +32,11 @@ def no_type_annotation(self, z):

def overloaded(self, x):
"""An overloaded method."""


__all__ = [
"func",
"var",
"Class",
"ImportedClass",
]
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ from typing import Any
from typing import Iterable
from typing import overload

from ._utils import ImportedClass

def func(x: str, y: Any, z: "Iterable[str]") -> int: ...

var: list[str]
Expand All @@ -21,3 +23,10 @@ class Class:
def overloaded(self, x: int) -> int: ...
@overload
def overloaded(self, x: str) -> str: ...

__all__ = [
"func",
"var",
"Class",
"ImportedClass",
]
2 changes: 2 additions & 0 deletions test/testdata/type_stubs/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ImportedClass:
"""Docstring from imported py file - ideally this should be overridden."""
2 changes: 2 additions & 0 deletions test/testdata/type_stubs/_utils.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ImportedClass:
"""Docstring from imported pyi file"""

0 comments on commit 2544fdd

Please sign in to comment.