mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 13:45:15 +00:00
[core] Enable ruff B (flake8-bugbear) lint family (#16655)
This commit is contained in:
@@ -608,7 +608,7 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||||
process_stacktrace = getattr(module, "process_stacktrace")
|
process_stacktrace = module.process_stacktrace
|
||||||
except (AttributeError, ImportError):
|
except (AttributeError, ImportError):
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'Stacktrace analysis is unavailable: no compatible analyzer found for target platform "%s".',
|
'Stacktrace analysis is unavailable: no compatible analyzer found for target platform "%s".',
|
||||||
@@ -1101,7 +1101,7 @@ def upload_program(
|
|||||||
host = devices[0]
|
host = devices[0]
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||||
if getattr(module, "upload_program")(config, args, host):
|
if module.upload_program(config, args, host):
|
||||||
return 0, host
|
return 0, host
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
@@ -1353,7 +1353,7 @@ def _validate_bootloader_binary(binary: Path) -> None:
|
|||||||
def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int | None:
|
def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int | None:
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||||
if getattr(module, "show_logs")(config, args, devices):
|
if module.show_logs(config, args, devices):
|
||||||
return 0
|
return 0
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -509,7 +509,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
lines.append(
|
lines.append(
|
||||||
f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):"
|
f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):"
|
||||||
)
|
)
|
||||||
for i, (symbol, demangled, size) in enumerate(large_core_symbols):
|
for i, (_symbol, demangled, size) in enumerate(large_core_symbols):
|
||||||
# Core symbols only track (symbol, demangled, size) without section info,
|
# Core symbols only track (symbol, demangled, size) without section info,
|
||||||
# so we don't show section labels here
|
# so we don't show section labels here
|
||||||
lines.append(
|
lines.append(
|
||||||
@@ -601,7 +601,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
lines.append(
|
lines.append(
|
||||||
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B & storage ({len(large_symbols)} symbols):"
|
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B & storage ({len(large_symbols)} symbols):"
|
||||||
)
|
)
|
||||||
for i, (symbol, demangled, size, section) in enumerate(large_symbols):
|
for i, (_symbol, demangled, size, section) in enumerate(large_symbols):
|
||||||
lines.append(
|
lines.append(
|
||||||
f"{i + 1}. {self._format_symbol_with_section(demangled, size, section)}"
|
f"{i + 1}. {self._format_symbol_with_section(demangled, size, section)}"
|
||||||
)
|
)
|
||||||
@@ -640,7 +640,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
|
|||||||
lines.append(
|
lines.append(
|
||||||
f" Symbols > {self.RAM_SYMBOL_SIZE_THRESHOLD} B ({len(large_ram_syms)}):"
|
f" Symbols > {self.RAM_SYMBOL_SIZE_THRESHOLD} B ({len(large_ram_syms)}):"
|
||||||
)
|
)
|
||||||
for symbol, demangled, size, section in large_ram_syms[:10]:
|
for _symbol, demangled, size, section in large_ram_syms[:10]:
|
||||||
# Format section label consistently by stripping leading dot
|
# Format section label consistently by stripping leading dot
|
||||||
section_label = section.lstrip(".") if section else ""
|
section_label = section.lstrip(".") if section else ""
|
||||||
display_name = _format_pstorage_name(demangled)
|
display_name = _format_pstorage_name(demangled)
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ def batch_demangle(
|
|||||||
failed_count = 0
|
failed_count = 0
|
||||||
|
|
||||||
for original, stripped, prefix, demangled in zip(
|
for original, stripped, prefix, demangled in zip(
|
||||||
symbols, symbols_stripped, symbols_prefixes, demangled_lines
|
symbols, symbols_stripped, symbols_prefixes, demangled_lines, strict=True
|
||||||
):
|
):
|
||||||
# Add back any prefix that was removed
|
# Add back any prefix that was removed
|
||||||
demangled = _restore_symbol_prefix(prefix, stripped, demangled)
|
demangled = _restore_symbol_prefix(prefix, stripped, demangled)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ async def async_run_logs(
|
|||||||
platform_process_stacktrace = None
|
platform_process_stacktrace = None
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||||
platform_process_stacktrace = getattr(module, "process_stacktrace")
|
platform_process_stacktrace = module.process_stacktrace
|
||||||
except (AttributeError, ImportError):
|
except (AttributeError, ImportError):
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
'Stacktrace analysis is unavailable: no compatible analyzer found for target platform "%s".',
|
'Stacktrace analysis is unavailable: no compatible analyzer found for target platform "%s".',
|
||||||
|
|||||||
@@ -594,7 +594,9 @@ async def to_code(config):
|
|||||||
x.height,
|
x.height,
|
||||||
]
|
]
|
||||||
for (x, y) in zip(
|
for (x, y) in zip(
|
||||||
glyph_args, list(accumulate([len(x.bitmap_data) for x in glyph_args]))
|
glyph_args,
|
||||||
|
list(accumulate([len(x.bitmap_data) for x in glyph_args])),
|
||||||
|
strict=True,
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ def color_retmapper(value):
|
|||||||
else:
|
else:
|
||||||
r, g, b, _ = from_rgbw(cval)
|
r, g, b, _ = from_rgbw(cval)
|
||||||
return literal(f"lv_color_make({r}, {g}, {b})")
|
return literal(f"lv_color_make({r}, {g}, {b})")
|
||||||
assert False
|
raise AssertionError(f"Unhandled lv_color value: {value!r}")
|
||||||
|
|
||||||
|
|
||||||
def option_string(value):
|
def option_string(value):
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class TabviewType(WidgetType):
|
|||||||
tab_bar = Widget(bar_obj, obj_spec)
|
tab_bar = Widget(bar_obj, obj_spec)
|
||||||
await set_obj_properties(tab_bar, tab_style)
|
await set_obj_properties(tab_bar, tab_style)
|
||||||
if tab_items_style:
|
if tab_items_style:
|
||||||
for index, tab_conf in enumerate(config[CONF_TABS]):
|
for index, _tab_conf in enumerate(config[CONF_TABS]):
|
||||||
await set_obj_properties(
|
await set_obj_properties(
|
||||||
Widget(lv_obj.get_child(bar_obj, index), button_spec),
|
Widget(lv_obj.get_child(bar_obj, index), button_spec),
|
||||||
tab_items_style,
|
tab_items_style,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ CONFIG_SCHEMA = MSA_SENSOR_SCHEMA.extend(
|
|||||||
),
|
),
|
||||||
key=CONF_NAME,
|
key=CONF_NAME,
|
||||||
)
|
)
|
||||||
for event, icon in zip(EVENT_SENSORS, ICONS)
|
for event, icon in zip(EVENT_SENSORS, ICONS, strict=True)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ async def new_openthermoutput(
|
|||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await output.register_output(var, config)
|
await output.register_output(var, config)
|
||||||
cg.add(getattr(var, "set_id")(cg.RawExpression(f'"{key}_{config[CONF_ID]}"')))
|
cg.add(var.set_id(cg.RawExpression(f'"{key}_{config[CONF_ID]}"')))
|
||||||
input.generate_setters(var, config)
|
input.generate_setters(var, config)
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|||||||
@@ -1192,7 +1192,7 @@ def _std(x):
|
|||||||
|
|
||||||
def _correlation_coeff(x, y):
|
def _correlation_coeff(x, y):
|
||||||
m_x, m_y = _mean(x), _mean(y)
|
m_x, m_y = _mean(x), _mean(y)
|
||||||
s_xy = sum((x_ - m_x) * (y_ - m_y) for x_, y_ in zip(x, y))
|
s_xy = sum((x_ - m_x) * (y_ - m_y) for x_, y_ in zip(x, y, strict=True))
|
||||||
s_sq_x = sum((x_ - m_x) ** 2 for x_ in x)
|
s_sq_x = sum((x_ - m_x) ** 2 for x_ in x)
|
||||||
s_sq_y = sum((y_ - m_y) ** 2 for y_ in y)
|
s_sq_y = sum((y_ - m_y) ** 2 for y_ in y)
|
||||||
return s_xy / math.sqrt(s_sq_x * s_sq_y)
|
return s_xy / math.sqrt(s_sq_x * s_sq_y)
|
||||||
@@ -1228,7 +1228,7 @@ def _mat_copy(m):
|
|||||||
|
|
||||||
|
|
||||||
def _mat_transpose(m):
|
def _mat_transpose(m):
|
||||||
return _mat_copy(zip(*m))
|
return _mat_copy(zip(*m, strict=True))
|
||||||
|
|
||||||
|
|
||||||
def _mat_identity(n):
|
def _mat_identity(n):
|
||||||
@@ -1237,7 +1237,10 @@ def _mat_identity(n):
|
|||||||
|
|
||||||
def _mat_dot(a, b):
|
def _mat_dot(a, b):
|
||||||
b_t = _mat_transpose(b)
|
b_t = _mat_transpose(b)
|
||||||
return [[sum(x * y for x, y in zip(row_a, col_b)) for col_b in b_t] for row_a in a]
|
return [
|
||||||
|
[sum(x * y for x, y in zip(row_a, col_b, strict=True)) for col_b in b_t]
|
||||||
|
for row_a in a
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _mat_inverse(m):
|
def _mat_inverse(m):
|
||||||
|
|||||||
@@ -1081,7 +1081,7 @@ class EnumValue:
|
|||||||
|
|
||||||
@enum_value.setter
|
@enum_value.setter
|
||||||
def enum_value(self, value):
|
def enum_value(self, value):
|
||||||
setattr(self, "_enum_value", value)
|
self._enum_value = value
|
||||||
|
|
||||||
|
|
||||||
CORE = EsphomeCore()
|
CORE = EsphomeCore()
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ class MDNSStatus:
|
|||||||
results = await asyncio.gather(
|
results = await asyncio.gather(
|
||||||
*(self.aiozc.async_resolve_host(name) for name in poll_names)
|
*(self.aiozc.async_resolve_host(name) for name in poll_names)
|
||||||
)
|
)
|
||||||
for name, address_list in zip(poll_names, results):
|
for name, address_list in zip(poll_names, results, strict=True):
|
||||||
result = bool(address_list)
|
result = bool(address_list)
|
||||||
host_mdns_state[name] = result
|
host_mdns_state[name] = result
|
||||||
for entry in poll_names[name]:
|
for entry in poll_names[name]:
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class PingStatus:
|
|||||||
return_exceptions=True,
|
return_exceptions=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry, result in zip(ping_group, dns_results):
|
for entry, result in zip(ping_group, dns_results, strict=True):
|
||||||
if isinstance(result, Exception):
|
if isinstance(result, Exception):
|
||||||
# Only update state if its unknown or from ping
|
# Only update state if its unknown or from ping
|
||||||
# so we don't mark it as offline if we have a state
|
# so we don't mark it as offline if we have a state
|
||||||
@@ -106,7 +106,7 @@ class PingStatus:
|
|||||||
return_exceptions=True,
|
return_exceptions=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
for entry_addresses, result in zip(entry_addresses, results):
|
for entry_address, result in zip(entry_addresses, results, strict=True):
|
||||||
if isinstance(result, Exception):
|
if isinstance(result, Exception):
|
||||||
ping_result = False
|
ping_result = False
|
||||||
elif isinstance(result, BaseException):
|
elif isinstance(result, BaseException):
|
||||||
@@ -114,7 +114,7 @@ class PingStatus:
|
|||||||
else:
|
else:
|
||||||
host: Host = result
|
host: Host = result
|
||||||
ping_result = host.is_alive
|
ping_result = host.is_alive
|
||||||
entry: DashboardEntry = entry_addresses[0]
|
entry: DashboardEntry = entry_address[0]
|
||||||
# If we can reach it via ping, we always set it
|
# If we can reach it via ping, we always set it
|
||||||
# online, however if we can't reach it via ping
|
# online, however if we can't reach it via ping
|
||||||
# we only set it to offline if the state is unknown
|
# we only set it to offline if the state is unknown
|
||||||
|
|||||||
@@ -1030,7 +1030,7 @@ class DownloadListRequestHandler(BaseHandler):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(f"esphome.components.{platform}")
|
module = importlib.import_module(f"esphome.components.{platform}")
|
||||||
get_download_types = getattr(module, "get_download_types")
|
get_download_types = module.get_download_types
|
||||||
except AttributeError as exc:
|
except AttributeError as exc:
|
||||||
raise ValueError(f"Unknown platform {platform}") from exc
|
raise ValueError(f"Unknown platform {platform}") from exc
|
||||||
downloads = get_download_types(storage_json)
|
downloads = get_download_types(storage_json)
|
||||||
@@ -1146,7 +1146,7 @@ class MainRequestHandler(BaseHandler):
|
|||||||
begin = bool(self.get_argument("begin", False))
|
begin = bool(self.get_argument("begin", False))
|
||||||
if settings.using_password:
|
if settings.using_password:
|
||||||
# Simply accessing the xsrf_token sets the cookie for us
|
# Simply accessing the xsrf_token sets the cookie for us
|
||||||
self.xsrf_token # pylint: disable=pointless-statement
|
self.xsrf_token # pylint: disable=pointless-statement # noqa: B018
|
||||||
else:
|
else:
|
||||||
self.clear_cookie("_xsrf")
|
self.clear_cookie("_xsrf")
|
||||||
|
|
||||||
@@ -1519,7 +1519,10 @@ def get_static_file_url(name: str) -> str:
|
|||||||
return f"{base}?hash={hash_}"
|
return f"{base}?hash={hash_}"
|
||||||
|
|
||||||
|
|
||||||
def make_app(debug=get_bool_env(ENV_DEV)) -> tornado.web.Application:
|
def make_app(debug: bool | None = None) -> tornado.web.Application:
|
||||||
|
if debug is None:
|
||||||
|
debug = get_bool_env(ENV_DEV)
|
||||||
|
|
||||||
def log_function(handler: tornado.web.RequestHandler) -> None:
|
def log_function(handler: tornado.web.RequestHandler) -> None:
|
||||||
if handler.get_status() < 400:
|
if handler.get_status() < 400:
|
||||||
log_method = access_log.info
|
log_method = access_log.info
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ def copy_src_tree():
|
|||||||
platform = "esphome.components." + CORE.target_platform
|
platform = "esphome.components." + CORE.target_platform
|
||||||
try:
|
try:
|
||||||
module = importlib.import_module(platform)
|
module = importlib.import_module(platform)
|
||||||
copy_files = getattr(module, "copy_files")
|
copy_files = module.copy_files
|
||||||
copy_files()
|
copy_files()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ async def async_resolve_hosts(
|
|||||||
),
|
),
|
||||||
return_exceptions=True,
|
return_exceptions=True,
|
||||||
)
|
)
|
||||||
for host, result in zip(pending, results):
|
for host, result in zip(pending, results, strict=True):
|
||||||
if isinstance(result, BaseException):
|
if isinstance(result, BaseException):
|
||||||
_LOGGER.debug("Failed to resolve %s: %s", host, result)
|
_LOGGER.debug("Failed to resolve %s: %s", host, result)
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ exclude = ['generated']
|
|||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
select = [
|
select = [
|
||||||
|
"B", # flake8-bugbear
|
||||||
"C4", # flake8-comprehensions
|
"C4", # flake8-comprehensions
|
||||||
"E", # pycodestyle
|
"E", # pycodestyle
|
||||||
"EXE", # flake8-executable
|
"EXE", # flake8-executable
|
||||||
|
|||||||
@@ -3551,7 +3551,7 @@ static const char *const TAG = "api.service";
|
|||||||
if id_ is not None and not mt.options.deprecated:
|
if id_ is not None and not mt.options.deprecated:
|
||||||
id_to_msg_name[id_] = mt.name
|
id_to_msg_name[id_] = mt.name
|
||||||
|
|
||||||
for id_, (_, _, case_label) in cases:
|
for id_, (_, _, _case_label) in cases:
|
||||||
msg_name = id_to_msg_name.get(id_, "")
|
msg_name = id_to_msg_name.get(id_, "")
|
||||||
if msg_name in message_auth_map:
|
if msg_name in message_auth_map:
|
||||||
needs_auth = message_auth_map[msg_name]
|
needs_auth = message_auth_map[msg_name]
|
||||||
@@ -3614,7 +3614,7 @@ static const char *const TAG = "api.service";
|
|||||||
|
|
||||||
# Dispatch switch
|
# Dispatch switch
|
||||||
out += " switch (msg_type) {\n"
|
out += " switch (msg_type) {\n"
|
||||||
for i, (case, ifdef, case_label) in cases:
|
for _i, (case, ifdef, case_label) in cases:
|
||||||
if ifdef is not None:
|
if ifdef is not None:
|
||||||
out += _make_ifdef_line(ifdef) + "\n"
|
out += _make_ifdef_line(ifdef) + "\n"
|
||||||
|
|
||||||
|
|||||||
@@ -972,7 +972,7 @@ def convert(schema, config_var, path):
|
|||||||
}
|
}
|
||||||
elif schema_type == "use_id":
|
elif schema_type == "use_id":
|
||||||
if inspect.ismodule(data):
|
if inspect.ismodule(data):
|
||||||
m_attr_obj = getattr(data, "CONFIG_SCHEMA")
|
m_attr_obj = data.CONFIG_SCHEMA
|
||||||
use_schema = known_schemas.get(repr(m_attr_obj))
|
use_schema = known_schemas.get(repr(m_attr_obj))
|
||||||
if use_schema:
|
if use_schema:
|
||||||
[output_module, output_name] = use_schema[0][1].split(".")
|
[output_module, output_name] = use_schema[0][1].split(".")
|
||||||
|
|||||||
@@ -342,8 +342,8 @@ def lint_const_ordered(fname, content):
|
|||||||
(i + 1, line) for i, line in enumerate(lines) if line.startswith(start)
|
(i + 1, line) for i, line in enumerate(lines) if line.startswith(start)
|
||||||
]
|
]
|
||||||
ordered = sorted(matching, key=lambda x: x[1].replace("_", " "))
|
ordered = sorted(matching, key=lambda x: x[1].replace("_", " "))
|
||||||
ordered = [(mi, ol) for (mi, _), (_, ol) in zip(matching, ordered)]
|
ordered = [(mi, ol) for (mi, _), (_, ol) in zip(matching, ordered, strict=True)]
|
||||||
for (mi, mline), (_, ol) in zip(matching, ordered):
|
for (mi, mline), (_, ol) in zip(matching, ordered, strict=True):
|
||||||
if mline == ol:
|
if mline == ol:
|
||||||
continue
|
continue
|
||||||
target = next(i for i, line in ordered if line == mline)
|
target = next(i for i, line in ordered if line == mline)
|
||||||
|
|||||||
@@ -1047,7 +1047,7 @@ def detect_memory_impact_config(
|
|||||||
# Find common platforms supported by ALL components
|
# Find common platforms supported by ALL components
|
||||||
# This ensures we can build all components together in a merged config
|
# This ensures we can build all components together in a merged config
|
||||||
common_platforms = set(MEMORY_IMPACT_PLATFORM_PREFERENCE)
|
common_platforms = set(MEMORY_IMPACT_PLATFORM_PREFERENCE)
|
||||||
for component, platforms in component_platforms_map.items():
|
for platforms in component_platforms_map.values():
|
||||||
common_platforms &= platforms
|
common_platforms &= platforms
|
||||||
|
|
||||||
# Select the most preferred platform from the common set
|
# Select the most preferred platform from the common set
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ def main() -> int:
|
|||||||
# Sort groups by signature for readability
|
# Sort groups by signature for readability
|
||||||
groupable_groups = []
|
groupable_groups = []
|
||||||
isolated_groups = []
|
isolated_groups = []
|
||||||
for (platform, signature), group_comps in sorted(signature_groups.items()):
|
for (_platform, signature), group_comps in sorted(signature_groups.items()):
|
||||||
if signature.startswith(ISOLATED_SIGNATURE_PREFIX):
|
if signature.startswith(ISOLATED_SIGNATURE_PREFIX):
|
||||||
isolated_groups.append((signature, group_comps))
|
isolated_groups.append((signature, group_comps))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -890,7 +890,7 @@ def run_grouped_component_tests(
|
|||||||
print("=" * 80 + "\n")
|
print("=" * 80 + "\n")
|
||||||
|
|
||||||
# Execute grouped tests
|
# Execute grouped tests
|
||||||
for (platform, signature), components in grouped_components.items():
|
for (platform, _signature), components in grouped_components.items():
|
||||||
# Only group if we have multiple components with same signature
|
# Only group if we have multiple components with same signature
|
||||||
if len(components) <= 1:
|
if len(components) <= 1:
|
||||||
continue
|
continue
|
||||||
@@ -1055,7 +1055,7 @@ def test_components(
|
|||||||
|
|
||||||
# Create empty test files for each platform (or filtered platform)
|
# Create empty test files for each platform (or filtered platform)
|
||||||
reference_tests: list[Path] = []
|
reference_tests: list[Path] = []
|
||||||
for platform_name, base_file in platform_bases.items():
|
for platform_name in platform_bases:
|
||||||
if platform_filter and not platform_name.startswith(platform_filter):
|
if platform_filter and not platform_name.startswith(platform_filter):
|
||||||
continue
|
continue
|
||||||
# Create an empty test file named to match the platform
|
# Create an empty test file named to match the platform
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from esphome.components.display import (
|
from esphome.components.display import (
|
||||||
DisplayMetaData,
|
DisplayMetaData,
|
||||||
add_metadata,
|
add_metadata,
|
||||||
@@ -74,8 +76,5 @@ def test_add_metadata_overwrites_existing():
|
|||||||
def test_metadata_is_frozen():
|
def test_metadata_is_frozen():
|
||||||
"""Test that DisplayMetaData instances are immutable (frozen dataclass)."""
|
"""Test that DisplayMetaData instances are immutable (frozen dataclass)."""
|
||||||
meta = DisplayMetaData(320, 240, True, False)
|
meta = DisplayMetaData(320, 240, True, False)
|
||||||
try:
|
with pytest.raises(AttributeError):
|
||||||
meta.width = 640
|
meta.width = 640
|
||||||
assert False, "Expected FrozenInstanceError"
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -510,15 +510,9 @@ def test_package_merge_by_missing_id() -> None:
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
error_raised = False
|
with pytest.raises(cv.Invalid) as exc_info:
|
||||||
try:
|
|
||||||
packages_pass(config)
|
packages_pass(config)
|
||||||
assert False, "Expected validation error for missing ID"
|
assert exc_info.value.path == [CONF_SENSOR, 2]
|
||||||
except cv.Invalid as err:
|
|
||||||
error_raised = True
|
|
||||||
assert err.path == [CONF_SENSOR, 2]
|
|
||||||
|
|
||||||
assert error_raised
|
|
||||||
|
|
||||||
|
|
||||||
def test_package_list_remove_by_id() -> None:
|
def test_package_list_remove_by_id() -> None:
|
||||||
|
|||||||
@@ -407,8 +407,10 @@ async def wait_and_connect_api_client(
|
|||||||
# Wait for connection with timeout
|
# Wait for connection with timeout
|
||||||
try:
|
try:
|
||||||
await asyncio.wait_for(connected_future, timeout=timeout)
|
await asyncio.wait_for(connected_future, timeout=timeout)
|
||||||
except TimeoutError:
|
except TimeoutError as err:
|
||||||
raise TimeoutError(f"Failed to connect to API after {timeout} seconds")
|
raise TimeoutError(
|
||||||
|
f"Failed to connect to API after {timeout} seconds"
|
||||||
|
) from err
|
||||||
|
|
||||||
if return_disconnect_event:
|
if return_disconnect_event:
|
||||||
yield client, disconnect_event
|
yield client, disconnect_event
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ def test_iter_component_configs_with_multi_conf(mock_get_component: Mock) -> Non
|
|||||||
configs = list(config.iter_component_configs(test_config))
|
configs = list(config.iter_component_configs(test_config))
|
||||||
assert len(configs) == 2
|
assert len(configs) == 2
|
||||||
|
|
||||||
for domain, component, conf in configs:
|
for domain, _component, conf in configs:
|
||||||
assert domain == "switch"
|
assert domain == "switch"
|
||||||
assert "name" in conf
|
assert "name" in conf
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user