Improve type hints in core helper tests (#120096)
This commit is contained in:
parent
4aecd23f1d
commit
648ef94888
8 changed files with 71 additions and 59 deletions
|
@ -37,7 +37,7 @@ def track_changes(coll: collection.ObservableCollection):
|
|||
class MockEntity(collection.CollectionEntity):
|
||||
"""Entity that is config based."""
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, config: ConfigType) -> None:
|
||||
"""Initialize entity."""
|
||||
self._config = config
|
||||
|
||||
|
@ -52,21 +52,21 @@ class MockEntity(collection.CollectionEntity):
|
|||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
def unique_id(self) -> str:
|
||||
"""Return unique ID of entity."""
|
||||
return self._config["id"]
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def name(self) -> str:
|
||||
"""Return name of entity."""
|
||||
return self._config["name"]
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> str:
|
||||
"""Return state of entity."""
|
||||
return self._config["state"]
|
||||
|
||||
async def async_update_config(self, config):
|
||||
async def async_update_config(self, config: ConfigType) -> None:
|
||||
"""Update entity config."""
|
||||
self._config = config
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -1240,7 +1240,7 @@ def test_enum() -> None:
|
|||
schema("value3")
|
||||
|
||||
|
||||
def test_socket_timeout():
|
||||
def test_socket_timeout() -> None:
|
||||
"""Test socket timeout validator."""
|
||||
schema = vol.Schema(cv.socket_timeout)
|
||||
|
||||
|
@ -1679,7 +1679,7 @@ def test_color_hex() -> None:
|
|||
cv.color_hex(123456)
|
||||
|
||||
|
||||
def test_determine_script_action_ambiguous():
|
||||
def test_determine_script_action_ambiguous() -> None:
|
||||
"""Test determine script action with ambiguous actions."""
|
||||
assert (
|
||||
cv.determine_script_action(
|
||||
|
@ -1696,6 +1696,6 @@ def test_determine_script_action_ambiguous():
|
|||
)
|
||||
|
||||
|
||||
def test_determine_script_action_non_ambiguous():
|
||||
def test_determine_script_action_non_ambiguous() -> None:
|
||||
"""Test determine script action with a non ambiguous action."""
|
||||
assert cv.determine_script_action({"delay": "00:00:05"}) == "delay"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
from unittest.mock import AsyncMock, call, patch
|
||||
|
||||
import pytest
|
||||
from typing_extensions import Generator
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.core import EVENT_HOMEASSISTANT_STARTED, CoreState, HomeAssistant
|
||||
|
@ -10,7 +11,7 @@ from homeassistant.helpers import discovery_flow
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_flow_init(hass):
|
||||
def mock_flow_init(hass: HomeAssistant) -> Generator[AsyncMock]:
|
||||
"""Mock hass.config_entries.flow.async_init."""
|
||||
with patch.object(
|
||||
hass.config_entries.flow, "async_init", return_value=AsyncMock()
|
||||
|
@ -18,7 +19,9 @@ def mock_flow_init(hass):
|
|||
yield mock_init
|
||||
|
||||
|
||||
async def test_async_create_flow(hass: HomeAssistant, mock_flow_init) -> None:
|
||||
async def test_async_create_flow(
|
||||
hass: HomeAssistant, mock_flow_init: AsyncMock
|
||||
) -> None:
|
||||
"""Test we can create a flow."""
|
||||
discovery_flow.async_create_flow(
|
||||
hass,
|
||||
|
@ -36,7 +39,7 @@ async def test_async_create_flow(hass: HomeAssistant, mock_flow_init) -> None:
|
|||
|
||||
|
||||
async def test_async_create_flow_deferred_until_started(
|
||||
hass: HomeAssistant, mock_flow_init
|
||||
hass: HomeAssistant, mock_flow_init: AsyncMock
|
||||
) -> None:
|
||||
"""Test flows are deferred until started."""
|
||||
hass.set_state(CoreState.stopped)
|
||||
|
@ -59,7 +62,7 @@ async def test_async_create_flow_deferred_until_started(
|
|||
|
||||
|
||||
async def test_async_create_flow_checks_existing_flows_after_startup(
|
||||
hass: HomeAssistant, mock_flow_init
|
||||
hass: HomeAssistant, mock_flow_init: AsyncMock
|
||||
) -> None:
|
||||
"""Test existing flows prevent an identical ones from being after startup."""
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
|
@ -77,7 +80,7 @@ async def test_async_create_flow_checks_existing_flows_after_startup(
|
|||
|
||||
|
||||
async def test_async_create_flow_checks_existing_flows_before_startup(
|
||||
hass: HomeAssistant, mock_flow_init
|
||||
hass: HomeAssistant, mock_flow_init: AsyncMock
|
||||
) -> None:
|
||||
"""Test existing flows prevent an identical ones from being created before startup."""
|
||||
hass.set_state(CoreState.stopped)
|
||||
|
@ -100,7 +103,7 @@ async def test_async_create_flow_checks_existing_flows_before_startup(
|
|||
|
||||
|
||||
async def test_async_create_flow_does_nothing_after_stop(
|
||||
hass: HomeAssistant, mock_flow_init
|
||||
hass: HomeAssistant, mock_flow_init: AsyncMock
|
||||
) -> None:
|
||||
"""Test we no longer create flows when hass is stopping."""
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
|
|
|
@ -237,12 +237,12 @@ async def test_async_async_request_call_without_lock(hass: HomeAssistant) -> Non
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id):
|
||||
def __init__(self, entity_id: str) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
|
||||
async def testhelper(self, count):
|
||||
async def testhelper(self, count: int) -> None:
|
||||
"""Helper function."""
|
||||
updates.append(count)
|
||||
|
||||
|
@ -274,7 +274,7 @@ async def test_async_async_request_call_with_lock(hass: HomeAssistant) -> None:
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id, lock):
|
||||
def __init__(self, entity_id: str, lock: asyncio.Semaphore) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
|
@ -324,13 +324,13 @@ async def test_async_parallel_updates_with_zero(hass: HomeAssistant) -> None:
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id, count):
|
||||
def __init__(self, entity_id: str, count: int) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
self._count = count
|
||||
|
||||
async def async_update(self):
|
||||
async def async_update(self) -> None:
|
||||
"""Test update."""
|
||||
updates.append(self._count)
|
||||
await test_lock.wait()
|
||||
|
@ -363,7 +363,7 @@ async def test_async_parallel_updates_with_zero_on_sync_update(
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id, count):
|
||||
def __init__(self, entity_id: str, count: int) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
|
@ -404,14 +404,14 @@ async def test_async_parallel_updates_with_one(hass: HomeAssistant) -> None:
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id, count):
|
||||
def __init__(self, entity_id: str, count: int) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
self._count = count
|
||||
self.parallel_updates = test_semaphore
|
||||
|
||||
async def async_update(self):
|
||||
async def async_update(self) -> None:
|
||||
"""Test update."""
|
||||
updates.append(self._count)
|
||||
await test_lock.acquire()
|
||||
|
@ -480,14 +480,14 @@ async def test_async_parallel_updates_with_two(hass: HomeAssistant) -> None:
|
|||
class AsyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id, count):
|
||||
def __init__(self, entity_id: str, count: int) -> None:
|
||||
"""Initialize Async test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
self._count = count
|
||||
self.parallel_updates = test_semaphore
|
||||
|
||||
async def async_update(self):
|
||||
async def async_update(self) -> None:
|
||||
"""Test update."""
|
||||
updates.append(self._count)
|
||||
await test_lock.acquire()
|
||||
|
@ -550,13 +550,13 @@ async def test_async_parallel_updates_with_one_using_executor(
|
|||
class SyncEntity(entity.Entity):
|
||||
"""Test entity."""
|
||||
|
||||
def __init__(self, entity_id):
|
||||
def __init__(self, entity_id: str) -> None:
|
||||
"""Initialize sync test entity."""
|
||||
self.entity_id = entity_id
|
||||
self.hass = hass
|
||||
self.parallel_updates = test_semaphore
|
||||
|
||||
def update(self):
|
||||
def update(self) -> None:
|
||||
"""Test update."""
|
||||
locked.append(self.parallel_updates.locked())
|
||||
|
||||
|
@ -629,7 +629,7 @@ async def test_async_remove_twice(hass: HomeAssistant) -> None:
|
|||
def __init__(self) -> None:
|
||||
self.remove_calls = []
|
||||
|
||||
async def async_will_remove_from_hass(self):
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
self.remove_calls.append(None)
|
||||
|
||||
platform = MockEntityPlatform(hass, domain="test")
|
||||
|
@ -2376,7 +2376,7 @@ async def test_cached_entity_property_class_attribute(hass: HomeAssistant) -> No
|
|||
This class overrides the attribute property.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self._attr_attribution = values[0]
|
||||
|
||||
@cached_property
|
||||
|
|
|
@ -7,7 +7,7 @@ import math
|
|||
import os
|
||||
from pathlib import Path
|
||||
import time
|
||||
from typing import NamedTuple
|
||||
from typing import Any, NamedTuple
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
@ -325,10 +325,10 @@ def test_find_unserializable_data() -> None:
|
|||
) == {"$[0](Event: bad_event).data.bad_attribute": bad_data}
|
||||
|
||||
class BadData:
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.bla = bad_data
|
||||
|
||||
def as_dict(self):
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return {"bla": self.bla}
|
||||
|
||||
assert find_paths_unserializable_data(
|
||||
|
|
|
@ -484,12 +484,12 @@ async def test_restore_entity_end_to_end(
|
|||
class MockRestoreEntity(RestoreEntity):
|
||||
"""Mock restore entity."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the mock entity."""
|
||||
self._state: str | None = None
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> str | None:
|
||||
"""Return the state."""
|
||||
return self._state
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ from homeassistant.helpers import significant_change
|
|||
|
||||
|
||||
@pytest.fixture(name="checker")
|
||||
async def checker_fixture(hass):
|
||||
async def checker_fixture(
|
||||
hass: HomeAssistant,
|
||||
) -> significant_change.SignificantlyChangedChecker:
|
||||
"""Checker fixture."""
|
||||
checker = await significant_change.create_checker(hass, "test")
|
||||
|
||||
|
@ -24,7 +26,9 @@ async def checker_fixture(hass):
|
|||
return checker
|
||||
|
||||
|
||||
async def test_signicant_change(hass: HomeAssistant, checker) -> None:
|
||||
async def test_signicant_change(
|
||||
checker: significant_change.SignificantlyChangedChecker,
|
||||
) -> None:
|
||||
"""Test initialize helper works."""
|
||||
ent_id = "test_domain.test_entity"
|
||||
attrs = {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY}
|
||||
|
@ -48,7 +52,9 @@ async def test_signicant_change(hass: HomeAssistant, checker) -> None:
|
|||
assert checker.async_is_significant_change(State(ent_id, STATE_UNAVAILABLE, attrs))
|
||||
|
||||
|
||||
async def test_significant_change_extra(hass: HomeAssistant, checker) -> None:
|
||||
async def test_significant_change_extra(
|
||||
checker: significant_change.SignificantlyChangedChecker,
|
||||
) -> None:
|
||||
"""Test extra significant checker works."""
|
||||
ent_id = "test_domain.test_entity"
|
||||
attrs = {ATTR_DEVICE_CLASS: SensorDeviceClass.BATTERY}
|
||||
|
@ -75,7 +81,7 @@ async def test_significant_change_extra(hass: HomeAssistant, checker) -> None:
|
|||
assert checker.async_is_significant_change(State(ent_id, "200", attrs), extra_arg=2)
|
||||
|
||||
|
||||
async def test_check_valid_float(hass: HomeAssistant) -> None:
|
||||
async def test_check_valid_float() -> None:
|
||||
"""Test extra significant checker works."""
|
||||
assert significant_change.check_valid_float("1")
|
||||
assert significant_change.check_valid_float("1.0")
|
||||
|
|
|
@ -40,13 +40,13 @@ MOCK_DATA2 = {"goodbye": "cruel world"}
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def store(hass):
|
||||
def store(hass: HomeAssistant) -> storage.Store:
|
||||
"""Fixture of a store that prevents writing on Home Assistant stop."""
|
||||
return storage.Store(hass, MOCK_VERSION, MOCK_KEY)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store_v_1_1(hass):
|
||||
def store_v_1_1(hass: HomeAssistant) -> storage.Store:
|
||||
"""Fixture of a store that prevents writing on Home Assistant stop."""
|
||||
return storage.Store(
|
||||
hass, MOCK_VERSION, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_1
|
||||
|
@ -54,7 +54,7 @@ def store_v_1_1(hass):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def store_v_1_2(hass):
|
||||
def store_v_1_2(hass: HomeAssistant) -> storage.Store:
|
||||
"""Fixture of a store that prevents writing on Home Assistant stop."""
|
||||
return storage.Store(
|
||||
hass, MOCK_VERSION, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_2
|
||||
|
@ -62,7 +62,7 @@ def store_v_1_2(hass):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def store_v_2_1(hass):
|
||||
def store_v_2_1(hass: HomeAssistant) -> storage.Store:
|
||||
"""Fixture of a store that prevents writing on Home Assistant stop."""
|
||||
return storage.Store(
|
||||
hass, MOCK_VERSION_2, MOCK_KEY, minor_version=MOCK_MINOR_VERSION_1
|
||||
|
@ -70,12 +70,12 @@ def store_v_2_1(hass):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def read_only_store(hass):
|
||||
def read_only_store(hass: HomeAssistant) -> storage.Store:
|
||||
"""Fixture of a read only store."""
|
||||
return storage.Store(hass, MOCK_VERSION, MOCK_KEY, read_only=True)
|
||||
|
||||
|
||||
async def test_loading(hass: HomeAssistant, store) -> None:
|
||||
async def test_loading(hass: HomeAssistant, store: storage.Store) -> None:
|
||||
"""Test we can save and load data."""
|
||||
await store.async_save(MOCK_DATA)
|
||||
data = await store.async_load()
|
||||
|
@ -100,7 +100,7 @@ async def test_custom_encoder(hass: HomeAssistant) -> None:
|
|||
assert data == "9"
|
||||
|
||||
|
||||
async def test_loading_non_existing(hass: HomeAssistant, store) -> None:
|
||||
async def test_loading_non_existing(hass: HomeAssistant, store: storage.Store) -> None:
|
||||
"""Test we can save and load data."""
|
||||
with patch("homeassistant.util.json.open", side_effect=FileNotFoundError):
|
||||
data = await store.async_load()
|
||||
|
@ -109,7 +109,7 @@ async def test_loading_non_existing(hass: HomeAssistant, store) -> None:
|
|||
|
||||
async def test_loading_parallel(
|
||||
hass: HomeAssistant,
|
||||
store,
|
||||
store: storage.Store,
|
||||
hass_storage: dict[str, Any],
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
|
@ -292,7 +292,7 @@ async def test_not_saving_while_stopping(
|
|||
|
||||
|
||||
async def test_loading_while_delay(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test we load new data even if not written yet."""
|
||||
await store.async_save({"delay": "no"})
|
||||
|
@ -316,7 +316,7 @@ async def test_loading_while_delay(
|
|||
|
||||
|
||||
async def test_writing_while_writing_delay(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test a write while a write with delay is active."""
|
||||
store.async_delay_save(lambda: {"delay": "yes"}, 1)
|
||||
|
@ -343,7 +343,7 @@ async def test_writing_while_writing_delay(
|
|||
|
||||
|
||||
async def test_multiple_delay_save_calls(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test a write while a write with changing delays."""
|
||||
store.async_delay_save(lambda: {"delay": "yes"}, 1)
|
||||
|
@ -390,7 +390,7 @@ async def test_delay_save_zero(
|
|||
|
||||
|
||||
async def test_multiple_save_calls(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test multiple write tasks."""
|
||||
|
||||
|
@ -410,7 +410,7 @@ async def test_multiple_save_calls(
|
|||
|
||||
|
||||
async def test_migrator_no_existing_config(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test migrator with no existing config."""
|
||||
with (
|
||||
|
@ -424,7 +424,7 @@ async def test_migrator_no_existing_config(
|
|||
|
||||
|
||||
async def test_migrator_existing_config(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test migrating existing config."""
|
||||
with patch("os.path.isfile", return_value=True), patch("os.remove") as mock_remove:
|
||||
|
@ -443,7 +443,7 @@ async def test_migrator_existing_config(
|
|||
|
||||
|
||||
async def test_migrator_transforming_config(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test migrating config to new format."""
|
||||
|
||||
|
@ -471,7 +471,7 @@ async def test_migrator_transforming_config(
|
|||
|
||||
|
||||
async def test_minor_version_default(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test minor version default."""
|
||||
|
||||
|
@ -480,7 +480,7 @@ async def test_minor_version_default(
|
|||
|
||||
|
||||
async def test_minor_version(
|
||||
hass: HomeAssistant, store_v_1_2, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store_v_1_2: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test minor version."""
|
||||
|
||||
|
@ -489,7 +489,7 @@ async def test_minor_version(
|
|||
|
||||
|
||||
async def test_migrate_major_not_implemented_raises(
|
||||
hass: HomeAssistant, store, store_v_2_1
|
||||
hass: HomeAssistant, store: storage.Store, store_v_2_1: storage.Store
|
||||
) -> None:
|
||||
"""Test migrating between major versions fails if not implemented."""
|
||||
|
||||
|
@ -499,7 +499,10 @@ async def test_migrate_major_not_implemented_raises(
|
|||
|
||||
|
||||
async def test_migrate_minor_not_implemented(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_1, store_v_1_2
|
||||
hass: HomeAssistant,
|
||||
hass_storage: dict[str, Any],
|
||||
store_v_1_1: storage.Store,
|
||||
store_v_1_2: storage.Store,
|
||||
) -> None:
|
||||
"""Test migrating between minor versions does not fail if not implemented."""
|
||||
|
||||
|
@ -525,7 +528,7 @@ async def test_migrate_minor_not_implemented(
|
|||
|
||||
|
||||
async def test_migration(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2: storage.Store
|
||||
) -> None:
|
||||
"""Test migration."""
|
||||
calls = 0
|
||||
|
@ -564,7 +567,7 @@ async def test_migration(
|
|||
|
||||
|
||||
async def test_legacy_migration(
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2
|
||||
hass: HomeAssistant, hass_storage: dict[str, Any], store_v_1_2: storage.Store
|
||||
) -> None:
|
||||
"""Test legacy migration method signature."""
|
||||
calls = 0
|
||||
|
@ -600,7 +603,7 @@ async def test_legacy_migration(
|
|||
|
||||
|
||||
async def test_changing_delayed_written_data(
|
||||
hass: HomeAssistant, store, hass_storage: dict[str, Any]
|
||||
hass: HomeAssistant, store: storage.Store, hass_storage: dict[str, Any]
|
||||
) -> None:
|
||||
"""Test changing data that is written with delay."""
|
||||
data_to_store = {"hello": "world"}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue