From 813754f49e3cfbed70c7f2068c779665cc189461 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 06:31:23 -0500 Subject: [PATCH 01/17] v1.3.1: imsuite patches --- src/lavlab/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lavlab/__about__.py b/src/lavlab/__about__.py index 5d7ef5a..19d1c8e 100644 --- a/src/lavlab/__about__.py +++ b/src/lavlab/__about__.py @@ -1,3 +1,3 @@ """Hatch Version Info""" -version = "1.4.0-alpha.1" # pylint: disable=C0103 +version = "1.3.1" # pylint: disable=C0103 From c61458f787119c192b744324618ba6032bea0b66 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 06:41:02 -0500 Subject: [PATCH 02/17] update codecov action --- .github/workflows/pytest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 837d87c..9fa5797 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -19,8 +19,8 @@ jobs: - name: Run pytest and generate coverage report run: docker run --rm -e HATCH_ENV=test -v "${{ github.workspace }}:/app" myapp:hatch cov - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true - files: ${{ github.workspace }}/.coverage \ No newline at end of file + files: ${{ github.workspace }}/.coverage From afac022964fb47d929b17603c50d20308f551ae9 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 06:51:57 -0500 Subject: [PATCH 03/17] xml coverage report --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 398357c..94e9ff9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,7 +98,7 @@ dependencies = [ ] [tool.hatch.envs.test.scripts] test = "pytest {args:test}" -cov = "pytest --cov=src --cov-report=term-missing {args:test}" +cov = "pytest --cov=src --cov-report=xml {args:test}" [tool.hatch.envs.lint] features = [ "omero", "jupyter" ] @@ -163,4 +163,4 @@ module = [ "omero", "scipy" ] -ignore_missing_imports = true \ No newline at end of file +ignore_missing_imports = true From 2a3153d6e9bfce4d147663b248b8f4a0b00f0fe5 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 06:53:02 -0500 Subject: [PATCH 04/17] upload xml report and use oidc instead of manual api token --- .github/workflows/pytest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 9fa5797..4abde5a 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -21,6 +21,6 @@ jobs: - name: Upload coverage report to Codecov uses: codecov/codecov-action@v4 with: - token: ${{ secrets.CODECOV_TOKEN }} + use_oidc: true fail_ci_if_error: true - files: ${{ github.workspace }}/.coverage + files: ${{ github.workspace }}/coverage.xml From ce6691b0af88a99a02e9c22ba851a091ed0ed59e Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 07:04:10 -0500 Subject: [PATCH 05/17] give oidc token permissions --- .github/workflows/pytest.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 4abde5a..b53e40d 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,5 +1,9 @@ name: Run Pytest and Codecov with Hatch +permissions: + id-token: write + contents: read + on: push: branches: From f274201fd26fc5d4593f47f4586fa492c48aa89e Mon Sep 17 00:00:00 2001 From: default Date: Tue, 4 Jun 2024 12:17:16 +0000 Subject: [PATCH 06/17] update requirements files --- requirements/requirements-docs.txt | 48 ++++++++++++++++++++++++++++- requirements/requirements-lint.txt | 48 ++++++++++++++++++++++++++++- requirements/requirements-test.txt | 48 ++++++++++++++++++++++++++++- requirements/requirements-types.txt | 48 ++++++++++++++++++++++++++++- 4 files changed, 188 insertions(+), 4 deletions(-) diff --git a/requirements/requirements-docs.txt b/requirements/requirements-docs.txt index 9459fe3..35c391c 100644 --- a/requirements/requirements-docs.txt +++ b/requirements/requirements-docs.txt @@ -8,6 +8,7 @@ # - mkdocs-minify-plugin # - mkdocs-material-extensions # - mkdocs-git-revision-date-localized-plugin +# - highdicom # - keyring # - matplotlib # - nibabel @@ -512,6 +513,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.docs htmlmin2==0.1.13 \ --hash=sha256:75609f2a42e64f7ce57dbff28a39890363bde9e7e5885db633317efbdf8c79a2 # via mkdocs-minify-plugin @@ -1058,6 +1063,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1181,10 +1187,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.0 \ --hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \ --hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768 @@ -1249,7 +1293,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.docs + # via + # hatch.envs.docs + # highdicom pygments==2.17.2 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 diff --git a/requirements/requirements-lint.txt b/requirements/requirements-lint.txt index 7795f26..54d69e9 100644 --- a/requirements/requirements-lint.txt +++ b/requirements/requirements-lint.txt @@ -5,6 +5,7 @@ # - pytest # - pylint # - black +# - highdicom # - keyring # - matplotlib # - nibabel @@ -512,6 +513,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.lint httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -1007,6 +1012,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1128,10 +1134,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.0 \ --hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \ --hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768 @@ -1200,7 +1244,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.lint + # via + # hatch.envs.lint + # highdicom pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index d661e94..4a92111 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -7,6 +7,7 @@ # - pytest-asyncio # - coverage[toml]>=6.2 # - pydicom-data +# - highdicom # - keyring # - matplotlib # - nibabel @@ -536,6 +537,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.test httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -1019,6 +1024,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1135,10 +1141,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.2 \ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 @@ -1204,7 +1248,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.test + # via + # hatch.envs.test + # highdicom pydicom-data==1.0.0 \ --hash=sha256:622ac97265f1d91f76b5120b5bd6eb0f57737c392ef863b72c71779c91e33637 \ --hash=sha256:93f2094f219b6fec1e6dbed2e5039fb879272f678646a351b46172f6d0bf110f diff --git a/requirements/requirements-types.txt b/requirements/requirements-types.txt index a186773..aedb4d6 100644 --- a/requirements/requirements-types.txt +++ b/requirements/requirements-types.txt @@ -2,6 +2,7 @@ # This file is autogenerated by hatch-pip-compile with Python 3.11 # # - mypy>=1.0.0 +# - highdicom # - keyring # - matplotlib # - nibabel @@ -475,6 +476,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.types httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -988,6 +993,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1103,10 +1109,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.2 \ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 @@ -1168,7 +1212,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.types + # via + # hatch.envs.types + # highdicom pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a From 222ee10a28f5983677e1d17f66d40a5ef4f2d813 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:22:10 -0500 Subject: [PATCH 07/17] upload logo --- logo.webp | Bin 0 -> 76170 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logo.webp diff --git a/logo.webp b/logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..7b3491b0802f45be26576447fa9204e69726e533 GIT binary patch literal 76170 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%0D^!wGEEDfaSSdO3U| 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 Date: Tue, 4 Jun 2024 14:43:19 -0500 Subject: [PATCH 08/17] Update README.md --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 589f4dd..251fea8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,42 @@ -TODO: this readme -================= -for more info goto: https://lavlab-python-utils.readthedocs.io/en/latest/ -python3 -m unittest -TODO: convention documentation. -TODO: pyXNAT support \ No newline at end of file +# LavLab Python Utils + +[![Documentation Status](https://readthedocs.org/projects/lavlab-python-utils/badge/?version=stable)](https://lavlab-python-utils.readthedocs.io/stable) +[![GitHub release](https://img.shields.io/github/v/release/laviolette-lab/lavlab-python-utils.svg)](https://github.com/laviolette-lab/lavlab-python-utils/releases) +[![Build Status](https://github.com/laviolette-lab/lavlab-python-utils/actions/workflows/pylint.yml/badge.svg)](https://github.com/laviolette-lab/lavlab-python-utils/actions) +[![Coverage Status](https://img.shields.io/codecov/c/github/laviolette-lab/lavlab-python-utils.svg)](https://codecov.io/gh/laviolette-lab/lavlab-python-utils) + +Welcome to the **LavLab Python Utils** repository! This library is a collection of Python utilities developed by the LaViolette Lab to support our research in RadioPathomics and digital pathology. + + + +## Overview + +LavLab Python Utils is designed to streamline common tasks in our research workflow, including data preprocessing, analysis, and visualization. Our goal is to provide a set of tools that are easy to use, well-documented, and performant. + +## Features + +- **Data Processing:** Functions to handle various data formats used in our research, including DICOM, NIfTI, and more. +- **Visualization:** Tools to create publication-quality plots and visualizations. +- **Integration:** Seamless integration with other tools and services used in our lab. + +## Installation + +You can install LavLab Python Utils via pip: + +```bash +python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl +# optional install targets +pip install lavlab-python-utils[omero,jupyter] +``` + +## Documentation + +Comprehensive documentation is available on [Read the Docs]([https://your-docs-link](https://lavlab-python-utils.readthedocs.io/stable/)). This includes detailed API references, usage examples, and tutorials. + +## Contributing + +We welcome contributions from the community! If you are interested in contributing, please read our [contributing guide]([CONTRIBUTING.md](https://lavlab-python-utils.readthedocs.io/stable/contributing/)) and check out our [open issues](https://github.com/laviolette-lab/lavlab-python-utils/issues). + +--- + +Thank you for using LavLab Python Utils! We hope you find it useful in your research. From 342abe90351e3a0683984efc4f139caa52e65280 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:52:31 -0500 Subject: [PATCH 09/17] add 'all' install target --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 94e9ff9..6d4608d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,9 @@ jupyter = [ "dash-slicer", "dash-bootstrap-components" ] +all = [ + "lavlab-python-utils[omero, jupyter]" +] [project.entry-points."lavlab_python_utils.service_providers"] OMERO = "lavlab.omero:OmeroServiceProvider" From 3405d3e49be1deda1c4b39f896c73601cc53b473 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:53:19 -0500 Subject: [PATCH 10/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 251fea8..7145d81 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ You can install LavLab Python Utils via pip: ```bash python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl # optional install targets -pip install lavlab-python-utils[omero,jupyter] +python3 -m pip install 'lavlab-python-utils[all]' ``` ## Documentation From 5f9f5eb965464baa6f5885a0e723d99f4e5c9c9a Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:54:27 -0500 Subject: [PATCH 11/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7145d81..9ecd8c1 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You can install LavLab Python Utils via pip: ```bash python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl -# optional install targets +# optional install targets, must install wheel from github using command above first! python3 -m pip install 'lavlab-python-utils[all]' ``` From 1ffd85e28a9f34f87ab3d015aaf5ed4817989893 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:56:25 -0500 Subject: [PATCH 12/17] add install target info to docs --- docs/installation.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 3d25607..fe5a3b4 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,10 +2,12 @@ ## Using latest wheel -You can install the latest release from GitHub: +You can install the latest release from GitHub, once installed you can get the optional dependencies: ```sh python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl +# optional install targets, must install wheel from github using command above first! +python3 -m pip install 'lavlab-python-utils[all]' ``` ## Using versioned wheel @@ -22,4 +24,4 @@ Install using pip+git: ```sh python3 -m pip install git+https://github.com/laviolette-lab/lavlab-python-utils.git -``` \ No newline at end of file +``` From 3a3c89eaa73b691c6a18c796694ac1f12711fe7f Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:58:09 -0500 Subject: [PATCH 13/17] Update installation.md --- docs/installation.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index fe5a3b4..1f79f0f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -9,6 +9,11 @@ python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/rel # optional install targets, must install wheel from github using command above first! python3 -m pip install 'lavlab-python-utils[all]' ``` +We support the following install targets: +* omero + * installs omero-py for omero api access +* jupyter + * installs dash for performant image viewing ## Using versioned wheel From 8834144fda2de1fbc34855b6021285b224d8305f Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:58:50 -0500 Subject: [PATCH 14/17] Update installation.md --- docs/installation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index 1f79f0f..91c7352 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -14,6 +14,8 @@ We support the following install targets: * installs omero-py for omero api access * jupyter * installs dash for performant image viewing +* all + * installs all optional dependencies ## Using versioned wheel From 2698f2ddbd74a914f5d67663fe62b5156634caf9 Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:08:24 -0500 Subject: [PATCH 15/17] fix broken docs link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ecd8c1..8c833c4 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ python3 -m pip install 'lavlab-python-utils[all]' ## Documentation -Comprehensive documentation is available on [Read the Docs]([https://your-docs-link](https://lavlab-python-utils.readthedocs.io/stable/)). This includes detailed API references, usage examples, and tutorials. +Comprehensive documentation is available on [Read the Docs](https://lavlab-python-utils.readthedocs.io/stable/). This includes detailed API references, usage examples, and tutorials. ## Contributing From 59da0cd0822c53de3cad6510cf463fce75cae5aa Mon Sep 17 00:00:00 2001 From: Michael Barrett <103449618+barrettMCW@users.noreply.github.com> Date: Wed, 20 Nov 2024 19:56:36 -0600 Subject: [PATCH 16/17] enhanced imcomplement --- src/lavlab/imsuite.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lavlab/imsuite.py b/src/lavlab/imsuite.py index 747def6..d7400cf 100644 --- a/src/lavlab/imsuite.py +++ b/src/lavlab/imsuite.py @@ -668,7 +668,7 @@ def imhist(img_arr: np.ndarray, bins=256) -> None: def imcomplement(img_arr: np.ndarray) -> np.ndarray: """Generates the image's complement (inverts the image). - + Parameters ---------- img_arr : np.ndarray @@ -679,7 +679,23 @@ def imcomplement(img_arr: np.ndarray) -> np.ndarray: np.ndarray Inverted image. """ - return ~img_arr + # Handle uint8 directly + if img_arr.dtype == np.uint8: + return ~img_arr + + min_val = np.min(img_arr) + max_val = np.max(img_arr) + + # Handle range [0, 1] + if max_val <= 1 and min_val >= 0: + return 1 - img_arr + + # Handle range [-1, 1] + if max_val <= 1 and min_val >= -1: + return -img_arr + + # Generalized case + return min_val + max_val - img_arr def edge(img_arr: np.ndarray, method: str = "SOBEL", **kwargs) -> np.ndarray: From 7a5581ddc2ec09e8cf1987d8aa3a1f0ec5155168 Mon Sep 17 00:00:00 2001 From: bench-mcw Date: Wed, 27 Nov 2024 10:36:46 -0600 Subject: [PATCH 17/17] fix mem leak --- src/lavlab/omero/tiles.py | 44 ++++++++++++++------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/src/lavlab/omero/tiles.py b/src/lavlab/omero/tiles.py index 5477907..62dc7ca 100644 --- a/src/lavlab/omero/tiles.py +++ b/src/lavlab/omero/tiles.py @@ -21,7 +21,7 @@ def get_tiles( # pylint: disable=R0914 ) -> Generator[ tuple[np.ndarray, tuple[int, int, int, tuple[int, int, int, int]]], None, None ]: - """Pull tiles from omero faster using a ThreadPoolExecutor! + """Pull tiles from omero faster using a ThreadPoolExecutor and executor.map! Parameters ---------- @@ -46,49 +46,37 @@ def get_tiles( # pylint: disable=R0914 conn = img._conn # pylint: disable=W0212 local = threading.local() - def work(pix_id, zct, coord, res_lvl, rps_bypass): - """runs inside a threadpool to get multiple tiles at a time""" + def work(args): + """Runs inside a thread pool to get multiple tiles at a time.""" + pix_id, zct, coord, res_lvl, rps_bypass = args if getattr(local, "rps", None) is None: - # need to prepare a thread-specific rps + # Need to prepare a thread-specific rps local.rps = conn.c.sf.createRawPixelsStore() local.rps.setPixelsId(pix_id, rps_bypass) if res_lvl is None: res_lvl = local.rps.getResolutionLevels() res_lvl -= 1 local.rps.setResolutionLevel(res_lvl) - return local.rps.getTile(*zct, *coord), (*zct, coord) + raw_data = local.rps.getTile(*zct, *coord) + return raw_data, (*zct, coord) def cleanup(): - """cleans out the raw pixels stores after work is done""" + """Cleans out the raw pixels stores after work is done.""" if hasattr(local, "rps"): local.rps.close() delattr(local, "rps") - futures = [ - tpe.submit( - work, - img.getPrimaryPixels().getId(), - (z, c, t), - coord, - res_lvl, - rps_bypass, - ) - for z, c, t, coord in tiles - ] try: - for future in as_completed(futures): - raw_data, (z, c, t, coord) = future.result() - processed_data = np.frombuffer(raw_data, dtype=np.uint8).reshape( - coord[3], coord[2] - ) + # Use executor.map for streamlined processing + pix_id = img.getPrimaryPixels().getId() + args_iter = ((pix_id, (z, c, t), coord, res_lvl, rps_bypass) for z, c, t, coord in tiles) + for raw_data, (z, c, t, coord) in tpe.map(work, args_iter): + processed_data = np.frombuffer(raw_data, dtype=np.uint8).reshape(coord[3], coord[2]) yield processed_data, (z, c, t, coord) finally: - futures = [ - tpe.submit(cleanup) - for x in range(tpe._max_workers) # pylint: disable=W0212 - ] # pylint: disable=W0212 - for future in as_completed(futures): - future.result() + # Cleanup resources + for _ in range(tpe._max_workers): # pylint: disable=W0212 + cleanup() def create_tile_list_2d( # pylint: disable=R0913