Search for component files and import them. Returns a list of module paths of imported files.
Autodiscover searches in the locations as defined by Loader.get_dirs
.
You can map the module paths with map_module
function. This serves as an escape hatch for when you need to use this function in tests.
Source code in src/django_components/autodiscover.py
| def autodiscover(
map_module: Optional[Callable[[str], str]] = None,
) -> List[str]:
"""
Search for component files and import them. Returns a list of module
paths of imported files.
Autodiscover searches in the locations as defined by `Loader.get_dirs`.
You can map the module paths with `map_module` function. This serves
as an escape hatch for when you need to use this function in tests.
"""
dirs = get_dirs(include_apps=False)
component_filepaths = search_dirs(dirs, "**/*.py")
logger.debug(f"Autodiscover found {len(component_filepaths)} files in component directories.")
if hasattr(settings, "BASE_DIR") and settings.BASE_DIR:
project_root = str(settings.BASE_DIR)
else:
# Fallback for getting the root dir, see https://stackoverflow.com/a/16413955/9788634
project_root = os.path.abspath(os.path.dirname(__name__))
modules: List[str] = []
# We handle dirs from `COMPONENTS.dirs` and from individual apps separately.
#
# Because for dirs in `COMPONENTS.dirs`, we assume they will be nested under `BASE_DIR`,
# and that `BASE_DIR` is the current working dir (CWD). So the path relatively to `BASE_DIR`
# is ALSO the python import path.
for filepath in component_filepaths:
module_path = _filepath_to_python_module(filepath, project_root, None)
# Ignore files starting with dot `.` or files in dirs that start with dot.
#
# If any of the parts of the path start with a dot, e.g. the filesystem path
# is `./abc/.def`, then this gets converted to python module as `abc..def`
#
# NOTE: This approach also ignores files:
# - with two dots in the middle (ab..cd.py)
# - an extra dot at the end (abcd..py)
# - files outside of the parent component (../abcd.py).
# But all these are NOT valid python modules so that's fine.
if ".." in module_path:
continue
modules.append(module_path)
# For for apps, the directories may be outside of the project, e.g. in case of third party
# apps. So we have to resolve the python import path relative to the package name / the root
# import path for the app.
# See https://github.com/EmilStenstrom/django-components/issues/669
for conf in apps.get_app_configs():
for app_dir in app_settings.APP_DIRS:
comps_path = Path(conf.path).joinpath(app_dir)
if not comps_path.exists():
continue
app_component_filepaths = search_dirs([comps_path], "**/*.py")
for filepath in app_component_filepaths:
app_component_module = _filepath_to_python_module(filepath, conf.path, conf.name)
modules.append(app_component_module)
return _import_modules(modules, map_module)
|