Skip to content

Commit b338f98

Browse files
authored
fix: Fix stubgen to order members properly (#45)
* fix: fix stubgen * update stubs
1 parent ea7571f commit b338f98

File tree

5 files changed

+483
-456
lines changed

5 files changed

+483
-456
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,3 @@ __pycache__
1515
.coverage
1616
coverage/
1717
coverage*
18-
site

meson.build

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ version : '11.3.0.71.1',
1010
py = import('python').find_installation(pure: false)
1111
nanobind_dep = dependency('nanobind', static: true)
1212

13+
# patch nanobind stubgen until https://github.com/wjakob/nanobind/pull/938
14+
_ = run_command(py.full_path(), 'scripts/patch_nanobind.py').stdout().strip()
15+
1316
# Run a command to get the Python include path
1417
python_include_path = run_command(
1518
py.full_path(), ['-c', 'import sysconfig; print(sysconfig.get_paths()["include"])']

scripts/build_stubs.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,24 @@ def build_stub(module_path: Path, output_path: str):
4848
ruff = Path(sys.executable).parent / "ruff"
4949
_ruff = str(ruff) if ruff.exists() else "ruff"
5050
subprocess.run([_ruff, "format", output_path], check=True)
51-
subprocess.run([_ruff, "check", "--fix-only", output_path])
51+
subprocess.run(
52+
[
53+
_ruff,
54+
"check",
55+
"--fix-only",
56+
"--unsafe-fixes",
57+
"--ignore=D",
58+
output_path,
59+
]
60+
)
5261

5362

5463
if __name__ == "__main__":
5564
if len(sys.argv) > 1:
5665
module_path = Path(sys.argv[1])
5766
else:
58-
build_dir = Path(__file__).parent.parent / "build"
59-
try:
60-
pydir = next(build_dir.glob("cp*"))
61-
except StopIteration:
62-
raise RuntimeError(
63-
"Project must be built before you can build stubs.\nRun `just install`."
64-
)
65-
module_path = next(x for x in pydir.glob("_pymmcore_nano.*") if x.is_file())
67+
build_dir = Path(__file__).parent.parent / "builddir"
68+
module_path = next(x for x in build_dir.glob("_pymmcore_nano.*") if x.is_file())
6669

6770
if len(sys.argv) > 2:
6871
output = Path(sys.argv[2])

scripts/patch_nanobind.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""Apply https://github.com/wjakob/nanobind/pull/938"""
2+
3+
import re
4+
from pathlib import Path
5+
import nanobind.stubgen
6+
7+
PATTERN = re.compile(r"^(\s*)(for name, child in getmembers\(value\):)", re.MULTILINE)
8+
9+
10+
def replace_getmembers_in_file(path: str) -> None:
11+
"""Replaces 'for name, child in getmembers(value):' with the desired sorted version in a file."""
12+
file_path = Path(path)
13+
content = file_path.read_text()
14+
if "sorted(getmembers(value)" in content:
15+
return
16+
17+
def replacement(match: re.Match) -> str:
18+
indent = match.group(1)
19+
return (
20+
f"{indent}order_map = {{name: index for index, name in enumerate(value.__dict__.keys())}}\n"
21+
f"{indent}for name, child in sorted(getmembers(value), key=lambda i: order_map.get(i[0], float('inf'))):"
22+
)
23+
24+
modified_content = PATTERN.sub(replacement, content)
25+
file_path.write_text(modified_content)
26+
27+
28+
replace_getmembers_in_file(nanobind.stubgen.__file__)

0 commit comments

Comments
 (0)