Home Assistant Unofficial Reference 2024.12.1
importlib.py
Go to the documentation of this file.
1 """Helper to import modules from asyncio."""
2 
3 from __future__ import annotations
4 
5 import asyncio
6 from contextlib import suppress
7 import importlib
8 import logging
9 import sys
10 from types import ModuleType
11 
12 from homeassistant.core import HomeAssistant
13 from homeassistant.util.hass_dict import HassKey
14 
15 _LOGGER = logging.getLogger(__name__)
16 
17 DATA_IMPORT_CACHE: HassKey[dict[str, ModuleType]] = HassKey("import_cache")
18 DATA_IMPORT_FUTURES: HassKey[dict[str, asyncio.Future[ModuleType]]] = HassKey(
19  "import_futures"
20 )
21 DATA_IMPORT_FAILURES: HassKey[dict[str, bool]] = HassKey("import_failures")
22 
23 
24 def _get_module(cache: dict[str, ModuleType], name: str) -> ModuleType:
25  """Get a module."""
26  cache[name] = importlib.import_module(name)
27  return cache[name]
28 
29 
30 async def async_import_module(hass: HomeAssistant, name: str) -> ModuleType:
31  """Import a module or return it from the cache."""
32  cache = hass.data.setdefault(DATA_IMPORT_CACHE, {})
33  if module := cache.get(name):
34  return module
35 
36  failure_cache = hass.data.setdefault(DATA_IMPORT_FAILURES, {})
37  if name in failure_cache:
38  raise ModuleNotFoundError(f"{name} not found", name=name)
39 
40  import_futures = hass.data.setdefault(DATA_IMPORT_FUTURES, {})
41  if future := import_futures.get(name):
42  return await future
43 
44  if name in sys.modules:
45  return _get_module(cache, name)
46 
47  import_future = hass.loop.create_future()
48  import_futures[name] = import_future
49  try:
50  module = await hass.async_add_import_executor_job(_get_module, cache, name)
51  import_future.set_result(module)
52  except BaseException as ex:
53  if isinstance(ex, ModuleNotFoundError):
54  failure_cache[name] = True
55  import_future.set_exception(ex)
56  with suppress(BaseException):
57  # Set the exception retrieved flag on the future since
58  # it will never be retrieved unless there
59  # are concurrent calls
60  import_future.result()
61  raise
62  finally:
63  del import_futures[name]
64 
65  return module
ModuleType async_import_module(HomeAssistant hass, str name)
Definition: importlib.py:30
ModuleType _get_module(dict[str, ModuleType] cache, str name)
Definition: importlib.py:24