mirror of
https://github.com/home-assistant/core.git
synced 2025-07-20 03:37:07 +00:00
Improve flexibility of the loader
This commit is contained in:
parent
0c7b6e26aa
commit
973ce21353
@ -3,7 +3,17 @@ homeassistant.loader
|
|||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Provides methods for loading Home Assistant components.
|
Provides methods for loading Home Assistant components.
|
||||||
|
|
||||||
|
This module has quite some complex parts. I have tried to add as much
|
||||||
|
documentation as possible to keep it understandable.
|
||||||
|
|
||||||
|
Components are loaded by calling get_component('switch') from your code.
|
||||||
|
If you want to retrieve a platform that is part of a component, you should
|
||||||
|
call get_component('switch.your_platform'). In both cases the config directory
|
||||||
|
is checked to see if it contains a user provided version. If not available it
|
||||||
|
will check the built-in components and platforms.
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import importlib
|
import importlib
|
||||||
@ -30,22 +40,27 @@ def prepare(hass):
|
|||||||
pkgutil.iter_modules(components.__path__, 'homeassistant.components.'))
|
pkgutil.iter_modules(components.__path__, 'homeassistant.components.'))
|
||||||
|
|
||||||
# Look for available custom components
|
# Look for available custom components
|
||||||
|
custom_path = hass.get_config_path("custom_components")
|
||||||
|
|
||||||
# Ensure we can load custom components from the config dir
|
if os.path.isdir(custom_path):
|
||||||
sys.path.append(hass.config_dir)
|
# Ensure we can load custom components using Pythons import
|
||||||
|
sys.path.insert(0, hass.config_dir)
|
||||||
|
|
||||||
try:
|
# We cannot use the same approach as for built-in components because
|
||||||
# pylint: disable=import-error
|
# custom components might only contain a platform for a component.
|
||||||
import custom_components
|
# ie custom_components/switch/some_platform.py. Using pkgutil would
|
||||||
|
# not give us the switch component (and neither should it).
|
||||||
|
|
||||||
AVAILABLE_COMPONENTS.extend(
|
# Assumption: the custom_components dir only contains directories or
|
||||||
item[1] for item in
|
# python components. If this assumption is not true, HA won't break,
|
||||||
pkgutil.iter_modules(
|
# just might output more errors.
|
||||||
custom_components.__path__, 'custom_components.'))
|
for fil in os.listdir(custom_path):
|
||||||
|
if os.path.isdir(os.path.join(custom_path, fil)):
|
||||||
|
AVAILABLE_COMPONENTS.append('custom_components.{}'.format(fil))
|
||||||
|
|
||||||
except ImportError:
|
else:
|
||||||
# No folder custom_components exist in the config directory
|
AVAILABLE_COMPONENTS.append(
|
||||||
pass
|
'custom_components.{}'.format(fil[0:-3]))
|
||||||
|
|
||||||
|
|
||||||
def get_component(comp_name):
|
def get_component(comp_name):
|
||||||
@ -61,8 +76,10 @@ def get_component(comp_name):
|
|||||||
# an exception because it will try to import the parent.
|
# an exception because it will try to import the parent.
|
||||||
# Because of this behavior, we will approach loading sub components
|
# Because of this behavior, we will approach loading sub components
|
||||||
# with caution: only load it if we can verify that the parent exists.
|
# with caution: only load it if we can verify that the parent exists.
|
||||||
|
# We do not want to silent the ImportErrors as they provide valuable
|
||||||
|
# information to track down when debugging Home Assistant.
|
||||||
|
|
||||||
# First check config dir, then built-in
|
# First check custom, then built-in
|
||||||
potential_paths = ['custom_components.{}'.format(comp_name),
|
potential_paths = ['custom_components.{}'.format(comp_name),
|
||||||
'homeassistant.components.{}'.format(comp_name)]
|
'homeassistant.components.{}'.format(comp_name)]
|
||||||
|
|
||||||
@ -76,17 +93,30 @@ def get_component(comp_name):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_COMPONENT_CACHE[comp_name] = importlib.import_module(path)
|
module = importlib.import_module(path)
|
||||||
|
|
||||||
|
# In Python 3 you can import files from directories that do not
|
||||||
|
# contain the file __init__.py. A directory is a valid module if
|
||||||
|
# it contains a file with the .py extension. In this case Python
|
||||||
|
# will succeed in importing the directory as a module and call it
|
||||||
|
# a namespace. We do not care about namespaces.
|
||||||
|
# This prevents that when only
|
||||||
|
# custom_components/switch/some_platform.py exists,
|
||||||
|
# the import custom_components.switch would succeeed.
|
||||||
|
if module.__spec__.origin == 'namespace':
|
||||||
|
continue
|
||||||
|
|
||||||
_LOGGER.info("Loaded %s from %s", comp_name, path)
|
_LOGGER.info("Loaded %s from %s", comp_name, path)
|
||||||
|
|
||||||
return _COMPONENT_CACHE[comp_name]
|
_COMPONENT_CACHE[comp_name] = module
|
||||||
|
|
||||||
|
return module
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_LOGGER.exception(
|
_LOGGER.exception(
|
||||||
("Error loading %s. Make sure all "
|
("Error loading %s. Make sure all "
|
||||||
"dependencies are installed"), path)
|
"dependencies are installed"), path)
|
||||||
|
|
||||||
# We did find components but were unable to load them
|
_LOGGER.error("Unable to find component %s", comp_name)
|
||||||
_LOGGER.error("Unable to load component %s", comp_name)
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user