def current_task(loop: asyncio.AbstractEventLoop) -> asyncio.Task[Any] | None:
    """Backwards compatible current_task."""
    report(
        "called async_timeout.current_task. The current_task call is deprecated and calls will fail after Home Assistant 2022.2; use asyncio.current_task instead",
        error_if_core=False,
    )
    return asyncio.current_task()
示例#2
0
文件: __init__.py 项目: 2Fake/core
async def async_get_device_automation_platform(
        hass: HomeAssistant, domain: str,
        automation_type: DeviceAutomationType | str) -> ModuleType:
    """Load device automation platform for integration.

    Throws InvalidDeviceAutomationConfig if the integration is not found or does not support device automation.
    """
    if isinstance(automation_type, str):
        report(
            "uses str for async_get_device_automation_platform automation_type. This "
            "is deprecated and will stop working in Home Assistant 2022.4, it should "
            "be updated to use DeviceAutomationType instead",
            error_if_core=False,
        )
        automation_type = DeviceAutomationType[automation_type.upper()]
    platform_name = automation_type.value.section
    try:
        integration = await async_get_integration_with_requirements(
            hass, domain)
        platform = integration.get_platform(platform_name)
    except IntegrationNotFound as err:
        raise InvalidDeviceAutomationConfig(
            f"Integration '{domain}' not found") from err
    except ImportError as err:
        raise InvalidDeviceAutomationConfig(
            f"Integration '{domain}' does not support device automation "
            f"{automation_type.name.lower()}s") from err

    return platform
示例#3
0
 def new_zeroconf_new(self: zeroconf.Zeroconf, *k: Any,
                      **kw: Any) -> HaZeroconf:
     report(
         "attempted to create another Zeroconf instance. Please use the shared Zeroconf via await homeassistant.components.zeroconf.async_get_instance(hass)",
         exclude_integrations={"zeroconf"},
         error_if_core=False,
     )
     return hass_zc
示例#4
0
文件: pool.py 项目: jbouwh/core
 def _do_get_db_connection_protected(self) -> Any:
     report(
         "accesses the database without the database executor; "
         f"{ADVISE_MSG} "
         "for faster database operations",
         exclude_integrations={"recorder"},
         error_if_core=False,
     )
     return super(NullPool, self)._create_connection()
示例#5
0
async def test_report_missing_integration_frame(caplog):
    """Test reporting when no integration is detected."""

    what = "teststring"
    with patch(
            "homeassistant.helpers.frame.get_integration_frame",
            side_effect=frame.MissingIntegrationFrame,
    ):
        frame.report(what, error_if_core=False)
        assert what in caplog.text
        assert caplog.text.count(what) == 1
示例#6
0
 def _do_get(self) -> Any:
     if self.recorder_or_dbworker:
         return super()._do_get()
     report(
         "accesses the database without the database executor; "
         "Use homeassistant.components.recorder.get_instance(hass).async_add_executor_job() "
         "for faster database operations",
         exclude_integrations={"recorder"},
         error_if_core=False,
     )
     return super(  # pylint: disable=bad-super-call
         NullPool, self)._create_connection()
示例#7
0
    def __getitem__(self, name: str) -> Any:
        """
        Allow property access by name for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        report(
            f"accessed discovery_info['{name}'] instead of discovery_info.{name}; "
            "this will fail in version 2022.6",
            exclude_integrations={DOMAIN},
            error_if_core=False,
        )
        return getattr(self, name)
    def __getitem__(self, name: str) -> Any:
        """
        Enable method for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        if not self._warning_logged:
            report(
                f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
                exclude_integrations={DOMAIN},
                error_if_core=False,
            )
            self._warning_logged = True
        return getattr(self, name)
示例#9
0
    def get(self, name: str, default: Any = None) -> Any:
        """
        Enable method for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        report(
            f"accessed discovery_info.get('{name}') instead of discovery_info.{name}; "
            "this will fail in version 2022.6",
            exclude_integrations={DOMAIN},
            error_if_core=False,
        )
        if hasattr(self, name):
            return getattr(self, name)
        return default
示例#10
0
    def get(self, name: str, default: Any = None) -> Any:
        """
        Enable method for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        if not self._warning_logged:
            report(
                f"accessed discovery_info.get('{name}') instead of discovery_info.{name}; this will fail in version 2022.6",
                exclude_integrations={DOMAIN},
                error_if_core=False,
            )
            self._warning_logged = True
        if hasattr(self, name):
            return getattr(self, name)
        return self.upnp.get(name, self.ssdp_headers.get(name, default))
