Skip to content

Commit 157c5b9

Browse files
committed
move docstring injection logic
1 parent 75d2f7f commit 157c5b9

File tree

2 files changed

+81
-22
lines changed

2 files changed

+81
-22
lines changed

python/CMakeLists.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,3 +1019,30 @@ if(PYARROW_BUILD_PARQUET)
10191019
target_link_libraries(_parquet_encryption PRIVATE arrow_python_parquet_encryption)
10201020
endif()
10211021
endif()
1022+
1023+
#
1024+
# Type stubs with docstring injection
1025+
#
1026+
# Install .pyi stub files from pyarrow-stubs/ into the wheel, then run a
1027+
# script that imports the just-built pyarrow to extract runtime docstrings
1028+
# and inject them into the installed stubs.
1029+
set(STUBS_SRC_DIR "${CMAKE_SOURCE_DIR}/pyarrow-stubs/pyarrow")
1030+
if(EXISTS "${STUBS_SRC_DIR}")
1031+
install(DIRECTORY "${STUBS_SRC_DIR}/"
1032+
DESTINATION "."
1033+
FILES_MATCHING
1034+
PATTERN "*.pyi")
1035+
1036+
install(CODE "
1037+
execute_process(
1038+
COMMAND \"${Python3_EXECUTABLE}\"
1039+
\"${CMAKE_SOURCE_DIR}/scripts/update_stub_docstrings.py\"
1040+
\"\${CMAKE_INSTALL_PREFIX}\"
1041+
\"${CMAKE_SOURCE_DIR}\"
1042+
RESULT_VARIABLE _result
1043+
)
1044+
if(NOT _result EQUAL 0)
1045+
message(WARNING \"Stub docstring injection failed (exit code: \${_result})\")
1046+
endif()
1047+
")
1048+
endif()

python/scripts/update_stub_docstrings.py

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@
1818
"""
1919
Extract docstrings from pyarrow runtime and insert them into stub files.
2020
21-
Usage (from python/ directory with pyarrow built):
22-
python scripts/update_stub_docstrings.py pyarrow-stubs
21+
Called from CMakeLists.txt install(CODE ...) after .pyi stubs and .so
22+
extensions have been installed to CMAKE_INSTALL_PREFIX.
23+
24+
Usage:
25+
python scripts/update_stub_docstrings.py <install_prefix> <source_dir>
2326
"""
2427

2528
import argparse
2629
import importlib
2730
import inspect
31+
import os
32+
import shutil
2833
import sys
34+
import sysconfig
35+
import tempfile
2936
from pathlib import Path
3037
from textwrap import indent
3138

@@ -198,31 +205,56 @@ def add_docstrings_to_stubs(stubs_dir):
198205
stub_file.write_text(modified.code)
199206

200207

201-
def add_docstrings_from_build(stubs_dir, build_lib):
208+
def _create_importable_pyarrow(pyarrow_pkg, source_dir, install_prefix):
202209
"""
203-
Entry point for setup.py: update docstrings using pyarrow from build directory.
204-
205-
During the build process, pyarrow is not installed in the system Python.
206-
We need to temporarily add the build directory to sys.path so we can
207-
import pyarrow and extract docstrings from it.
210+
Populate pyarrow_pkg with symlinks to source .py files, compiled
211+
extensions, shared libraries, and subpackages so that pyarrow is
212+
importable from the parent of pyarrow_pkg.
208213
"""
209-
stubs_dir, build_lib = Path(stubs_dir), Path(build_lib)
210-
211-
sys.path.insert(0, str(build_lib))
212-
try:
213-
add_docstrings_to_stubs(stubs_dir)
214-
finally:
215-
sys.path.pop(0)
214+
ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") or ".so"
215+
source_pyarrow = source_dir / "pyarrow"
216+
link = shutil.copy2 if sys.platform == "win32" else os.symlink
217+
218+
for f in source_pyarrow.iterdir():
219+
if f.suffix == ".py":
220+
link(f, pyarrow_pkg / f.name)
221+
elif f.is_dir() and not f.name.startswith((".", "__")):
222+
if sys.platform == "win32":
223+
shutil.copytree(f, pyarrow_pkg / f.name, symlinks=True)
224+
else:
225+
link(f, pyarrow_pkg / f.name)
226+
227+
# Link compiled extensions and shared libraries from the install prefix
228+
for f in install_prefix.iterdir():
229+
dest = pyarrow_pkg / f.name
230+
if dest.exists():
231+
continue
232+
is_extension = ext_suffix in f.name or f.suffix == ".pyd"
233+
is_shared_lib = f.name.startswith("lib") and (
234+
".so" in f.name or f.suffix in (".dylib", ".dll")
235+
)
236+
if is_extension or is_shared_lib:
237+
link(f, dest)
216238

217239

218240
if __name__ == "__main__":
219241
parser = argparse.ArgumentParser(description=__doc__)
220-
parser.add_argument("stubs_dir", type=Path, help="Path to pyarrow-stubs folder")
242+
parser.add_argument("install_prefix", type=Path,
243+
help="CMAKE_INSTALL_PREFIX with built .so and .pyi files")
244+
parser.add_argument("source_dir", type=Path,
245+
help="CMake source directory (python/)")
221246
args = parser.parse_args()
222247

223-
# Add the directory containing this script's parent (python/) to sys.path
224-
# so pyarrow can be imported when running from the python/ directory
225-
script_dir = Path(__file__).resolve().parent
226-
python_dir = script_dir.parent
227-
sys.path.insert(0, str(python_dir))
228-
add_docstrings_to_stubs(args.stubs_dir.resolve())
248+
install_prefix = args.install_prefix.resolve()
249+
source_dir = args.source_dir.resolve()
250+
251+
if not any(install_prefix.glob("*.pyi")):
252+
print("No .pyi files in install prefix, skipping docstring injection")
253+
sys.exit(0)
254+
255+
with tempfile.TemporaryDirectory() as tmpdir:
256+
pyarrow_pkg = Path(tmpdir) / "pyarrow"
257+
pyarrow_pkg.mkdir()
258+
_create_importable_pyarrow(pyarrow_pkg, source_dir, install_prefix)
259+
sys.path.insert(0, tmpdir)
260+
add_docstrings_to_stubs(install_prefix)

0 commit comments

Comments
 (0)