Add python3 support #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test with Optional Dependencies | |
| on: | |
| push: | |
| branches: [ master, main ] | |
| pull_request: | |
| branches: [ master, main ] | |
| schedule: | |
| # Run weekly to catch issues with dependency updates | |
| - cron: '0 0 * * 0' | |
| jobs: | |
| test-extras: | |
| name: Test with ${{ matrix.extras }} on Python ${{ matrix.python-version }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.9', '3.11'] | |
| extras: | |
| - 'tornado' | |
| - 'flask' | |
| - 'jinja2' | |
| - 'redis' | |
| - 'twisted' | |
| - 'tornado,flask,jinja2' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install dependencies with ${{ matrix.extras }} | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[${{ matrix.extras }}]" | |
| - name: Create test runner script | |
| run: | | |
| cat > run_tests_with_extras.py << 'EOF' | |
| import sys | |
| import unittest | |
| import importlib | |
| import os | |
| # Define which tests require which packages | |
| EXTRA_TEST_REQUIREMENTS = { | |
| 'tests.ioc.extra.tornado.test_handler': ['tornado'], | |
| 'tests.ioc.extra.tornado.test_router': ['tornado', 'werkzeug'], | |
| 'tests.ioc.extra.jinja.test_helper': ['jinja2'], | |
| } | |
| def check_module_available(module_name): | |
| """Check if a module can be imported.""" | |
| try: | |
| importlib.import_module(module_name) | |
| return True | |
| except ImportError: | |
| return False | |
| def should_skip_test(test_module): | |
| """Check if a test should be skipped due to missing dependencies.""" | |
| if test_module in EXTRA_TEST_REQUIREMENTS: | |
| required_modules = EXTRA_TEST_REQUIREMENTS[test_module] | |
| for req in required_modules: | |
| if not check_module_available(req): | |
| return True, req | |
| return False, None | |
| def discover_and_run_tests(): | |
| """Discover and run tests, skipping those with missing dependencies.""" | |
| loader = unittest.TestLoader() | |
| suite = unittest.TestSuite() | |
| # Discover all tests | |
| discovered_suite = loader.discover('tests', pattern='test_*.py') | |
| # Track skipped tests | |
| skipped_tests = [] | |
| # Filter tests based on available dependencies | |
| for test_group in discovered_suite: | |
| for test_case in test_group: | |
| if hasattr(test_case, '__module__'): | |
| module_name = test_case.__module__ | |
| should_skip, missing_module = should_skip_test(module_name) | |
| if should_skip: | |
| skipped_tests.append((module_name, missing_module)) | |
| else: | |
| suite.addTest(test_case) | |
| elif hasattr(test_case, '_tests'): | |
| # Handle test suites | |
| for test in test_case._tests: | |
| if hasattr(test, '__module__'): | |
| module_name = test.__module__ | |
| should_skip, missing_module = should_skip_test(module_name) | |
| if should_skip: | |
| skipped_tests.append((module_name, missing_module)) | |
| else: | |
| suite.addTest(test) | |
| else: | |
| suite.addTest(test) | |
| else: | |
| # Fallback: try to check if it's a failed import | |
| test_str = str(test_case) | |
| if 'FailedTest' in test_str: | |
| # This is a failed import, skip it | |
| skipped_tests.append((test_str, 'import failed')) | |
| else: | |
| suite.addTest(test_case) | |
| # Print summary of skipped tests | |
| if skipped_tests: | |
| print("\n" + "="*70) | |
| print("SKIPPED TESTS DUE TO MISSING DEPENDENCIES:") | |
| for test_module, missing in set(skipped_tests): | |
| print(f" - {test_module} (missing: {missing})") | |
| print("="*70 + "\n") | |
| # Run the filtered test suite | |
| runner = unittest.TextTestRunner(verbosity=2) | |
| result = runner.run(suite) | |
| # Return appropriate exit code | |
| if result.wasSuccessful(): | |
| return 0 | |
| else: | |
| # Check if all failures are import errors | |
| if hasattr(result, 'errors') and result.errors: | |
| import_errors = sum(1 for error in result.errors | |
| if 'ImportError' in str(error[1]) or 'ModuleNotFoundError' in str(error[1])) | |
| if import_errors == len(result.errors) and result.failures == []: | |
| print("\nAll errors were import errors - this is expected for optional dependencies") | |
| return 0 | |
| return 1 | |
| if __name__ == '__main__': | |
| sys.exit(discover_and_run_tests()) | |
| EOF | |
| - name: Run tests with smart dependency detection | |
| run: | | |
| python run_tests_with_extras.py |