示例#11
0
文件: __init__.py 项目: 2Fake/core
async def async_get_device_automations(
    hass: HomeAssistant,
    automation_type: DeviceAutomationType | str,
    device_ids: Iterable[str] | None = None,
) -> Mapping[str, Any]:
    """Return all the device automations for a type optionally limited to specific device ids."""
    if isinstance(automation_type, str):
        report(
            "uses str for async_get_device_automations automation_type. This is "
            "deprecated and will stop working in Home Assistant 2022.4, it should be "
            "updated to use DeviceAutomationType instead",
            error_if_core=False,
        )
        automation_type = DeviceAutomationType[automation_type.upper()]
    return await _async_get_device_automations(hass, automation_type,
                                               device_ids)
示例#12
0
    def __contains__(self, name: str) -> bool:
        """
        Enable method for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        report(
            f"accessed discovery_info.__contains__('{name}') "
            f"instead of discovery_info.upnp.__contains__('{name}') "
            f"or discovery_info.ssdp_headers.__contains__('{name}'); "
            "this will fail in version 2022.6",
            exclude_integrations={DOMAIN},
            error_if_core=False,
        )
        if hasattr(self, name):
            return getattr(self, name) is not None
        return name in self.upnp or name in self.ssdp_headers
示例#13
0
async def test_prevent_flooding(caplog):
    """Test to ensure a report is only written once to the log."""

    what = "accessed hi instead of hello"
    key = "/home/paulus/homeassistant/components/hue/light.py:23"

    frame.report(what, error_if_core=False)
    assert what in caplog.text
    assert key in frame._REPORTED_INTEGRATIONS
    assert len(frame._REPORTED_INTEGRATIONS) == 1

    caplog.clear()

    frame.report(what, error_if_core=False)
    assert what not in caplog.text
    assert key in frame._REPORTED_INTEGRATIONS
    assert len(frame._REPORTED_INTEGRATIONS) == 1
def timeout(
        delay: float | None,
        loop: asyncio.AbstractEventLoop | None = None
) -> async_timeout.Timeout:
    """Backwards compatible timeout context manager that warns with loop usage."""
    if loop is None:
        loop = asyncio.get_running_loop()
    else:
        report(
            "called async_timeout.timeout with loop keyword argument. The loop keyword argument is deprecated and calls will fail after Home Assistant 2022.2",
            error_if_core=False,
        )
    if delay is not None:
        deadline: float | None = loop.time() + delay
    else:
        deadline = None
    return async_timeout.Timeout(deadline, loop)
示例#15
0
文件: models.py 项目: jbouwh/core
 def __init__(self, address_or_ble_device: str | BLEDevice, *args: Any,
              **kwargs: Any) -> None:
     """Initialize the BleakClient."""
     if isinstance(address_or_ble_device, BLEDevice):
         super().__init__(address_or_ble_device, *args, **kwargs)
         return
     report(
         "attempted to call BleakClient with an address instead of a BLEDevice",
         exclude_integrations={"bluetooth"},
         error_if_core=False,
     )
     assert MANAGER is not None
     ble_device = MANAGER.async_ble_device_from_address(
         address_or_ble_device, True)
     if ble_device is None:
         raise BleakError(
             f"No device found for address {address_or_ble_device}")
     super().__init__(ble_device, *args, **kwargs)
示例#16
0
def extract_entities(
    hass: HomeAssistantType,
    template: Optional[str],
    variables: TemplateVarsType = None,
) -> Union[str, List[str]]:
    """Extract all entities for state_changed listener from template string."""

    report(
        "called template.extract_entities. Please use event.async_track_template_result instead as it can accurately handle watching entities"
    )

    if template is None or not is_template_string(template):
        return []

    if _RE_NONE_ENTITIES.search(template):
        return MATCH_ALL

    extraction_final = []

    for result in _RE_GET_ENTITIES.finditer(template):
        if (result.group("entity_id") == "trigger.entity_id" and variables
                and "trigger" in variables
                and "entity_id" in variables["trigger"]):
            extraction_final.append(variables["trigger"]["entity_id"])
        elif result.group("entity_id"):
            if result.group("func") == "expand":
                for entity in expand(hass, result.group("entity_id")):
                    extraction_final.append(entity.entity_id)

            extraction_final.append(result.group("entity_id"))
        elif result.group("domain_inner") or result.group("domain_outer"):
            extraction_final.extend(
                hass.states.async_entity_ids(
                    result.group("domain_inner")
                    or result.group("domain_outer")))

        if (variables and result.group("variable") in variables
                and isinstance(variables[result.group("variable")], str)
                and valid_entity_id(variables[result.group("variable")])):
            extraction_final.append(variables[result.group("variable")])

    if extraction_final:
        return list(set(extraction_final))
    return MATCH_ALL
示例#17
0
async def async_resolve_media(
    hass: HomeAssistant,
    media_content_id: str,
    target_media_player: str | None | UndefinedType = UNDEFINED,
) -> PlayMedia:
    """Get info to play media."""
    if DOMAIN not in hass.data:
        raise Unresolvable("Media Source not loaded")

    if target_media_player is UNDEFINED:
        report("calls media_source.async_resolve_media without passing an entity_id")
        target_media_player = None

    try:
        item = _get_media_item(hass, media_content_id, target_media_player)
    except ValueError as err:
        raise Unresolvable(str(err)) from err

    return await item.async_resolve()
示例#18
0
    def __getitem__(self, name: str) -> Any:
        """
        Allow property access by name for compatibility reason.

        Deprecated, and will be removed in version 2022.6.
        """
        if not self._warning_logged:
            report(
                f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
                exclude_integrations={DOMAIN},
                error_if_core=False,
            )
            self._warning_logged = True
        # Use a property if it is available, fallback to upnp data
        if hasattr(self, name):
            return getattr(self, name)
        if name in self.ssdp_headers and name not in self.upnp:
            return self.ssdp_headers.get(name)
        return self.upnp[name]
    def async_get_or_create(
        self,
        domain: str,
        platform: str,
        unique_id: str,
        *,
        # To influence entity ID generation
        known_object_ids: Iterable[str] | None = None,
        suggested_object_id: str | None = None,
        # To disable an entity if it gets created
        disabled_by: RegistryEntryDisabler | None = None,
        # Data that we want entry to have
        area_id: str | None = None,
        capabilities: Mapping[str, Any] | None = None,
        config_entry: ConfigEntry | None = None,
        device_id: str | None = None,
        entity_category: str | None = None,
        original_device_class: str | None = None,
        original_icon: str | None = None,
        original_name: str | None = None,
        supported_features: int | None = None,
        unit_of_measurement: str | None = None,
    ) -> RegistryEntry:
        """Get entity. Create if it doesn't exist."""
        config_entry_id = None
        if config_entry:
            config_entry_id = config_entry.entry_id

        entity_id = self.async_get_entity_id(domain, platform, unique_id)

        if entity_id:
            return self._async_update_entity(
                entity_id,
                area_id=area_id or UNDEFINED,
                capabilities=capabilities or UNDEFINED,
                config_entry_id=config_entry_id or UNDEFINED,
                device_id=device_id or UNDEFINED,
                entity_category=entity_category or UNDEFINED,
                original_device_class=original_device_class or UNDEFINED,
                original_icon=original_icon or UNDEFINED,
                original_name=original_name or UNDEFINED,
                supported_features=supported_features or UNDEFINED,
                unit_of_measurement=unit_of_measurement or UNDEFINED,
                # When we changed our slugify algorithm, we invalidated some
                # stored entity IDs with either a __ or ending in _.
                # Fix introduced in 0.86 (Jan 23, 2019). Next line can be
                # removed when we release 1.0 or in 2020.
                new_entity_id=".".join(
                    slugify(part) for part in entity_id.split(".", 1)),
            )

        entity_id = self.async_generate_entity_id(
            domain, suggested_object_id or f"{platform}_{unique_id}",
            known_object_ids)

        if isinstance(disabled_by, str) and not isinstance(
                disabled_by, RegistryEntryDisabler):
            report(  # type: ignore[unreachable]
                "uses str for entity registry disabled_by. This is deprecated and will "
                "stop working in Home Assistant 2022.3, it should be updated to use "
                "RegistryEntryDisabler instead",
                error_if_core=False,
            )
            disabled_by = RegistryEntryDisabler(disabled_by)
        elif (disabled_by is None and config_entry
              and config_entry.pref_disable_new_entities):
            disabled_by = RegistryEntryDisabler.INTEGRATION

        entry = RegistryEntry(
            area_id=area_id,
            capabilities=capabilities,
            config_entry_id=config_entry_id,
            device_id=device_id,
            disabled_by=disabled_by,
            entity_category=entity_category,
            entity_id=entity_id,
            original_device_class=original_device_class,
            original_icon=original_icon,
            original_name=original_name,
            platform=platform,
            supported_features=supported_features or 0,
            unique_id=unique_id,
            unit_of_measurement=unit_of_measurement,
        )
        self.entities[entity_id] = entry
        _LOGGER.info("Registered new %s.%s entity: %s", domain, platform,
                     entity_id)
        self.async_schedule_save()

        self.hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, {
            "action": "create",
            "entity_id": entity_id
        })

        return entry
