diff --git a/homeassistant/components/filesize/__init__.py b/homeassistant/components/filesize/__init__.py index b3292ed9c9f..61ef26f0a66 100644 --- a/homeassistant/components/filesize/__init__.py +++ b/homeassistant/components/filesize/__init__.py @@ -11,13 +11,19 @@ from homeassistant.exceptions import ConfigEntryNotReady from .const import PLATFORMS +def check_path(path: pathlib.Path) -> bool: + """Check path.""" + return path.exists() and path.is_file() + + async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up from a config entry.""" path = entry.data[CONF_FILE_PATH] - get_path = await hass.async_add_executor_job(pathlib.Path, path) + get_path = pathlib.Path(path) - if not get_path.exists() and not get_path.is_file(): + check_file = await hass.async_add_executor_job(check_path, get_path) + if not check_file: raise ConfigEntryNotReady(f"Can not access file {path}") if not hass.config.is_allowed_path(path): diff --git a/homeassistant/components/filesize/config_flow.py b/homeassistant/components/filesize/config_flow.py index ed2d4ab0940..3f58e636b0e 100644 --- a/homeassistant/components/filesize/config_flow.py +++ b/homeassistant/components/filesize/config_flow.py @@ -11,6 +11,7 @@ from homeassistant.config_entries import ConfigFlow from homeassistant.const import CONF_FILE_PATH from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResult +from homeassistant.exceptions import HomeAssistantError from .const import DOMAIN @@ -19,19 +20,20 @@ DATA_SCHEMA = vol.Schema({vol.Required(CONF_FILE_PATH): str}) _LOGGER = logging.getLogger(__name__) -def validate_path(hass: HomeAssistant, path: str) -> pathlib.Path: +def validate_path(hass: HomeAssistant, path: str) -> str: """Validate path.""" - try: - get_path = pathlib.Path(path) - except OSError as error: - _LOGGER.error("Can not access file %s, error %s", path, error) - raise NotValidError from error + get_path = pathlib.Path(path) + if not get_path.exists() or not get_path.is_file(): + _LOGGER.error("Can not access file %s", path) + raise NotValidError if not hass.config.is_allowed_path(path): - _LOGGER.error("Filepath %s is not valid or allowed", path) + _LOGGER.error("Filepath %s is not allowed", path) raise NotAllowedError - return get_path + full_path = get_path.absolute() + + return str(full_path) class FilesizeConfigFlow(ConfigFlow, domain=DOMAIN): @@ -47,14 +49,13 @@ class FilesizeConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: try: - get_path = validate_path(self.hass, user_input[CONF_FILE_PATH]) + full_path = validate_path(self.hass, user_input[CONF_FILE_PATH]) except NotValidError: errors["base"] = "not_valid" except NotAllowedError: errors["base"] = "not_allowed" else: - fullpath = str(get_path.absolute()) - await self.async_set_unique_id(fullpath) + await self.async_set_unique_id(full_path) self._abort_if_unique_id_configured() name = str(user_input[CONF_FILE_PATH]).rsplit("/", maxsplit=1)[-1] @@ -68,9 +69,9 @@ class FilesizeConfigFlow(ConfigFlow, domain=DOMAIN): ) -class NotValidError(Exception): +class NotValidError(HomeAssistantError): """Path is not valid error.""" -class NotAllowedError(Exception): +class NotAllowedError(HomeAssistantError): """Path is not allowed error.""" diff --git a/homeassistant/components/filesize/sensor.py b/homeassistant/components/filesize/sensor.py index 70896bcacad..6c52fcbdd5a 100644 --- a/homeassistant/components/filesize/sensor.py +++ b/homeassistant/components/filesize/sensor.py @@ -74,13 +74,10 @@ async def async_setup_entry( coordinator = FileSizeCoordinator(hass, fullpath) await coordinator.async_config_entry_first_refresh() - if get_path.exists() and get_path.is_file(): - async_add_entities( - [ - FilesizeEntity(description, fullpath, entry.entry_id, coordinator) - for description in SENSOR_TYPES - ] - ) + async_add_entities( + FilesizeEntity(description, fullpath, entry.entry_id, coordinator) + for description in SENSOR_TYPES + ) class FileSizeCoordinator(DataUpdateCoordinator): @@ -119,7 +116,7 @@ class FileSizeCoordinator(DataUpdateCoordinator): class FilesizeEntity(CoordinatorEntity[FileSizeCoordinator], SensorEntity): - """Encapsulates file size information.""" + """Filesize sensor.""" entity_description: SensorEntityDescription @@ -130,7 +127,7 @@ class FilesizeEntity(CoordinatorEntity[FileSizeCoordinator], SensorEntity): entry_id: str, coordinator: FileSizeCoordinator, ) -> None: - """Initialize the data object.""" + """Initialize the Filesize sensor.""" super().__init__(coordinator) base_name = path.split("/")[-1] self._attr_name = f"{base_name} {description.name}" diff --git a/tests/components/filesize/__init__.py b/tests/components/filesize/__init__.py index d7aa8dd2481..3e09a745387 100644 --- a/tests/components/filesize/__init__.py +++ b/tests/components/filesize/__init__.py @@ -1,6 +1,8 @@ """Tests for the filesize component.""" import os +from homeassistant.core import HomeAssistant + TEST_DIR = os.path.join(os.path.dirname(__file__)) TEST_FILE_NAME = "mock_file_test_filesize.txt" TEST_FILE_NAME2 = "mock_file_test_filesize2.txt" @@ -8,7 +10,12 @@ TEST_FILE = os.path.join(TEST_DIR, TEST_FILE_NAME) TEST_FILE2 = os.path.join(TEST_DIR, TEST_FILE_NAME2) -def create_file(path) -> None: +async def async_create_file(hass: HomeAssistant, path: str) -> None: """Create a test file.""" + await hass.async_add_executor_job(create_file, path) + + +def create_file(path: str) -> None: + """Create the test file.""" with open(path, "w", encoding="utf-8") as test_file: test_file.write("test") diff --git a/tests/components/filesize/test_config_flow.py b/tests/components/filesize/test_config_flow.py index f6873e64128..16f0ab38dc1 100644 --- a/tests/components/filesize/test_config_flow.py +++ b/tests/components/filesize/test_config_flow.py @@ -11,14 +11,14 @@ from homeassistant.data_entry_flow import ( RESULT_TYPE_FORM, ) -from . import TEST_DIR, TEST_FILE, TEST_FILE_NAME, create_file +from . import TEST_DIR, TEST_FILE, TEST_FILE_NAME, async_create_file from tests.common import MockConfigEntry async def test_full_user_flow(hass: HomeAssistant) -> None: """Test the full user configuration flow.""" - create_file(TEST_FILE) + await async_create_file(hass, TEST_FILE) hass.config.allowlist_external_dirs = {TEST_DIR} result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER} @@ -43,6 +43,7 @@ async def test_unique_path( mock_config_entry: MockConfigEntry, ) -> None: """Test we abort if already setup.""" + await async_create_file(hass, TEST_FILE) hass.config.allowlist_external_dirs = {TEST_DIR} mock_config_entry.add_to_hass(hass) @@ -56,7 +57,7 @@ async def test_unique_path( async def test_flow_fails_on_validation(hass: HomeAssistant) -> None: """Test config flow errors.""" - create_file(TEST_FILE) + hass.config.allowlist_external_dirs = {} result = await hass.config_entries.flow.async_init( @@ -66,19 +67,17 @@ async def test_flow_fails_on_validation(hass: HomeAssistant) -> None: assert result["type"] == RESULT_TYPE_FORM assert result["step_id"] == SOURCE_USER - with patch( - "homeassistant.components.filesize.config_flow.pathlib.Path", - side_effect=OSError, - ): - result2 = await hass.config_entries.flow.async_configure( - result["flow_id"], - user_input={ - CONF_FILE_PATH: TEST_FILE, - }, - ) + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={ + CONF_FILE_PATH: TEST_FILE, + }, + ) assert result2["errors"] == {"base": "not_valid"} + await async_create_file(hass, TEST_FILE) + with patch("homeassistant.components.filesize.config_flow.pathlib.Path",), patch( "homeassistant.components.filesize.async_setup_entry", return_value=True, diff --git a/tests/components/filesize/test_init.py b/tests/components/filesize/test_init.py index 99285e56b6f..effab8f75d8 100644 --- a/tests/components/filesize/test_init.py +++ b/tests/components/filesize/test_init.py @@ -4,7 +4,7 @@ from homeassistant.config_entries import ConfigEntryState from homeassistant.const import CONF_FILE_PATH from homeassistant.core import HomeAssistant -from . import create_file +from . import async_create_file from tests.common import MockConfigEntry @@ -14,7 +14,7 @@ async def test_load_unload_config_entry( ) -> None: """Test the Filesize configuration entry loading/unloading.""" testfile = f"{tmpdir}/file.txt" - create_file(testfile) + await async_create_file(hass, testfile) hass.config.allowlist_external_dirs = {tmpdir} mock_config_entry.add_to_hass(hass) hass.config_entries.async_update_entry( @@ -54,7 +54,7 @@ async def test_not_valid_path_to_file( ) -> None: """Test that an invalid path is caught.""" testfile = f"{tmpdir}/file.txt" - create_file(testfile) + await async_create_file(hass, testfile) mock_config_entry.add_to_hass(hass) hass.config_entries.async_update_entry( mock_config_entry, unique_id=testfile, data={CONF_FILE_PATH: testfile} diff --git a/tests/components/filesize/test_sensor.py b/tests/components/filesize/test_sensor.py index 803aa96610d..5b072769f56 100644 --- a/tests/components/filesize/test_sensor.py +++ b/tests/components/filesize/test_sensor.py @@ -5,7 +5,7 @@ from homeassistant.const import CONF_FILE_PATH, STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_component import async_update_entity -from . import TEST_FILE, TEST_FILE_NAME, create_file +from . import TEST_FILE, TEST_FILE_NAME, async_create_file from tests.common import MockConfigEntry @@ -28,7 +28,7 @@ async def test_valid_path( ) -> None: """Test for a valid path.""" testfile = f"{tmpdir}/file.txt" - create_file(testfile) + await async_create_file(hass, testfile) hass.config.allowlist_external_dirs = {tmpdir} mock_config_entry.add_to_hass(hass) hass.config_entries.async_update_entry( @@ -50,7 +50,7 @@ async def test_state_unavailable( ) -> None: """Verify we handle state unavailable.""" testfile = f"{tmpdir}/file.txt" - create_file(testfile) + await async_create_file(hass, testfile) hass.config.allowlist_external_dirs = {tmpdir} mock_config_entry.add_to_hass(hass) hass.config_entries.async_update_entry(