refactor: fix clash with autodiscovery

This commit is contained in:
Juro Oravec 2024-04-13 21:34:43 +02:00
parent ddc62c7dfc
commit 003c8ba4d5
3 changed files with 31 additions and 19 deletions

View file

@ -1,8 +1,7 @@
import importlib import importlib
import importlib.util import importlib.util
import sys import os
from pathlib import Path from pathlib import Path
from typing import Union
import django import django
from django.utils.module_loading import autodiscover_modules from django.utils.module_loading import autodiscover_modules
@ -21,7 +20,7 @@ def autodiscover() -> None:
autodiscover_modules("components") autodiscover_modules("components")
# Autodetect a <component>.py file in a components dir # Autodetect a <component>.py file in a components dir
component_filepaths = search(search_glob="**/*.py") component_filepaths = search(search_glob="**/*.py").matched_files
for path in component_filepaths: for path in component_filepaths:
import_file(path) import_file(path)
@ -29,12 +28,20 @@ def autodiscover() -> None:
importlib.import_module(path_lib) importlib.import_module(path_lib)
def import_file(path: Union[str, Path]) -> None: def import_file(file_path: Path) -> None:
MODULE_PATH = path # Get the root dir, see https://stackoverflow.com/a/16413955/9788634
MODULE_NAME = Path(path).stem project_root = os.path.abspath(os.path.dirname(__name__))
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
if spec is None: # Derive python import path from the filesystem path
raise ValueError(f"Cannot import file '{path}' - invalid path") # Example:
module = importlib.util.module_from_spec(spec) # If project root is `/path/to/project`
sys.modules[spec.name] = module # And file_path is `/path/to/project/app/components/mycomp.py`
spec.loader.exec_module(module) # type: ignore # Then the path relative to project root is `app/components/mycomp.py`
# Which we then turn into python import path `app.components.mycomp`
rel_path = os.path.relpath(file_path, start=project_root)
rel_path_without_suffix = str(Path(rel_path).with_suffix(""))
module_name = rel_path_without_suffix.replace(os.sep, ".")
# This imports the file and runs it's code. So if the file defines any
# django components, they will be registered.
importlib.import_module(module_name)

View file

@ -89,7 +89,7 @@ def _resolve_component_relative_files(attrs: MutableMapping) -> None:
# Prepare all possible directories we need to check when searching for # Prepare all possible directories we need to check when searching for
# component's template and media files # component's template and media files
components_dirs = search() components_dirs = search().searched_dirs
# Get the directory where the component class is defined # Get the directory where the component class is defined
try: try:

View file

@ -1,13 +1,18 @@
import glob import glob
from pathlib import Path from pathlib import Path
from typing import List, Optional, Union from typing import List, Optional, NamedTuple
from django.template.engine import Engine from django.template.engine import Engine
from django_components.template_loader import Loader from django_components.template_loader import Loader
def search(search_glob: Optional[str] = None, engine: Optional[Engine] = None) -> Union[List[str], List[Path]]: class SearchResult(NamedTuple):
searched_dirs: List[Path]
matched_files: List[Path]
def search(search_glob: Optional[str] = None, engine: Optional[Engine] = None) -> SearchResult:
""" """
Search for directories that may contain components. Search for directories that may contain components.
@ -22,11 +27,11 @@ def search(search_glob: Optional[str] = None, engine: Optional[Engine] = None) -
dirs = loader.get_dirs() dirs = loader.get_dirs()
if search_glob is None: if search_glob is None:
return dirs return SearchResult(searched_dirs=dirs, matched_files=[])
component_filenames: List[str] = [] component_filenames: List[Path] = []
for directory in dirs: for directory in dirs:
for path in glob.iglob(str(Path(directory) / search_glob), recursive=True): for path in glob.iglob(str(Path(directory) / search_glob), recursive=True):
component_filenames.append(path) component_filenames.append(Path(path))
return component_filenames return SearchResult(searched_dirs=dirs, matched_files=component_filenames)