passes pytest fails pre-commit

custom_components/adaptive_lighting/switch.py:393:1: C901 'async_setup_entry' is too complex (22)
This commit is contained in:
Benjamin Auquite 2023-04-08 11:52:33 -05:00
commit 2ec2912115
3 changed files with 141 additions and 110 deletions

View file

@ -196,9 +196,9 @@ DOCS[CONF_TURN_ON_LIGHTS] = "Whether to turn on lights that are currently off.
SERVICE_CHANGE_SWITCH_SETTINGS = "change_switch_settings"
CONF_USE_DEFAULTS = "use_defaults"
DOCS[CONF_USE_DEFAULTS] = (
"Sets the default values not specified in this service call. Options: "
"Where to autofill config options that are not passed to this service. Options: "
'"current" (default, retains current values), "factory" (resets to '
'documented defaults), or "configuration" (reverts to switch config defaults). ⚙️'
'documented defaults), or "configuration" (reverts to original user config). ⚙️'
)
TURNING_OFF_DELAY = 5
@ -321,28 +321,36 @@ _DOMAIN_SCHEMA = vol.Schema(
)
def apply_service_schema(initial_transition: int = 1):
"""Return the schema for the apply service."""
return vol.Schema(
{
vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
vol.Optional(CONF_LIGHTS, default=[]): cv.entity_ids,
vol.Optional(
CONF_TRANSITION,
default=initial_transition,
): VALID_TRANSITION,
vol.Optional(ATTR_ADAPT_BRIGHTNESS, default=True): cv.boolean,
vol.Optional(ATTR_ADAPT_COLOR, default=True): cv.boolean,
vol.Optional(CONF_PREFER_RGB_COLOR, default=False): cv.boolean,
vol.Optional(CONF_TURN_ON_LIGHTS, default=False): cv.boolean,
}
)
SCHEMA_APPLY = vol.Schema(
{
vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
vol.Optional(CONF_LIGHTS, default=[]): cv.entity_ids,
vol.Optional(CONF_TRANSITION): VALID_TRANSITION,
vol.Optional(ATTR_ADAPT_BRIGHTNESS, default=True): cv.boolean,
vol.Optional(ATTR_ADAPT_COLOR, default=True): cv.boolean,
vol.Optional(CONF_PREFER_RGB_COLOR, default=False): cv.boolean,
vol.Optional(CONF_TURN_ON_LIGHTS, default=False): cv.boolean,
}
)
SET_MANUAL_CONTROL_SCHEMA = vol.Schema(
SCHEMA_SET_MANUAL_CONTROL = vol.Schema(
{
vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
vol.Optional(CONF_LIGHTS, default=[]): cv.entity_ids,
vol.Optional(CONF_MANUAL_CONTROL, default=True): cv.boolean,
}
)
SCHEMA_CHANGE_SWITCH_SETTINGS = vol.Schema(
{
vol.Optional(CONF_USE_DEFAULTS): cv.string,
vol.Optional(CONF_ENTITY_ID): cv.entity_ids,
vol.Required(CONF_LIGHTS, default=[]): [],
**{
vol.Optional(k): valid
for k, _, valid in VALIDATION_TUPLES
if k not in [CONF_INTERVAL, CONF_NAME, CONF_LIGHTS]
},
}
)

View file

@ -71,7 +71,7 @@ from homeassistant.core import (
State,
callback,
)
from homeassistant.helpers import entity_platform, entity_registry
from homeassistant.helpers import entity_registry
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import (
async_track_state_change_event,
@ -89,7 +89,6 @@ from homeassistant.util.color import (
)
import homeassistant.util.dt as dt_util
import ulid_transform
import voluptuous as vol
from .const import (
ADAPT_BRIGHTNESS_SWITCH,
@ -135,16 +134,17 @@ from .const import (
ICON_COLOR_TEMP,
ICON_MAIN,
ICON_SLEEP,
SCHEMA_APPLY,
SCHEMA_CHANGE_SWITCH_SETTINGS,
SCHEMA_SET_MANUAL_CONTROL,
SERVICE_APPLY,
SERVICE_CHANGE_SWITCH_SETTINGS,
SERVICE_SET_MANUAL_CONTROL,
SET_MANUAL_CONTROL_SCHEMA,
SLEEP_MODE_SWITCH,
SUN_EVENT_MIDNIGHT,
SUN_EVENT_NOON,
TURNING_OFF_DELAY,
VALIDATION_TUPLES,
apply_service_schema,
replace_none_str,
)
@ -286,9 +286,9 @@ def _split_service_data(service_data, adapt_brightness, adapt_color):
def _get_switches_with_lights(
hass: HomeAssistant, lights: list[str]
hass: HomeAssistant, lights: list[str] | None = None
) -> list[AdaptiveSwitch]:
"""Get all switches that control at least one of the lights passed."""
"""Get all switches. If lights is defined, return only switches found with these lights."""
config_entries = hass.config_entries.async_entries(DOMAIN)
data = hass.data[DOMAIN]
switches = []
@ -297,10 +297,13 @@ def _get_switches_with_lights(
if entry is None: # entry might be disabled and therefore missing
continue
switch = data[config.entry_id]["instance"]
all_check_lights = _expand_light_groups(hass, lights)
switch._expand_light_groups()
# Check if any of the lights are in the switch's lights
if set(switch._lights) & set(all_check_lights):
if lights:
all_check_lights = _expand_light_groups(hass, lights)
switch._expand_light_groups()
# Check if any of the lights are in the switch's lights
if set(switch._lights) & set(all_check_lights):
switches.append(switch)
else:
switches.append(switch)
return switches
@ -342,13 +345,7 @@ def _get_switches_from_service_call(
switch_entity_ids: list[str] | None = data.get("entity_id")
if not lights and not switch_entity_ids:
raise ValueError(
"adaptive-lighting: Neither a switch nor a light was provided in the service call."
" If you intend to adapt all lights on all switches, please inform the developers at"
" https://github.com/basnijholt/adaptive-lighting about your use case."
" Currently, you must pass either an adaptive-lighting switch or the lights to an"
" `adaptive_lighting` service call."
)
return _get_switches_with_lights(hass)
if switch_entity_ids is not None:
if len(switch_entity_ids) > 1 and lights:
@ -374,44 +371,6 @@ def _get_switches_from_service_call(
)
async def handle_change_switch_settings(
switch: AdaptiveSwitch, service_call: ServiceCall
) -> None:
"""Allows HASS to change config values via a service call."""
data = service_call.data
which = data.get(CONF_USE_DEFAULTS, "current")
if which == "current": # use whatever we're already using.
defaults = switch._current_settings # pylint: disable=protected-access
elif which == "factory": # use actual defaults listed in the documentation
defaults = {key: default for key, default, _ in VALIDATION_TUPLES}
elif which == "configuration":
# use whatever's in the config flow or configuration.yaml
defaults = switch._config_backup # pylint: disable=protected-access
else:
defaults = None
switch._set_changeable_settings(
data=data,
defaults=defaults,
)
_LOGGER.debug(
"Called 'adaptive_lighting.change_switch_settings' service with '%s'",
data,
)
all_lights = switch._lights # pylint: disable=protected-access
switch.turn_on_off_listener.reset(*all_lights, reset_manual_control=False)
if switch.is_on:
await switch._update_attrs_and_maybe_adapt_lights( # pylint: disable=protected-access
all_lights,
transition=switch._initial_transition,
force=True,
context=switch.create_context("service", parent=service_call.context),
)
@callback
def _fire_manual_control_event(
switch: AdaptiveSwitch, light: str, context: Context, is_async=True
@ -489,18 +448,29 @@ async def async_setup_entry(
all_lights = _expand_light_groups(switch.hass, lights)
switch.turn_on_off_listener.lights.update(all_lights)
for light in all_lights:
if data[CONF_TURN_ON_LIGHTS] or is_on(hass, light):
await switch._adapt_light( # pylint: disable=protected-access
light,
data[CONF_TRANSITION],
data[ATTR_ADAPT_BRIGHTNESS],
data[ATTR_ADAPT_COLOR],
data[CONF_PREFER_RGB_COLOR],
force=True,
context=switch.create_context(
"service", parent=service_call.context
),
)
transition = data.get(CONF_TRANSITION)
if not data[CONF_TURN_ON_LIGHTS]:
if not is_on(hass, light):
continue
if not transition:
transition = (
switch._transition
) # pylint: disable=protected-access
elif not transition:
transition = (
switch._initial_transition
) # pylint: disable=protected-access
await switch._adapt_light( # pylint: disable=protected-access
light,
transition,
data[ATTR_ADAPT_BRIGHTNESS],
data[ATTR_ADAPT_COLOR],
data[CONF_PREFER_RGB_COLOR],
force=True,
context=switch.create_context(
"service", parent=service_call.context
),
)
@callback
async def handle_set_manual_control(service_call: ServiceCall):
@ -534,14 +504,54 @@ async def async_setup_entry(
),
)
@callback
async def handle_change_switch_settings(service_call: ServiceCall) -> None:
"""Allows HASS to change config values via a service call."""
data = service_call.data
_LOGGER.debug(
"Called 'adaptive_lighting.change_switch_settings' service with '%s'",
data,
)
switches = _get_switches_from_service_call(hass, service_call)
for switch in switches:
# which denotes where to autofill blank config options.
which = data.get(CONF_USE_DEFAULTS, "current")
if which == "current":
# use whatever we're already using.
defaults = switch._current_settings # pylint: disable=protected-access
elif which == "factory":
# use actual defaults listed in the documentation
defaults = {key: default for key, default, _ in VALIDATION_TUPLES}
elif which == "configuration":
# use whatever's in the config flow or configuration.yaml
defaults = switch._config_backup # pylint: disable=protected-access
else:
defaults = None
switch._set_changeable_settings(
data=data,
defaults=defaults,
)
all_lights = switch._lights # pylint: disable=protected-access
switch.turn_on_off_listener.reset(*all_lights, reset_manual_control=False)
if not switch.is_on:
continue
await switch._update_attrs_and_maybe_adapt_lights( # pylint: disable=protected-access
all_lights,
transition=switch._transition,
force=True,
context=switch.create_context("service", parent=service_call.context),
)
# Register `apply` service
hass.services.async_register(
domain=DOMAIN,
service=SERVICE_APPLY,
service_func=handle_apply,
schema=apply_service_schema(
switch._initial_transition
), # pylint: disable=protected-access
schema=SCHEMA_APPLY,
)
# Register `set_manual_control` service
@ -549,20 +559,14 @@ async def async_setup_entry(
domain=DOMAIN,
service=SERVICE_SET_MANUAL_CONTROL,
service_func=handle_set_manual_control,
schema=SET_MANUAL_CONTROL_SCHEMA,
schema=SCHEMA_SET_MANUAL_CONTROL,
)
args = {vol.Optional(CONF_USE_DEFAULTS, default="current"): cv.string}
# Modifying these after init isn't possible
skip = (CONF_INTERVAL, CONF_NAME, CONF_LIGHTS)
for k, _, valid in VALIDATION_TUPLES:
if k not in skip:
args[vol.Optional(k)] = valid
platform = entity_platform.current_platform.get()
platform.async_register_entity_service(
SERVICE_CHANGE_SWITCH_SETTINGS,
args,
handle_change_switch_settings,
hass.services.async_register(
domain=DOMAIN,
service=SERVICE_CHANGE_SWITCH_SETTINGS,
service_func=handle_change_switch_settings,
schema=SCHEMA_CHANGE_SWITCH_SETTINGS,
)

View file

@ -1256,6 +1256,9 @@ async def test_area(hass):
async def test_change_switch_settings_service(hass):
"""Test adaptive_lighting.change_switch_settings service."""
switch, (_, _, light) = await setup_lights_and_switch(hass)
switch2, (_, light2, _) = await setup_lights_and_switch(
hass, {CONF_NAME: "second_switch"}
)
entity_id = light.entity_id
assert entity_id not in switch._lights
@ -1264,7 +1267,6 @@ async def test_change_switch_settings_service(hass):
DOMAIN,
SERVICE_CHANGE_SWITCH_SETTINGS,
{
ATTR_ENTITY_ID: ENTITY_SWITCH,
**kwargs,
},
blocking=True,
@ -1273,12 +1275,16 @@ async def test_change_switch_settings_service(hass):
# Test changing sunrise offset
assert switch._sun_light_settings.sunrise_offset.total_seconds() == 0
await change_switch_settings(**{CONF_SUNRISE_OFFSET: 10})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_SUNRISE_OFFSET: 10}
)
assert switch._sun_light_settings.sunrise_offset.total_seconds() == 10
# Test changing max brightness
assert switch._sun_light_settings.max_brightness == 100
await change_switch_settings(**{CONF_MAX_BRIGHTNESS: 50})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_MAX_BRIGHTNESS: 50}
)
assert switch._sun_light_settings.max_brightness == 50
# Test changing to illegal max brightness
@ -1286,20 +1292,33 @@ async def test_change_switch_settings_service(hass):
voluptuous.error.MultipleInvalid,
match="value must be at most 100 for dictionary",
):
await change_switch_settings(**{CONF_MAX_BRIGHTNESS: 5000})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_MAX_BRIGHTNESS: 5000}
)
# Change CONF_MIN_COLOR_TEMP, the factory default is 2000, but setup_lights_and_switch
# sets it to 2500
assert switch._sun_light_settings.min_color_temp == 2500
# testing with "factory" should change it to 2000
await change_switch_settings(**{CONF_USE_DEFAULTS: "factory"})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_USE_DEFAULTS: "factory"}
)
assert switch._sun_light_settings.min_color_temp == 2000
# testing with "current" should not change things
await change_switch_settings(**{CONF_USE_DEFAULTS: "current"})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_USE_DEFAULTS: "current"}
)
assert switch._sun_light_settings.min_color_temp == 2000
# testing with "configuration" should revert back to 2500
await change_switch_settings(**{CONF_USE_DEFAULTS: "configuration"})
await change_switch_settings(
**{ATTR_ENTITY_ID: ENTITY_SWITCH, CONF_USE_DEFAULTS: "configuration"}
)
assert switch._sun_light_settings.min_color_temp == 2500
# testing with no switches or lights defined.
assert switch2._sun_light_settings.max_brightness == 100
await change_switch_settings(**{CONF_MAX_BRIGHTNESS: 50})
assert switch2._sun_light_settings.max_brightness == 50