diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..1f03fae --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,70 @@ +name: Test +on: [push, pull_request] + +concurrency: + group: cicd-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Test + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12"] + steps: + - uses: actions/checkout@v4 + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install matplotlib default font + run: | + wget -O dejavu.zip http://sourceforge.net/projects/dejavu/files/dejavu/2.37/dejavu-fonts-ttf-2.37.zip + unzip -d dejavu/ dejavu.zip + mv dejavu /usr/share/fonts/ + fc-cache -fv + - name: Install dependencies + run: pip install '.[dev]' + - name: Format + run: ruff format --check . + - name: Lint + run: ruff check . + - name: Type + run: mypy + - name: Test + run: pytest + - name: Upload test charts + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-charts + path: tests/*.jpg + if-no-files-found: warn + retention-days: 14 + publish: + name: Build & Publish + needs: test + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + # Used to authenticate to PyPI via OIDC. + # Used to sign the release's artifacts with sigstore-python. + id-token: write + # Used to attach signing artifacts to the published release. + contents: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + - name: Install build deps + run: pip install --upgrade build + - name: Build Python package + run: python -m build + - name: Publish to PyPi + uses: pypa/gh-action-pypi-publish@release/v1 + with: + verbose: true + print-hash: true diff --git a/.gitignore b/.gitignore index 49de00c..c2e66bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Custom .vscode/ .ruff_cache +test.png # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/pyproject.toml b/pyproject.toml index 9937aea..13d8f78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ ] dependencies = ["matplotlib", "numpy", "scipy", "statsmodels"] optional-dependencies = { dev = [ + "build", "linearmodels", "mypy", "notebook", @@ -48,6 +49,8 @@ files = ["lmdiag/**/*.py", "tests/**/*.py"] exclude = ["build/"] follow_imports = "skip" ignore_missing_imports = true +# ONHOLD: Remove cache_dir once https://github.com/python/mypy/issues/17396 is fixed +cache_dir = "/dev/null" [tool.ruff] target-version = "py39" diff --git a/tests/test_plot.py b/tests/test_plot.py index da86e80..2005dcf 100644 --- a/tests/test_plot.py +++ b/tests/test_plot.py @@ -19,7 +19,6 @@ def test_plot_generates_expected_image( ) -> None: base_path = Path(__file__).parent filename = base_path / f"test_plot_actual_{lm_type}.jpg" - plt.style.use("seaborn-v0_8") lmdiag.style.use("black_and_red") @@ -33,13 +32,20 @@ def test_plot_generates_expected_image( else: raise ValueError(f"Unsupported lm_type: {lm_type}") + # Set a specific font to make the test deterministic across different systems + plt.rcParams["font.family"] = "sans-serif" + plt.rcParams["font.sans-serif"] = ["Liberation Sans"] + # Using lowess_delta leads to small differences between plot of # linearmodels and statsmodels, therefore we set it to 0 during testing fig = lmdiag.plot(lm_fitted, x=x, y=y, lowess_delta=0) fig.savefig(filename) + # Log used font name, as different fonts lead to different jpg file sizes + font_name = fig.get_axes()[0].title.get_fontproperties().get_name() + # Quick and simple way to compare the plots is to compare jpg file sizes actual_bytes = Path(filename).stat().st_size expected_bytes = Path(base_path / "test_plot_expected.jpg").stat().st_size acceptable_byte_difference = 10 - assert abs(actual_bytes - expected_bytes) < acceptable_byte_difference + assert abs(actual_bytes - expected_bytes) < acceptable_byte_difference, font_name diff --git a/tests/test_plot_expected.jpg b/tests/test_plot_expected.jpg index ad8a94e..d029ba9 100644 Binary files a/tests/test_plot_expected.jpg and b/tests/test_plot_expected.jpg differ