I can, but I can’t directly fetch that repo from the URL in this environment. If you paste (or upload) the package source (the src/parallel/ directory) or a zip/tar of the repo, I’ll generate a single consolidated parallel.pyi that covers the full public footprint and copies docstrings 1:1.
Meanwhile, here’s the exact approach I’ll use, and a ready-to-run script you can run locally to generate the single-file .pyi automatically from that repo—then you can send me the generated .pyi for review/tweaks if you want.
python -m pip install "mypy>=1.8" "stubgenj>=0.2" || truestubgen comes with mypy; stubgenj is optional (ignore if it fails). If stubgenj fails, that’s fine.
From the repo root (where src/parallel exists):
python -m mypy.stubgen -p parallel -o _stubs_out --include-docstringsThis produces _stubs_out/parallel/**/*.pyi.
Save as combine_stubs.py:
from __future__ import annotations
import os
import re
from pathlib import Path
ROOT = Path("_stubs_out") / "parallel"
OUT = Path("parallel.pyi")
def iter_pyi_files(root: Path) -> list[Path]:
files = []
for p in root.rglob("*.pyi"):
# ignore private caches etc.
if "__pycache__" in p.parts:
continue
files.append(p)
# deterministic order: package __init__ first, then modules by path
files.sort(key=lambda p: (0 if p.name == "__init__.pyi" else 1, str(p)))
return files
def strip_future_imports(text: str) -> str:
# Keep only one future import at top-level later
text = re.sub(r"^from __future__ import .*\n", "", text, flags=re.MULTILINE)
return text
def normalize_relative_imports(text: str, module_qualname: str) -> str:
"""
In a single-file stub, relative imports are meaningless.
Replace simple relative imports with absolute where possible,
otherwise leave a comment.
"""
lines = []
for line in text.splitlines(True):
m = re.match(r"^\s*from\s+(\.+)([\w\.]*)\s+import\s+(.*)$", line)
if not m:
lines.append(line)
continue
dots, tail, rest = m.group(1), m.group(2), m.group(3)
# Compute absolute module prefix based on dots count
parts = module_qualname.split(".")
up = len(dots)
if up > len(parts):
lines.append(f"# [unresolved relative import in {module_qualname}]: {line}")
continue
base = parts[:-up]
abs_mod = ".".join(["parallel", *base[1:], tail] if base and base[0] == "parallel" else [*base, tail])
abs_mod = abs_mod.strip(".")
if not abs_mod:
lines.append(f"# [unresolved relative import in {module_qualname}]: {line}")
else:
lines.append(f"from {abs_mod} import {rest}\n")
return "".join(lines)
def qualify_module(path: Path) -> str:
rel = path.relative_to(ROOT)
if rel.name == "__init__.pyi":
mod_parts = rel.parent.parts
else:
mod_parts = (*rel.parent.parts, rel.stem)
return ".".join(("parallel", *mod_parts)) if mod_parts else "parallel"
def main() -> None:
files = iter_pyi_files(ROOT)
out_parts: list[str] = []
out_parts.append("# This file is auto-generated by combine_stubs.py\n")
out_parts.append("from __future__ import annotations\n\n")
for p in files:
mod = qualify_module(p)
text = p.read_text(encoding="utf-8")
text = strip_future_imports(text)
text = normalize_relative_imports(text, mod)
out_parts.append("\n")
out_parts.append("#" * 88 + "\n")
out_parts.append(f"# Module: {mod} (source: {p.as_posix()})\n")
out_parts.append("#" * 88 + "\n")
out_parts.append(text.rstrip() + "\n")
OUT.write_text("".join(out_parts), encoding="utf-8")
print(f"Wrote {OUT} ({OUT.stat().st_size} bytes)")
if __name__ == "__main__":
main()Run:
python combine_stubs.pyYou’ll get a single parallel.pyi.
Upload either:
- a zip of the repo, or
- just
src/parallel/**.py(and anypy.typed, etc.)
Then I’ll produce:
parallel.pyi(single file, consolidated)- notes about any dynamically-defined exports that can’t be perfectly inferred
- verification that docstrings were copied 1:1 (when present / extractable)
- Do you want only public API (what’s re-exported from
parallel/__init__.py), or everything undersrc/parallelincluding internal modules? - Should the single
.pyipreserve module boundaries as commented sections (as in the script), or should it flatten everything into one namespace?
Send the source (or the generated stub), answer those two questions, and I’ll return the final single .pyi.