Use unicode slugify (#19192)

* Update __init__.py

* Update setup.py

* Update requirements_all.txt

* Update __init__.py

* Update __init__.py

* Update __init__.py

* Update __init__.py

* Update __init__.py

* remove `-`

* fix packages

* Update package_constraints.txt

* Update __init__.py

* Update package_constraints.txt

* Update requirements_all.txt

* Update setup.py

* Fix tests

* Fix line issue

* fix all test

* fix type

* Fix lint
This commit is contained in:
Pascal Vizeli 2018-12-17 07:51:13 +01:00 committed by GitHub
parent cc90cba78a
commit 2bf36bb1db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 216 additions and 215 deletions

View File

@ -9,6 +9,7 @@ jinja2>=2.10
PyJWT==1.6.4 PyJWT==1.6.4
cryptography==2.3.1 cryptography==2.3.1
pip>=8.0.3 pip>=8.0.3
python-slugify==1.2.6
pytz>=2018.04 pytz>=2018.04
pyyaml>=3.13,<4 pyyaml>=3.13,<4
requests==2.20.1 requests==2.20.1

View File

@ -10,10 +10,11 @@ import random
import string import string
from functools import wraps from functools import wraps
from types import MappingProxyType from types import MappingProxyType
from unicodedata import normalize
from typing import (Any, Optional, TypeVar, Callable, KeysView, Union, # noqa from typing import (Any, Optional, TypeVar, Callable, KeysView, Union, # noqa
Iterable, List, Dict, Iterator, Coroutine, MutableSet) Iterable, List, Dict, Iterator, Coroutine, MutableSet)
import slugify as unicode_slug
from .dt import as_local, utcnow from .dt import as_local, utcnow
# pylint: disable=invalid-name # pylint: disable=invalid-name
@ -24,10 +25,6 @@ ENUM_T = TypeVar('ENUM_T', bound=enum.Enum)
RE_SANITIZE_FILENAME = re.compile(r'(~|\.\.|/|\\)') RE_SANITIZE_FILENAME = re.compile(r'(~|\.\.|/|\\)')
RE_SANITIZE_PATH = re.compile(r'(~|\.(\.)+)') RE_SANITIZE_PATH = re.compile(r'(~|\.(\.)+)')
RE_SLUGIFY = re.compile(r'[^a-z0-9_]+')
TBL_SLUGIFY = {
ord('ß'): 'ss'
}
def sanitize_filename(filename: str) -> str: def sanitize_filename(filename: str) -> str:
@ -42,13 +39,7 @@ def sanitize_path(path: str) -> str:
def slugify(text: str) -> str: def slugify(text: str) -> str:
"""Slugify a given text.""" """Slugify a given text."""
text = normalize('NFKD', text) return unicode_slug.slugify(text, separator='_') # type: ignore
text = text.lower()
text = text.replace(" ", "_")
text = text.translate(TBL_SLUGIFY)
text = RE_SLUGIFY.sub("", text)
return text
def repr_helper(inp: Any) -> str: def repr_helper(inp: Any) -> str:

View File

@ -10,6 +10,7 @@ jinja2>=2.10
PyJWT==1.6.4 PyJWT==1.6.4
cryptography==2.3.1 cryptography==2.3.1
pip>=8.0.3 pip>=8.0.3
python-slugify==1.2.6
pytz>=2018.04 pytz>=2018.04
pyyaml>=3.13,<4 pyyaml>=3.13,<4
requests==2.20.1 requests==2.20.1

View File

@ -45,6 +45,7 @@ REQUIRES = [
# PyJWT has loose dependency. We want the latest one. # PyJWT has loose dependency. We want the latest one.
'cryptography==2.3.1', 'cryptography==2.3.1',
'pip>=8.0.3', 'pip>=8.0.3',
'python-slugify==1.2.6',
'pytz>=2018.04', 'pytz>=2018.04',
'pyyaml>=3.13,<4', 'pyyaml>=3.13,<4',
'requests==2.20.1', 'requests==2.20.1',

View File

@ -408,10 +408,10 @@ async def test_see_state(hass, yaml_devices):
timedelta(seconds=0)) timedelta(seconds=0))
assert len(config) == 1 assert len(config) == 1
state = hass.states.get('device_tracker.examplecom') state = hass.states.get('device_tracker.example_com')
attrs = state.attributes attrs = state.attributes
assert state.state == 'Work' assert state.state == 'Work'
assert state.object_id == 'examplecom' assert state.object_id == 'example_com'
assert state.name == 'example.com' assert state.name == 'example.com'
assert attrs['friendly_name'] == 'example.com' assert attrs['friendly_name'] == 'example.com'
assert attrs['battery'] == 100 assert attrs['battery'] == 100

View File