示例#20
0
    def _async_update_device(
        self,
        device_id: str,
        *,
        add_config_entry_id: str | UndefinedType = UNDEFINED,
        area_id: str | None | UndefinedType = UNDEFINED,
        configuration_url: str | None | UndefinedType = UNDEFINED,
        disabled_by: DeviceEntryDisabler | None | UndefinedType = UNDEFINED,
        entry_type: DeviceEntryType | None | UndefinedType = UNDEFINED,
        manufacturer: str | None | UndefinedType = UNDEFINED,
        merge_connections: set[tuple[str, str]] | UndefinedType = UNDEFINED,
        merge_identifiers: set[tuple[str, str]] | UndefinedType = UNDEFINED,
        model: str | None | UndefinedType = UNDEFINED,
        name_by_user: str | None | UndefinedType = UNDEFINED,
        name: str | None | UndefinedType = UNDEFINED,
        new_identifiers: set[tuple[str, str]] | UndefinedType = UNDEFINED,
        remove_config_entry_id: str | UndefinedType = UNDEFINED,
        suggested_area: str | None | UndefinedType = UNDEFINED,
        sw_version: str | None | UndefinedType = UNDEFINED,
        via_device_id: str | None | UndefinedType = UNDEFINED,
    ) -> DeviceEntry | None:
        """Update device attributes."""
        old = self.devices[device_id]

        changes: dict[str, Any] = {}

        config_entries = old.config_entries

        if isinstance(disabled_by, str) and not isinstance(
                disabled_by, DeviceEntryDisabler):
            report(  # type: ignore[unreachable]
                "uses str for device registry disabled_by. This is deprecated and will "
                "stop working in Home Assistant 2022.3, it should be updated to use "
                "DeviceEntryDisabler instead",
                error_if_core=False,
            )
            disabled_by = DeviceEntryDisabler(disabled_by)

        if (suggested_area not in (UNDEFINED, None, "")
                and area_id is UNDEFINED and old.area_id is None):
            area = self.hass.helpers.area_registry.async_get(
                self.hass).async_get_or_create(suggested_area)
            area_id = area.id

        if (add_config_entry_id is not UNDEFINED
                and add_config_entry_id not in old.config_entries):
            config_entries = old.config_entries | {add_config_entry_id}

        if (remove_config_entry_id is not UNDEFINED
                and remove_config_entry_id in config_entries):
            if config_entries == {remove_config_entry_id}:
                self.async_remove_device(device_id)
                return None

            config_entries = config_entries - {remove_config_entry_id}

        if config_entries != old.config_entries:
            changes["config_entries"] = config_entries

        for attr_name, setvalue in (
            ("connections", merge_connections),
            ("identifiers", merge_identifiers),
        ):
            old_value = getattr(old, attr_name)
            # If not undefined, check if `value` contains new items.
            if setvalue is not UNDEFINED and not setvalue.issubset(old_value):
                changes[attr_name] = old_value | setvalue

        if new_identifiers is not UNDEFINED:
            changes["identifiers"] = new_identifiers

        for attr_name, value in (
            ("configuration_url", configuration_url),
            ("disabled_by", disabled_by),
            ("entry_type", entry_type),
            ("manufacturer", manufacturer),
            ("model", model),
            ("name", name),
            ("suggested_area", suggested_area),
            ("sw_version", sw_version),
            ("via_device_id", via_device_id),
        ):
            if value is not UNDEFINED and value != getattr(old, attr_name):
                changes[attr_name] = value

        if area_id is not UNDEFINED and area_id != old.area_id:
            changes["area_id"] = area_id

        if name_by_user is not UNDEFINED and name_by_user != old.name_by_user:
            changes["name_by_user"] = name_by_user

        if old.is_new:
            changes["is_new"] = False

        if not changes:
            return old

        new = attr.evolve(old, **changes)
        self._update_device(old, new)
        self.async_schedule_save()

        self.hass.bus.async_fire(
            EVENT_DEVICE_REGISTRY_UPDATED,
            {
                "action": "create" if "is_new" in changes else "update",
                "device_id": new.id,
            },
        )

        return new
