hatch_build.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. """Custom build hook for Hatch."""
  2. import importlib.util
  3. import pathlib
  4. import subprocess
  5. import sys
  6. from typing import Any
  7. from hatchling.builders.hooks.plugin.interface import BuildHookInterface
  8. class CustomBuilder(BuildHookInterface):
  9. """Custom build hook for Hatch."""
  10. PLUGIN_NAME = "custom"
  11. def marker(self) -> pathlib.Path:
  12. """Get the marker file path.
  13. Returns:
  14. The marker file path.
  15. """
  16. return (
  17. pathlib.Path(self.directory)
  18. / f".reflex-{self.metadata.version}.pyi_generated"
  19. )
  20. def finalize(
  21. self, version: str, build_data: dict[str, Any], artifact_path: str
  22. ) -> None:
  23. """Finalize the build process.
  24. Args:
  25. version: The version of the package.
  26. build_data: The build data.
  27. artifact_path: The path to the artifact.
  28. Raises:
  29. RuntimeError: If the pre-commit patches are not applied correctly.
  30. """
  31. if self.marker().exists():
  32. return
  33. if importlib.util.find_spec("pre_commit"):
  34. import pre_commit.constants
  35. import pre_commit.yaml
  36. patches = [
  37. (
  38. pre_commit.constants.__file__,
  39. """from __future__ import annotations
  40. import importlib.metadata
  41. CONFIG_FILE = '.pre-commit-config.yaml'
  42. MANIFEST_FILE = '.pre-commit-hooks.yaml'
  43. # Bump when modifying `empty_template`
  44. LOCAL_REPO_VERSION = '1'
  45. VERSION = importlib.metadata.version('pre_commit')
  46. DEFAULT = 'default'""",
  47. """from __future__ import annotations
  48. import importlib.metadata
  49. CONFIG_FILE = 'pyproject.toml'
  50. MANIFEST_FILE = '.pre-commit-hooks.yaml'
  51. # Bump when modifying `empty_template`
  52. LOCAL_REPO_VERSION = '1'
  53. VERSION = importlib.metadata.version('pre_commit')
  54. DEFAULT = 'default'""",
  55. ),
  56. (
  57. pre_commit.yaml.__file__,
  58. """from __future__ import annotations
  59. import functools
  60. from typing import Any
  61. import yaml
  62. Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
  63. yaml_compose = functools.partial(yaml.compose, Loader=Loader)
  64. yaml_load = functools.partial(yaml.load, Loader=Loader)
  65. Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
  66. def yaml_dump(o: Any, **kwargs: Any) -> str:
  67. # when python/mypy#1484 is solved, this can be `functools.partial`
  68. return yaml.dump(
  69. o, Dumper=Dumper, default_flow_style=False, indent=4, sort_keys=False,
  70. **kwargs,
  71. )""",
  72. """from __future__ import annotations
  73. import functools
  74. from typing import Any
  75. import yaml
  76. import toml
  77. Loader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
  78. yaml_compose = functools.partial(yaml.compose, Loader=Loader)
  79. def yaml_load(stream):
  80. try:
  81. return toml.loads(stream).get("tool", {}).get("pre-commit", {})
  82. except ValueError:
  83. return yaml.load(stream, Loader=Loader)
  84. Dumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
  85. def yaml_dump(o: Any, **kwargs: Any) -> str:
  86. # when python/mypy#1484 is solved, this can be `functools.partial`
  87. return yaml.dump(
  88. o, Dumper=Dumper, default_flow_style=False, indent=4, sort_keys=False,
  89. **kwargs,
  90. )""",
  91. ),
  92. ]
  93. for file, old, new in patches:
  94. file_path = pathlib.Path(file)
  95. file_content = file_path.read_text()
  96. if new not in file_content and old not in file_content:
  97. raise RuntimeError(
  98. f"Unexpected content in {file_path}. Did you update pre-commit without updating the patches?"
  99. )
  100. if old in file_content:
  101. file_path.write_text(file_content.replace(old, new))
  102. if not (pathlib.Path(self.root) / "scripts").exists():
  103. return
  104. for file in (pathlib.Path(self.root) / "reflex").rglob("**/*.pyi"):
  105. file.unlink(missing_ok=True)
  106. subprocess.run(
  107. [sys.executable, "-m", "reflex.utils.pyi_generator"],
  108. check=True,
  109. )
  110. self.marker().touch()