#!/usr/bin/env python3 """Script to generate a custom .coveragerc file for backend testing. This script: 1. Reads SIDEBAR_BUNDLES from frontend styleUtils.ts to get bundled component names 2. Scans backend components for files containing 'legacy = True' 3. Generates a .coveragerc file that omits these paths from coverage reporting Usage: python scripts/generate_coverage_config.py """ import re from pathlib import Path def extract_sidebar_bundles(frontend_path: Path) -> set[str]: """Extract component names from SIDEBAR_BUNDLES in styleUtils.ts.""" style_utils_path = frontend_path / "src/utils/styleUtils.ts" if not style_utils_path.exists(): print(f"Warning: styleUtils.ts not found at {style_utils_path}") return set() bundle_names = set() with style_utils_path.open(encoding="utf-8") as f: content = f.read() # Find SIDEBAR_BUNDLES array sidebar_match = re.search(r"export const SIDEBAR_BUNDLES = \[(.*?)\];", content, re.DOTALL) if not sidebar_match: print("Warning: SIDEBAR_BUNDLES not found in styleUtils.ts") return set() bundles_content = sidebar_match.group(1) # Extract name fields using regex name_matches = re.findall(r'name:\s*["\']([^"\']+)["\']', bundles_content) for name in name_matches: bundle_names.add(name) print(f"Found {len(bundle_names)} bundled components from SIDEBAR_BUNDLES") return bundle_names def find_legacy_components(backend_components_path: Path) -> set[str]: """Find Python files containing 'legacy = True'.""" legacy_files = set() if not backend_components_path.exists(): print(f"Warning: Backend components path not found: {backend_components_path}") return set() # Walk through all Python files in components directory for py_file in backend_components_path.rglob("*.py"): try: with py_file.open(encoding="utf-8") as f: content = f.read() # Check if file contains 'legacy = True' if re.search(r"\blegacy\s*=\s*True\b", content): # Get relative path from components directory rel_path = py_file.relative_to(backend_components_path) legacy_files.add(str(rel_path)) except (UnicodeDecodeError, PermissionError) as e: print(f"Warning: Could not read {py_file}: {e}") continue print(f"Found {len(legacy_files)} legacy component files") return legacy_files def generate_coveragerc(bundle_names: set[str], legacy_files: set[str], output_path: Path): """Generate .coveragerc file with omit patterns.""" # Base coveragerc content config_content = """# Auto-generated .coveragerc file # Generated by scripts/generate_coverage_config.py # Do not edit manually - changes will be overwritten [run] source = src/backend/base/langflow omit = # Test files */tests/* */test_* */*test* # Migration files */alembic/* */migrations/* # Cache and build files */__pycache__/* */.* # Init files (typically just imports) */__init__.py # Deactivate Components */components/deactivated/* """ # Add bundled components to omit list if bundle_names: config_content += " # Bundled components from SIDEBAR_BUNDLES\n" for bundle_name in sorted(bundle_names): config_content += f" */components/{bundle_name}/*\n" config_content += "\n" # Add legacy components to omit list if legacy_files: config_content += " # Legacy components (contain 'legacy = True')\n" for legacy_file in sorted(legacy_files): # Convert relative path to omit pattern omit_pattern = f" */components/{legacy_file}\n" config_content += omit_pattern config_content += """ # Note: [report] and [html] sections omitted for Codecov compatibility # Codecov handles its own reporting and ignores these sections """ # Write the config file output_path.parent.mkdir(parents=True, exist_ok=True) with output_path.open("w", encoding="utf-8") as f: f.write(config_content) print(f"Generated .coveragerc at {output_path}") print(f" - Omitting {len(bundle_names)} bundled component directories") print(f" - Omitting {len(legacy_files)} legacy component files") def main(): """Main function.""" # Determine project root (script is in scripts/ directory) script_dir = Path(__file__).parent project_root = script_dir.parent # Paths frontend_path = project_root / "src" / "frontend" backend_components_path = project_root / "src" / "backend" / "base" / "langflow" / "components" output_path = project_root / "src" / "backend" / ".coveragerc" print(f"Project root: {project_root}") print(f"Frontend path: {frontend_path}") print(f"Backend components path: {backend_components_path}") print(f"Output path: {output_path}") print() # Extract bundled component names bundle_names = extract_sidebar_bundles(frontend_path) # Find legacy components legacy_files = find_legacy_components(backend_components_path) # Generate .coveragerc file generate_coveragerc(bundle_names, legacy_files, output_path) print("\nDone! You can now run backend tests with coverage using:") print("cd src/backend && python -m pytest --cov=src/backend/base/langflow --cov-config=.coveragerc") if __name__ == "__main__": main()