diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..33b0505 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,20 @@ +[run] +branch = True +parallel = False +source = + src + +[report] +show_missing = True +skip_covered = False +exclude_lines = + pragma: no cover + if __name__ == .__main__.: + # Add project-specific exclusions as needed + +omit = + tests/* + **/__init__.py + +[html] +directory = htmlcov diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..0c48f32 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,84 @@ +name: Code Coverage + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + env: + # Probably unnecessary, if we install the code as a package + PYTHONPATH: src + # Set your thresholds here + OVERALL_COVERAGE_FAIL_UNDER: "60" + DIFF_COVER_FAIL_UNDER: "70" + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed for diff-cover to compare against main + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Install test deps + run: | + python -m pip install --upgrade pip + pip install coverage diff-cover + + - name: Prepare for tests + run: sh prepare_for_tests.sh + + - name: Run unit tests with coverage + run: | + pip install -e ".[dev]" + coverage run --rcfile=.coveragerc --source=src -m unittest discover tests + coverage report -m --fail-under="${OVERALL_COVERAGE_FAIL_UNDER}" + coverage xml -o coverage.xml + coverage html -d htmlcov + + - name: Diff coverage for PR changes + if: ${{ github.event_name == 'pull_request' }} + run: | + # Ensure main is available for comparison + git fetch origin main:refs/remotes/origin/main + + # Compute coverage on changed lines only and fail if under threshold + diff-cover coverage.xml \ + --compare-branch=origin/main \ + --fail-under="${DIFF_COVER_FAIL_UNDER}" \ + --html-report diffcov.html > diffcov.txt || RC=$? + + # Attach a concise summary to the job summary + { + echo "## Diff Coverage Summary" + echo "" + echo "\`diff-cover --fail-under=${DIFF_COVER_FAIL_UNDER}\` against origin/main" + echo "" + echo '```' + cat diffcov.txt + echo '```' + } >> "$GITHUB_STEP_SUMMARY" + + # Exit with diff-cover status if it failed + exit ${RC:-0} + + - name: Upload HTML reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-reports + path: | + htmlcov/ + diffcov.html + coverage.xml + if-no-files-found: ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index b90ad62..b562c35 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ target build dist gen +.coverage diff --git a/README.md b/README.md index de72ab6..215f387 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ This library is released under the Apache V2 License. Read the [Documentation](https://lionweb.io/lionweb-python) +We support Python 3.9 to 3.13 + ## Linting ``` @@ -47,4 +49,15 @@ twine upload dist/* ``` sh prepare_for_tests.sh # to be run just once PYTHONPATH=src python -m unittest discover tests +``` + +You can measure coverage like this: +``` +PYTHONPATH=src coverage run -m unittest discover tests +``` + +And then generate a report with: +``` +coverage html +# report generated under htmlcov/index.html ``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 41f7e00..b78de1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,8 +18,16 @@ description = "A Python package for working with LionWeb" readme = "README.md" authors = [{ name = "Federico Tomassetti", email = "federico@strumenta.com" }] license = { file = "LICENSE.txt" } -requires-python = ">=3.8" +requires-python = ">=3.9" dependencies = [ "requests", - "pydantic" + "pydantic", + "typing_extensions>=4.8", +] + +[project.optional-dependencies] +dev = [ + "coverage", + "diff-cover", + "testcontainers>=4.0", ] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index d4ceeee..6ae0aba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ certifi==2025.1.31 cfgv==3.4.0 charset-normalizer==3.4.1 click==8.1.8 +coverage==7.10.6 decorator==5.2.1 distlib==0.3.9 distro==1.9.0 @@ -47,6 +48,7 @@ mypy==1.15.0 mypy-extensions==1.0.0 nh3==0.2.20 nodeenv==1.9.1 +numpy==2.0.2 packaging==24.2 parso==0.8.4 pathspec==0.12.1 diff --git a/tests/docker/Dockerfile b/tests/docker/Dockerfile index 085d692..fb4fcd7 100644 --- a/tests/docker/Dockerfile +++ b/tests/docker/Dockerfile @@ -1,5 +1,5 @@ FROM node -ARG lionwebServerCommitId=64aeb0de69bbb39626e7f107ba26eb0061063c9c +ARG lionwebServerCommitId=e6549d62a4728a91e1ca31afb9b5341b47b88c99 RUN mkdir lionweb-server WORKDIR lionweb-server RUN git init