diff --git a/script/analyze_component_buses.py b/script/analyze_component_buses.py index 1bfcdfda83..34ea338d09 100644 --- a/script/analyze_component_buses.py +++ b/script/analyze_component_buses.py @@ -78,6 +78,38 @@ def uses_local_file_references(component_dir: Path) -> bool: return bool(re.search(r"\$\{?component_dir\}?", content)) +def is_platform_component(component_dir: Path) -> bool: + """Check if a component is a platform component (abstract base class). + + Platform components have IS_PLATFORM_COMPONENT = True and cannot be + instantiated without a platform-specific implementation. These components + define abstract methods and cause linker errors if compiled standalone. + + Examples: canbus, mcp23x08_base, mcp23x17_base + + Args: + component_dir: Path to the component's test directory + + Returns: + True if this is a platform component + """ + # Check in the actual component source, not tests + # tests/components/X -> tests/components -> tests -> repo root + repo_root = component_dir.parent.parent.parent + comp_init = ( + repo_root / "esphome" / "components" / component_dir.name / "__init__.py" + ) + + if not comp_init.exists(): + return False + + try: + content = comp_init.read_text() + return "IS_PLATFORM_COMPONENT = True" in content + except Exception: # pylint: disable=broad-exception-caught + return False + + def extract_common_buses(yaml_file: Path) -> set[str]: """Extract which common bus configs are included in a YAML test file. @@ -149,7 +181,7 @@ def analyze_all_components( Returns: Tuple of: - Dictionary mapping component name to platform->buses mapping - - Set of component names that use local files (cannot be grouped) + - Set of component names that cannot be grouped (use local files or are platform components) """ if tests_dir is None: tests_dir = Path("tests/components") @@ -175,6 +207,11 @@ def analyze_all_components( if uses_local_file_references(component_dir): non_groupable.add(component_name) + # Check if component is a platform component (abstract base class) + # Platform components define abstract methods and cause linker errors + if is_platform_component(component_dir): + non_groupable.add(component_name) + return components, non_groupable @@ -280,6 +317,8 @@ def main() -> None: components[comp] = platform_buses if uses_local_file_references(comp_dir): non_groupable.add(comp) + if is_platform_component(comp_dir): + non_groupable.add(comp) else: # Analyze all components components, non_groupable = analyze_all_components(tests_dir) diff --git a/tests/components/ft63x6/common.yaml b/tests/components/ft63x6/common.yaml index 1db0944981..422abe7a61 100644 --- a/tests/components/ft63x6/common.yaml +++ b/tests/components/ft63x6/common.yaml @@ -10,6 +10,7 @@ display: touchscreen: - platform: ft63x6 + id: ft63x6_touchscreen interrupt_pin: ${interrupt_pin} transform: swap_xy: true