make_pyi.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. """The pyi generator module."""
  2. import logging
  3. import subprocess
  4. import sys
  5. from pathlib import Path
  6. from reflex.utils.pyi_generator import PyiGenerator, _relative_to_pwd
  7. logger = logging.getLogger("pyi_generator")
  8. LAST_RUN_COMMIT_SHA_FILE = Path(".pyi_generator_last_run").resolve()
  9. GENERATOR_FILE = Path(__file__).resolve()
  10. GENERATOR_DIFF_FILE = Path(".pyi_generator_diff").resolve()
  11. DEFAULT_TARGETS = ["reflex/components", "reflex/__init__.py"]
  12. def _git_diff(args: list[str]) -> str:
  13. """Run a git diff command.
  14. Args:
  15. args: The args to pass to git diff.
  16. Returns:
  17. The output of the git diff command.
  18. """
  19. cmd = ["git", "diff", "--no-color", *args]
  20. return subprocess.run(cmd, capture_output=True, encoding="utf-8").stdout
  21. def _git_changed_files(args: list[str] | None = None) -> list[Path]:
  22. """Get the list of changed files for a git diff command.
  23. Args:
  24. args: The args to pass to git diff.
  25. Returns:
  26. The list of changed files.
  27. """
  28. if not args:
  29. args = []
  30. if "--name-only" not in args:
  31. args.insert(0, "--name-only")
  32. diff = _git_diff(args).splitlines()
  33. return [Path(file.strip()) for file in diff]
  34. def _get_changed_files() -> list[Path] | None:
  35. """Get the list of changed files since the last run of the generator.
  36. Returns:
  37. The list of changed files, or None if all files should be regenerated.
  38. """
  39. try:
  40. last_run_commit_sha = LAST_RUN_COMMIT_SHA_FILE.read_text().strip()
  41. except FileNotFoundError:
  42. logger.info(
  43. "make_pyi.py last run could not be determined, regenerating all .pyi files"
  44. )
  45. return None
  46. changed_files = _git_changed_files([f"{last_run_commit_sha}..HEAD"])
  47. # get all unstaged changes
  48. changed_files.extend(_git_changed_files())
  49. if _relative_to_pwd(GENERATOR_FILE) not in changed_files:
  50. return changed_files
  51. logger.info("make_pyi.py has changed, checking diff now")
  52. diff = "".join(_git_diff([GENERATOR_FILE.as_posix()]).splitlines()[2:])
  53. try:
  54. last_diff = GENERATOR_DIFF_FILE.read_text()
  55. if diff != last_diff:
  56. logger.info("make_pyi.py has changed, regenerating all .pyi files")
  57. changed_files = None
  58. else:
  59. logger.info("make_pyi.py has not changed, only regenerating changed files")
  60. except FileNotFoundError:
  61. logger.info(
  62. "make_pyi.py diff could not be determined, regenerating all .pyi files"
  63. )
  64. changed_files = None
  65. GENERATOR_DIFF_FILE.write_text(diff)
  66. return changed_files
  67. if __name__ == "__main__":
  68. logging.basicConfig(level=logging.DEBUG)
  69. logging.getLogger("blib2to3.pgen2.driver").setLevel(logging.INFO)
  70. targets = (
  71. [arg for arg in sys.argv[1:] if not arg.startswith("tests")]
  72. if len(sys.argv) > 1
  73. else DEFAULT_TARGETS
  74. )
  75. # Only include targets that have a prefix in the default target list
  76. targets = [
  77. target
  78. for target in targets
  79. if any(str(target).startswith(prefix) for prefix in DEFAULT_TARGETS)
  80. ]
  81. logger.info(f"Running .pyi generator for {targets}")
  82. changed_files = _get_changed_files()
  83. if changed_files is None:
  84. logger.info("Changed files could not be detected, regenerating all .pyi files")
  85. else:
  86. logger.info(f"Detected changed files: {changed_files}")
  87. gen = PyiGenerator()
  88. gen.scan_all(targets, changed_files)
  89. current_commit_sha = subprocess.run(
  90. ["git", "rev-parse", "HEAD"], capture_output=True, encoding="utf-8"
  91. ).stdout.strip()
  92. LAST_RUN_COMMIT_SHA_FILE.write_text(current_commit_sha)