Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/6714.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix `reflex component build` crashing with `AttributeError` on Python 3.10 and 3.11 by replacing `pathlib.Path.walk()` (added in 3.12) with `os.walk()` when generating custom component `.pyi` files.
4 changes: 2 additions & 2 deletions reflex/custom_components/custom_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,8 @@ def _make_pyi_files():
for top_level_dir in Path.cwd().iterdir():
if not top_level_dir.is_dir() or top_level_dir.name.startswith("."):
continue
for dir, _, _ in top_level_dir.walk():
if "__pycache__" in dir.name:
for dir, _, _ in os.walk(top_level_dir):
if "__pycache__" in Path(dir).name:
continue
PyiGenerator().scan_all([dir])

Expand Down
Empty file.
47 changes: 47 additions & 0 deletions tests/units/custom_components/test_custom_components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Unit tests for reflex/custom_components/custom_components.py."""

from __future__ import annotations

from pathlib import Path

from reflex.custom_components import custom_components


def test_make_pyi_files_walks_without_path_walk(monkeypatch, tmp_path: Path):
"""``_make_pyi_files`` scans component dirs without relying on ``Path.walk``.

``pathlib.Path.walk`` only exists on Python 3.12+, but Reflex supports 3.10
and 3.11 too, so the build must not depend on it. ``Path.walk`` is removed
here to reproduce the 3.10/3.11 environment on any interpreter; the function
must still recurse (skipping ``__pycache__``) instead of raising
``AttributeError``.

Args:
monkeypatch: The pytest monkeypatch fixture.
tmp_path: A temporary directory used as the project root.
"""
package = tmp_path / "my_component"
nested = package / "sub"
nested.mkdir(parents=True)
(package / "__pycache__").mkdir()
(tmp_path / ".hidden").mkdir()

scanned: list[str] = []

class _RecordingGenerator:
def scan_all(self, targets, *_args, **_kwargs):
scanned.extend(str(target) for target in targets)

monkeypatch.setattr(
"reflex_base.utils.pyi_generator.PyiGenerator", _RecordingGenerator
)
monkeypatch.delattr(Path, "walk", raising=False)
monkeypatch.chdir(tmp_path)

custom_components._make_pyi_files()

scanned_names = {Path(target).name for target in scanned}
assert "my_component" in scanned_names
assert "sub" in scanned_names
assert "__pycache__" not in scanned_names
assert ".hidden" not in scanned_names
Loading