diff --git a/.github/workflows/pyrefly.yml b/.github/workflows/pyrefly.yml index 08206e171..a5ccf3c95 100644 --- a/.github/workflows/pyrefly.yml +++ b/.github/workflows/pyrefly.yml @@ -39,6 +39,9 @@ jobs: with: toolchain: nightly-2025-08-01 components: clippy, rustfmt + # to generate stub doc + - name: Install uv + uses: astral-sh/setup-uv@v6 - run: cargo fmt -- --check - run: cargo clippy --release - run: cargo build --release diff --git a/crates/pyrefly_bundled/build.rs b/crates/pyrefly_bundled/build.rs index c8efd0af0..8b3d791c6 100644 --- a/crates/pyrefly_bundled/build.rs +++ b/crates/pyrefly_bundled/build.rs @@ -9,6 +9,7 @@ use std::env; use std::fs::File; use std::path::Path; use std::path::PathBuf; +use std::process::Command; fn get_input_path() -> PathBuf { match env::var_os("TYPESHED_ROOT") { @@ -18,7 +19,7 @@ fn get_input_path() -> PathBuf { } None => { // When building with Cargo, we could locate typeshed directly using relative dir - PathBuf::from("third_party/typeshed") + PathBuf::from("third_party/docstubs") } } } @@ -40,6 +41,15 @@ fn main() -> Result<(), std::io::Error> { // changes in the entire typeshed dir. println!("cargo::rerun-if-changed=third_party/typeshed_metadata.json"); + println!("cargo::rerun-if-changed=crates/pyrefly_bundled/generate_docstubs.py"); + + let status = Command::new("uv") + .args(["run", "generate_docstubs.py"]) + .status() + .expect("failed to invoke uv"); + + assert!(status.success(), "`uv run …` returned non-zero"); + let input_path = get_input_path(); let output_path = get_output_path().unwrap(); let output_file = File::create(output_path)?; diff --git a/crates/pyrefly_bundled/generate_docstubs.py b/crates/pyrefly_bundled/generate_docstubs.py new file mode 100644 index 000000000..851261161 --- /dev/null +++ b/crates/pyrefly_bundled/generate_docstubs.py @@ -0,0 +1,42 @@ +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "docify", +# ] +# /// + +from __future__ import annotations + +from pathlib import Path +from shutil import copytree, rmtree + +from docify import main as docify # type: ignore + + +def main(*, overwrite: bool): + """ + adds docstrings to the stubs located in `../stubdocs` for any modules that are compiled, + because otherwise pyrefly would have no way to see the docstrings because there's no source + code. + + note that it only generates stubs for modules and objects that exist on your current python + version and OS. + + :param overwrite: + whether to overwrite existing generated docstubs if they already exist. should be `True` + when running locally to avoid running with a potentially outdated version of typeshed, but + `False` in CI when generating them for all platforms because it needs to run multiple times + on the previously generated output + """ + stubs_path = Path(__file__).parent / "third_party/typeshed" + stubs_with_docs_path = Path(__file__).parent / "third_party/docstubs" + if overwrite: + if stubs_with_docs_path.exists(): + rmtree(stubs_with_docs_path) + copytree(stubs_path, stubs_with_docs_path, dirs_exist_ok=False) + elif not stubs_with_docs_path.exists(): + copytree(stubs_path, stubs_with_docs_path, dirs_exist_ok=True) + docify([str(stubs_with_docs_path / "stdlib"), "--if-needed", "--in-place"]) + +if __name__ == "__main__": + main(overwrite=False)