Skip to content

Commit ec5b741

Browse files
move some utility functions to a utils module (#149)
1 parent d0bcca0 commit ec5b741

File tree

6 files changed

+89
-21
lines changed

6 files changed

+89
-21
lines changed

src/django_bird/components.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
from .staticfiles import AssetType
2727
from .templates import gather_bird_tag_template_usage
2828
from .templates import get_component_directories
29-
from .templates import get_files_from_dirs
3029
from .templates import get_template_names
3130
from .templates import scan_template_for_bird_tag
3231
from .templatetags.tags.bird import BirdNode
3332
from .templatetags.tags.slot import DEFAULT_SLOT
3433
from .templatetags.tags.slot import SlotNode
34+
from .utils import get_files_from_dirs
3535

3636

3737
@dataclass(frozen=True, slots=True)

src/django_bird/conf.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from django.conf import settings
1212

1313
from ._typing import override
14+
from .utils import unique_ordered
1415

1516
DJANGO_BIRD_SETTINGS_NAME = "DJANGO_BIRD"
1617

@@ -40,6 +41,9 @@ def autoconfigure(self) -> None:
4041

4142
self._configurator.autoconfigure()
4243

44+
def get_component_directory_names(self):
45+
return unique_ordered([*self.COMPONENT_DIRS, "bird"])
46+
4347

4448
@final
4549
class AutoConfigurator:

src/django_bird/staticfiles.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from ._typing import override
2121
from .apps import DjangoBirdAppConfig
22-
from .templates import get_component_directory_names
22+
from .conf import app_settings
2323

2424
if TYPE_CHECKING:
2525
pass
@@ -92,7 +92,7 @@ def storage(self):
9292
@property
9393
def template_dir(self):
9494
template_dir = self.path.parent
95-
component_dirs = get_component_directory_names()
95+
component_dirs = app_settings.get_component_directory_names()
9696
while (
9797
len(template_dir.parts) > 1 and template_dir.parts[-1] not in component_dirs
9898
):

src/django_bird/templates.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import re
44
from collections.abc import Callable
55
from collections.abc import Generator
6-
from collections.abc import Iterable
76
from collections.abc import Iterator
87
from pathlib import Path
98
from typing import Any
@@ -19,14 +18,13 @@
1918
from django.template.loader_tags import IncludeNode
2019
from django.template.utils import get_app_template_dirs
2120

21+
from django_bird.utils import unique_ordered
22+
2223
from ._typing import _has_nodelist
2324
from .conf import app_settings
2425
from .templatetags.tags.bird import TAG
2526
from .templatetags.tags.bird import BirdNode
26-
27-
28-
def get_component_directory_names():
29-
return list(dict.fromkeys([*app_settings.COMPONENT_DIRS, "bird"]))
27+
from .utils import get_files_from_dirs
3028

3129

3230
def get_template_names(name: str) -> list[str]:
@@ -64,8 +62,8 @@ def get_template_names(name: str) -> list[str]:
6462
Returns:
6563
list[str]: A list of potential template names in resolution order.
6664
"""
67-
template_names = []
68-
component_dirs = get_component_directory_names()
65+
template_names: list[str] = []
66+
component_dirs = app_settings.get_component_directory_names()
6967

7068
name_parts = name.split(".")
7169
path_name = "/".join(name_parts)
@@ -79,7 +77,7 @@ def get_template_names(name: str) -> list[str]:
7977
]
8078
template_names.extend(potential_names)
8179

82-
return list(dict.fromkeys(template_names))
80+
return unique_ordered(template_names)
8381

8482

8583
def get_template_directories() -> Generator[Path, Any, None]:
@@ -99,19 +97,10 @@ def get_component_directories(
9997
return [
10098
Path(template_dir) / component_dir
10199
for template_dir in template_dirs
102-
for component_dir in get_component_directory_names()
100+
for component_dir in app_settings.get_component_directory_names()
103101
]
104102

105103

106-
def get_files_from_dirs(
107-
dirs: Iterable[Path],
108-
) -> Generator[tuple[Path, Path], Any, None]:
109-
for dir in dirs:
110-
for path in dir.rglob("*"):
111-
if path.is_file():
112-
yield path, dir
113-
114-
115104
BIRD_TAG_PATTERN = re.compile(
116105
rf"{{%\s*{TAG}\s+(?:\"|')?([a-zA-Z0-9_.-]+)(?:\"|')?.*?%}}"
117106
)

src/django_bird/utils.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from __future__ import annotations
2+
3+
from collections.abc import Generator
4+
from collections.abc import Iterable
5+
from pathlib import Path
6+
from typing import Any
7+
from typing import TypeVar
8+
9+
10+
def get_files_from_dirs(
11+
dirs: Iterable[Path],
12+
pattern: str = "*",
13+
) -> Generator[tuple[Path, Path], Any, None]:
14+
for dir in dirs:
15+
for path in dir.rglob(pattern):
16+
if path.is_file():
17+
yield path, dir
18+
19+
20+
Item = TypeVar("Item")
21+
22+
23+
def unique_ordered(items: Iterable[Item]) -> list[Item]:
24+
return list(dict.fromkeys(items))

tests/test_utils.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
5+
from django_bird.utils import get_files_from_dirs
6+
from django_bird.utils import unique_ordered
7+
8+
9+
def test_get_files_from_dirs(tmp_path):
10+
first = tmp_path / "first"
11+
first.mkdir()
12+
13+
for i in range(10):
14+
file = first / f"to_find{i}.txt"
15+
file.write_text("file should be found")
16+
17+
for i in range(10):
18+
file = first / f"do_not_find{i}.txt"
19+
file.write_text("file should not be found")
20+
21+
second = tmp_path / "second"
22+
second.mkdir()
23+
24+
for i in range(10):
25+
file = second / f"to_find{i}.txt"
26+
file.write_text("file should be found")
27+
28+
for i in range(10):
29+
file = second / f"do_not_find{i}.txt"
30+
file.write_text("file should not be found")
31+
32+
dirs = [first, second]
33+
34+
found_paths = list(get_files_from_dirs(dirs, "to_find*.txt"))
35+
36+
assert len(found_paths) == 20
37+
assert all("to_find" in path.name for path, _ in found_paths)
38+
assert not any("do_not_find" in path.name for path, _ in found_paths)
39+
40+
41+
@pytest.mark.parametrize(
42+
"items,expected",
43+
[
44+
(["a", "b", "c", "a"], ["a", "b", "c"]),
45+
(["first", "second", "first", "third"], ["first", "second", "third"]),
46+
([1, 2, 1, 3], [1, 2, 3]),
47+
([1, "b", 1, "a"], [1, "b", "a"]),
48+
],
49+
)
50+
def test_unique_ordered(items, expected):
51+
assert unique_ordered(items) == expected

0 commit comments

Comments
 (0)