Improve code quality filesize (#65240)

This commit is contained in:
G Johansson 2022-02-07 18:59:06 +01:00 committed by GitHub
parent 910b1f1ec8
commit 480ce84b8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 86 additions and 47 deletions

View File

@ -4,10 +4,14 @@ from __future__ import annotations
import datetime
import logging
import os
import pathlib
import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
from homeassistant.components.sensor import (
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
SensorEntity,
)
from homeassistant.const import DATA_MEGABYTES
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
@ -23,7 +27,7 @@ _LOGGER = logging.getLogger(__name__)
CONF_FILE_PATHS = "file_paths"
ICON = "mdi:file"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
{vol.Required(CONF_FILE_PATHS): vol.All(cv.ensure_list, [cv.isfile])}
)
@ -39,11 +43,23 @@ def setup_platform(
setup_reload_service(hass, DOMAIN, PLATFORMS)
sensors = []
paths = set()
for path in config[CONF_FILE_PATHS]:
try:
fullpath = str(pathlib.Path(path).absolute())
except OSError as error:
_LOGGER.error("Can not access file %s, error %s", path, error)
continue
if fullpath in paths:
continue
paths.add(fullpath)
if not hass.config.is_allowed_path(path):
_LOGGER.error("Filepath %s is not valid or allowed", path)
continue
sensors.append(Filesize(path))
sensors.append(Filesize(fullpath))
if sensors:
add_entities(sensors, True)
@ -52,48 +68,28 @@ def setup_platform(
class Filesize(SensorEntity):
"""Encapsulates file size information."""
def __init__(self, path):
_attr_native_unit_of_measurement = DATA_MEGABYTES
_attr_icon = ICON
def __init__(self, path: str) -> None:
"""Initialize the data object."""
self._path = path # Need to check its a valid path
self._size = None
self._last_updated = None
self._name = path.split("/")[-1]
self._unit_of_measurement = DATA_MEGABYTES
self._attr_name = path.split("/")[-1]
def update(self):
def update(self) -> None:
"""Update the sensor."""
statinfo = os.stat(self._path)
self._size = statinfo.st_size
last_updated = datetime.datetime.fromtimestamp(statinfo.st_mtime)
self._last_updated = last_updated.isoformat()
try:
statinfo = os.stat(self._path)
except OSError as error:
_LOGGER.error("Can not retrieve file statistics %s", error)
self._attr_native_value = None
return
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def native_value(self):
"""Return the size of the file in MB."""
decimals = 2
state_mb = round(self._size / 1e6, decimals)
return state_mb
@property
def icon(self):
"""Icon to use in the frontend, if any."""
return ICON
@property
def extra_state_attributes(self):
"""Return other details about the sensor state."""
return {
size = statinfo.st_size
last_updated = datetime.datetime.fromtimestamp(statinfo.st_mtime).isoformat()
self._attr_native_value = round(size / 1e6, 2) if size else None
self._attr_extra_state_attributes = {
"path": self._path,
"last_updated": self._last_updated,
"bytes": self._size,
"last_updated": last_updated,
"bytes": size,
}
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._unit_of_measurement

View File

@ -7,7 +7,9 @@ import pytest
from homeassistant import config as hass_config
from homeassistant.components.filesize import DOMAIN
from homeassistant.components.filesize.sensor import CONF_FILE_PATHS
from homeassistant.const import SERVICE_RELOAD
from homeassistant.const import SERVICE_RELOAD, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_component import async_update_entity
from homeassistant.setup import async_setup_component
from tests.common import get_fixture_path
@ -16,21 +18,21 @@ TEST_DIR = os.path.join(os.path.dirname(__file__))
TEST_FILE = os.path.join(TEST_DIR, "mock_file_test_filesize.txt")
def create_file(path):
def create_file(path) -> None:
"""Create a test file."""
with open(path, "w") as test_file:
test_file.write("test")
@pytest.fixture(autouse=True)
def remove_file():
def remove_file() -> None:
"""Remove test file."""
yield
if os.path.isfile(TEST_FILE):
os.remove(TEST_FILE)
async def test_invalid_path(hass):
async def test_invalid_path(hass: HomeAssistant) -> None:
"""Test that an invalid path is caught."""
config = {"sensor": {"platform": "filesize", CONF_FILE_PATHS: ["invalid_path"]}}
assert await async_setup_component(hass, "sensor", config)
@ -38,7 +40,21 @@ async def test_invalid_path(hass):
assert len(hass.states.async_entity_ids("sensor")) == 0
async def test_valid_path(hass):
async def test_cannot_access_file(hass: HomeAssistant) -> None:
"""Test that an invalid path is caught."""
config = {"sensor": {"platform": "filesize", CONF_FILE_PATHS: [TEST_FILE]}}
with patch(
"homeassistant.components.filesize.sensor.pathlib",
side_effect=OSError("Can not access"),
):
assert await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
assert len(hass.states.async_entity_ids("sensor")) == 0
async def test_valid_path(hass: HomeAssistant) -> None:
"""Test for a valid path."""
create_file(TEST_FILE)
config = {"sensor": {"platform": "filesize", CONF_FILE_PATHS: [TEST_FILE]}}
@ -51,7 +67,34 @@ async def test_valid_path(hass):
assert state.attributes.get("bytes") == 4
async def test_reload(hass, tmpdir):
async def test_state_unknown(hass: HomeAssistant, tmpdir: str) -> None:
"""Verify we handle state unavailable."""
create_file(TEST_FILE)
testfile = f"{tmpdir}/file"
await hass.async_add_executor_job(create_file, testfile)
with patch.object(hass.config, "is_allowed_path", return_value=True):
await async_setup_component(
hass,
"sensor",
{
"sensor": {
"platform": "filesize",
"file_paths": [testfile],
}
},
)
await hass.async_block_till_done()
assert hass.states.get("sensor.file")
await hass.async_add_executor_job(os.remove, testfile)
await async_update_entity(hass, "sensor.file")
state = hass.states.get("sensor.file")
assert state.state == STATE_UNKNOWN
async def test_reload(hass: HomeAssistant, tmpdir: str) -> None:
"""Verify we can reload filesize sensors."""
testfile = f"{tmpdir}/file"
await hass.async_add_executor_job(create_file, testfile)