@ -15,15 +15,19 @@ from homeassistant.components.device_tracker.meraki import URL
@pytest.fixture @pytest.fixture
def meraki_client(loop, hass, hass_client): def meraki_client(loop, hass, hass_client):
"""Meraki mock client.""" """Meraki mock client."""
assert loop.run_until_complete(async_setup_component( assert loop.run_until_complete(
hass, device_tracker.DOMAIN, { async_setup_component(
device_tracker.DOMAIN: { hass,
CONF_PLATFORM: 'meraki', device_tracker.DOMAIN,
CONF_VALIDATOR: 'validator', {
CONF_SECRET: 'secret' device_tracker.DOMAIN: {
CONF_PLATFORM: "meraki",
} CONF_VALIDATOR: "validator",
})) CONF_SECRET: "secret",
}
},
)
)
yield loop.run_until_complete(hass_client()) yield loop.run_until_complete(hass_client())
@ -34,53 +38,41 @@ def test_invalid_or_missing_data(mock_device_tracker_conf, meraki_client):
req = yield from meraki_client.get(URL) req = yield from meraki_client.get(URL)
text = yield from req.text() text = yield from req.text()
assert req.status == 200 assert req.status == 200
assert text == 'validator' assert text == "validator"
req = yield from meraki_client.post(URL, data=b"invalid") req = yield from meraki_client.post(URL, data=b"invalid")
text = yield from req.json() text = yield from req.json()
assert req.status == 400 assert req.status == 400
assert text['message'] == 'Invalid JSON' assert text["message"] == "Invalid JSON"
req = yield from meraki_client.post(URL, data=b"{}") req = yield from meraki_client.post(URL, data=b"{}")
text = yield from req.json() text = yield from req.json()
assert req.status == 422 assert req.status == 422
assert text['message'] == 'No secret' assert text["message"] == "No secret"
data = { data = {"version": "1.0", "secret": "secret"}
"version": "1.0",
"secret": "secret"
}
req = yield from meraki_client.post(URL, data=json.dumps(data)) req = yield from meraki_client.post(URL, data=json.dumps(data))
text = yield from req.json() text = yield from req.json()
assert req.status == 422 assert req.status == 422
assert text['message'] == 'Invalid version' assert text["message"] == "Invalid version"
data = { data = {"version": "2.0", "secret": "invalid"}
"version": "2.0",
"secret": "invalid"
}
req = yield from meraki_client.post(URL, data=json.dumps(data)) req = yield from meraki_client.post(URL, data=json.dumps(data))
text = yield from req.json() text = yield from req.json()
assert req.status == 422 assert req.status == 422
assert text['message'] == 'Invalid secret' assert text["message"] == "Invalid secret"
data = { data = {"version": "2.0", "secret": "secret", "type": "InvalidType"}
"version": "2.0",
"secret": "secret",
"type": "InvalidType"
}
req = yield from meraki_client.post(URL, data=json.dumps(data)) req = yield from meraki_client.post(URL, data=json.dumps(data))
text = yield from req.json() text = yield from req.json()
assert req.status == 422 assert req.status == 422
assert text['message'] == 'Invalid device type' assert text["message"] == "Invalid device type"
data = { data = {
"version": "2.0", "version": "2.0",
"secret": "secret", "secret": "secret",
"type": "BluetoothDevicesSeen", "type": "BluetoothDevicesSeen",
"data": { "data": {"observations": []},
"observations": []
}
} }
req = yield from meraki_client.post(URL, data=json.dumps(data)) req = yield from meraki_client.post(URL, data=json.dumps(data))
assert req.status == 200 assert req.status == 200
@ -102,13 +94,13 @@ def test_data_will_be_saved(mock_device_tracker_conf, hass, meraki_client):
"unc": "46.3610585", "unc": "46.3610585",
}, },
"seenTime": "2016-09-12T16:23:13Z", "seenTime": "2016-09-12T16:23:13Z",
"ssid": 'ssid', "ssid": "ssid",
"os": 'HA', "os": "HA",
"ipv6": '2607:f0d0:1002:51::4/64', "ipv6": "2607:f0d0:1002:51::4/64",
"clientMac": "00:26:ab:b8:a9:a4", "clientMac": "00:26:ab:b8:a9:a4",
"seenEpoch": "147369739", "seenEpoch": "147369739",
"rssi": "20", "rssi": "20",
"manufacturer": "Seiko Epson" "manufacturer": "Seiko Epson",
}, },
{ {
"location": { "location": {
@ -117,24 +109,26 @@ def test_data_will_be_saved(mock_device_tracker_conf, hass, meraki_client):
"unc": "46.3610585", "unc": "46.3610585",
}, },
"seenTime": "2016-09-12T16:21:13Z", "seenTime": "2016-09-12T16:21:13Z",
"ssid": 'ssid', "ssid": "ssid",
"os": 'HA', "os": "HA",
"ipv4": '192.168.0.1', "ipv4": "192.168.0.1",
"clientMac": "00:26:ab:b8:a9:a5", "clientMac": "00:26:ab:b8:a9:a5",
"seenEpoch": "147369750", "seenEpoch": "147369750",
"rssi": "20", "rssi": "20",
"manufacturer": "Seiko Epson" "manufacturer": "Seiko Epson",
} },
] ]
} },
} }
req = yield from meraki_client.post(URL, data=json.dumps(data)) req = yield from meraki_client.post(URL, data=json.dumps(data))
assert req.status == 200 assert req.status == 200
yield from hass.async_block_till_done() yield from hass.async_block_till_done()
state_name = hass.states.get('{}.{}'.format('device_tracker', state_name = hass.states.get(
'0026abb8a9a4')).state "{}.{}".format("device_tracker", "00_26_ab_b8_a9_a4")
assert 'home' == state_name ).state
assert "home" == state_name
state_name = hass.states.get('{}.{}'.format('device_tracker', state_name = hass.states.get(
'0026abb8a9a5')).state "{}.{}".format("device_tracker", "00_26_ab_b8_a9_a5")
assert 'home' == state_name ).state
assert "home" == state_name

