update ci/cd 4 #4
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: CI | |
| on: | |
| push: | |
| branches: [ master, main, develop, '**' ] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - '.gitignore' | |
| - 'LICENSE' | |
| pull_request: | |
| branches: [ master, main, develop ] | |
| paths-ignore: | |
| - '**.md' | |
| - 'docs/**' | |
| - '.gitignore' | |
| - 'LICENSE' | |
| schedule: | |
| # Run tests once a week to catch dependency issues | |
| - cron: '0 0 * * 0' | |
| jobs: | |
| test: | |
| name: Test Python ${{ matrix.python-version }} on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] | |
| include: | |
| # Add Python 3.13 only for Ubuntu where it's more stable | |
| - os: ubuntu-latest | |
| python-version: '3.13-dev' | |
| # Set timeout for the entire job | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| allow-prereleases: true | |
| - name: Display Python version | |
| run: python -c "import sys; print(sys.version)" | |
| - name: Cache pip packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cache/pip | |
| ~/Library/Caches/pip | |
| ~/AppData/Local/pip/Cache | |
| key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements*.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip-${{ matrix.python-version }}- | |
| ${{ runner.os }}-pip- | |
| - name: Upgrade pip | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install --upgrade setuptools wheel | |
| - name: Install test dependencies | |
| run: | | |
| pip install pytest pytest-cov pytest-xdist pytest-timeout parameterized | |
| - name: Install package dependencies | |
| run: | | |
| # Install all requirements first | |
| pip install ipython>=7.0.0 | |
| pip install matplotlib>=3.0.0 numpy>=1.20.0 pandas>=1.3.0 | |
| pip install flask>=2.0.0 pytz>=2019.3 scikit-learn>=0.22.0 scipy>=1.5.0 seaborn>=0.10.0 | |
| - name: Install empyrical (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| # Try installing empyrical with retries | |
| for i in 1 2 3; do | |
| echo "Attempt $i to install empyrical..." | |
| if pip install git+https://github.com/cloudQuant/empyrical.git; then | |
| echo "Successfully installed empyrical from GitHub" | |
| break | |
| elif [ $i -eq 3 ]; then | |
| echo "GitHub failed, trying Gitee..." | |
| pip install git+https://gitee.com/yunjinqi/empyrical.git || exit 1 | |
| else | |
| echo "Attempt $i failed, retrying..." | |
| sleep 5 | |
| fi | |
| done | |
| - name: Install empyrical (Windows) | |
| if: runner.os == 'Windows' | |
| shell: cmd | |
| run: | | |
| pip install git+https://github.com/cloudQuant/empyrical.git || pip install git+https://gitee.com/yunjinqi/empyrical.git | |
| - name: Install pyfolio | |
| run: | | |
| pip install -e . --no-deps | |
| # Verify installation | |
| python -c "import pyfolio; print(f'PyFolio {pyfolio.__version__} installed successfully')" | |
| - name: Run tests with pytest | |
| run: | | |
| pytest tests/ -v --cov=pyfolio --cov-report=xml --cov-report=term -n auto --tb=short | |
| continue-on-error: true | |
| id: pytest | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-${{ matrix.os }}-${{ matrix.python-version }} | |
| path: | | |
| coverage.xml | |
| .coverage | |
| - name: Check test results | |
| if: steps.pytest.outcome == 'failure' | |
| run: exit 1 | |
| - name: Upload coverage to Codecov | |
| if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11' | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./coverage.xml | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install flake8 black isort mypy | |
| pip install ipython>=7.0.0 | |
| # Install empyrical for linting | |
| pip install git+https://github.com/cloudQuant/empyrical.git || pip install git+https://gitee.com/yunjinqi/empyrical.git | |
| pip install -e . | |
| - name: Lint with flake8 | |
| run: | | |
| # Stop the build if there are Python syntax errors or undefined names | |
| flake8 pyfolio --count --select=E9,F63,F7,F82 --show-source --statistics | |
| # exit-zero treats all errors as warnings | |
| flake8 pyfolio --count --exit-zero --max-complexity=10 --max-line-length=100 --statistics | |
| - name: Check formatting with black | |
| run: | | |
| black --check pyfolio || echo "Code formatting issues found. Run 'black pyfolio' to fix." | |
| - name: Check import sorting with isort | |
| run: | | |
| isort --check-only pyfolio || echo "Import sorting issues found. Run 'isort pyfolio' to fix." | |
| build: | |
| name: Build distribution | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install build | |
| - name: Build distribution | |
| run: python -m build | |
| - name: Check distribution | |
| run: | | |
| pip install twine | |
| twine check dist/* | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| test-install: | |
| name: Test installation | |
| needs: build | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python-version: ['3.8', '3.11'] | |
| steps: | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dist | |
| path: dist/ | |
| - name: Install from wheel | |
| run: | | |
| # Install dependencies first | |
| pip install ipython>=7.0.0 | |
| # Install empyrical | |
| pip install git+https://github.com/cloudQuant/empyrical.git || pip install git+https://gitee.com/yunjinqi/empyrical.git | |
| # Install pyfolio wheel | |
| pip install dist/*.whl | |
| python -c "import pyfolio; print(f'Successfully imported pyfolio {pyfolio.__version__}')" | |
| - name: Test basic functionality | |
| run: | | |
| python -c " | |
| import pyfolio | |
| import pandas as pd | |
| import numpy as np | |
| # Create sample returns | |
| dates = pd.date_range('2020-01-01', periods=252, freq='D') | |
| returns = pd.Series(np.random.randn(252) * 0.01, index=dates) | |
| # Test basic stats computation | |
| print('Testing pyfolio basic functionality...') | |
| print(f'Annual return: {pyfolio.timeseries.annual_return(returns):.2%}') | |
| print(f'Sharpe ratio: {pyfolio.timeseries.sharpe_ratio(returns):.2f}') | |
| print('Basic functionality test passed!') | |
| " |