Files
langflow/scripts/generate_coverage_config.py
Eric Pinzur da4208dcc9 feat: generate custom coverage config to omit legacy and external compoents (#9221)
* feat: generate custom coverage config to omit legacy and external components

* lint

* fix components config

* also remove deactivated componenets

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-07-30 04:46:19 +00:00

169 lines
5.4 KiB
Python
Executable File

#!/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()