Files
LEDMatrix/scripts/run_plugin_tests.py
Chuck 55161f309b fix: remove unused imports and bare exception aliases (pyflakes F401/F841)
Remove unused imports across 86 files in src/, web_interface/, test/,
and scripts/ using autoflake. No logic changes — only dead import
statements and unused names in from-imports are removed.

Also remove bare exception aliases where the variable is never
referenced in the handler body:
- src/cache/disk_cache.py: except (IOError, OSError, PermissionError) as e
- src/cache_manager.py: except (OSError, IOError, PermissionError) as perm_error
- src/plugin_system/resource_monitor.py: except Exception as e
- web_interface/app.py: except Exception as read_err

86 files changed, 205 lines removed, 18 pre-existing test failures unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 10:41:55 -04:00

215 lines
6.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Plugin Test Runner
Discovers and runs tests for LEDMatrix plugins.
Supports both unittest and pytest.
"""
import sys
import argparse
from pathlib import Path
from typing import Optional
# Add project root to path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
def discover_plugin_tests(plugins_dir: Path, plugin_id: Optional[str] = None) -> list:
"""
Discover test files in plugin directories.
Args:
plugins_dir: Plugins directory path
plugin_id: Optional specific plugin ID to test
Returns:
List of test file paths
"""
test_files = []
if plugin_id:
# Test specific plugin
plugin_dir = plugins_dir / plugin_id
if plugin_dir.exists():
test_files.extend(_find_tests_in_dir(plugin_dir))
else:
# Test all plugins
for item in plugins_dir.iterdir():
if not item.is_dir():
continue
if item.name.startswith('.') or item.name.startswith('_'):
continue
test_files.extend(_find_tests_in_dir(item))
return test_files
def _find_tests_in_dir(directory: Path) -> list:
"""Find test files in a directory."""
test_files = []
# Look for test files
patterns = ['test_*.py', '*_test.py', 'tests/test_*.py', 'tests/*_test.py']
for pattern in patterns:
if '/' in pattern:
# Subdirectory pattern
subdir, file_pattern = pattern.split('/', 1)
test_dir = directory / subdir
if test_dir.exists():
test_files.extend(test_dir.glob(file_pattern))
else:
# Direct pattern
test_files.extend(directory.glob(pattern))
return sorted(set(test_files))
def run_unittest_tests(test_files: list, verbose: bool = False) -> int:
"""
Run tests using unittest.
Args:
test_files: List of test file paths
verbose: Enable verbose output
Returns:
Exit code (0 for success, non-zero for failure)
"""
import unittest
# Discover tests
loader = unittest.TestLoader()
suite = unittest.TestSuite()
for test_file in test_files:
# Import the test module
module_name = test_file.stem
spec = importlib.util.spec_from_file_location(module_name, test_file)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Load tests from module
tests = loader.loadTestsFromModule(module)
suite.addTests(tests)
# Run tests
runner = unittest.TextTestRunner(verbosity=2 if verbose else 1)
result = runner.run(suite)
return 0 if result.wasSuccessful() else 1
def run_pytest_tests(test_files: list, verbose: bool = False, coverage: bool = False) -> int:
"""
Run tests using pytest.
Args:
test_files: List of test file paths
verbose: Enable verbose output
coverage: Generate coverage report
Returns:
Exit code (0 for success, non-zero for failure)
"""
import pytest
args = []
if verbose:
args.append('-v')
else:
args.append('-q')
if coverage:
args.extend(['--cov', 'plugins', '--cov-report', 'html', '--cov-report', 'term'])
# Add test files
args.extend([str(f) for f in test_files])
# Run pytest
exit_code = pytest.main(args)
return exit_code
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description='Run LEDMatrix plugin tests')
parser.add_argument('--plugin', '-p', help='Test specific plugin ID')
parser.add_argument('--plugins-dir', '-d', default=None,
help='Plugins directory (default: auto-detect plugins/ or plugin-repos/)')
parser.add_argument('--runner', '-r', choices=['unittest', 'pytest', 'auto'],
default='auto', help='Test runner to use (default: auto)')
parser.add_argument('--verbose', '-v', action='store_true',
help='Enable verbose output')
parser.add_argument('--coverage', '-c', action='store_true',
help='Generate coverage report (pytest only)')
args = parser.parse_args()
if args.plugins_dir:
plugins_dir = Path(args.plugins_dir)
else:
# Auto-detect: prefer plugins/ if it has content, then plugin-repos/
plugins_path = PROJECT_ROOT / 'plugins'
plugin_repos_path = PROJECT_ROOT / 'plugin-repos'
try:
has_plugins = plugins_path.exists() and any(
p for p in plugins_path.iterdir()
if p.is_dir() and not p.name.startswith('.')
)
except PermissionError:
print(f"Warning: cannot read {plugins_path}, falling back to plugin-repos/")
has_plugins = False
if has_plugins:
plugins_dir = plugins_path
elif plugin_repos_path.exists():
plugins_dir = plugin_repos_path
else:
plugins_dir = plugins_path
if not plugins_dir.exists():
print(f"Error: Plugins directory not found: {plugins_dir}")
return 1
# Discover tests
test_files = discover_plugin_tests(plugins_dir, args.plugin)
if not test_files:
if args.plugin:
print(f"No tests found for plugin: {args.plugin}")
else:
print("No test files found in plugins directory")
return 0
print(f"Found {len(test_files)} test file(s)")
for test_file in test_files:
print(f" - {test_file}")
print()
# Determine runner
runner = args.runner
if runner == 'auto':
# Try pytest first, fall back to unittest
try:
runner = 'pytest'
except ImportError:
runner = 'unittest'
# Run tests
if runner == 'pytest':
return run_pytest_tests(test_files, args.verbose, args.coverage)
else:
return run_unittest_tests(test_files, args.verbose)
if __name__ == '__main__':
import importlib.util
from typing import Optional
sys.exit(main())