From 9ab1a88349547ac7535a1a66ddeb3cca975f245b Mon Sep 17 00:00:00 2001 From: Paul Lockaby Date: Mon, 5 Aug 2024 16:07:40 -0700 Subject: [PATCH 1/2] feat: adding mypy and cov requirements --- .github/workflows/tests.yaml | 2 +- .idea/poetry.xml | 10 +++ .idea/test-repo.iml | 6 +- poetry.lock | 124 ++++++++++++++++++++++++++++++++++- pyproject.toml | 2 + src/testrepo/app.py | 5 +- tests/test_app.py | 17 +++++ tests/test_repo.py | 16 ++++- 8 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 .idea/poetry.xml create mode 100644 tests/test_app.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 74dc2e2..571919a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -63,7 +63,7 @@ jobs: - name: Run python tests run: | poetry install --no-interaction - poetry run pytest + poetry run pytest --mypy --cov=src --cov-report=term --cov-fail-under=90 - name: Run container tests run: | diff --git a/.idea/poetry.xml b/.idea/poetry.xml new file mode 100644 index 0000000..75bfffd --- /dev/null +++ b/.idea/poetry.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/test-repo.iml b/.idea/test-repo.iml index d0876a7..f695dff 100644 --- a/.idea/test-repo.iml +++ b/.idea/test-repo.iml @@ -1,8 +1,10 @@ - - + + + + \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 59c8605..a21a0d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,6 +11,25 @@ files = [ {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"}, ] +[[package]] +name = "attrs" +version = "24.1.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.1.0-py3-none-any.whl", hash = "sha256:377b47448cb61fea38533f671fba0d0f8a96fd58facd4dc518e3dac9dbea0905"}, + {file = "attrs-24.1.0.tar.gz", hash = "sha256:adbdec84af72d38be7628e353a09b6a6790d15cd71819f6e9d7b0faa8a125745"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + [[package]] name = "blinker" version = "1.8.2" @@ -365,6 +384,63 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] +[[package]] +name = "mypy" +version = "1.11.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.11.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a32fc80b63de4b5b3e65f4be82b4cfa362a46702672aa6a0f443b4689af7008c"}, + {file = "mypy-1.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c1952f5ea8a5a959b05ed5f16452fddadbaae48b5d39235ab4c3fc444d5fd411"}, + {file = "mypy-1.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1e30dc3bfa4e157e53c1d17a0dad20f89dc433393e7702b813c10e200843b03"}, + {file = "mypy-1.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2c63350af88f43a66d3dfeeeb8d77af34a4f07d760b9eb3a8697f0386c7590b4"}, + {file = "mypy-1.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:a831671bad47186603872a3abc19634f3011d7f83b083762c942442d51c58d58"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7b6343d338390bb946d449677726edf60102a1c96079b4f002dedff375953fc5"}, + {file = "mypy-1.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4fe9f4e5e521b458d8feb52547f4bade7ef8c93238dfb5bbc790d9ff2d770ca"}, + {file = "mypy-1.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:886c9dbecc87b9516eff294541bf7f3655722bf22bb898ee06985cd7269898de"}, + {file = "mypy-1.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fca4a60e1dd9fd0193ae0067eaeeb962f2d79e0d9f0f66223a0682f26ffcc809"}, + {file = "mypy-1.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0bd53faf56de9643336aeea1c925012837432b5faf1701ccca7fde70166ccf72"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f39918a50f74dc5969807dcfaecafa804fa7f90c9d60506835036cc1bc891dc8"}, + {file = "mypy-1.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0bc71d1fb27a428139dd78621953effe0d208aed9857cb08d002280b0422003a"}, + {file = "mypy-1.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b868d3bcff720dd7217c383474008ddabaf048fad8d78ed948bb4b624870a417"}, + {file = "mypy-1.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a707ec1527ffcdd1c784d0924bf5cb15cd7f22683b919668a04d2b9c34549d2e"}, + {file = "mypy-1.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:64f4a90e3ea07f590c5bcf9029035cf0efeae5ba8be511a8caada1a4893f5525"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:749fd3213916f1751fff995fccf20c6195cae941dc968f3aaadf9bb4e430e5a2"}, + {file = "mypy-1.11.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b639dce63a0b19085213ec5fdd8cffd1d81988f47a2dec7100e93564f3e8fb3b"}, + {file = "mypy-1.11.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c956b49c5d865394d62941b109728c5c596a415e9c5b2be663dd26a1ff07bc0"}, + {file = "mypy-1.11.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45df906e8b6804ef4b666af29a87ad9f5921aad091c79cc38e12198e220beabd"}, + {file = "mypy-1.11.1-cp38-cp38-win_amd64.whl", hash = "sha256:d44be7551689d9d47b7abc27c71257adfdb53f03880841a5db15ddb22dc63edb"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2684d3f693073ab89d76da8e3921883019ea8a3ec20fa5d8ecca6a2db4c54bbe"}, + {file = "mypy-1.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79c07eb282cb457473add5052b63925e5cc97dfab9812ee65a7c7ab5e3cb551c"}, + {file = "mypy-1.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11965c2f571ded6239977b14deebd3f4c3abd9a92398712d6da3a772974fad69"}, + {file = "mypy-1.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a2b43895a0f8154df6519706d9bca8280cda52d3d9d1514b2d9c3e26792a0b74"}, + {file = "mypy-1.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:1a81cf05975fd61aec5ae16501a091cfb9f605dc3e3c878c0da32f250b74760b"}, + {file = "mypy-1.11.1-py3-none-any.whl", hash = "sha256:0624bdb940255d2dd24e829d99a13cfeb72e4e9031f9492148f410ed30bcab54"}, + {file = "mypy-1.11.1.tar.gz", hash = "sha256:f404a0b069709f18bbdb702eb3dcfe51910602995de00bd39cea3050b5772d08"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -467,6 +543,24 @@ pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.23.8" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, + {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, +] + +[package.dependencies] +pytest = ">=7.0.0,<9" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] + [[package]] name = "pytest-cov" version = "5.0.0" @@ -485,6 +579,23 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] +[[package]] +name = "pytest-mypy" +version = "0.10.3" +description = "Mypy static type checker plugin for Pytest" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-mypy-0.10.3.tar.gz", hash = "sha256:f8458f642323f13a2ca3e2e61509f7767966b527b4d8adccd5032c3e7b4fd3db"}, + {file = "pytest_mypy-0.10.3-py3-none-any.whl", hash = "sha256:7638d0d3906848fc1810cb2f5cc7fceb4cc5c98524aafcac58f28620e3102053"}, +] + +[package.dependencies] +attrs = ">=19.0" +filelock = ">=3.0" +mypy = {version = ">=0.900", markers = "python_version >= \"3.11\""} +pytest = {version = ">=6.2", markers = "python_version >= \"3.10\""} + [[package]] name = "pyyaml" version = "6.0.1" @@ -571,6 +682,17 @@ werkzeug = ">=3.0.0" docs = ["pydata_sphinx_theme"] dotenv = ["python-dotenv"] +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + [[package]] name = "uvloop" version = "0.19.0" @@ -669,4 +791,4 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "2.0" python-versions = "^3.12 <3.13" -content-hash = "d69fe0669ea60ece1619e216b742bfa38865b01b54a012572c6cce8c32e51304" +content-hash = "1650068b48d0c80c9c173a9ae6eed710b2bbf013172df743343173d16440b613" diff --git a/pyproject.toml b/pyproject.toml index 06b2d39..ef18978 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,8 @@ hypercorn = {extras = ["uvloop"], version = "^0.17.3"} [tool.poetry.group.dev.dependencies] pytest = "^8.2.1" pytest-cov = "^5.0.0" +pytest-mypy = "^0.10.3" +pytest-asyncio = "^0.23.8" pre-commit = "^3.7.1" [build-system] diff --git a/src/testrepo/app.py b/src/testrepo/app.py index b6799fc..128acce 100644 --- a/src/testrepo/app.py +++ b/src/testrepo/app.py @@ -1,6 +1,7 @@ import logging -from quart import Quart, Response, jsonify, make_response +from quart import Quart, jsonify, make_response +from quart.typing import ResponseTypes from testrepo import __version__ @@ -11,7 +12,7 @@ def load() -> Quart: app.logger.info("starting web application version %s", __version__) @app.route("/") - async def health() -> Response: + async def health() -> ResponseTypes: return await make_response( jsonify({ "status": "pass", diff --git a/tests/test_app.py b/tests/test_app.py new file mode 100644 index 0000000..64cf8e3 --- /dev/null +++ b/tests/test_app.py @@ -0,0 +1,17 @@ +import pytest + +from testrepo.app import load + + +@pytest.mark.asyncio +async def test_health_route(): + app = load() + test_client = app.test_client() + response = await test_client.get("/") + assert response.status_code == 200 + json_data = await response.get_json() + assert json_data == { + "status": "pass", + "message": "flux capacitor is fluxing", + "version": "0.0.0" + } diff --git a/tests/test_repo.py b/tests/test_repo.py index b6ed9ab..80e0f69 100644 --- a/tests/test_repo.py +++ b/tests/test_repo.py @@ -1,2 +1,14 @@ -def test_repo(): - assert True +import importlib.metadata +from unittest.mock import patch + +import testrepo + + +def test_version_found(): + with patch.object(importlib.metadata, "version", return_value="1.2.3"): + assert testrepo.version("test_package") == "1.2.3" + + +def test_version_not_found(): + with patch.object(importlib.metadata, "version", side_effect=importlib.metadata.PackageNotFoundError): + assert testrepo.version("test_package") == "0.0.0" From 3fb99d29c6a02fc4f18443bc8076f1c72d8e448f Mon Sep 17 00:00:00 2001 From: Paul Lockaby Date: Mon, 5 Aug 2024 16:10:54 -0700 Subject: [PATCH 2/2] fix: shrink required code coverage with a realistic number --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 571919a..2cfd0f6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -63,7 +63,7 @@ jobs: - name: Run python tests run: | poetry install --no-interaction - poetry run pytest --mypy --cov=src --cov-report=term --cov-fail-under=90 + poetry run pytest --mypy --cov=src --cov-report=term --cov-fail-under=50 - name: Run container tests run: |