View File

@ -252,10 +252,10 @@ WAYPOINT_MESSAGE = {
} }
WAYPOINT_ENTITY_NAMES = [ WAYPOINT_ENTITY_NAMES = [
'zone.greg_phone__exp_wayp1', 'zone.greg_phone_exp_wayp1',
'zone.greg_phone__exp_wayp2', 'zone.greg_phone_exp_wayp2',
'zone.ram_phone__exp_wayp1', 'zone.ram_phone_exp_wayp1',
'zone.ram_phone__exp_wayp2', 'zone.ram_phone_exp_wayp2',
] ]
LWT_MESSAGE = { LWT_MESSAGE = {
@ -407,7 +407,7 @@ def assert_mobile_tracker_accuracy(hass, accuracy, beacon=IBEACON_DEVICE):
async def test_location_invalid_devid(hass, context): async def test_location_invalid_devid(hass, context):
"""Test the update of a location.""" """Test the update of a location."""
await send_message(hass, 'owntracks/paulus/nexus-5x', LOCATION_MESSAGE) await send_message(hass, 'owntracks/paulus/nexus-5x', LOCATION_MESSAGE)
state = hass.states.get('device_tracker.paulus_nexus5x') state = hass.states.get('device_tracker.paulus_nexus_5x')
assert state.state == 'outer' assert state.state == 'outer'

View File

@ -8,51 +8,53 @@ from unittest.mock import patch
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.sensor.awair import ( from homeassistant.components.sensor.awair import (
ATTR_LAST_API_UPDATE, ATTR_TIMESTAMP, DEVICE_CLASS_CARBON_DIOXIDE, ATTR_LAST_API_UPDATE,
DEVICE_CLASS_PM2_5, DEVICE_CLASS_SCORE, ATTR_TIMESTAMP,
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS) DEVICE_CLASS_CARBON_DIOXIDE,
DEVICE_CLASS_PM2_5,
DEVICE_CLASS_SCORE,
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
)
from homeassistant.const import ( from homeassistant.const import (
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, STATE_UNAVAILABLE, DEVICE_CLASS_HUMIDITY,
TEMP_CELSIUS) DEVICE_CLASS_TEMPERATURE,
STATE_UNAVAILABLE,
TEMP_CELSIUS,
)
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import parse_datetime, utcnow from homeassistant.util.dt import parse_datetime, utcnow
from tests.common import async_fire_time_changed, load_fixture, mock_coro from tests.common import async_fire_time_changed, load_fixture, mock_coro
DISCOVERY_CONFIG = { DISCOVERY_CONFIG = {"sensor": {"platform": "awair", "access_token": "qwerty"}}
'sensor': {
'platform': 'awair',
'access_token': 'qwerty',
}
}
MANUAL_CONFIG = { MANUAL_CONFIG = {
'sensor': { "sensor": {
'platform': 'awair', "platform": "awair",
'access_token': 'qwerty', "access_token": "qwerty",
'devices': [ "devices": [{"uuid": "awair_foo"}],
{'uuid': 'awair_foo'}
]
} }
} }
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
NOW = utcnow() NOW = utcnow()
AIR_DATA_FIXTURE = json.loads(load_fixture('awair_air_data_latest.json')) AIR_DATA_FIXTURE = json.loads(load_fixture("awair_air_data_latest.json"))
AIR_DATA_FIXTURE[0][ATTR_TIMESTAMP] = str(NOW) AIR_DATA_FIXTURE[0][ATTR_TIMESTAMP] = str(NOW)
AIR_DATA_FIXTURE_UPDATED = json.loads( AIR_DATA_FIXTURE_UPDATED = json.loads(
load_fixture('awair_air_data_latest_updated.json')) load_fixture("awair_air_data_latest_updated.json")
)
AIR_DATA_FIXTURE_UPDATED[0][ATTR_TIMESTAMP] = str(NOW + timedelta(minutes=5)) AIR_DATA_FIXTURE_UPDATED[0][ATTR_TIMESTAMP] = str(NOW + timedelta(minutes=5))
@contextmanager @contextmanager
def alter_time(retval): def alter_time(retval):
"""Manage multiple time mocks.""" """Manage multiple time mocks."""
patch_one = patch('homeassistant.util.dt.utcnow', return_value=retval) patch_one = patch("homeassistant.util.dt.utcnow", return_value=retval)
patch_two = patch('homeassistant.util.utcnow', return_value=retval) patch_two = patch("homeassistant.util.utcnow", return_value=retval)
patch_three = patch('homeassistant.components.sensor.awair.dt.utcnow', patch_three = patch(
return_value=retval) "homeassistant.components.sensor.awair.dt.utcnow", return_value=retval
)
with patch_one, patch_two, patch_three: with patch_one, patch_two, patch_three:
yield yield
@ -60,13 +62,14 @@ def alter_time(retval):
async def setup_awair(hass, config=None): async def setup_awair(hass, config=None):
"""Load the Awair platform.""" """Load the Awair platform."""
devices_json = json.loads(load_fixture('awair_devices.json')) devices_json = json.loads(load_fixture("awair_devices.json"))
devices_mock = mock_coro(devices_json) devices_mock = mock_coro(devices_json)
devices_patch = patch('python_awair.AwairClient.devices', devices_patch = patch(
return_value=devices_mock) "python_awair.AwairClient.devices", return_value=devices_mock)
air_data_mock = mock_coro(AIR_DATA_FIXTURE) air_data_mock = mock_coro(AIR_DATA_FIXTURE)
air_data_patch = patch('python_awair.AwairClient.air_data_latest', air_data_patch = patch(
return_value=air_data_mock) "python_awair.AwairClient.air_data_latest", return_value=air_data_mock
)
if config is None: if config is None:
config = DISCOVERY_CONFIG config = DISCOVERY_CONFIG
@ -84,8 +87,8 @@ async def test_platform_manually_configured(hass):
# Ensure that we loaded the device with uuid 'awair_foo', not the # Ensure that we loaded the device with uuid 'awair_foo', not the
# 'awair_12345' device that we stub out for API device discovery # 'awair_12345' device that we stub out for API device discovery
entity = hass.data[SENSOR_DOMAIN].get_entity('sensor.awair_co2') entity = hass.data[SENSOR_DOMAIN].get_entity("sensor.awair_co2")
assert entity.unique_id == 'awair_foo_CO2' assert entity.unique_id == "awair_foo_CO2"
async def test_platform_automatically_configured(hass): async def test_platform_automatically_configured(hass):
@ -96,34 +99,40 @@ async def test_platform_automatically_configured(hass):
# Ensure that we loaded the device with uuid 'awair_12345', which is # Ensure that we loaded the device with uuid 'awair_12345', which is
# the device that we stub out for API device discovery # the device that we stub out for API device discovery
entity = hass.data[SENSOR_DOMAIN].get_entity('sensor.awair_co2') entity = hass.data[SENSOR_DOMAIN].get_entity("sensor.awair_co2")
assert entity.unique_id == 'awair_12345_CO2' assert entity.unique_id == "awair_12345_CO2"
async def test_bad_platform_setup(hass): async def test_bad_platform_setup(hass):
"""Tests that we throw correct exceptions when setting up Awair.""" """Tests that we throw correct exceptions when setting up Awair."""
from python_awair import AwairClient from python_awair import AwairClient
auth_patch = patch('python_awair.AwairClient.devices', auth_patch = patch(
side_effect=AwairClient.AuthError) "python_awair.AwairClient.devices",
rate_patch = patch('python_awair.AwairClient.devices', side_effect=AwairClient.AuthError
side_effect=AwairClient.RatelimitError) )
generic_patch = patch('python_awair.AwairClient.devices', rate_patch = patch(
side_effect=AwairClient.GenericError) "python_awair.AwairClient.devices",
side_effect=AwairClient.RatelimitError
)
generic_patch = patch(
"python_awair.AwairClient.devices",
side_effect=AwairClient.GenericError
)
with auth_patch: with auth_patch:
assert await async_setup_component(hass, SENSOR_DOMAIN, assert await async_setup_component(
DISCOVERY_CONFIG) hass, SENSOR_DOMAIN, DISCOVERY_CONFIG)
assert not hass.states.async_all() assert not hass.states.async_all()
with rate_patch: with rate_patch:
assert await async_setup_component(hass, SENSOR_DOMAIN, assert await async_setup_component(
DISCOVERY_CONFIG) hass, SENSOR_DOMAIN, DISCOVERY_CONFIG)
assert not hass.states.async_all() assert not hass.states.async_all()
with generic_patch: with generic_patch:
assert await async_setup_component(hass, SENSOR_DOMAIN, assert await async_setup_component(
DISCOVERY_CONFIG) hass, SENSOR_DOMAIN, DISCOVERY_CONFIG)
assert not hass.states.async_all() assert not hass.states.async_all()
@ -131,60 +140,62 @@ async def test_awair_misc_attributes(hass):
"""Test that desired attributes are set.""" """Test that desired attributes are set."""
await setup_awair(hass) await setup_awair(hass)
attributes = hass.states.get('sensor.awair_co2').attributes attributes = hass.states.get("sensor.awair_co2").attributes
assert (attributes[ATTR_LAST_API_UPDATE] == assert attributes[ATTR_LAST_API_UPDATE] == parse_datetime(
parse_datetime(AIR_DATA_FIXTURE[0][ATTR_TIMESTAMP])) AIR_DATA_FIXTURE[0][ATTR_TIMESTAMP]
)
async def test_awair_score(hass): async def test_awair_score(hass):
"""Test that we create a sensor for the 'Awair score'.""" """Test that we create a sensor for the 'Awair score'."""
await setup_awair(hass) await setup_awair(hass)
sensor = hass.states.get('sensor.awair_score') sensor = hass.states.get("sensor.awair_score")
assert sensor.state == '78' assert sensor.state == "78"
assert sensor.attributes['device_class'] == DEVICE_CLASS_SCORE assert sensor.attributes["device_class"] == DEVICE_CLASS_SCORE
assert sensor.attributes['unit_of_measurement'] == '%' assert sensor.attributes["unit_of_measurement"] == "%"
async def test_awair_temp(hass): async def test_awair_temp(hass):
"""Test that we create a temperature sensor.""" """Test that we create a temperature sensor."""
await setup_awair(hass) await setup_awair(hass)
sensor = hass.states.get('sensor.awair_temperature') sensor = hass.states.get("sensor.awair_temperature")
assert sensor.state == '22.4' assert sensor.state == "22.4"
assert sensor.attributes['device_class'] == DEVICE_CLASS_TEMPERATURE assert sensor.attributes["device_class"] == DEVICE_CLASS_TEMPERATURE
assert sensor.attributes['unit_of_measurement'] == TEMP_CELSIUS assert sensor.attributes["unit_of_measurement"] == TEMP_CELSIUS
async def test_awair_humid(hass): async def test_awair_humid(hass):
"""Test that we create a humidity sensor.""" """Test that we create a humidity sensor."""
await setup_awair(hass) await setup_awair(hass)
sensor = hass.states.get('sensor.awair_humidity') sensor = hass.states.get("sensor.awair_humidity")
assert sensor.state == '32.73' assert sensor.state == "32.73"
assert sensor.attributes['device_class'] == DEVICE_CLASS_HUMIDITY assert sensor.attributes["device_class"] == DEVICE_CLASS_HUMIDITY
assert sensor.attributes['unit_of_measurement'] == '%' assert sensor.attributes["unit_of_measurement"] == "%"
async def test_awair_co2(hass): async def test_awair_co2(hass):
"""Test that we create a CO2 sensor.""" """Test that we create a CO2 sensor."""
await setup_awair(hass) await setup_awair(hass)
sensor = hass.states.get('sensor.awair_co2') sensor = hass.states.get("sensor.awair_co2")
assert sensor.state == '612' assert sensor.state == "612"
assert sensor.attributes['device_class'] == DEVICE_CLASS_CARBON_DIOXIDE assert sensor.attributes["device_class"] == \
assert sensor.attributes['unit_of_measurement'] == 'ppm' DEVICE_CLASS_CARBON_DIOXIDE
assert sensor.attributes["unit_of_measurement"] == "ppm"
async def test_awair_voc(hass): async def test_awair_voc(hass):
"""Test that we create a CO2 sensor.""" """Test that we create a CO2 sensor."""
await setup_awair(hass) await setup_awair(hass)
sensor = hass.states.get('sensor.awair_voc') sensor = hass.states.get("sensor.awair_voc")
assert sensor.state == '1012' assert sensor.state == "1012"
assert (sensor.attributes['device_class'] == assert sensor.attributes["device_class"] == \
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS) DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS
assert sensor.attributes['unit_of_measurement'] == 'ppb' assert sensor.attributes["unit_of_measurement"] == "ppb"
async def test_awair_dust(hass): async def test_awair_dust(hass):
@ -193,10 +204,10 @@ async def test_awair_dust(hass):
# The Awair Gen1 that we mock actually returns 'DUST', but that # The Awair Gen1 that we mock actually returns 'DUST', but that
# is mapped to pm25 internally so that it shows up in Homekit # is mapped to pm25 internally so that it shows up in Homekit
sensor = hass.states.get('sensor.awair_pm25') sensor = hass.states.get("sensor.awair_pm2_5")
assert sensor.state == '6.2' assert sensor.state == "6.2"
assert sensor.attributes['device_class'] == DEVICE_CLASS_PM2_5 assert sensor.attributes["device_class"] == DEVICE_CLASS_PM2_5
assert sensor.attributes['unit_of_measurement'] == 'µg/m3' assert sensor.attributes["unit_of_measurement"] == "µg/m3"
async def test_awair_unsupported_sensors(hass): async def test_awair_unsupported_sensors(hass):
@ -206,36 +217,40 @@ async def test_awair_unsupported_sensors(hass):
# Our tests mock an Awair Gen 1 device, which should never return # Our tests mock an Awair Gen 1 device, which should never return
# PM10 sensor readings. Assert that we didn't create a pm10 sensor, # PM10 sensor readings. Assert that we didn't create a pm10 sensor,
# which could happen if someone were ever to refactor incorrectly. # which could happen if someone were ever to refactor incorrectly.
assert hass.states.get('sensor.awair_pm10') is None assert hass.states.get("sensor.awair_pm10") is None
async def test_availability(hass): async def test_availability(hass):
"""Ensure that we mark the component available/unavailable correctly.""" """Ensure that we mark the component available/unavailable correctly."""
await setup_awair(hass) await setup_awair(hass)
assert hass.states.get('sensor.awair_score').state == '78' assert hass.states.get("sensor.awair_score").state == "78"
future = NOW + timedelta(minutes=30) future = NOW + timedelta(minutes=30)
data_patch = patch('python_awair.AwairClient.air_data_latest', data_patch = patch(
return_value=mock_coro(AIR_DATA_FIXTURE)) "python_awair.AwairClient.air_data_latest",
return_value=mock_coro(AIR_DATA_FIXTURE),
)
with data_patch, alter_time(future): with data_patch, alter_time(future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get('sensor.awair_score').state == STATE_UNAVAILABLE assert hass.states.get("sensor.awair_score").state == STATE_UNAVAILABLE
future = NOW + timedelta(hours=1) future = NOW + timedelta(hours=1)
fixture = AIR_DATA_FIXTURE_UPDATED fixture = AIR_DATA_FIXTURE_UPDATED
fixture[0][ATTR_TIMESTAMP] = str(future) fixture[0][ATTR_TIMESTAMP] = str(future)
data_patch = patch('python_awair.AwairClient.air_data_latest', data_patch = patch(
return_value=mock_coro(fixture)) "python_awair.AwairClient.air_data_latest",
return_value=mock_coro(fixture)
)
with data_patch, alter_time(future): with data_patch, alter_time(future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get('sensor.awair_score').state == '79' assert hass.states.get("sensor.awair_score").state == "79"
async def test_async_update(hass): async def test_async_update(hass):
@ -243,21 +258,23 @@ async def test_async_update(hass):
await setup_awair(hass) await setup_awair(hass)
future = NOW + timedelta(minutes=10) future = NOW + timedelta(minutes=10)
data_patch = patch('python_awair.AwairClient.air_data_latest', data_patch = patch(
return_value=mock_coro(AIR_DATA_FIXTURE_UPDATED)) "python_awair.AwairClient.air_data_latest",
return_value=mock_coro(AIR_DATA_FIXTURE_UPDATED),
)
with data_patch, alter_time(future): with data_patch, alter_time(future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
score_sensor = hass.states.get('sensor.awair_score') score_sensor = hass.states.get("sensor.awair_score")
assert score_sensor.state == '79' assert score_sensor.state == "79"
assert hass.states.get('sensor.awair_temperature').state == '23.4' assert hass.states.get("sensor.awair_temperature").state == "23.4"
assert hass.states.get('sensor.awair_humidity').state == '33.73' assert hass.states.get("sensor.awair_humidity").state == "33.73"
assert hass.states.get('sensor.awair_co2').state == '613' assert hass.states.get("sensor.awair_co2").state == "613"
assert hass.states.get('sensor.awair_voc').state == '1013' assert hass.states.get("sensor.awair_voc").state == "1013"
assert hass.states.get('sensor.awair_pm25').state == '7.2' assert hass.states.get("sensor.awair_pm2_5").state == "7.2"
async def test_throttle_async_update(hass): async def test_throttle_async_update(hass):
@ -265,18 +282,20 @@ async def test_throttle_async_update(hass):
await setup_awair(hass) await setup_awair(hass)
future = NOW + timedelta(minutes=1) future = NOW + timedelta(minutes=1)
data_patch = patch('python_awair.AwairClient.air_data_latest', data_patch = patch(
return_value=mock_coro(AIR_DATA_FIXTURE_UPDATED)) "python_awair.AwairClient.air_data_latest",
return_value=mock_coro(AIR_DATA_FIXTURE_UPDATED),
)
with data_patch, alter_time(future): with data_patch, alter_time(future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get('sensor.awair_score').state == '78' assert hass.states.get("sensor.awair_score").state == "78"
future = NOW + timedelta(minutes=15) future = NOW + timedelta(minutes=15)
with data_patch, alter_time(future): with data_patch, alter_time(future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get('sensor.awair_score').state == '79' assert hass.states.get("sensor.awair_score").state == "79"

View File

@ -8,12 +8,12 @@ from tests.common import get_test_home_assistant
TEST_DIR = os.path.join(os.path.dirname(__file__)) TEST_DIR = os.path.join(os.path.dirname(__file__))
TEST_FILE = os.path.join(TEST_DIR, 'mock_file_test_filesize.txt') TEST_FILE = os.path.join(TEST_DIR, "mock_file_test_filesize.txt")
def create_file(path): def create_file(path):
"""Create a test file.""" """Create a test file."""
with open(path, 'w') as test_file: with open(path, "w") as test_file:
test_file.write("test") test_file.write("test")
@ -34,23 +34,23 @@ class TestFileSensor(unittest.TestCase):
def test_invalid_path(self): def test_invalid_path(self):
"""Test that an invalid path is caught.""" """Test that an invalid path is caught."""
config = { config = {
'sensor': { "sensor": {
'platform': 'filesize', "platform": "filesize", CONF_FILE_PATHS: ["invalid_path"]
CONF_FILE_PATHS: ['invalid_path']} }
} }
assert setup_component(self.hass, 'sensor', config) assert setup_component(self.hass, "sensor", config)
assert len(self.hass.states.entity_ids()) == 0 assert len(self.hass.states.entity_ids()) == 0
def test_valid_path(self): def test_valid_path(self):
"""Test for a valid path.""" """Test for a valid path."""
create_file(TEST_FILE) create_file(TEST_FILE)
config = { config = {
'sensor': { "sensor": {
'platform': 'filesize', "platform": "filesize", CONF_FILE_PATHS: [TEST_FILE]
CONF_FILE_PATHS: [TEST_FILE]} }
} }
assert setup_component(self.hass, 'sensor', config) assert setup_component(self.hass, "sensor", config)
assert len(self.hass.states.entity_ids()) == 1 assert len(self.hass.states.entity_ids()) == 1
state = self.hass.states.get('sensor.mock_file_test_filesizetxt') state = self.hass.states.get("sensor.mock_file_test_filesize_txt")
assert state.state == '0.0' assert state.state == "0.0"
assert state.attributes.get('bytes') == 4 assert state.attributes.get("bytes") == 4

View File

@ -32,7 +32,7 @@ async def test_default_setup(hass, aioclient_mock):
metrics = {'co2': ['1232.0', 'ppm'], metrics = {'co2': ['1232.0', 'ppm'],
'temperature': ['21.1', TEMP_CELSIUS], 'temperature': ['21.1', TEMP_CELSIUS],
'humidity': ['49.5', '%'], 'humidity': ['49.5', '%'],
'pm25': ['144.8', 'µg/m3'], 'pm2_5': ['144.8', 'µg/m3'],
'voc': ['340.7', 'ppb'], 'voc': ['340.7', 'ppb'],
'index': ['138.9', '%']} 'index': ['138.9', '%']}

View File

@ -155,7 +155,7 @@ class TestHDDTempSensor(unittest.TestCase):
"""Test hddtemp one disk configuration.""" """Test hddtemp one disk configuration."""
assert setup_component(self.hass, 'sensor', VALID_CONFIG_ONE_DISK) assert setup_component(self.hass, 'sensor', VALID_CONFIG_ONE_DISK)
state = self.hass.states.get('sensor.hd_temperature_devsdd1') state = self.hass.states.get('sensor.hd_temperature_dev_sdd1')
reference = self.reference[state.attributes.get('device')] reference = self.reference[state.attributes.get('device')]
@ -173,7 +173,7 @@ class TestHDDTempSensor(unittest.TestCase):
assert setup_component(self.hass, 'sensor', VALID_CONFIG_WRONG_DISK) assert setup_component(self.hass, 'sensor', VALID_CONFIG_WRONG_DISK)
assert len(self.hass.states.all()) == 1 assert len(self.hass.states.all()) == 1
state = self.hass.states.get('sensor.hd_temperature_devsdx1') state = self.hass.states.get('sensor.hd_temperature_dev_sdx1')
assert state.attributes.get('friendly_name') == \ assert state.attributes.get('friendly_name') == \
'HD Temperature ' + '/dev/sdx1' 'HD Temperature ' + '/dev/sdx1'
@ -183,9 +183,9 @@ class TestHDDTempSensor(unittest.TestCase):
assert setup_component(self.hass, assert setup_component(self.hass,
'sensor', VALID_CONFIG_MULTIPLE_DISKS) 'sensor', VALID_CONFIG_MULTIPLE_DISKS)
for sensor in ['sensor.hd_temperature_devsda1', for sensor in ['sensor.hd_temperature_dev_sda1',
'sensor.hd_temperature_devsdb1', 'sensor.hd_temperature_dev_sdb1',
'sensor.hd_temperature_devsdc1']: 'sensor.hd_temperature_dev_sdc1']:
state = self.hass.states.get(sensor) state = self.hass.states.get(sensor)

View File

@ -34,7 +34,7 @@ class TestOpenHardwareMonitorSetup(unittest.TestCase):
assert len(entities) == 38 assert len(entities) == 38
state = self.hass.states.get( state = self.hass.states.get(
'sensor.testpc_intel_core_i77700_clocks_bus_speed') 'sensor.test_pc_intel_core_i7_7700_clocks_bus_speed')
assert state is not None assert state is not None
assert state.state == '100' assert state.state == '100'

View File

@ -47,51 +47,51 @@ def test_capped_setup(hass, aioclient_mock):
yield from async_setup_component(hass, 'sensor', {'sensor': config}) yield from async_setup_component(hass, 'sensor', {'sensor': config})
state = hass.states.get('sensor.startca_usage_ratio') state = hass.states.get('sensor.start_ca_usage_ratio')
assert state.attributes.get('unit_of_measurement') == '%' assert state.attributes.get('unit_of_measurement') == '%'
assert state.state == '76.24' assert state.state == '76.24'
state = hass.states.get('sensor.startca_usage') state = hass.states.get('sensor.start_ca_usage')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_data_limit') state = hass.states.get('sensor.start_ca_data_limit')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '400' assert state.state == '400'
state = hass.states.get('sensor.startca_used_download') state = hass.states.get('sensor.start_ca_used_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_used_upload') state = hass.states.get('sensor.start_ca_used_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '6.48' assert state.state == '6.48'
state = hass.states.get('sensor.startca_used_total') state = hass.states.get('sensor.start_ca_used_total')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '311.43' assert state.state == '311.43'
state = hass.states.get('sensor.startca_grace_download') state = hass.states.get('sensor.start_ca_grace_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_grace_upload') state = hass.states.get('sensor.start_ca_grace_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '6.48' assert state.state == '6.48'
state = hass.states.get('sensor.startca_grace_total') state = hass.states.get('sensor.start_ca_grace_total')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '311.43' assert state.state == '311.43'
state = hass.states.get('sensor.startca_total_download') state = hass.states.get('sensor.start_ca_total_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_total_upload') state = hass.states.get('sensor.start_ca_total_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '6.48' assert state.state == '6.48'
state = hass.states.get('sensor.startca_remaining') state = hass.states.get('sensor.start_ca_remaining')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '95.05' assert state.state == '95.05'
@ -138,51 +138,51 @@ def test_unlimited_setup(hass, aioclient_mock):
yield from async_setup_component(hass, 'sensor', {'sensor': config}) yield from async_setup_component(hass, 'sensor', {'sensor': config})
state = hass.states.get('sensor.startca_usage_ratio') state = hass.states.get('sensor.start_ca_usage_ratio')
assert state.attributes.get('unit_of_measurement') == '%' assert state.attributes.get('unit_of_measurement') == '%'
assert state.state == '0' assert state.state == '0'
state = hass.states.get('sensor.startca_usage') state = hass.states.get('sensor.start_ca_usage')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '0.0' assert state.state == '0.0'
state = hass.states.get('sensor.startca_data_limit') state = hass.states.get('sensor.start_ca_data_limit')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == 'inf' assert state.state == 'inf'
state = hass.states.get('sensor.startca_used_download') state = hass.states.get('sensor.start_ca_used_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '0.0' assert state.state == '0.0'
state = hass.states.get('sensor.startca_used_upload') state = hass.states.get('sensor.start_ca_used_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '0.0' assert state.state == '0.0'
state = hass.states.get('sensor.startca_used_total') state = hass.states.get('sensor.start_ca_used_total')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '0.0' assert state.state == '0.0'
state = hass.states.get('sensor.startca_grace_download') state = hass.states.get('sensor.start_ca_grace_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_grace_upload') state = hass.states.get('sensor.start_ca_grace_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '6.48' assert state.state == '6.48'
state = hass.states.get('sensor.startca_grace_total') state = hass.states.get('sensor.start_ca_grace_total')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '311.43' assert state.state == '311.43'
state = hass.states.get('sensor.startca_total_download') state = hass.states.get('sensor.start_ca_total_download')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '304.95' assert state.state == '304.95'
state = hass.states.get('sensor.startca_total_upload') state = hass.states.get('sensor.start_ca_total_upload')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == '6.48' assert state.state == '6.48'
state = hass.states.get('sensor.startca_remaining') state = hass.states.get('sensor.start_ca_remaining')
assert state.attributes.get('unit_of_measurement') == 'GB' assert state.attributes.get('unit_of_measurement') == 'GB'
assert state.state == 'inf' assert state.state == 'inf'

View File

@ -33,14 +33,6 @@ def test_generate_entity_id_given_keys():
'test.another_entity']) == 'test.overwrite_hidden_true' 'test.another_entity']) == 'test.overwrite_hidden_true'
def test_generate_entity_id_with_nonlatin_name():
"""Test generate_entity_id given a name containing non-latin characters."""
fmt = 'test.{}'
assert entity.generate_entity_id(
fmt, 'ホームアシスタント', current_ids=[]
) == 'test.unnamed_device'
def test_async_update_support(hass): def test_async_update_support(hass):
"""Test async update getting called.""" """Test async update getting called."""
sync_update = [] sync_update = []

View File

@ -27,17 +27,19 @@ class TestUtil(unittest.TestCase):
def test_slugify(self): def test_slugify(self):
"""Test slugify.""" """Test slugify."""
assert "test" == util.slugify("T-!@#$!#@$!$est") assert "t_est" == util.slugify("T-!@#$!#@$!$est")
assert "test_more" == util.slugify("Test More") assert "test_more" == util.slugify("Test More")
assert "test_more" == util.slugify("Test_(More)") assert "test_more" == util.slugify("Test_(More)")
assert "test_more" == util.slugify("Tèst_Mörê") assert "test_more" == util.slugify("Tèst_Mörê")
assert "b827eb000000" == util.slugify("B8:27:EB:00:00:00") assert "b8_27_eb_00_00_00" == util.slugify("B8:27:EB:00:00:00")
assert "testcom" == util.slugify("test.com") assert "test_com" == util.slugify("test.com")
assert "greg_phone__exp_wayp1" == \ assert "greg_phone_exp_wayp1" == \
util.slugify("greg_phone - exp_wayp1") util.slugify("greg_phone - exp_wayp1")
assert "we_are_we_are_a_test_calendar" == \ assert "we_are_we_are_a_test_calendar" == \
util.slugify("We are, we are, a... Test Calendar") util.slugify("We are, we are, a... Test Calendar")
assert "test_aouss_aou" == util.slugify("Tèst_äöüß_ÄÖÜ") assert "test_aouss_aou" == util.slugify("Tèst_äöüß_ÄÖÜ")
assert "ying_shi_ma" == util.slugify("影師嗎")
assert "keihuonto" == util.slugify("けいふぉんと")
def test_repr_helper(self): def test_repr_helper(self):
"""Test repr_helper.""" """Test repr_helper."""