diff --git a/src/django_components/__init__.py b/src/django_components/__init__.py index 7d54377b..f1c5ccd4 100644 --- a/src/django_components/__init__.py +++ b/src/django_components/__init__.py @@ -6,6 +6,7 @@ from pathlib import Path import django from django.utils.module_loading import autodiscover_modules +from django_components.logger import logger from django_components.utils import search if django.VERSION < (3, 2): @@ -21,27 +22,41 @@ def autodiscover() -> None: # Autodetect a .py file in a components dir component_filepaths = search(search_glob="**/*.py").matched_files + logger.debug( + f"Autodiscover found {len(component_filepaths)} files in component directories." + ) + for path in component_filepaths: - import_file(path) + # This imports the file and runs it's code. So if the file defines any + # django components, they will be registered. + module_name = _filepath_to_python_module(path) + logger.debug(f'Importing module "{module_name}" (derived from path "{path}")') + importlib.import_module(module_name) for path_lib in app_settings.LIBRARIES: importlib.import_module(path_lib) -def import_file(file_path: Path) -> None: +def _filepath_to_python_module(file_path: Path) -> str: + """ + Derive python import path from the filesystem path. + + Example: + - If project root is `/path/to/project` + - And file_path is `/path/to/project/app/components/mycomp.py` + - Then the path relative to project root is `app/components/mycomp.py` + - Which we then turn into python import path `app.components.mycomp` + """ # Get the root dir, see https://stackoverflow.com/a/16413955/9788634 project_root = os.path.abspath(os.path.dirname(__name__)) - # Derive python import path from the filesystem path - # Example: - # If project root is `/path/to/project` - # And file_path is `/path/to/project/app/components/mycomp.py` - # 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) + # NOTE: Path normalizes paths to use `/` as separator, while os.path + # uses `os.path.sep`. + sep = os.path.sep if os.path.sep in rel_path_without_suffix else "/" + module_name = rel_path_without_suffix.replace(sep, ".") + + return module_name