示例#21
0
    def async_get_or_create(
        self,
        *,
        config_entry_id: str,
        configuration_url: str | None | UndefinedType = UNDEFINED,
        connections: set[tuple[str, str]] | None = None,
        default_manufacturer: str | None | UndefinedType = UNDEFINED,
        default_model: str | None | UndefinedType = UNDEFINED,
        default_name: str | None | UndefinedType = UNDEFINED,
        # To disable a device if it gets created
        disabled_by: DeviceEntryDisabler | None | UndefinedType = UNDEFINED,
        entry_type: DeviceEntryType | None | UndefinedType = UNDEFINED,
        identifiers: set[tuple[str, str]] | None = None,
        manufacturer: str | None | UndefinedType = UNDEFINED,
        model: str | None | UndefinedType = UNDEFINED,
        name: str | None | UndefinedType = UNDEFINED,
        suggested_area: str | None | UndefinedType = UNDEFINED,
        sw_version: str | None | UndefinedType = UNDEFINED,
        via_device: tuple[str, str] | None = None,
    ) -> DeviceEntry:
        """Get device. Create if it doesn't exist."""
        if not identifiers and not connections:
            raise RequiredParameterMissing(["identifiers", "connections"])

        if identifiers is None:
            identifiers = set()

        if connections is None:
            connections = set()
        else:
            connections = _normalize_connections(connections)

        device = self.async_get_device(identifiers, connections)

        if device is None:
            deleted_device = self._async_get_deleted_device(
                identifiers, connections)
            if deleted_device is None:
                device = DeviceEntry(is_new=True)
            else:
                self._remove_device(deleted_device)
                device = deleted_device.to_device_entry(
                    config_entry_id, connections, identifiers)
            self._add_device(device)

        if default_manufacturer is not UNDEFINED and device.manufacturer is None:
            manufacturer = default_manufacturer

        if default_model is not UNDEFINED and device.model is None:
            model = default_model

        if default_name is not UNDEFINED and device.name is None:
            name = default_name

        if via_device is not None:
            via = self.async_get_device({via_device})
            via_device_id: str | UndefinedType = via.id if via else UNDEFINED
        else:
            via_device_id = UNDEFINED

        if isinstance(entry_type,
                      str) and not isinstance(entry_type, DeviceEntryType):
            report(  # type: ignore[unreachable]
                "uses str for device registry entry_type. This is deprecated and will "
                "stop working in Home Assistant 2022.3, it should be updated to use "
                "DeviceEntryType instead",
                error_if_core=False,
            )
            entry_type = DeviceEntryType(entry_type)

        device = self._async_update_device(
            device.id,
            add_config_entry_id=config_entry_id,
            configuration_url=configuration_url,
            disabled_by=disabled_by,
            entry_type=entry_type,
            manufacturer=manufacturer,
            merge_connections=connections or UNDEFINED,
            merge_identifiers=identifiers or UNDEFINED,
            model=model,
            name=name,
            suggested_area=suggested_area,
            sw_version=sw_version,
            via_device_id=via_device_id,
        )

        # This is safe because _async_update_device will always return a device
        # in this use case.
        assert device
        return device
    def _async_update_entity(
        self,
        entity_id: str,
        *,
        area_id: str | None | UndefinedType = UNDEFINED,
        capabilities: Mapping[str, Any] | None | UndefinedType = UNDEFINED,
        config_entry_id: str | None | UndefinedType = UNDEFINED,
        device_class: str | None | UndefinedType = UNDEFINED,
        device_id: str | None | UndefinedType = UNDEFINED,
        disabled_by: RegistryEntryDisabler | None | UndefinedType = UNDEFINED,
        entity_category: str | None | UndefinedType = UNDEFINED,
        icon: str | None | UndefinedType = UNDEFINED,
        name: str | None | UndefinedType = UNDEFINED,
        new_entity_id: str | UndefinedType = UNDEFINED,
        new_unique_id: str | UndefinedType = UNDEFINED,
        original_device_class: str | None | UndefinedType = UNDEFINED,
        original_icon: str | None | UndefinedType = UNDEFINED,
        original_name: str | None | UndefinedType = UNDEFINED,
        supported_features: int | UndefinedType = UNDEFINED,
        unit_of_measurement: str | None | UndefinedType = UNDEFINED,
    ) -> RegistryEntry:
        """Private facing update properties method."""
        old = self.entities[entity_id]

        new_values = {}  # Dict with new key/value pairs
        old_values = {}  # Dict with old key/value pairs

        if isinstance(disabled_by, str) and not isinstance(
                disabled_by, RegistryEntryDisabler):
            report(  # type: ignore[unreachable]
                "uses str for entity registry disabled_by. This is deprecated and will "
                "stop working in Home Assistant 2022.3, it should be updated to use "
                "RegistryEntryDisabler instead",
                error_if_core=False,
            )
            disabled_by = RegistryEntryDisabler(disabled_by)

        for attr_name, value in (
            ("area_id", area_id),
            ("capabilities", capabilities),
            ("config_entry_id", config_entry_id),
            ("device_class", device_class),
            ("device_id", device_id),
            ("disabled_by", disabled_by),
            ("entity_category", entity_category),
            ("icon", icon),
            ("name", name),
            ("original_device_class", original_device_class),
            ("original_icon", original_icon),
            ("original_name", original_name),
            ("supported_features", supported_features),
            ("unit_of_measurement", unit_of_measurement),
        ):
            if value is not UNDEFINED and value != getattr(old, attr_name):
                new_values[attr_name] = value
                old_values[attr_name] = getattr(old, attr_name)

        if new_entity_id is not UNDEFINED and new_entity_id != old.entity_id:
            if self.async_is_registered(new_entity_id):
                raise ValueError("Entity with this ID is already registered")

            if not valid_entity_id(new_entity_id):
                raise ValueError("Invalid entity ID")

            if split_entity_id(new_entity_id)[0] != split_entity_id(
                    entity_id)[0]:
                raise ValueError("New entity ID should be same domain")

            self.entities.pop(entity_id)
            entity_id = new_values["entity_id"] = new_entity_id
            old_values["entity_id"] = old.entity_id

        if new_unique_id is not UNDEFINED:
            conflict_entity_id = self.async_get_entity_id(
                old.domain, old.platform, new_unique_id)
            if conflict_entity_id:
                raise ValueError(
                    f"Unique id '{new_unique_id}' is already in use by "
                    f"'{conflict_entity_id}'")
            new_values["unique_id"] = new_unique_id
            old_values["unique_id"] = old.unique_id

        if not new_values:
            return old

        new = self.entities[entity_id] = attr.evolve(old, **new_values)

        self.async_schedule_save()

        data = {
            "action": "update",
            "entity_id": entity_id,
            "changes": old_values
        }

        if old.entity_id != entity_id:
            data["old_entity_id"] = old.entity_id

        self.hass.bus.async_fire(EVENT_ENTITY_REGISTRY_UPDATED, data)

        return new