diff --git a/.github/workflows/package-validation-reusable.yml b/.github/workflows/package-validation-reusable.yml new file mode 100644 index 000000000..95b88d047 --- /dev/null +++ b/.github/workflows/package-validation-reusable.yml @@ -0,0 +1,73 @@ +name: package-validation-reusable + +on: + workflow_call: + +permissions: + contents: read + +env: + MAIN_PYTHON_VERSION: 3.12 + +jobs: + build-package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Install uv + uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3.2.4 + with: + version: "latest" + - name: Set up Python + run: uv python install ${{ env.MAIN_PYTHON_VERSION }} + - name: Check versions + run: uv run python .github/pyproject_versions.py -c + - name: Build pip package + run: uv build + - name: Archive Pypi artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pypi_dist + path: dist + + test-package-from-wheel: + runs-on: ubuntu-24.04 + needs: [build-package] + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + sparse-checkout: | + tests/ + pytest.ini + sparse-checkout-cone-mode: false + - name: Install uv + uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3.2.4 + with: + version: "latest" + - name: Set up Python + run: uv python install ${{ env.MAIN_PYTHON_VERSION }} + - name: Download built package + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: pypi_dist + path: dist + - name: Create clean virtual environment + run: | + uv venv .venv --python ${{ env.MAIN_PYTHON_VERSION }} + echo "VIRTUAL_ENV=$PWD/.venv" >> $GITHUB_ENV + echo "$PWD/.venv/bin" >> $GITHUB_PATH + - name: Install package from wheel (without source) + run: | + # Install the wheel and test dependencies without the source code + uv pip install dist/*.whl + uv pip install pytest pytest-mock requests-mock responses pandas logfire + - name: Test package integrity + run: | + # Run the package integrity tests to verify all data files are included + uv run python -m pytest tests/test_package_integrity.py -v + CODECARBON_ALLOW_MULTIPLE_RUNS=True pytest --ignore=tests/test_viz_data.py -vv -m 'not integ_test' tests/ + - name: Test CLI functionality + run: | + # Test that the CLI is functional + codecarbon --help + python -c "from codecarbon import EmissionsTracker; print('Package import successful')" diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index f67669a99..8167dc201 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -2,71 +2,16 @@ name: package permissions: contents: read on: + pull_request: + paths: + - "codecarbon/**" + - "pyproject.toml" + branches: [master] push: paths: - "codecarbon/**" - "pyproject.toml" branches: [master] jobs: - - build-package: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Install uv - uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3.2.4 - with: - version: "latest" - - name: Set up Python - run: uv python install 3.12 - - name: Check versions - run: uv run python .github/pyproject_versions.py -o - - name: Build pip package - run: uv build - - name: Archive Pypi artifacts - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pypi_dist - path: dist - - test-package-from-wheel: - runs-on: ubuntu-24.04 - needs: [build-package] - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - sparse-checkout: | - tests/ - pytest.ini - sparse-checkout-cone-mode: false - - name: Install uv - uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3.2.4 - with: - version: "latest" - - name: Set up Python - run: uv python install 3.12 - - name: Download built package - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - with: - name: pypi_dist - path: dist - - name: Create clean virtual environment - run: | - uv venv .venv --python 3.12 - echo "VIRTUAL_ENV=$PWD/.venv" >> $GITHUB_ENV - echo "$PWD/.venv/bin" >> $GITHUB_PATH - - name: Install package from wheel (without source) - run: | - # Install the wheel and test dependencies without the source code - uv pip install dist/*.whl - uv pip install pytest pytest-mock requests-mock responses pandas logfire - - name: Test package integrity - run: | - # Run the package integrity tests to verify all data files are included - uv run python -m pytest tests/test_package_integrity.py -v - CODECARBON_ALLOW_MULTIPLE_RUNS=True pytest --ignore=tests/test_viz_data.py -vv -m 'not integ_test' tests/ - - name: Test CLI functionality - run: | - # Test that the CLI is functional - codecarbon --help - python -c "from codecarbon import EmissionsTracker; print('✓ Package import successful')" + validate-package: + uses: ./.github/workflows/package-validation-reusable.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1fd398fcd..3395cdc4c 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -11,25 +11,24 @@ on: permissions: contents: read jobs: + validate-package: + uses: ./.github/workflows/package-validation-reusable.yml + deploy-pypi: runs-on: ubuntu-latest + needs: [validate-package] # Specifying a GitHub environment is optional, but strongly encouraged environment: pypi permissions: # IMPORTANT: this permission is mandatory for Trusted Publishing id-token: write steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Install uv - uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3.2.4 - with: - version: "latest" - - name: Set up Python - run: uv python install 3.12 - - name: Check versions - run: | - uv run python .github/pyproject_versions.py -c - - name: Build package - run: uv build - - name: Publish package - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1.13.0 + - name: Download validated package + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: pypi_dist # This is where validate-package uploads the pypi package + path: dist + - name: Publish package + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1.13.0 + with: + packages-dir: dist diff --git a/pyproject.toml b/pyproject.toml index 96b213f1e..57fb3996b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,7 @@ codecarbon = [ "data/canada_provinces.geojson", "data/private_infra/global_energy_mix.json", "data/private_infra/carbon_intensity_per_source.json", + "data/private_infra/nordic_emissions.json", "data/private_infra/2016/usa_emissions.json", "data/private_infra/2023/canada_energy_mix.json", "viz/assets/car_icon.png", diff --git a/tests/test_package_integrity.py b/tests/test_package_integrity.py index 57a9317f0..3299664fc 100644 --- a/tests/test_package_integrity.py +++ b/tests/test_package_integrity.py @@ -3,6 +3,8 @@ This test should be run against the installed package, not the source. """ +from importlib import resources as importlib_resources + import pandas as pd import pytest @@ -72,6 +74,14 @@ def test_global_energy_mix_data_included(): assert len(global_energy_data) > 0, "Global energy mix data should not be empty" +def test_nordic_emissions_data_included(): + """Test that nordic emissions data file is included in the package.""" + nordic_file = importlib_resources.files("codecarbon").joinpath( + "data/private_infra/nordic_emissions.json" + ) + assert nordic_file.is_file(), f"Nordic emissions file missing: {nordic_file}" + + def test_country_specific_data_access(): """Test that we can access country-specific data if available.""" ds = DataSource()