diff --git a/.dockerignore b/.dockerignore index 8de9b46ba..02c3075a7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,5 +11,4 @@ !Pipfile.lock !setup.py !setup.cfg -!tests **/__pycache__ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 559b7939f..fc6993809 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -36,6 +36,9 @@ jobs: - name: Build run: make build + - name: Checks + run: make checks + - name: Acceptance run: make acceptance diff --git a/.gitignore b/.gitignore index cb03781d7..0529d7eb4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ __pycache__ /docs/*/build/ /.mypy_cache /acceptance_tests/tests/docker-compose.override.yaml +/results/ diff --git a/Dockerfile b/Dockerfile index c9f855cd1..48af26d04 100644 --- a/Dockerfile +++ b/Dockerfile @@ -80,8 +80,8 @@ FROM base-lint as tests COPY . /opt/c2cwsgiutils/ RUN python3 -m pip install --disable-pip-version-check --no-cache-dir --no-deps \ --editable=/opt/c2cwsgiutils -RUN (cd /opt/c2cwsgiutils/ && prospector -X --output=pylint) -RUN (cd /opt/c2cwsgiutils/ && pytest -vv --cov=c2cwsgiutils --color=yes tests && rm -r tests) + +WORKDIR /opt/c2cwsgiutils FROM base as standard diff --git a/Makefile b/Makefile index 51fc16da2..b84c41433 100644 --- a/Makefile +++ b/Makefile @@ -21,13 +21,30 @@ all: build acceptance .PHONY: build build: build_docker build_acceptance build_test_app +.PHONY: checks +checks: prospector pytest + +.PHONY: prospector +prospector: build_docker_test + docker run \ + --volume=$(shell pwd)/c2cwsgiutils:/opt/c2cwsgiutils/c2cwsgiutils \ + --volume=$(shell pwd)/tests:/opt/c2cwsgiutils/tests \ + $(DOCKER_BASE):tests prospector --die-on-tool-error --output=pylint . + +.PHONY: pytest +pytest: build_docker_test + mkdir -p reports/coverage/api/ + docker run \ + --volume=$(shell pwd)/results:/results \ + --volume=$(shell pwd)/c2cwsgiutils:/opt/c2cwsgiutils/c2cwsgiutils \ + --volume=$(shell pwd)/tests:/opt/c2cwsgiutils/tests \ + $(DOCKER_BASE):tests pytest -vv --cov=c2cwsgiutils --color=yes tests > reports/coverage/api/coverage.ut.1 + .PHONY: acceptance -acceptance: build_acceptance build_test_app +acceptance: build_acceptance build_test_app pytest docker build --tag=camptocamp/c2cwsgiutils-redis-sentinel:6 acceptance_tests/tests/redis/ rm -rf reports/coverage/api reports/acceptance.xml mkdir -p reports/coverage/api - # Get the UT reports - docker run --rm $(DOCKER_BASE):tests cat /opt/c2cwsgiutils/.coverage > reports/coverage/api/coverage.ut.1 # Run the tests docker run $(DOCKER_TTY) --volume=/var/run/docker.sock:/var/run/docker.sock \ --name=c2cwsgiutils_acceptance_$$PPID --env=WAITRESS $(DOCKER_BASE)_acceptance \ @@ -95,5 +112,5 @@ c2cciutils: .venv/timestamp .PHONY: acceptance_local acceptance_local: .venv/timestamp DOCKER_RUN=0 ./.venv/bin/pytest \ - -vv --color=yes --junitxml reports/acceptance.xml --html reports/acceptance.html \ + -vv --color=yes --junitxml=reports/acceptance.xml --html=reports/acceptance.html \ --self-contained-html $(PYTEST_OPTS) acceptance_tests/tests diff --git a/Pipfile b/Pipfile index 651ca41e8..1434c2732 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,7 @@ types-redis = "==4.2.8" types-ujson = "==5.2.0" types-python-dateutil = "==2.8.18" typing-extensions = "==4.2.0" +scikit-image = "==0.19.3" [packages] alembic = "==1.8.0" diff --git a/Pipfile.lock b/Pipfile.lock index 646ec071f..a2c1d3c5f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "cf921b53f177cae1c24f7e7c94b8921baf4e659d7eed233c70b191d37729c6fc" + "sha256": "9b5cb8bdfac57b5e47c13dd63cc68fcd61c07ad1f53a30d05eed33fc1dc90886" }, "pipfile-spec": 6, "requires": { @@ -954,6 +954,14 @@ "markers": "python_version >= '3.7'", "version": "==3.1.27" }, + "imageio": { + "hashes": [ + "sha256:5f0278217c1cf99d90ef855dab948f93d9fce0ab7ab388e13a597c706b7ec4e5", + "sha256:ea8770d082cea02de6ca5500ab3ad649a8c09832528152efd07da5c225b13722" + ], + "markers": "python_version >= '3.7'", + "version": "==2.21.1" + }, "iniconfig": { "hashes": [ "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", @@ -1116,6 +1124,48 @@ ], "version": "==0.4.3" }, + "networkx": { + "hashes": [ + "sha256:2a30822761f34d56b9a370d96a4bf4827a535f5591a4078a453425caeba0c5bb", + "sha256:bd2b7730300860cbd2dafe8e5af89ff5c9a65c3975b352799d87a6238b4301a6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.8.6" + }, + "numpy": { + "hashes": [ + "sha256:17e5226674f6ea79e14e3b91bfbc153fdf3ac13f5cc54ee7bc8fdbe820a32da0", + "sha256:2bd879d3ca4b6f39b7770829f73278b7c5e248c91d538aab1e506c628353e47f", + "sha256:4f41f5bf20d9a521f8cab3a34557cd77b6f205ab2116651f12959714494268b0", + "sha256:5593f67e66dea4e237f5af998d31a43e447786b2154ba1ad833676c788f37cde", + "sha256:5e28cd64624dc2354a349152599e55308eb6ca95a13ce6a7d5679ebff2962913", + "sha256:633679a472934b1c20a12ed0c9a6c9eb167fbb4cb89031939bfd03dd9dbc62b8", + "sha256:806970e69106556d1dd200e26647e9bee5e2b3f1814f9da104a943e8d548ca38", + "sha256:806cc25d5c43e240db709875e947076b2826f47c2c340a5a2f36da5bb10c58d6", + "sha256:8247f01c4721479e482cc2f9f7d973f3f47810cbc8c65e38fd1bbd3141cc9842", + "sha256:8ebf7e194b89bc66b78475bd3624d92980fca4e5bb86dda08d677d786fefc414", + "sha256:8ecb818231afe5f0f568c81f12ce50f2b828ff2b27487520d85eb44c71313b9e", + "sha256:8f9d84a24889ebb4c641a9b99e54adb8cab50972f0166a3abc14c3b93163f074", + "sha256:909c56c4d4341ec8315291a105169d8aae732cfb4c250fbc375a1efb7a844f8f", + "sha256:9b83d48e464f393d46e8dd8171687394d39bc5abfe2978896b77dc2604e8635d", + "sha256:ac987b35df8c2a2eab495ee206658117e9ce867acf3ccb376a19e83070e69418", + "sha256:b78d00e48261fbbd04aa0d7427cf78d18401ee0abd89c7559bbf422e5b1c7d01", + "sha256:b8b97a8a87cadcd3f94659b4ef6ec056261fa1e1c3317f4193ac231d4df70215", + "sha256:bd5b7ccae24e3d8501ee5563e82febc1771e73bd268eef82a1e8d2b4d556ae66", + "sha256:bdc02c0235b261925102b1bd586579b7158e9d0d07ecb61148a1799214a4afd5", + "sha256:be6b350dfbc7f708d9d853663772a9310783ea58f6035eec649fb9c4371b5389", + "sha256:c403c81bb8ffb1c993d0165a11493fd4bf1353d258f6997b3ee288b0a48fce77", + "sha256:cf8c6aed12a935abf2e290860af8e77b26a042eb7f2582ff83dc7ed5f963340c", + "sha256:d98addfd3c8728ee8b2c49126f3c44c703e2b005d4a95998e2167af176a9e722", + "sha256:dc76bca1ca98f4b122114435f83f1fcf3c0fe48e4e6f660e07996abf2f53903c", + "sha256:dec198619b7dbd6db58603cd256e092bcadef22a796f778bf87f8592b468441d", + "sha256:df28dda02c9328e122661f399f7655cdcbcf22ea42daa3650a26bce08a187450", + "sha256:e603ca1fb47b913942f3e660a15e55a9ebca906857edfea476ae5f0fe9b457d5", + "sha256:ecfdd68d334a6b97472ed032b5b37a30d8217c097acfff15e8452c710e775524" + ], + "markers": "python_version >= '3.8'", + "version": "==1.23.2" + }, "packaging": { "hashes": [ "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", @@ -1139,6 +1189,70 @@ ], "version": "==0.10.0" }, + "pillow": { + "hashes": [ + "sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927", + "sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14", + "sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc", + "sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58", + "sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60", + "sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76", + "sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c", + "sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac", + "sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490", + "sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1", + "sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f", + "sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d", + "sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f", + "sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069", + "sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402", + "sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885", + "sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e", + "sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be", + "sha256:408673ed75594933714482501fe97e055a42996087eeca7e5d06e33218d05aa8", + "sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff", + "sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da", + "sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004", + "sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f", + "sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20", + "sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d", + "sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c", + "sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544", + "sha256:727dd1389bc5cb9827cbd1f9d40d2c2a1a0c9b32dd2261db522d22a604a6eec9", + "sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3", + "sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04", + "sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c", + "sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5", + "sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4", + "sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb", + "sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4", + "sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c", + "sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467", + "sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e", + "sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421", + "sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b", + "sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8", + "sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb", + "sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3", + "sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf", + "sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1", + "sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a", + "sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28", + "sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0", + "sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1", + "sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8", + "sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd", + "sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4", + "sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8", + "sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f", + "sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013", + "sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59", + "sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc", + "sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4" + ], + "markers": "python_version >= '3.7'", + "version": "==9.2.0" + }, "platformdirs": { "hashes": [ "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", @@ -1268,11 +1382,47 @@ }, "pytest-metadata": { "hashes": [ - "sha256:141ba561a17659cda00cf74e7c7cf6103bab4550acad76a46f893339de63b1df", - "sha256:5cdb6aeea8ba9109181cf9f149c8a3ae1430ff7e44506a8f866af8a98ca46301" + "sha256:39261ee0086f17649b180baf2a8633e1922a4c4b6fcc28a2de7d8127a82541bf", + "sha256:fcd2f416f15be295943527b3c8ba16a44ae5a7141939c90c3dc5ce9d167cf2a5" + ], + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==2.0.2" + }, + "pywavelets": { + "hashes": [ + "sha256:0ed3afbda88498b3ea3c861bf5b55e4feca41747730a71a22102ed5a74d1e453", + "sha256:27e99818d3c26481de3c68dbe880a7fcafe661cc031b22eff4a64237fe17a7ff", + "sha256:307ab8a4c3e5c2b8f7d3d371de4a5f019cf4b030b897c3394a4a7ad157369367", + "sha256:3383d106fa8da0c2df30401ad056cd7a11b76d885f4bfa16ca7bcc6b4ca2831c", + "sha256:35a945bea9da6db9755e42e06e871846514ae91bde3ae24a08a1d090b003a23b", + "sha256:38cc635c08a050e175a492e66c9b63a8e1f42254e6879e614b6c9d8d69e0887f", + "sha256:3c4ebe7ff2c9092f6bdd1f8bf98ce2745f5d43a9936d6e342ee83fbcae548116", + "sha256:3d3ecc2ee87be94fb2dc8c2d35bcae3f24708677196e80028d24ba0fd2f6a70a", + "sha256:3eeffcf2f7eebae5cc27cb11a7d0d96118e2e9f75ac38ff1a05373d5fe75accb", + "sha256:41e4f0a3a6a088e955006513fe72f863cea3ce293033131cacb8a1a3068ed228", + "sha256:437806465cfa5f2d91809ec13154be050b84a11025784a6b6ce04ac452872b36", + "sha256:5b76731d2077242611b32f2e11c72adbf126b432ceae92e2ce8d0f693974c96d", + "sha256:69e9a46facf89b51e5700d10f6d831f29745471c1ab42917f2f849a257b9fd77", + "sha256:6ecfe051ccb097c2dcdcb0977e0a684e76144d6694a202badf0780143d8536f0", + "sha256:84c58a179bdb9fc71039b1f68bcd0718a7d9814b5e3741d7681d3e027bb81b52", + "sha256:8a5941d1f4eb1bc9569c655b63ecb31aa15b3ef0fc9b57df275892c39bccc59e", + "sha256:91e1b220f0ddd4c127bab718363c2c4a07dbcd95b9c4bfed09a3cdae47dbba43", + "sha256:a354979e2ee8cd71a8952ded381f3d9f981692b73c6842bcc6c9f64047e0a5be", + "sha256:a486160f83efd8517cd748796adbab7c445ee8a3e1d168b4b8b60ed0f5aee3a0", + "sha256:a51225d24811ba7ef5184c03bb7072db0aa9651c4370a115d4069dedfb8d2f7a", + "sha256:a555a7a85da01357d8258cb45f751881f69013f8920f8738718c60cf8a47b755", + "sha256:c98ac1cee6276db05768e450dc3002033be6c2819c906103a974e0fb0d436f41", + "sha256:cbaa9d62052d9daf8da765fc8e7c30c38ea2b8e9e1c18841913dfb4aec671ee5", + "sha256:d4f9ed4f175c66c9b8646a93fd54c588fd8f4b2517f53c59aea5cdf370f9c9ba", + "sha256:d7369597e1b1d125eb4b458a36cef052beed188444e55ed21445c1196008e200", + "sha256:de67deb275474094e160900ab7e07f2a721b9cd351cf3826c4a3ab89bb71d4b3", + "sha256:e8876764e349673ee8d48bc3cd0afd2f9f7b65378998e2665af12c277c8a56de", + "sha256:eebaa9c28600da336743fefd650332460c132792660e70eb09abf343b0664b87", + "sha256:f6e7d969a6ef64ae8be1766b0b0e32debb13424543d331911b8d7e967d60dd42", + "sha256:fccf468c55427828a3c534b651311f2759210836491c1112e1548e1babe368a5" ], - "markers": "python_version >= '3.7' and python_full_version < '3.11.0'", - "version": "==2.0.1" + "markers": "python_version >= '3.7'", + "version": "==1.3.0" }, "pyyaml": { "hashes": [ @@ -1319,6 +1469,67 @@ ], "version": "==0.7" }, + "scikit-image": { + "hashes": [ + "sha256:03779a7e1736fdf89d83c0ba67d44110496edd736a3bfce61a2b5177a1c8a099", + "sha256:0b0a199157ce8487c77de4fde0edc0b42d6d42818881c11f459262351d678b2d", + "sha256:19a21a101a20c587a3b611a2cf6f86c35aae9f8d9563279b987e83ee1c9a9790", + "sha256:24b5367de1762da6ee126dd8f30cc4e7efda474e0d7d70685433f0e3aa2ec450", + "sha256:2a02d1bd0e2b53e36b952bd5fd6118d9ccc3ee51de35705d63d8eb1f2e86adef", + "sha256:2f50b923f8099c1045fcde7418d86b206c87e333e43da980f41d8577b9605245", + "sha256:32fb88cc36203b99c9672fb972c9ef98635deaa5fc889fe969f3e11c44f22919", + "sha256:33dfd463ee6cc509defa279b963829f2230c9e0639ccd3931045be055878eea6", + "sha256:3a01372ae4bca223873304b0bff79b9d92446ac6d6177f73d89b45561e2d09d8", + "sha256:651de1c2ce1fbee834753b46b8e7d81cb12a5594898babba63ac82b30ddad49d", + "sha256:6b6a8f98f2ac9bb73706461fd1dec875f6a5141759ed526850a5a49e90003d19", + "sha256:7f9f8a1387afc6c70f2bed007c3854a2d7489f9f7713c242f16f32ee05934bc2", + "sha256:84baa3179f3ae983c3a5d81c1e404bc92dcf7daeb41bfe9369badcda3fb22b92", + "sha256:8d8917fcf85b987b1f287f823f3a1a7dac38b70aaca759bc0200f3bc292d5ced", + "sha256:9439e5294de3f18d6e82ec8eee2c46590231cf9c690da80545e83a0733b7a69e", + "sha256:9fb0923a3bfa99457c5e17888f27b3b8a83a3600b4fef317992e7b7234764732", + "sha256:a7c3985c68bfe05f7571167ee021d14f5b8d1a4a250c91f0b13be7fb07e6af34", + "sha256:a8714348ddd671f819457a797c97d4c672166f093def66d66c3254cbd1d43f83", + "sha256:ad5d8000207a264d1a55681a9276e6a739d3f05cf4429004ad00d61d1892235f", + "sha256:cc24177de3fdceca5d04807ad9c87d665f0bf01032ed94a9055cd1ed2b3f33e9", + "sha256:ce3d2207f253b8eb2c824e30d145a9f07a34a14212d57f3beca9f7e03c383cbe", + "sha256:cfbb073f23deb48e0e60c47f8741d8089121d89cc78629ea8c5b51096efc5be7", + "sha256:e207c6ce5ce121d7d9b9d2b61b9adca57d1abed112c902d8ffbfdc20fb42c12b", + "sha256:fd9dd3994bb6f9f7a35f228323f3c4dc44b3cf2ff15fd72d895216e9333550c6", + "sha256:fdf48d9b1f13af69e4e2c78e05067e322e9c8c97463c315cd0ecb47a94e259fc", + "sha256:ff3b1025356508d41f4fe48528e509d95f9e4015e90cf158cd58c56dc63e0ac5" + ], + "index": "pypi", + "version": "==0.19.3" + }, + "scipy": { + "hashes": [ + "sha256:01c2015e132774feefe059d5354055fec6b751d7a7d70ad2cf5ce314e7426e2a", + "sha256:0424d1bbbfa51d5ddaa16d067fd593863c9f2fb7c6840c32f8a08a8832f8e7a4", + "sha256:10417935486b320d98536d732a58362e3d37e84add98c251e070c59a6bfe0863", + "sha256:12005d30894e4fe7b247f7233ba0801a341f887b62e2eb99034dd6f2a8a33ad6", + "sha256:16207622570af10f9e6a2cdc7da7a9660678852477adbcd056b6d1057a036fef", + "sha256:45f0d6c0d6e55582d3b8f5c58ad4ca4259a02affb190f89f06c8cc02e21bba81", + "sha256:5d1b9cf3771fd921f7213b4b886ab2606010343bb36259b544a816044576d69e", + "sha256:693b3fe2e7736ce0dbc72b4d933798eb6ca8ce51b8b934e3f547cc06f48b2afb", + "sha256:73b704c5eea9be811919cae4caacf3180dd9212d9aed08477c1d2ba14900a9de", + "sha256:79dd7876614fc2869bf5d311ef33962d2066ea888bc66c80fd4fa80f8772e5a9", + "sha256:7bad16b91918bf3288089a78a4157e04892ea6475fb7a1d9bcdf32c30c8a3dba", + "sha256:8d541db2d441ef87afb60c4a2addb00c3af281633602a4967e733ef4b7050504", + "sha256:8f2232c9d9119ec356240255a715a289b3a33be828c3e4abac11fd052ce15b1e", + "sha256:97a1f1e51ea30782d7baa8d0c52f72c3f9f05cb609cf1b990664231c5102bccd", + "sha256:adb6c438c6ef550e2bb83968e772b9690cb421f2c6073f9c2cb6af15ee538bc9", + "sha256:bb687d245b6963673c639f318eea7e875d1ba147a67925586abed3d6f39bb7d8", + "sha256:bd490f77f35800d5620f4d9af669e372d9a88db1f76ef219e1609cc4ecdd1a24", + "sha256:c0dfd7d2429452e7e94904c6a3af63cbaa3cf51b348bd9d35b42db7e9ad42791", + "sha256:d3a326673ac5afa9ef5613a61626b9ec15c8f7222b4ecd1ce0fd8fcba7b83c59", + "sha256:e2004d2a3c397b26ca78e67c9d320153a1a9b71ae713ad33f4a3a3ab3d79cc65", + "sha256:e2ac088ea4aa61115b96b47f5f3d94b3fa29554340b6629cd2bfe6b0521ee33b", + "sha256:f7c3c578ff556333f3890c2df6c056955d53537bb176698359088108af73a58f", + "sha256:fc58c3fcb8a724b703ffbc126afdca5a8353d4d5945d5c92db85617e165299e7" + ], + "markers": "python_version < '3.12' and python_version >= '3.8'", + "version": "==1.9.0" + }, "setoptconf-tmp": { "hashes": [ "sha256:76035d5cd1593d38b9056ae12d460eca3aaa34ad05c315b69145e138ba80a745", @@ -1326,14 +1537,6 @@ ], "version": "==0.3.1" }, - "setuptools": { - "hashes": [ - "sha256:d1746e7fd520e83bbe210d02fff1aa1a425ad671c7a9da7d246ec2401a087198", - "sha256:e7d11f3db616cda0751372244c2ba798e8e56a28e096ec4529010b803485f3fe" - ], - "index": "pypi", - "version": "==62.3.3" - }, "smmap": { "hashes": [ "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94", @@ -1351,11 +1554,19 @@ }, "stevedore": { "hashes": [ - "sha256:a547de73308fd7e90075bb4d301405bebf705292fa90a90fc3bcf9133f58616c", - "sha256:f40253887d8712eaa2bb0ea3830374416736dc8ec0e22f5a65092c1174c44335" + "sha256:87e4d27fe96d0d7e4fc24f0cbe3463baae4ec51e81d95fbe60d2474636e0c7d8", + "sha256:f82cc99a1ff552310d19c379827c2c64dd9f85a38bcd5559db2470161867b786" ], - "markers": "python_version >= '3.6'", - "version": "==3.5.0" + "markers": "python_version >= '3.8'", + "version": "==4.0.0" + }, + "tifffile": { + "hashes": [ + "sha256:1456f9f6943c85082ef4d73f5329038826da67f70d5d513873a06f3b1598d23e", + "sha256:3e74e0fd48838477ebcf40e09b7780bd095ee5920b2238f485e2c68463a3dcb4" + ], + "markers": "python_version >= '3.8'", + "version": "==2022.8.12" }, "toml": { "hashes": [ diff --git a/c2cwsgiutils/acceptance/image.py b/c2cwsgiutils/acceptance/image.py new file mode 100644 index 000000000..10705022e --- /dev/null +++ b/c2cwsgiutils/acceptance/image.py @@ -0,0 +1,89 @@ +import os +from typing import TYPE_CHECKING, Any + +import numpy as np +import skimage.color +import skimage.io +import skimage.metrics +import skimage.transform + +if TYPE_CHECKING: + NpNdarrayInt = np.ndarray[np.uint8, Any] +else: + NpNdarrayInt = np.ndarray + + +def check_image_file( + result_folder: str, + image_filename_to_check: str, + expected_filename: str, + level: float = 1.0, + generate_expected_image: bool = False, +) -> None: + """ + Test that the `` corresponds to the image `tests/.expected.png`. + + If the images differ too much, ``/.result.png and + ``/.diff.png are created with the corresponding content. + + Where `` is the name of the `expected_filename`. + + `generate_expected_image` can be set to True to generate the expected image, but it should be + set to False in the committed code, because it also disable the test. + """ + result = skimage.io.imread(image_filename_to_check) + assert result is not None, "Wrong image: " + image_filename_to_check + check_image(result_folder, result, expected_filename, level, generate_expected_image) + + +def check_image( + result_folder: str, + image_to_check: NpNdarrayInt, + expected_filename: str, + level: float = 1.0, + generate_expected_image: bool = False, +) -> None: + """ + Test that the `` corresponds to the image `tests/.expected.png`. + + If they don't corresponds the images ``/.result.png and + ``/.diff.png are created with the corresponding content. + + Where is the name if the `expected_filename`. + + `generate_expected_image` can be set to True to generate the expected image, but it should be + set to False in the committed code, because it also disable the test. + """ + assert image_to_check is not None, "Image required" + image_file_basename = os.path.splitext(os.path.basename(expected_filename))[0] + if image_file_basename.endswith(".expected"): + image_file_basename = os.path.splitext(image_file_basename)[0] + result_filename = os.path.join(result_folder, f"{image_file_basename}.result.png") + diff_filename = os.path.join(result_folder, f"{image_file_basename}.diff.png") + + if not os.path.exists(result_folder): + os.makedirs(result_folder) + if generate_expected_image: + skimage.io.imsave(expected_filename, image_to_check) + return + if not os.path.isfile(expected_filename): + skimage.io.imsave(result_filename, image_to_check) + skimage.io.imsave(expected_filename, image_to_check) + assert False, "Expected image not found: " + expected_filename + expected = skimage.io.imread(expected_filename) + assert expected is not None, "Wrong image: " + expected_filename + + score, diff = skimage.metrics.structural_similarity( + expected, image_to_check, multichannel=True, full=True + ) + diff = (255 - diff * 255).astype("uint8") + + if diff is None: + skimage.io.imsave(result_filename, image_to_check) + assert diff is not None, "No diff generated" + if score < level: + skimage.io.imsave(result_filename, image_to_check) + skimage.io.imsave(diff_filename, diff) + assert ( + score >= level + ), f"{result_filename} != {expected_filename} => {diff_filename} ({score} > {level})" diff --git a/c2cwsgiutils/setup_process.py b/c2cwsgiutils/setup_process.py index 112913ff9..f0fa01d5e 100644 --- a/c2cwsgiutils/setup_process.py +++ b/c2cwsgiutils/setup_process.py @@ -9,22 +9,14 @@ import warnings from typing import Any, Callable, Dict, Optional, TypedDict, cast +import pyramid.config import pyramid.registry import pyramid.request import pyramid.router -import pyramid.config - from pyramid.paster import bootstrap from pyramid.scripts.common import get_config_loader, parse_vars -from c2cwsgiutils import ( - broadcast, - coverage_setup, - redis_stats, - sentry, - stats, - sql_profiler, -) +from c2cwsgiutils import broadcast, coverage_setup, redis_stats, sentry, sql_profiler, stats def fill_arguments( diff --git a/setup.py b/setup.py index 435a65e73..d69ee188e 100644 --- a/setup.py +++ b/setup.py @@ -52,6 +52,7 @@ def long_description() -> str: extras_require={ "standard": [e for e in INSTALL_REQUIRES if e != "redis"], "broadcast": ["redis"], + "test_images": ["scikit-image"], }, entry_points={ "console_scripts": [ diff --git a/tests/test.diff.expected.png b/tests/test.diff.expected.png new file mode 100644 index 000000000..d89a0a0d6 Binary files /dev/null and b/tests/test.diff.expected.png differ diff --git a/tests/test.expected.png b/tests/test.expected.png new file mode 100644 index 000000000..bcd1c2a70 Binary files /dev/null and b/tests/test.expected.png differ diff --git a/tests/test.wrong.png b/tests/test.wrong.png new file mode 100644 index 000000000..13c73d55f Binary files /dev/null and b/tests/test.wrong.png differ diff --git a/tests/test_acceptance_image.py b/tests/test_acceptance_image.py new file mode 100644 index 000000000..d8c7ce02a --- /dev/null +++ b/tests/test_acceptance_image.py @@ -0,0 +1,21 @@ +import os + +import pytest + +from c2cwsgiutils.acceptance.image import check_image_file + + +def test_good(): + image = os.path.join(os.path.dirname(__file__), "test.expected.png") + check_image_file("/results", image, os.path.join(os.path.dirname(__file__), "test.expected.png")) + + +def test_wrong(): + image = os.path.join(os.path.dirname(__file__), os.path.join(os.path.dirname(__file__), "test.wrong.png")) + with pytest.raises(AssertionError): + check_image_file("/results", image, os.path.join(os.path.dirname(__file__), "test.expected.png")) + check_image_file( + "/results", + "/results/test.diff.png", + os.path.join(os.path.dirname(__file__), "test.diff.expected.png"), + )