Improve loops and lists (#113269)

* Enable PERF

* Enable PERF rule

* Enable PERF rule

* Don't enable flag yet
pull/113401/head
Joost Lekkerkerker 2024-03-14 10:22:20 +01:00 committed by GitHub
parent 8a98fb7cfd
commit 05172d8e4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 125 additions and 172 deletions

View File

@ -58,10 +58,7 @@ def _merge_policies(sources: list[CategoryType]) -> CategoryType:
continue continue
seen.add(key) seen.add(key)
key_sources = [] key_sources = [src.get(key) for src in sources if isinstance(src, dict)]
for src in sources:
if isinstance(src, dict):
key_sources.append(src.get(key))
policy[key] = _merge_policies(key_sources) policy[key] = _merge_policies(key_sources)

View File

@ -98,16 +98,16 @@ async def async_setup_entry(
_LOGGER.error("No devices found") _LOGGER.error("No devices found")
return return
tasks = [] tasks = [
for heater in data_connection.get_devices(): asyncio.create_task(heater.update_device_info())
tasks.append(asyncio.create_task(heater.update_device_info())) for heater in data_connection.get_devices()
]
await asyncio.wait(tasks) await asyncio.wait(tasks)
devs = [] async_add_entities(
for heater in data_connection.get_devices(): (AmbiclimateEntity(heater, store) for heater in data_connection.get_devices()),
devs.append(AmbiclimateEntity(heater, store)) True,
)
async_add_entities(devs, True)
async def send_comfort_feedback(service: ServiceCall) -> None: async def send_comfort_feedback(service: ServiceCall) -> None:
"""Send comfort feedback.""" """Send comfort feedback."""

View File

@ -230,15 +230,14 @@ class AWSSQS(AWSNotify):
async with self.session.create_client( async with self.session.create_client(
self.service, **self.aws_config self.service, **self.aws_config
) as client: ) as client:
tasks = [] tasks = [
for target in kwargs.get(ATTR_TARGET, []): client.send_message(
tasks.append( QueueUrl=target,
client.send_message( MessageBody=json_body,
QueueUrl=target, MessageAttributes=message_attributes,
MessageBody=json_body,
MessageAttributes=message_attributes,
)
) )
for target in kwargs.get(ATTR_TARGET, [])
]
if tasks: if tasks:
await asyncio.gather(*tasks) await asyncio.gather(*tasks)

View File

@ -46,13 +46,13 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Ecovacs vacuums.""" """Set up the Ecovacs vacuums."""
vacuums: list[EcovacsVacuum | EcovacsLegacyVacuum] = []
controller: EcovacsController = hass.data[DOMAIN][config_entry.entry_id] controller: EcovacsController = hass.data[DOMAIN][config_entry.entry_id]
vacuums: list[EcovacsVacuum | EcovacsLegacyVacuum] = [
EcovacsVacuum(device) for device in controller.devices(VacuumCapabilities)
]
for device in controller.legacy_devices: for device in controller.legacy_devices:
await hass.async_add_executor_job(device.connect_and_wait_until_ready) await hass.async_add_executor_job(device.connect_and_wait_until_ready)
vacuums.append(EcovacsLegacyVacuum(device)) vacuums.append(EcovacsLegacyVacuum(device))
for device in controller.devices(VacuumCapabilities):
vacuums.append(EcovacsVacuum(device))
_LOGGER.debug("Adding Ecovacs Vacuums to Home Assistant: %s", vacuums) _LOGGER.debug("Adding Ecovacs Vacuums to Home Assistant: %s", vacuums)
async_add_entities(vacuums) async_add_entities(vacuums)

View File

@ -223,29 +223,29 @@ async def async_setup_entry(
"""Set up the Glances sensors.""" """Set up the Glances sensors."""
coordinator: GlancesDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] coordinator: GlancesDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]
entities = [] entities: list[GlancesSensor] = []
for sensor_type, sensors in coordinator.data.items(): for sensor_type, sensors in coordinator.data.items():
if sensor_type in ["fs", "sensors", "raid"]: if sensor_type in ["fs", "sensors", "raid"]:
for sensor_label, params in sensors.items(): entities.extend(
for param in params: GlancesSensor(
if sensor_description := SENSOR_TYPES.get((sensor_type, param)): coordinator,
entities.append( sensor_description,
GlancesSensor( sensor_label,
coordinator, )
sensor_description, for sensor_label, params in sensors.items()
sensor_label, for param in params
) if (sensor_description := SENSOR_TYPES.get((sensor_type, param)))
) )
else: else:
for sensor in sensors: entities.extend(
if sensor_description := SENSOR_TYPES.get((sensor_type, sensor)): GlancesSensor(
entities.append( coordinator,
GlancesSensor( sensor_description,
coordinator, )
sensor_description, for sensor in sensors
) if (sensor_description := SENSOR_TYPES.get((sensor_type, sensor)))
) )
async_add_entities(entities) async_add_entities(entities)

View File

@ -66,8 +66,8 @@ class BroadcastNotificationService(BaseNotificationService):
if not targets: if not targets:
commands.append(broadcast_commands(language_code)[0].format(message)) commands.append(broadcast_commands(language_code)[0].format(message))
else: else:
for target in targets: commands.extend(
commands.append( broadcast_commands(language_code)[1].format(message, target)
broadcast_commands(language_code)[1].format(message, target) for target in targets
) )
await async_send_text_commands(self.hass, commands) await async_send_text_commands(self.hass, commands)

View File

@ -72,16 +72,14 @@ def setup_platform(
easyfire.run_thread() easyfire.run_thread()
sensors = []
for sensor in easyfire.get_sensors():
if (sensor.sensor_type != kwb.PROP_SENSOR_RAW) or (
sensor.sensor_type == kwb.PROP_SENSOR_RAW and raw
):
sensors.append(KWBSensor(easyfire, sensor, client_name))
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, lambda event: easyfire.stop_thread()) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, lambda event: easyfire.stop_thread())
add_entities(sensors) add_entities(
KWBSensor(easyfire, sensor, client_name)
for sensor in easyfire.get_sensors()
if (sensor.sensor_type != kwb.PROP_SENSOR_RAW)
or (sensor.sensor_type == kwb.PROP_SENSOR_RAW and raw)
)
class KWBSensor(SensorEntity): class KWBSensor(SensorEntity):

View File

@ -134,21 +134,6 @@ async def async_setup_entry(
"""Set up the Honeywell Lyric sensor platform based on a config entry.""" """Set up the Honeywell Lyric sensor platform based on a config entry."""
coordinator: DataUpdateCoordinator[Lyric] = hass.data[DOMAIN][entry.entry_id] coordinator: DataUpdateCoordinator[Lyric] = hass.data[DOMAIN][entry.entry_id]
entities = []
for location in coordinator.data.locations:
for device in location.devices:
for device_sensor in DEVICE_SENSORS:
if device_sensor.suitable_fn(device):
entities.append(
LyricSensor(
coordinator,
device_sensor,
location,
device,
)
)
async_add_entities( async_add_entities(
LyricSensor( LyricSensor(
coordinator, coordinator,

View File

@ -311,15 +311,12 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Add a NextDNS entities from a config_entry.""" """Add a NextDNS entities from a config_entry."""
sensors: list[NextDnsSensor] = []
coordinators = hass.data[DOMAIN][entry.entry_id] coordinators = hass.data[DOMAIN][entry.entry_id]
for description in SENSORS: async_add_entities(
sensors.append( NextDnsSensor(coordinators[description.coordinator_type], description)
NextDnsSensor(coordinators[description.coordinator_type], description) for description in SENSORS
) )
async_add_entities(sensors)
class NextDnsSensor( class NextDnsSensor(

View File

@ -21,11 +21,10 @@ def setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up the QR code image processing platform.""" """Set up the QR code image processing platform."""
entities = [] add_entities(
for camera in config[CONF_SOURCE]: QrEntity(camera[CONF_ENTITY_ID], camera.get(CONF_NAME))
entities.append(QrEntity(camera[CONF_ENTITY_ID], camera.get(CONF_NAME))) for camera in config[CONF_SOURCE]
)
add_entities(entities)
class QrEntity(ImageProcessingEntity): class QrEntity(ImageProcessingEntity):

View File

@ -556,10 +556,11 @@ def _drop_foreign_key_constraints(
) -> None: ) -> None:
"""Drop foreign key constraints for a table on specific columns.""" """Drop foreign key constraints for a table on specific columns."""
inspector = sqlalchemy.inspect(engine) inspector = sqlalchemy.inspect(engine)
drops = [] drops = [
for foreign_key in inspector.get_foreign_keys(table): ForeignKeyConstraint((), (), name=foreign_key["name"])
if foreign_key["name"] and foreign_key["constrained_columns"] == columns: for foreign_key in inspector.get_foreign_keys(table)
drops.append(ForeignKeyConstraint((), (), name=foreign_key["name"])) if foreign_key["name"] and foreign_key["constrained_columns"] == columns
]
# Bind the ForeignKeyConstraints to the table # Bind the ForeignKeyConstraints to the table
old_table = Table(table, MetaData(), *drops) # noqa: F841 old_table = Table(table, MetaData(), *drops) # noqa: F841

View File

@ -219,14 +219,17 @@ async def get_coap_context(hass: HomeAssistant) -> COAP:
ipv4: list[IPv4Address] = [] ipv4: list[IPv4Address] = []
if not network.async_only_default_interface_enabled(adapters): if not network.async_only_default_interface_enabled(adapters):
for address in await network.async_get_enabled_source_ips(hass): ipv4.extend(
if address.version == 4 and not ( address
for address in await network.async_get_enabled_source_ips(hass)
if address.version == 4
and not (
address.is_link_local address.is_link_local
or address.is_loopback or address.is_loopback
or address.is_multicast or address.is_multicast
or address.is_unspecified or address.is_unspecified
): )
ipv4.append(address) )
LOGGER.debug("Network IPv4 addresses: %s", ipv4) LOGGER.debug("Network IPv4 addresses: %s", ipv4)
if DOMAIN in hass.data: if DOMAIN in hass.data:
port = hass.data[DOMAIN].get(CONF_COAP_PORT, DEFAULT_COAP_PORT) port = hass.data[DOMAIN].get(CONF_COAP_PORT, DEFAULT_COAP_PORT)

View File

@ -89,10 +89,7 @@ class SigfoxAPI:
"""Get a list of device types.""" """Get a list of device types."""
url = urljoin(API_URL, "devicetypes") url = urljoin(API_URL, "devicetypes")
response = requests.get(url, auth=self._auth, timeout=10) response = requests.get(url, auth=self._auth, timeout=10)
device_types = [] return [device["id"] for device in json.loads(response.text)["data"]]
for device in json.loads(response.text)["data"]:
device_types.append(device["id"])
return device_types
def get_devices(self, device_types): def get_devices(self, device_types):
"""Get the device_id of each device registered.""" """Get the device_id of each device registered."""

View File

@ -29,14 +29,14 @@ async def async_setup_entry(
data: SleepIQData = hass.data[DOMAIN][entry.entry_id] data: SleepIQData = hass.data[DOMAIN][entry.entry_id]
entities: list[SleepIQBedEntity] = [] entities: list[SleepIQBedEntity] = []
for bed in data.client.beds.values(): for bed in data.client.beds.values():
for preset in bed.foundation.presets: entities.extend(
entities.append(SleepIQSelectEntity(data.data_coordinator, bed, preset)) SleepIQSelectEntity(data.data_coordinator, bed, preset)
for foot_warmer in bed.foundation.foot_warmers: for preset in bed.foundation.presets
entities.append( )
SleepIQFootWarmingTempSelectEntity( entities.extend(
data.data_coordinator, bed, foot_warmer SleepIQFootWarmingTempSelectEntity(data.data_coordinator, bed, foot_warmer)
) for foot_warmer in bed.foundation.foot_warmers
) )
async_add_entities(entities) async_add_entities(entities)

View File

@ -124,18 +124,18 @@ class SynologyPhotosMediaSource(MediaSource):
can_expand=True, can_expand=True,
) )
] ]
for album in albums: ret.extend(
ret.append( BrowseMediaSource(
BrowseMediaSource( domain=DOMAIN,
domain=DOMAIN, identifier=f"{item.identifier}/{album.album_id}",
identifier=f"{item.identifier}/{album.album_id}", media_class=MediaClass.DIRECTORY,
media_class=MediaClass.DIRECTORY, media_content_type=MediaClass.IMAGE,
media_content_type=MediaClass.IMAGE, title=album.name,
title=album.name, can_play=False,
can_play=False, can_expand=True,
can_expand=True,
)
) )
for album in albums
)
return ret return ret

View File

@ -60,11 +60,11 @@ async def async_setup_entry(
for device_id in device_ids: for device_id in device_ids:
device = hass_data.manager.device_map[device_id] device = hass_data.manager.device_map[device_id]
if descriptions := SIRENS.get(device.category): if descriptions := SIRENS.get(device.category):
for description in descriptions: entities.extend(
if description.key in device.status: TuyaSirenEntity(device, hass_data.manager, description)
entities.append( for description in descriptions
TuyaSirenEntity(device, hass_data.manager, description) if description.key in device.status
) )
async_add_entities(entities) async_add_entities(entities)

View File

@ -55,15 +55,6 @@ async def async_setup_entry(
for device_coordinator in device_coordinators.values() for device_coordinator in device_coordinators.values()
if device_coordinator.device.device_type in DEVICE_TYPE if device_coordinator.device.device_type in DEVICE_TYPE
] ]
entities = []
for siren_device_coordinator in siren_device_coordinators:
for description in DEVICE_TYPES:
if description.exists_fn(siren_device_coordinator.device):
entities.append(
YoLinkSirenEntity(
config_entry, siren_device_coordinator, description
)
)
async_add_entities( async_add_entities(
YoLinkSirenEntity(config_entry, siren_device_coordinator, description) YoLinkSirenEntity(config_entry, siren_device_coordinator, description)
for siren_device_coordinator in siren_device_coordinators for siren_device_coordinator in siren_device_coordinators

View File

@ -206,12 +206,11 @@ class ZHAGroup(LogMixin):
@property @property
def member_entity_ids(self) -> list[str]: def member_entity_ids(self) -> list[str]:
"""Return the ZHA entity ids for all entities for the members of this group.""" """Return the ZHA entity ids for all entities for the members of this group."""
all_entity_ids: list[str] = [] return [
for member in self.members: entity_reference["entity_id"]
entity_references = member.associated_entities for member in self.members
for entity_reference in entity_references: for entity_reference in member.associated_entities
all_entity_ids.append(entity_reference["entity_id"]) ]
return all_entity_ids
def get_domain_entity_ids(self, domain: str) -> list[str]: def get_domain_entity_ids(self, domain: str) -> list[str]:
"""Return entity ids from the entity domain for this group.""" """Return entity ids from the entity domain for this group."""

View File

@ -221,10 +221,10 @@ class YamlCollection(ObservableCollection[dict]):
self.data[item_id] = item self.data[item_id] = item
change_sets.append(CollectionChangeSet(event, item_id, item)) change_sets.append(CollectionChangeSet(event, item_id, item))
for item_id in old_ids: change_sets.extend(
change_sets.append( CollectionChangeSet(CHANGE_REMOVED, item_id, self.data.pop(item_id))
CollectionChangeSet(CHANGE_REMOVED, item_id, self.data.pop(item_id)) for item_id in old_ids
) )
if change_sets: if change_sets:
await self.notify_changes(change_sets) await self.notify_changes(change_sets)

View File

@ -142,10 +142,9 @@ def _convert_globs_to_pattern(globs: list[str] | None) -> re.Pattern[str] | None
if globs is None: if globs is None:
return None return None
translated_patterns: list[str] = [] translated_patterns: list[str] = [
for glob in set(globs): pattern for glob in set(globs) if (pattern := fnmatch.translate(glob))
if pattern := fnmatch.translate(glob): ]
translated_patterns.append(pattern)
if not translated_patterns: if not translated_patterns:
return None return None

View File

@ -175,8 +175,7 @@ class HomeAssistantView:
handler = request_handler_factory(hass, self, handler) handler = request_handler_factory(hass, self, handler)
for url in urls: routes.extend(router.add_route(method, url, handler) for url in urls)
routes.append(router.add_route(method, url, handler))
# Use `get` because CORS middleware is not be loaded in emulated_hue # Use `get` because CORS middleware is not be loaded in emulated_hue
if self.cors_allowed: if self.cors_allowed:

View File

@ -57,9 +57,7 @@ class FrozenOrThawed(type):
def _make_dataclass(cls, name: str, bases: tuple[type, ...], kw_only: bool) -> None: def _make_dataclass(cls, name: str, bases: tuple[type, ...], kw_only: bool) -> None:
class_fields = _class_fields(cls, kw_only) class_fields = _class_fields(cls, kw_only)
dataclass_bases = [] dataclass_bases = [getattr(base, "_dataclass", base) for base in bases]
for base in bases:
dataclass_bases.append(getattr(base, "_dataclass", base))
cls._dataclass = dataclasses.make_dataclass( cls._dataclass = dataclasses.make_dataclass(
name, class_fields, bases=tuple(dataclass_bases), frozen=True name, class_fields, bases=tuple(dataclass_bases), frozen=True
) )

View File

@ -347,8 +347,7 @@ def generate_requirements_list(reqs: dict[str, list[str]]) -> str:
"""Generate a pip file based on requirements.""" """Generate a pip file based on requirements."""
output = [] output = []
for pkg, requirements in sorted(reqs.items(), key=itemgetter(0)): for pkg, requirements in sorted(reqs.items(), key=itemgetter(0)):
for req in sorted(requirements): output.extend(f"\n# {req}" for req in sorted(requirements))
output.append(f"\n# {req}")
if comment_requirement(pkg): if comment_requirement(pkg):
output.append(f"\n# {pkg}\n") output.append(f"\n# {pkg}\n")

View File

@ -16,8 +16,7 @@ def generate_and_validate(integrations: dict[str, Integration]) -> str:
if not match_types: if not match_types:
continue continue
for entry in match_types: match_list.extend({"domain": domain, **entry} for entry in match_types)
match_list.append({"domain": domain, **entry})
return format_python_namespace( return format_python_namespace(
{"BLUETOOTH": match_list}, {"BLUETOOTH": match_list},

View File

@ -16,8 +16,7 @@ def generate_and_validate(integrations: dict[str, Integration]) -> str:
if not match_types: if not match_types:
continue continue
for entry in match_types: match_list.extend({"domain": domain, **entry} for entry in match_types)
match_list.append({"domain": domain, **entry})
return format_python_namespace( return format_python_namespace(
{"DHCP": match_list}, {"DHCP": match_list},

View File

@ -16,13 +16,13 @@ def generate_and_validate(integrations: dict[str, Integration]) -> str:
if not match_types: if not match_types:
continue continue
for entry in match_types: match_list.extend(
match_list.append( {
{ "domain": domain,
"domain": domain, **{k: v for k, v in entry.items() if k != "known_devices"},
**{k: v for k, v in entry.items() if k != "known_devices"}, }
} for entry in match_types
) )
return format_python_namespace({"USB": match_list}) return format_python_namespace({"USB": match_list})

View File

@ -2397,9 +2397,9 @@ async def test_cached_entity_property_class_attribute(hass: HomeAssistant) -> No
EntityWithClassAttribute4, EntityWithClassAttribute4,
) )
entities: list[tuple[entity.Entity, entity.Entity]] = [] entities: list[tuple[entity.Entity, entity.Entity]] = [
for cls in classes: (cls(), cls()) for cls in classes
entities.append((cls(), cls())) ]
for ent in entities: for ent in entities:
assert getattr(ent[0], property) == values[0] assert getattr(ent[0], property) == values[0]

View File

@ -3915,9 +3915,9 @@ async def test_entry_reload_concurrency(
), ),
) )
mock_platform(hass, "comp.config_flow", None) mock_platform(hass, "comp.config_flow", None)
tasks = [] tasks = [
for _ in range(15): asyncio.create_task(manager.async_reload(entry.entry_id)) for _ in range(15)
tasks.append(asyncio.create_task(manager.async_reload(entry.entry_id))) ]
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
assert entry.state is config_entries.ConfigEntryState.LOADED assert entry.state is config_entries.ConfigEntryState.LOADED
assert loaded == 1 assert loaded == 1

View File

@ -17,10 +17,7 @@ from tests.common import (
def _create_tuples( def _create_tuples(
value: Enum | list[Enum], constant_prefix: str value: Enum | list[Enum], constant_prefix: str
) -> list[tuple[Enum, str]]: ) -> list[tuple[Enum, str]]:
result = [] return [(enum, constant_prefix) for enum in value]
for enum in value:
result.append((enum, constant_prefix))
return result
def test_all() -> None: def test_all() -> None:

View File

@ -21,10 +21,7 @@ async def test_executor_shutdown_can_interrupt_threads(
while True: while True:
time.sleep(0.1) time.sleep(0.1)
sleep_futures = [] sleep_futures = [iexecutor.submit(_loop_sleep_in_executor) for _ in range(100)]
for _ in range(100):
sleep_futures.append(iexecutor.submit(_loop_sleep_in_executor))
iexecutor.shutdown() iexecutor.shutdown()