Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions homeassistant/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ def get_component(hass, comp_or_platform):

# Try custom component
module = _load_module(hass.config.path(PATH_CUSTOM_COMPONENTS),
comp_or_platform)
PATH_CUSTOM_COMPONENTS, comp_or_platform)

if module is None:
try:
module = importlib.import_module(
'{}.{}'.format(PACKAGE_COMPONENTS, comp_or_platform))
_LOGGER.debug('Loaded %s (built-in)', comp_or_platform)
except ImportError:
_LOGGER.warning('Unable to find %s', comp_or_platform)
module = None

cache = hass.data.get(DATA_KEY)
Expand All @@ -102,18 +104,20 @@ def _find_spec(path, name):
return None


def _load_module(path, name):
def _load_module(path, base_module, name):
"""Load a module based on a folder and a name."""
mod_name = "{}.{}".format(base_module, name)
spec = _find_spec([path], name)

# Special handling if loading platforms and the folder is a namespace
# (namespace is a folder without __init__.py)
if spec is None and '.' in name:
parent_spec = _find_spec([path], name.split('.')[0])
mod_parent_name = name.split('.')[0]
parent_spec = _find_spec([path], mod_parent_name)
if (parent_spec is None or
parent_spec.submodule_search_locations is None):
return None
spec = _find_spec(parent_spec.submodule_search_locations, name)
spec = _find_spec(parent_spec.submodule_search_locations, mod_name)

# Not found
if spec is None:
Expand All @@ -123,8 +127,19 @@ def _load_module(path, name):
if spec.loader is None:
return None

_LOGGER.debug('Loaded %s (%s)', name, base_module)

module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# A hack, I know. Don't currently know how to work around it.
if not module.__name__.startswith(base_module):
module.__name__ = "{}.{}".format(base_module, name)

if not module.__package__:
module.__package__ = base_module
elif not module.__package__.startswith(base_module):
module.__package__ = "{}.{}".format(base_module, name)

return module


Expand Down
18 changes: 16 additions & 2 deletions tests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ def test_set_component(self):
comp = object()
loader.set_component(self.hass, 'switch.test_set', comp)

self.assertEqual(comp,
loader.get_component(self.hass, 'switch.test_set'))
assert loader.get_component(self.hass, 'switch.test_set') is comp

def test_get_component(self):
"""Test if get_component works."""
Expand Down Expand Up @@ -106,3 +105,18 @@ def discovery_callback(service, discovered):
yield from hass.async_block_till_done()

assert result == ['hello']


async def test_custom_component_name(hass):
"""Test the name attribte of custom components."""
comp = loader.get_component(hass, 'test_standalone')
assert comp.__name__ == 'custom_components.test_standalone'
assert comp.__package__ == 'custom_components'

comp = loader.get_component(hass, 'test_package')
assert comp.__name__ == 'custom_components.test_package'
assert comp.__package__ == 'custom_components.test_package'

comp = loader.get_component(hass, 'light.test')
assert comp.__name__ == 'custom_components.light.test'
assert comp.__package__ == 'custom_components.light'
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
DOMAIN = 'test_package'


def setup(hass, config):
async def async_setup(hass, config):
"""Mock a successful setup."""
return True