diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 196a00dda7c..81ae4eb6e18 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -110,8 +110,7 @@ async def async_setup_hass( runtime_config: RuntimeConfig, ) -> core.HomeAssistant | None: """Set up Home Assistant.""" - hass = core.HomeAssistant() - hass.config.config_dir = runtime_config.config_dir + hass = core.HomeAssistant(runtime_config.config_dir) async_enable_logging( hass, @@ -178,14 +177,13 @@ async def async_setup_hass( old_config = hass.config old_logging = hass.data.get(DATA_LOGGING) - hass = core.HomeAssistant() + hass = core.HomeAssistant(old_config.config_dir) if old_logging: hass.data[DATA_LOGGING] = old_logging hass.config.skip_pip = old_config.skip_pip hass.config.skip_pip_packages = old_config.skip_pip_packages hass.config.internal_url = old_config.internal_url hass.config.external_url = old_config.external_url - hass.config.config_dir = old_config.config_dir # Setup loader cache after the config dir has been set loader.async_setup(hass) diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index 7bd80000ca4..6fbcfc30f69 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -54,7 +54,6 @@ class CloudClient(Interface): @property def base_path(self) -> Path: """Return path to base dir.""" - assert self._hass.config.config_dir is not None return Path(self._hass.config.config_dir) @property diff --git a/homeassistant/components/file/notify.py b/homeassistant/components/file/notify.py index 3238fe91102..ca0deb89c7b 100644 --- a/homeassistant/components/file/notify.py +++ b/homeassistant/components/file/notify.py @@ -51,9 +51,6 @@ class FileNotificationService(BaseNotificationService): def send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to a file.""" file: TextIO - if not self.hass.config.config_dir: - return - filepath: str = os.path.join(self.hass.config.config_dir, self.filename) with open(filepath, "a", encoding="utf8") as file: if os.stat(filepath).st_size == 0: diff --git a/homeassistant/components/homematicip_cloud/services.py b/homeassistant/components/homematicip_cloud/services.py index a8393ff88ac..09457ce0792 100644 --- a/homeassistant/components/homematicip_cloud/services.py +++ b/homeassistant/components/homematicip_cloud/services.py @@ -286,7 +286,7 @@ async def _set_active_climate_profile( async def _async_dump_hap_config(hass: HomeAssistant, service: ServiceCall) -> None: """Service to dump the configuration of a Homematic IP Access Point.""" config_path: str = ( - service.data.get(ATTR_CONFIG_OUTPUT_PATH) or hass.config.config_dir or "." + service.data.get(ATTR_CONFIG_OUTPUT_PATH) or hass.config.config_dir ) config_file_prefix = service.data[ATTR_CONFIG_OUTPUT_FILE_PREFIX] anonymize = service.data[ATTR_ANONYMIZE] diff --git a/homeassistant/components/system_log/__init__.py b/homeassistant/components/system_log/__init__.py index f025013cc2b..cba8082d23c 100644 --- a/homeassistant/components/system_log/__init__.py +++ b/homeassistant/components/system_log/__init__.py @@ -234,7 +234,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: hass_path: str = HOMEASSISTANT_PATH[0] config_dir = hass.config.config_dir - assert config_dir is not None paths_re = re.compile( r"(?:{})/(.*)".format("|".join([re.escape(x) for x in (hass_path, config_dir)])) ) diff --git a/homeassistant/components/verisure/camera.py b/homeassistant/components/verisure/camera.py index c9d98041a2c..a240d45cf7e 100644 --- a/homeassistant/components/verisure/camera.py +++ b/homeassistant/components/verisure/camera.py @@ -36,7 +36,6 @@ async def async_setup_entry( VerisureSmartcam.capture_smartcam.__name__, ) - assert hass.config.config_dir async_add_entities( VerisureSmartcam(coordinator, serial_number, hass.config.config_dir) for serial_number in coordinator.data["cameras"] diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 1f3a71f4cbf..1320e77ba3c 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -802,7 +802,6 @@ class LogRelayHandler(logging.Handler): hass_path: str = HOMEASSISTANT_PATH[0] config_dir = self.hass.config.config_dir - assert config_dir is not None paths_re = re.compile( r"(?:{})/(.*)".format( "|".join([re.escape(x) for x in (hass_path, config_dir)]) diff --git a/homeassistant/config.py b/homeassistant/config.py index eed296baf0e..0d9e1d9034e 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -337,7 +337,6 @@ async def async_create_default_config(hass: HomeAssistant) -> bool: Return if creation was successful. """ - assert hass.config.config_dir return await hass.async_add_executor_job( _write_default_config, hass.config.config_dir ) @@ -390,10 +389,7 @@ async def async_hass_config_yaml(hass: HomeAssistant) -> dict: This function allow a component inside the asyncio loop to reload its configuration by itself. Include package merge. """ - if hass.config.config_dir is None: - secrets = None - else: - secrets = Secrets(Path(hass.config.config_dir)) + secrets = Secrets(Path(hass.config.config_dir)) # Not using async_add_executor_job because this is an internal method. config = await hass.loop.run_in_executor( diff --git a/homeassistant/core.py b/homeassistant/core.py index a025eacd4bc..140cf203e70 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -288,13 +288,13 @@ class HomeAssistant: http: HomeAssistantHTTP = None # type: ignore[assignment] config_entries: ConfigEntries = None # type: ignore[assignment] - def __new__(cls) -> HomeAssistant: + def __new__(cls, config_dir: str) -> HomeAssistant: """Set the _hass thread local data.""" hass = super().__new__(cls) _hass.hass = hass return hass - def __init__(self) -> None: + def __init__(self, config_dir: str) -> None: """Initialize new Home Assistant object.""" self.loop = asyncio.get_running_loop() self._tasks: set[asyncio.Future[Any]] = set() @@ -302,7 +302,7 @@ class HomeAssistant: self.bus = EventBus(self) self.services = ServiceRegistry(self) self.states = StateMachine(self.bus, self.loop) - self.config = Config(self) + self.config = Config(self, config_dir) self.components = loader.Components(self) self.helpers = loader.Helpers(self) # This is a dictionary that any component can store any data on. @@ -2011,7 +2011,7 @@ class ServiceRegistry: class Config: """Configuration settings for Home Assistant.""" - def __init__(self, hass: HomeAssistant) -> None: + def __init__(self, hass: HomeAssistant, config_dir: str) -> None: """Initialize a new config object.""" self.hass = hass @@ -2047,7 +2047,7 @@ class Config: self.api: ApiConfig | None = None # Directory that holds the configuration - self.config_dir: str | None = None + self.config_dir: str = config_dir # List of allowed external dirs to access self.allowlist_external_dirs: set[str] = set() @@ -2078,8 +2078,6 @@ class Config: Async friendly. """ - if self.config_dir is None: - raise HomeAssistantError("config_dir is not set") return os.path.join(self.config_dir, *path) def is_allowed_external_url(self, url: str) -> bool: diff --git a/homeassistant/helpers/check_config.py b/homeassistant/helpers/check_config.py index a580c013cd0..1e1cac050f1 100644 --- a/homeassistant/helpers/check_config.py +++ b/homeassistant/helpers/check_config.py @@ -94,8 +94,6 @@ async def async_check_ha_config_file( # noqa: C901 if not await hass.async_add_executor_job(os.path.isfile, config_path): return result.add_error("File configuration.yaml not found.") - assert hass.config.config_dir is not None - config = await hass.async_add_executor_job( load_yaml_config_file, config_path, diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 340888a2f7a..697e47187ce 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -1148,17 +1148,13 @@ async def _async_component_dependencies( return loaded -def _async_mount_config_dir(hass: HomeAssistant) -> bool: +def _async_mount_config_dir(hass: HomeAssistant) -> None: """Mount config dir in order to load custom_component. Async friendly but not a coroutine. """ - if hass.config.config_dir is None: - _LOGGER.error("Can't load integrations - configuration directory is not set") - return False if hass.config.config_dir not in sys.path: sys.path.insert(0, hass.config.config_dir) - return True def _lookup_path(hass: HomeAssistant) -> list[str]: diff --git a/homeassistant/scripts/auth.py b/homeassistant/scripts/auth.py index 11ab6aadfbf..5714e5814a4 100644 --- a/homeassistant/scripts/auth.py +++ b/homeassistant/scripts/auth.py @@ -50,8 +50,7 @@ def run(args): async def run_command(args): """Run the command.""" - hass = HomeAssistant() - hass.config.config_dir = os.path.join(os.getcwd(), args.config) + hass = HomeAssistant(os.path.join(os.getcwd(), args.config)) hass.auth = await auth_manager_from_config(hass, [{"type": "homeassistant"}], []) provider = hass.auth.auth_providers[0] await provider.async_initialize() diff --git a/homeassistant/scripts/benchmark/__init__.py b/homeassistant/scripts/benchmark/__init__.py index 3627e4096d3..a04493a8935 100644 --- a/homeassistant/scripts/benchmark/__init__.py +++ b/homeassistant/scripts/benchmark/__init__.py @@ -49,7 +49,7 @@ def run(args): async def run_benchmark(bench): """Run a benchmark.""" - hass = core.HomeAssistant() + hass = core.HomeAssistant("") runtime = await bench(hass) print(f"Benchmark {bench.__name__} done in {runtime}s") await hass.async_stop() diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index 7c4a200bbc5..5c81c4664da 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -231,9 +231,8 @@ def check(config_dir, secrets=False): async def async_check_config(config_dir): """Check the HA config.""" - hass = core.HomeAssistant() + hass = core.HomeAssistant(config_dir) loader.async_setup(hass) - hass.config.config_dir = config_dir hass.config_entries = ConfigEntries(hass, {}) await ar.async_load(hass) await dr.async_load(hass) diff --git a/homeassistant/scripts/ensure_config.py b/homeassistant/scripts/ensure_config.py index 6dbda59522f..786b16ca923 100644 --- a/homeassistant/scripts/ensure_config.py +++ b/homeassistant/scripts/ensure_config.py @@ -39,8 +39,7 @@ def run(args): async def async_run(config_dir): """Make sure config exists.""" - hass = HomeAssistant() - hass.config.config_dir = config_dir + hass = HomeAssistant(config_dir) path = await config_util.async_ensure_config_exists(hass) await hass.async_stop(force=True) return path diff --git a/tests/common.py b/tests/common.py index 95947719ef4..6f2209276ce 100644 --- a/tests/common.py +++ b/tests/common.py @@ -179,7 +179,7 @@ def get_test_home_assistant(): async def async_test_home_assistant(event_loop, load_registries=True): """Return a Home Assistant object pointing at test config dir.""" - hass = HomeAssistant() + hass = HomeAssistant(get_test_config_dir()) store = auth_store.AuthStore(hass) hass.auth = auth.AuthManager(hass, store, {}, {}) ensure_auth_manager_loaded(hass.auth) @@ -231,7 +231,6 @@ async def async_test_home_assistant(event_loop, load_registries=True): hass.data[loader.DATA_CUSTOM_COMPONENTS] = {} hass.config.location_name = "test home" - hass.config.config_dir = get_test_config_dir() hass.config.latitude = 32.87336 hass.config.longitude = -117.22743 hass.config.elevation = 0 diff --git a/tests/conftest.py b/tests/conftest.py index 31900dff6de..f90984e1c7b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -552,8 +552,8 @@ async def stop_hass( created = [] - def mock_hass(): - hass_inst = orig_hass() + def mock_hass(*args): + hass_inst = orig_hass(*args) created.append(hass_inst) return hass_inst diff --git a/tests/test_core.py b/tests/test_core.py index 9f6e5aeb2dd..4f7916e757b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1428,7 +1428,7 @@ async def test_serviceregistry_return_response_optional( async def test_config_defaults() -> None: """Test config defaults.""" hass = Mock() - config = ha.Config(hass) + config = ha.Config(hass, "/test/ha-config") assert config.hass is hass assert config.latitude == 0 assert config.longitude == 0 @@ -1442,7 +1442,7 @@ async def test_config_defaults() -> None: assert config.skip_pip_packages == [] assert config.components == set() assert config.api is None - assert config.config_dir is None + assert config.config_dir == "/test/ha-config" assert config.allowlist_external_dirs == set() assert config.allowlist_external_urls == set() assert config.media_dirs == {} @@ -1455,22 +1455,19 @@ async def test_config_defaults() -> None: async def test_config_path_with_file() -> None: """Test get_config_path method.""" - config = ha.Config(None) - config.config_dir = "/test/ha-config" + config = ha.Config(None, "/test/ha-config") assert config.path("test.conf") == "/test/ha-config/test.conf" async def test_config_path_with_dir_and_file() -> None: """Test get_config_path method.""" - config = ha.Config(None) - config.config_dir = "/test/ha-config" + config = ha.Config(None, "/test/ha-config") assert config.path("dir", "test.conf") == "/test/ha-config/dir/test.conf" async def test_config_as_dict() -> None: """Test as dict.""" - config = ha.Config(None) - config.config_dir = "/test/ha-config" + config = ha.Config(None, "/test/ha-config") config.hass = MagicMock() type(config.hass.state).value = PropertyMock(return_value="RUNNING") expected = { @@ -1501,7 +1498,7 @@ async def test_config_as_dict() -> None: async def test_config_is_allowed_path() -> None: """Test is_allowed_path method.""" - config = ha.Config(None) + config = ha.Config(None, "/test/ha-config") with TemporaryDirectory() as tmp_dir: # The created dir is in /tmp. This is a symlink on OS X # causing this test to fail unless we resolve path first. @@ -1533,7 +1530,7 @@ async def test_config_is_allowed_path() -> None: async def test_config_is_allowed_external_url() -> None: """Test is_allowed_external_url method.""" - config = ha.Config(None) + config = ha.Config(None, "/test/ha-config") config.allowlist_external_urls = [ "http://x.com/", "https://y.com/bla/", @@ -1584,7 +1581,7 @@ async def test_start_taking_too_long( event_loop, caplog: pytest.LogCaptureFixture ) -> None: """Test when async_start takes too long.""" - hass = ha.HomeAssistant() + hass = ha.HomeAssistant("/test/ha-config") caplog.set_level(logging.WARNING) hass.async_create_task(asyncio.sleep(0)) @@ -1751,7 +1748,7 @@ async def test_additional_data_in_core_config( hass: HomeAssistant, hass_storage: dict[str, Any] ) -> None: """Test that we can handle additional data in core configuration.""" - config = ha.Config(hass) + config = ha.Config(hass, "/test/ha-config") hass_storage[ha.CORE_STORAGE_KEY] = { "version": 1, "data": {"location_name": "Test Name", "additional_valid_key": "value"}, @@ -1764,7 +1761,7 @@ async def test_incorrect_internal_external_url( hass: HomeAssistant, hass_storage: dict[str, Any], caplog: pytest.LogCaptureFixture ) -> None: """Test that we warn when detecting invalid internal/external url.""" - config = ha.Config(hass) + config = ha.Config(hass, "/test/ha-config") hass_storage[ha.CORE_STORAGE_KEY] = { "version": 1, @@ -1777,7 +1774,7 @@ async def test_incorrect_internal_external_url( assert "Invalid external_url set" not in caplog.text assert "Invalid internal_url set" not in caplog.text - config = ha.Config(hass) + config = ha.Config(hass, "/test/ha-config") hass_storage[ha.CORE_STORAGE_KEY] = { "version": 1,