Repository: rapidsai/cucim (language: python)

Issue:
Forward-merge branch-23.12 to branch-24.02
Forward-merge triggered by push to `branch-23.12` that creates a PR to keep `branch-24.02` up-to-date. If this PR is unable to be immediately merged due to conflicts, it will remain open for the team to manually merge.
[BUG] fix isolated test failure in `test_cache_hit_miss`
**Describe the bug**

When working on wheel builds in #619, it was observed that a single test case, `test_cache_hit_miss` would fail when running the wheel tests. Temporarily, this test case is not being run because `imagecodecs` is not installed as part of the test dependencies during wheel testing.  Before release 23.12.00 we should enable install of `imagecodecs` and `openslide-python` again so that all `cucim.clara` submodule test cases get run.


build wheels on CI
This MR includes the commits from #617, so that one should be merged first.

The purpose of this MR is to build and test wheels on RAPIDS CI infrastructure. Previously, cuCIM was using a custom manual wheel building process based on running:
```
./run build_python_package
```
which used `dockcross`/`cibuildwheel`. We would then manually upload the resulting wheel to PyPI using `twine`.

The changes in this MR are to enable automated wheel builds for future RAPIDS releases in a similar way to other RAPIDS projects.

### Misc issues/questions for discussion
- The `build_wheels.sh` script installs the YASM and the openslide libraries via system package managers. This is currently hard-coded in that script rather than using the `dependencies.yaml` mechanism being used elsewhere. Is this reasonable or is there a better way?
- Following cuML's example, I added a separate `ci/release/apply_wheel_modifications.sh` script that updates the pyproject.toml as needed (to fixup version string and the CUDA version strings in the cucim package name and CuPy dependency)
- I updated the cuCIM test suite to make a handful of tests that relied on `imagecodecs` to be skipped if it is not installed. This is because I did not find a pre-compiled wheel for it on aarch64 and when it tried to compile from source instead, it failed due to various missing system packages needed for the compilation.
- Unlike most RAPIDS projects, which seem to use scikit-build, this project performs a separate CMake build via `run build_local` commands and copies the C++ libraries into the Python source tree. The `pyproject.toml` then just does a standard pure-python build, but will package the previously compiled libraries along with the other files.
- The wheel tests are currently taking approximately 35-50 minutes to run. It should be possible to reduce that time by an order of magnitude if the CuPy kernels are cached across runs. Does any RAPIDS projects cache the compiled CuPy kernels in this way? (cached kernels end up in `~/.cupy/kernel_cache/` by default, although an alternative location can be specified via `CUPY_CACHE_DIR`) 

Review & cleanup `python/cucim`
This is unused

https://github.com/rapidsai/cucim/blob/87410cd6a053482e06695751ac848fffd1444a1a/python/cucim/tox.ini#L13

This is unused

https://github.com/rapidsai/cucim/blob/87410cd6a053482e06695751ac848fffd1444a1a/python/cucim/.cookiecutterrc#L3-L4

Also this

https://github.com/rapidsai/cucim/blob/87410cd6a053482e06695751ac848fffd1444a1a/python/cucim/.appveyor.yml#L3


Discussion / hints:


I think this recent failure will be fixed by merging #623:
https://github.com/rapidsai/cucim/actions/runs/6711052263/job/18238149350?pr=619

In discussion with Vyas offline, we've agreed to go ahead and merge. We can follow up on anything else in subsequent PRs/issues
Thanks Greg for the PR and everyone for the reviews! 🙏
/merge


Fix patch:
diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 26a3e77ec..000000000
--- a/.dockerignore
+++ /dev/null
@@ -1,6 +0,0 @@
-*
-!docker
-#cmake-build-*
-#build
-#install
-!temp/gds
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 745f4a5e4..8bbb437b7 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -10,10 +10,7 @@ python/            @rapidsai/cucim-python-codeowners
 **/cmake/          @rapidsai/cucim-cmake-codeowners
 
 #build/ops code owners
-.github/           @rapidsai/ops-codeowners
-ci/                @rapidsai/ops-codeowners
-conda/             @rapidsai/ops-codeowners
-**/Dockerfile      @rapidsai/ops-codeowners
-**/.dockerignore   @rapidsai/ops-codeowners
-docker/            @rapidsai/ops-codeowners
+/.github/           @rapidsai/ops-codeowners
+/ci/                @rapidsai/ops-codeowners
+/conda/             @rapidsai/ops-codeowners
 dependencies.yaml  @rapidsai/ops-codeowners
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 1710aa4c1..0ba4825e9 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -28,7 +28,7 @@ concurrency:
 jobs:
   cpp-build:
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@branch-24.02
     with:
       build_type: ${{ inputs.build_type || 'branch' }}
       branch: ${{ inputs.branch }}
@@ -38,7 +38,7 @@ jobs:
     if: github.ref_type == 'branch'
     needs: [python-build]
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02
     with:
       arch: "amd64"
       branch: ${{ inputs.branch }}
@@ -51,7 +51,7 @@ jobs:
   python-build:
     needs: [cpp-build]
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.02
     with:
       build_type: ${{ inputs.build_type || 'branch' }}
       branch: ${{ inputs.branch }}
@@ -60,7 +60,7 @@ jobs:
   upload-conda:
     needs: [cpp-build, python-build]
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-upload-packages.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-upload-packages.yaml@branch-24.02
     with:
       build_type: ${{ inputs.build_type || 'branch' }}
       branch: ${{ inputs.branch }}
@@ -68,7 +68,7 @@ jobs:
       sha: ${{ inputs.sha }}
   wheel-build:
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.02
     with:
       build_type: ${{ inputs.build_type || 'branch' }}
       branch: ${{ inputs.branch }}
@@ -78,7 +78,7 @@ jobs:
   wheel-publish:
     needs: wheel-build
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/wheels-publish.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/wheels-publish.yaml@branch-24.02
     with:
       build_type: ${{ inputs.build_type || 'branch' }}
       branch: ${{ inputs.branch }}
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index d098ff326..7d22e56a2 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -20,32 +20,32 @@ jobs:
       - wheel-build
       - wheel-tests
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@branch-24.02
   checks:
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/checks.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/checks.yaml@branch-24.02
   conda-cpp-build:
     needs: checks
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@branch-24.02
     with:
       build_type: pull-request
   conda-python-build:
     needs: conda-cpp-build
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@branch-24.02
     with:
       build_type: pull-request
   conda-python-tests:
     needs: conda-python-build
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.02
     with:
       build_type: pull-request
   docs-build:
     needs: conda-python-build
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@branch-24.02
     with:
       build_type: pull-request
       node_type: "gpu-v100-latest-1"
@@ -55,14 +55,14 @@ jobs:
   wheel-build:
     needs: checks
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@branch-24.02
     with:
       build_type: pull-request
       script: ci/build_wheel.sh
   wheel-tests:
     needs: wheel-build
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.02
     with:
       build_type: pull-request
       script: ci/test_wheel.sh
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 73f69e095..000000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
deleted file mode 100644
index c8f84c353..000000000
--- a/.idea/codeStyles/Project.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <code_scheme name="Project" version="173">
-    <clangFormatSettings>
-      <option name="ENABLED" value="true" />
-    </clangFormatSettings>
-  </code_scheme>
-</component>
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 0f7bc519d..000000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <state>
-    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
-  </state>
-</component>
diff --git a/.idea/cucim.iml b/.idea/cucim.iml
deleted file mode 100644
index 08cda128a..000000000
--- a/.idea/cucim.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module classpath="CMake" type="CPP_MODULE" version="4" />
diff --git a/.idea/fileTemplates/includes/NVIDIA_CMAKE_HEADER.cmake b/.idea/fileTemplates/includes/NVIDIA_CMAKE_HEADER.cmake
deleted file mode 100644
index 7272e0dec..000000000
--- a/.idea/fileTemplates/includes/NVIDIA_CMAKE_HEADER.cmake
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Copyright (c) $YEAR, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
diff --git a/.idea/fileTemplates/includes/NVIDIA_C_HEADER.h b/.idea/fileTemplates/includes/NVIDIA_C_HEADER.h
deleted file mode 100644
index cf0461d4c..000000000
--- a/.idea/fileTemplates/includes/NVIDIA_C_HEADER.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (c) $YEAR, NVIDIA CORPORATION.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
diff --git a/.idea/fileTemplates/internal/C Header File.h b/.idea/fileTemplates/internal/C Header File.h
deleted file mode 100644
index 9cb1d09e2..000000000
--- a/.idea/fileTemplates/internal/C Header File.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#parse("NVIDIA_C_HEADER.h")
-#[[#ifndef]]# ${INCLUDE_GUARD}
-#[[#define]]# ${INCLUDE_GUARD}
-
-#[[#endif]]# //${INCLUDE_GUARD}
diff --git a/.idea/fileTemplates/internal/C Source File.c b/.idea/fileTemplates/internal/C Source File.c
deleted file mode 100644
index b04dd6c62..000000000
--- a/.idea/fileTemplates/internal/C Source File.c
+++ /dev/null
@@ -1,4 +0,0 @@
-#parse("NVIDIA_C_HEADER.h")
-#if (${HEADER_FILENAME})
-#[[#include]]# "${HEADER_FILENAME}"
-#end
diff --git a/.idea/fileTemplates/internal/C++ Class Header.h b/.idea/fileTemplates/internal/C++ Class Header.h
deleted file mode 100644
index f521fa555..000000000
--- a/.idea/fileTemplates/internal/C++ Class Header.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#parse("NVIDIA_C_HEADER.h")
-#[[#ifndef]]# ${INCLUDE_GUARD}
-#[[#define]]# ${INCLUDE_GUARD}
-
-${NAMESPACES_OPEN}
-
-class ${NAME} {
-
-};
-
-${NAMESPACES_CLOSE}
-
-#[[#endif]]# //${INCLUDE_GUARD}
diff --git a/.idea/fileTemplates/internal/C++ Class.cc b/.idea/fileTemplates/internal/C++ Class.cc
deleted file mode 100644
index 42f43ccf4..000000000
--- a/.idea/fileTemplates/internal/C++ Class.cc
+++ /dev/null
@@ -1,2 +0,0 @@
-#parse("NVIDIA_C_HEADER.h")
-#[[#include]]# "${HEADER_FILENAME}"
diff --git a/.idea/fileTemplates/internal/CMakeLists.txt.cmake b/.idea/fileTemplates/internal/CMakeLists.txt.cmake
deleted file mode 100644
index 846356219..000000000
--- a/.idea/fileTemplates/internal/CMakeLists.txt.cmake
+++ /dev/null
@@ -1,1 +0,0 @@
-#parse("NVIDIA_CMAKE_HEADER.cmake")
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 2019083a1..000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
-  <component name="JavaScriptSettings">
-    <option name="languageLevel" value="ES6" />
-  </component>
-</project>
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 5ace414d8..000000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa1e0b55e..c826766cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,30 @@
+# cuCIM 24.02.00 (12 Feb 2024)
+
+## 🐛 Bug Fixes
+
+- Fix CUDA trove classifiers &amp; update README install instructions ([#695](https://github.com/rapidsai/cucim/pull/695)) [@jakirkham](https://github.com/jakirkham)
+- Exclude PyTest 8 ([#689](https://github.com/rapidsai/cucim/pull/689)) [@jakirkham](https://github.com/jakirkham)
+- Update OpenJPEG to 2.5.0 ([#685](https://github.com/rapidsai/cucim/pull/685)) [@jakirkham](https://github.com/jakirkham)
+- Fix CI (pt. 2) ([#680](https://github.com/rapidsai/cucim/pull/680)) [@jakirkham](https://github.com/jakirkham)
+- Fix CI issues ([#676](https://github.com/rapidsai/cucim/pull/676)) [@jakirkham](https://github.com/jakirkham)
+- Remove update to symlink ([#674](https://github.com/rapidsai/cucim/pull/674)) [@raydouglass](https://github.com/raydouglass)
+- Add 3rd party license file in Conda packages ([#654](https://github.com/rapidsai/cucim/pull/654)) [@jakirkham](https://github.com/jakirkham)
+- Fix style issue in `docs/source/conf.py` ([#648](https://github.com/rapidsai/cucim/pull/648)) [@jakirkham](https://github.com/jakirkham)
+
+## 🛠️ Improvements
+
+- Consolidate test requirements in `dependencies.yaml` ([#683](https://github.com/rapidsai/cucim/pull/683)) [@jakirkham](https://github.com/jakirkham)
+- Remove usages of rapids-env-update ([#673](https://github.com/rapidsai/cucim/pull/673)) [@KyleFromNVIDIA](https://github.com/KyleFromNVIDIA)
+- refactor CUDA versions in dependencies.yaml ([#671](https://github.com/rapidsai/cucim/pull/671)) [@jameslamb](https://github.com/jameslamb)
+- minor updates/fixes for consistency with scikit-image 0.22 ([#670](https://github.com/rapidsai/cucim/pull/670)) [@grlee77](https://github.com/grlee77)
+- Update CODEOWNERS ([#669](https://github.com/rapidsai/cucim/pull/669)) [@ajschmidt8](https://github.com/ajschmidt8)
+- remove redundant notebook ([#668](https://github.com/rapidsai/cucim/pull/668)) [@grlee77](https://github.com/grlee77)
+- remove .idea folder (CLion IDE configuration) ([#667](https://github.com/rapidsai/cucim/pull/667)) [@grlee77](https://github.com/grlee77)
+- Cleanup old ci and docs subfolders and related files under python/cucim ([#666](https://github.com/rapidsai/cucim/pull/666)) [@grlee77](https://github.com/grlee77)
+- remove various files related to old wheel building mechanism ([#665](https://github.com/rapidsai/cucim/pull/665)) [@grlee77](https://github.com/grlee77)
+- Relax `openslide` pin ([#653](https://github.com/rapidsai/cucim/pull/653)) [@jakirkham](https://github.com/jakirkham)
+- install imagecodecs and openslide-python dependencies so additional tests will run ([#634](https://github.com/rapidsai/cucim/pull/634)) [@grlee77](https://github.com/grlee77)
+
 # cuCIM 23.12.00 (6 Dec 2023)
 
 ## 🐛 Bug Fixes
diff --git a/Cache Example.ipynb b/Cache Example.ipynb
deleted file mode 100644
index ae686fabd..000000000
--- a/Cache Example.ipynb
+++ /dev/null
@@ -1,531 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "69aeee77",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from cucim import CuImage\n",
-    "from cucim.clara.cache import calc_preferred_cache_memory\n",
-    "\n",
-    "img = CuImage(\"notebooks/input/image.tif\")\n",
-    "memory_capacity = calc_preferred_cache_memory(img, (256, 256))\n",
-    "CuImage.cache(\"per_process\", memory_capacity=memory_capacity, record_stat=True)\n",
-    "#CuImage.cache(\"per_process\", memory_capacity=2048, record_stat=True)\n",
-    "\n",
-    "region = img.read_region((0,0), (100,100))\n",
-    "\n",
-    "cache = CuImage.cache()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "f2121d1b",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'type': 'per_process',\n",
-       " 'memory_capacity': 2048,\n",
-       " 'capacity': 5461,\n",
-       " 'mutex_pool_capacity': 11117,\n",
-       " 'list_padding': 10000,\n",
-       " 'extra_shared_memory_size': 100,\n",
-       " 'record_stat': True}"
-      ]
-     },
-     "execution_count": 2,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "cache.config"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "fbea8f0a",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "cache hit: 0, chche miss: 1\n"
-     ]
-    }
-   ],
-   "source": [
-    "print(f\"cache hit: {cache.hit_count}, chche miss: {cache.miss_count}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "0f60842a",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "cache hit: 1, chche miss: 1\n",
-      "items in cache: 1/5461, memory usage in cache: 196608/2147483648\n"
-     ]
-    }
-   ],
-   "source": [
-    "region = img.read_region((0,0), (100,100))\n",
-    "\n",
-    "print(f\"cache hit: {cache.hit_count}, chche miss: {cache.miss_count}\")\n",
-    "print(f\"items in cache: {cache.size}/{cache.capacity}, memory usage in cache: {cache.memory_size}/{cache.memory_capacity}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "5453dbcc",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from cucim import CuImage\n",
-    "img = CuImage(\"notebooks/input/image.tif\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "059d8ba3",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "['__bool__',\n",
-       " '__class__',\n",
-       " '__delattr__',\n",
-       " '__dict__',\n",
-       " '__dir__',\n",
-       " '__doc__',\n",
-       " '__eq__',\n",
-       " '__format__',\n",
-       " '__ge__',\n",
-       " '__getattribute__',\n",
-       " '__gt__',\n",
-       " '__hash__',\n",
-       " '__init__',\n",
-       " '__init_subclass__',\n",
-       " '__le__',\n",
-       " '__lt__',\n",
-       " '__module__',\n",
-       " '__ne__',\n",
-       " '__new__',\n",
-       " '__reduce__',\n",
-       " '__reduce_ex__',\n",
-       " '__repr__',\n",
-       " '__setattr__',\n",
-       " '__sizeof__',\n",
-       " '__str__',\n",
-       " '__subclasshook__',\n",
-       " '_set_array_interface',\n",
-       " 'associated_image',\n",
-       " 'associated_images',\n",
-       " 'cache',\n",
-       " 'channel_names',\n",
-       " 'coord_sys',\n",
-       " 'device',\n",
-       " 'dims',\n",
-       " 'direction',\n",
-       " 'dtype',\n",
-       " 'is_loaded',\n",
-       " 'metadata',\n",
-       " 'ndim',\n",
-       " 'origin',\n",
-       " 'path',\n",
-       " 'raw_metadata',\n",
-       " 'read_region',\n",
-       " 'resolutions',\n",
-       " 'save',\n",
-       " 'shape',\n",
-       " 'size',\n",
-       " 'spacing',\n",
-       " 'spacing_units']"
-      ]
-     },
-     "execution_count": 3,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "dir(img._C)\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "895db3d2",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from cucim import CuImage\n",
-    "\n",
-    "img = CuImage(\"notebooks/input/image.tif\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "1800de44",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "430 ns ± 4.64 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "\n",
-    "img.is_loaded"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "3a85c7ff",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "177 ns ± 1.51 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "img._C.is_loaded"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "id": "a3872e46",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Processing ./dist/cucim-0.19.1.dev2-py3-none-manylinux2014_x86_64.whl\n",
-      "Collecting numpy\n",
-      "  Using cached numpy-1.20.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (15.4 MB)\n",
-      "Collecting click\n",
-      "  Using cached click-8.0.1-py3-none-any.whl (97 kB)\n",
-      "Installing collected packages: numpy, click, cucim\n",
-      "  Attempting uninstall: numpy\n",
-      "    Found existing installation: numpy 1.20.3\n",
-      "    Uninstalling numpy-1.20.3:\n",
-      "      Successfully uninstalled numpy-1.20.3\n",
-      "  Attempting uninstall: click\n",
-      "    Found existing installation: click 8.0.1\n",
-      "    Uninstalling click-8.0.1:\n",
-      "      Successfully uninstalled click-8.0.1\n",
-      "  Attempting uninstall: cucim\n",
-      "    Found existing installation: cucim 0.19.1.dev2\n",
-      "    Uninstalling cucim-0.19.1.dev2:\n",
-      "      Successfully uninstalled cucim-0.19.1.dev2\n",
-      "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
-      "rasterio 1.2.3 requires click<8,>=4.0, but you have click 8.0.1 which is incompatible.\n",
-      "cligj 0.7.1 requires click<8,>=4.0, but you have click 8.0.1 which is incompatible.\u001b[0m\n",
-      "Successfully installed click-8.0.1 cucim-0.19.1.dev2 numpy-1.20.3\n",
-      "\u001b[33mWARNING: You are using pip version 21.0.1; however, version 21.1.2 is available.\n",
-      "You should consider upgrading via the '/home/gbae/.virtualenvs/cucim/bin/python -m pip install --upgrade pip' command.\u001b[0m\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "['__bool__',\n",
-       " '__class__',\n",
-       " '__delattr__',\n",
-       " '__dict__',\n",
-       " '__dir__',\n",
-       " '__doc__',\n",
-       " '__eq__',\n",
-       " '__format__',\n",
-       " '__ge__',\n",
-       " '__getattribute__',\n",
-       " '__gt__',\n",
-       " '__hash__',\n",
-       " '__init__',\n",
-       " '__init_subclass__',\n",
-       " '__le__',\n",
-       " '__lt__',\n",
-       " '__module__',\n",
-       " '__ne__',\n",
-       " '__new__',\n",
-       " '__reduce__',\n",
-       " '__reduce_ex__',\n",
-       " '__repr__',\n",
-       " '__setattr__',\n",
-       " '__sizeof__',\n",
-       " '__str__',\n",
-       " '__subclasshook__',\n",
-       " '_set_array_interface',\n",
-       " 'associated_image',\n",
-       " 'associated_images',\n",
-       " 'cache',\n",
-       " 'channel_names',\n",
-       " 'coord_sys',\n",
-       " 'device',\n",
-       " 'dims',\n",
-       " 'direction',\n",
-       " 'dtype',\n",
-       " 'is_loaded',\n",
-       " 'metadata',\n",
-       " 'ndim',\n",
-       " 'origin',\n",
-       " 'path',\n",
-       " 'raw_metadata',\n",
-       " 'read_region',\n",
-       " 'resolutions',\n",
-       " 'save',\n",
-       " 'shape',\n",
-       " 'size',\n",
-       " 'spacing',\n",
-       " 'spacing_units']"
-      ]
-     },
-     "execution_count": 14,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "!pip install --force-reinstall dist/*.whl\n",
-    "\n",
-    "dir(img)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "5ec0b0d6",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "161 ns ± 0.967 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
-     ]
-    }
-   ],
-   "source": [
-    "%%timeit\n",
-    "\n",
-    "img.is_loaded"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "fcc68767",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Help on method read_region in module cucim.clara._cucim:\n",
-      "\n",
-      "read_region(...) method of cucim.clara.CuImage instance\n",
-      "    read_region(self: cucim.clara._cucim.CuImage, location: List[int] = [], size: List[int] = [], level: int = 0, device: cucim.clara._cucim.io.Device = cpu, buf: object = None, shm_name: str = '', **kwargs) -> object\n",
-      "    \n",
-      "    Returns a subresolution image.\n",
-      "    \n",
-      "    - `location` and `size`'s dimension order is reverse of image's dimension order.\n",
-      "    - Need to specify (X,Y) and (Width, Height) instead of (Y,X) and (Height, Width).\n",
-      "    - If location is not specified, location would be (0, 0) if Z=0. Otherwise, location would be (0, 0, 0)\n",
-      "    - Like OpenSlide, location is level-0 based coordinates (using the level-0 reference frame)\n",
-      "    - If `size` is not specified, size would be (width, height) of the image at the specified `level`.\n",
-      "    - `<not supported yet>` Additional parameters (S,T,C,Z) are similar to\n",
-      "    <https://allencellmodeling.github.io/aicsimageio/aicsimageio.html#aicsimageio.aics_image.AICSImage.get_image_data>\n",
-      "      - We may not want to support indices/ranges for (S,T,C,Z) for the first release.\n",
-      "      - Default value for level, S, T, Z are zero.\n",
-      "      - Default value for C is -1 (whole channels)\n",
-      "    - `<not supported yet>` `device` could be one of the following strings or Device object: e.g., `'cpu'`, `'cuda'`, `'cuda:0'` (use index 0), `cucim.clara.io.Device(cucim.clara.io.CUDA,0)`.\n",
-      "    - `<not supported yet>` If `buf` is specified (buf's type can be either numpy object that implements `__array_interface__`, or cupy-compatible object that implements `__cuda_array_interface__`), the read image would be saved into buf object without creating CPU/GPU memory.\n",
-      "    - `<not supported yet>` If `shm_name` is specified, shared memory would be created and data would be read in the shared memory.\n",
-      "\n"
-     ]
-    }
-   ],
-   "source": [
-    "help(img.read_region)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "3397aa75",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "from cucim import CuImage\n",
-    "img = CuImage(\"notebooks/input/image.tif\")\n",
-    "region = img.read_region((1000,1000), (100, 100))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "e9595d38",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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\n",
-      "text/plain": [
-       "<PIL.Image.Image image mode=RGB size=100x100 at 0x7FCE2DE3D0D0>"
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "from PIL import Image\n",
-    "import numpy as np\n",
-    "Image.fromarray(np.asarray(region))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "de9a4771",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import cupy as cp\n",
-    "\n",
-    "region_cupy = img.read_region((1000,1000), (100, 100), device='cuda')\n",
-    "vis = cp.asarray(region_cupy)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "id": "5a932ac8",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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\n",
-      "text/plain": [
-       "<PIL.Image.Image image mode=RGB size=100x100 at 0x7FCE68041C10>"
-      ]
-     },
-     "execution_count": 15,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "Image.fromarray(vis.get())"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "id": "4098b771",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "del vis"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "id": "aac6a6fe",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'data': (46733280, False),\n",
-       " 'strides': None,\n",
-       " 'descr': [('', '|u1')],\n",
-       " 'typestr': '|u1',\n",
-       " 'shape': (10, 10, 3),\n",
-       " 'version': 3}"
-      ]
-     },
-     "execution_count": 12,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "b.__array_interface__"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "id": "a836258a",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Requirement already satisfied: cupy-cuda112 in /home/gbae/.virtualenvs/cucim/lib/python3.8/site-packages (9.0.0)\n",
-      "Requirement already satisfied: numpy>=1.17 in /home/gbae/.virtualenvs/cucim/lib/python3.8/site-packages (from cupy-cuda112) (1.20.3)\n",
-      "Requirement already satisfied: fastrlock>=0.5 in /home/gbae/.virtualenvs/cucim/lib/python3.8/site-packages (from cupy-cuda112) (0.6)\n",
-      "\u001b[33mWARNING: You are using pip version 21.0.1; however, version 21.1.2 is available.\n",
-      "You should consider upgrading via the '/home/gbae/.virtualenvs/cucim/bin/python -m pip install --upgrade pip' command.\u001b[0m\n"
-     ]
-    }
-   ],
-   "source": [
-    "!pip install cupy-cuda112"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.5"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/Dockerfile-cuda110 b/Dockerfile-cuda110
deleted file mode 100644
index 725ddf2b6..000000000
--- a/Dockerfile-cuda110
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-FROM dockcross/manylinux2014-x64:20230215-2dd9a1c
-
-ENV DEFAULT_DOCKCROSS_IMAGE gigony/manylinux2014-x64:cuda110
-ENV PATH=/usr/local/cuda/bin/:$PATH
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64/:/usr/local/cuda/nvvm/lib64:${LD_LIBRARY_PATH}
-
-RUN curl -LO https://developer.download.nvidia.com/compute/cuda/11.0.3/local_installers/cuda_11.0.3_450.51.06_linux.run && \
-    chmod +x cuda_*.run && \
-    ./cuda_*.run --silent --no-opengl-libs --toolkit --override && \
-    rm -f cuda_*.run;
-
-RUN curl -LO https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/libnvjpeg2k0-0.0.1.17-1.x86_64.rpm && \
-    curl -LO https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/libnvjpeg2k-devel-0.0.1.17-1.x86_64.rpm && \
-    rpm -i libnvjpeg2k*.rpm
-
-# TODO: Currently we don't install dependencies from libtiff here.
-RUN yum install -y openslide-python openslide-devel python-devel python3-devel
-
-# Copy stub libcuda file
-RUN cp /usr/local/cuda-11.0/targets/x86_64-linux/lib/stubs/libcuda.so /usr/lib64/libcuda.so.1
-
-RUN cp -P /usr/include/nvjpeg2k* /usr/local/cuda/include/ && \
-    cp -P /usr/lib64/libnvjpeg2k* /usr/local/cuda/lib64/
diff --git a/Dockerfile-cuda111 b/Dockerfile-cuda111
deleted file mode 100644
index 428c154d6..000000000
--- a/Dockerfile-cuda111
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-FROM dockcross/manylinux2014-x64:20230215-2dd9a1c
-
-ENV DEFAULT_DOCKCROSS_IMAGE gigony/manylinux2014-x64:cuda111
-ENV PATH=/usr/local/cuda/bin/:$PATH
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64/:/usr/local/cuda/nvvm/lib64:${LD_LIBRARY_PATH}
-
-RUN curl -LO https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run && \
-    chmod +x cuda_*.run && \
-    ./cuda_*.run --silent --no-opengl-libs --toolkit --override && \
-    rm -f cuda_*.run;
-
-RUN curl -LO https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/libnvjpeg2k0-0.0.1.17-1.x86_64.rpm && \
-    curl -LO https://developer.download.nvidia.com/compute/cuda/repos/rhel7/x86_64/libnvjpeg2k-devel-0.0.1.17-1.x86_64.rpm && \
-    rpm -i libnvjpeg2k*.rpm
-
-# TODO: Currently we don't install dependencies from libtiff here.
-RUN yum install -y openslide-python openslide-devel python-devel python3-devel
-
-# Copy stub libcuda file
-RUN cp /usr/local/cuda-11.1/targets/x86_64-linux/lib/stubs/libcuda.so /usr/lib64/libcuda.so.1
-
-RUN cp -P /usr/include/nvjpeg2k* /usr/local/cuda/include/ && \
-    cp -P /usr/lib64/libnvjpeg2k* /usr/local/cuda/lib64/
diff --git a/LICENSE-3rdparty.md b/LICENSE-3rdparty.md
index 4c2a045b1..984d0e952 100644
--- a/LICENSE-3rdparty.md
+++ b/LICENSE-3rdparty.md
@@ -287,9 +287,3 @@ PBA+
   - https://github.com/orzzzjq/Parallel-Banding-Algorithm-plus/blob/master/LICENSE
 - Copyright: School of Computing, National University of Singapore
 - Usage: PBA+ is used to implement the Euclidean distance transform.
-
-dockcross
-- License: MIT License
-  - https://github.com/dockcross/dockcross/blob/master/LICENSE
-- Copyright: Steeve Morin, Rob Burns, Matthew McCormick, Jean-Christophe-Fillion-Robin, Bensuperpc
-- Usage: Building Python wheels for Linux
diff --git a/README.md b/README.md
index 0fcb1bcee..1e2fa988b 100644
--- a/README.md
+++ b/README.md
@@ -49,28 +49,37 @@ cuCIM supports the following formats:
 
 #### [Conda (stable)](https://anaconda.org/rapidsai/cucim)
 
-> conda create -n cucim -c rapidsai -c conda-forge cucim cudatoolkit=`<CUDA version>`
+```bash
+conda create -n cucim -c rapidsai -c conda-forge cucim cuda-version=`<CUDA version>`
+```
 
-`<CUDA version>` should be 11.0+ (e.g., `11.0`, `11.2`, etc.)
+`<CUDA version>` should be 11.2+ (e.g., `11.2`, `12.0`, etc.)
 
 #### [Conda (nightlies)](https://anaconda.org/rapidsai-nightly/cucim)
 
-> conda create -n cucim -c rapidsai-nightly -c conda-forge cucim cudatoolkit=`<CUDA version>`
+```bash
+conda create -n cucim -c rapidsai-nightly -c conda-forge cucim cuda-version=`<CUDA version>`
+```
 
-`<CUDA version>` should be 11.0+ (e.g., `11.0`, `11.2`, etc)
+`<CUDA version>` should be 11.2+ (e.g., `11.2`, `12.0`, etc.)
 
 ### [PyPI](https://pypi.org/project/cucim/)
 
+Install for CUDA 12:
+
 ```bash
-pip install cucim
+pip install cucim-cu12
+```
 
-# Install dependencies for `cucim.skimage` (assuming that CUDA 11.0 is used for CuPy)
-pip install scipy scikit-image cupy-cuda110
+Alternatively install for CUDA 11:
+
+```bash
+pip install cucim-cu11
 ```
 
 ### Notebooks
 
-Please check out our [Welcome](notebooks/Welcome.ipynb) notebook ([NBViewer](https://nbviewer.jupyter.org/github/rapidsai/cucim/blob/branch-23.12/notebooks/Welcome.ipynb))
+Please check out our [Welcome](notebooks/Welcome.ipynb) notebook ([NBViewer](https://nbviewer.jupyter.org/github/rapidsai/cucim/blob/branch-24.02/notebooks/Welcome.ipynb))
 
 #### Downloading sample images
 
diff --git a/VERSION b/VERSION
index bb94af9dd..3c6c5e2b7 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-23.12.00a56
+24.02.00
diff --git a/build.sh b/build.sh
deleted file mode 100755
index 2f96597d6..000000000
--- a/build.sh
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-if [ "$0" != "/bin/bash" ]; then
-    SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
-fi
-
-################################################################################
-# Utility functions
-################################################################################
-
-c_str() {
-    local old_color=39
-    local old_attr=0
-    local color=39
-    local attr=0
-    local text=""
-    local no_change=0
-    for i in "$@"; do
-        case "$i" in
-            r|R)
-                color=31
-                ;;
-            g|G)
-                color=32
-                ;;
-            y|Y)
-                color=33
-                ;;
-            b|B)
-                color=34
-                ;;
-            p|P)
-                color=35
-                ;;
-            c|C)
-                color=36
-                ;;
-            w|W)
-                color=37
-                ;;
-
-            z|Z)
-                color=0
-                ;;
-        esac
-        case "$i" in
-            l|L|R|G|Y|B|P|C|W)
-                attr=1
-                ;;
-            n|N|r|g|y|b|p|c|w)
-                attr=0
-                ;;
-            z|Z)
-                attr=0
-                ;;
-            *)
-                text="${text}$i"
-        esac
-        if [ ${old_color} -ne ${color} ] || [ ${old_attr} -ne ${attr} ]; then
-            text="${text}\033[${attr};${color}m"
-            old_color=$color
-            old_attr=$attr
-        fi
-    done
-    /bin/echo -en "$text"
-}
-
-c_echo() {
-    local old_opt="$(shopt -op xtrace)" # save old xtrace option
-    set +x # unset xtrace
-    local text="$(c_str "$@")"
-    /bin/echo -e "$text\033[0m"
-    eval "${old_opt}" # restore old xtrace option
-}
-
-
-echo_err() {
-    >&2 echo "$@"
-}
-
-c_echo_err() {
-    >&2 c_echo "$@"
-}
-
-printf_err() {
-    >&2 printf "$@"
-}
-
-get_item_ranges() {
-  local indexes="$1"
-  local list="$2"
-  echo -n "$(echo "${list}" | xargs | cut -d " " -f "${indexes}")"
-  return $?
-}
-
-get_unused_ports() {
-    local num_of_ports=${1:-1}
-    comm -23 \
-    <(seq 49152 61000 | sort) \
-    <(ss -tan | awk '{print $4}' | while read line; do echo ${line##*\:}; done | grep '[0-9]\{1,5\}' | sort -u) \
-    | shuf | tail -n ${num_of_ports} # use tail instead head to avoid broken pipe in VSCode terminal
-}
-
-newline() {
-    echo
-}
-
-info() {
-    c_echo W "$(date -u '+%Y-%m-%d %H:%M:%S') [INFO] " Z "$@"
-}
-
-error() {
-    echo R "$(date -u '+%Y-%m-%d %H:%M:%S') [ERROR] " Z "$@"
-}
-
-fatal() {
-    echo R "$(date -u '+%Y-%m-%d %H:%M:%S') [FATAL] " Z "$@"
-    echo
-    if [ -n "${SCRIPT_DIR}" ]; then
-        exit 1
-    fi
-}
-
-run_command() {
-  local status=0
-  local cmd="$@"
-
-  c_echo B "$(date -u '+%Y-%m-%d %H:%M:%S') \$ " G "${cmd}"
-
-  [ "$(echo -n "$@")" = "" ] && return 1  # return 1 if there is no command available
-
-  eval "$@"
-  status=$?
-
-  if [ -n "${cmd_result}" ]; then
-    echo "${cmd_result}"
-  fi
-  unset IFS
-
-  return $status
-}
-
-retry() {
-  local retries=$1
-  shift
-
-  local count=0
-  until run_command "$@"; do
-    exit=$?
-    wait=$((2 ** $count))
-    count=$(($count + 1))
-    if [ $count -lt $retries ]; then
-      info "Retry $count/$retries. Exit code=$exit, Retrying in $wait seconds..."
-      sleep $wait
-    else
-      fatal "Retry $count/$retries. Exit code=$exit, no more retries left."
-      return 1
-    fi
-  done
-  return 0
-}
-
-parse_args() {
-    local OPTIND
-    while getopts 'yh' option;
-    do
-        case "${option}" in
-            # a)
-            #     VALUE=${OPTARG}
-            #     ;;
-            y)
-                ALWAYS_YES=true;
-                ;;
-            h)
-                print_usage
-                exit 1
-                ;;
-        esac
-    done
-    shift $((OPTIND-1))
-
-    CMD="$1"
-    shift
-
-    ARGS=("$@")
-}
-
-print_usage() {
-    set +x
-    echo_err
-    echo_err "USAGE: $0 [command] [arguments]..."
-    echo_err ""
-    echo_err "Global Arguments"
-    echo_err
-    echo_err "Command List"
-
-    echo_err
-    echo_err "Examples"
-}
-
-init_script() {
-    TOP=$(git rev-parse --show-toplevel || pwd)
-}
-
-main() {
-    parse_args "$@"
-    local file_type
-    case "$CMD" in
-        list|ls)
-            # list_testdata "${ARGS[@]}"
-            ;;
-        ''|main)
-            print_usage
-            ;;
-        *)
-            if type ${CMD} > /dev/null 2>&1; then
-                init_script
-                run_command "$CMD" "${ARGS[@]}"
-            else
-                print_usage
-                exit 1
-            fi
-            ;;
-    esac
-}
-
-if [ -n "${SCRIPT_DIR}" ]; then
-    main "$@"
-fi
-
-# CLARA_VERSION=0.7.1-2008.4 ./serverctl get_latest_version_of recipes clara_bootstrap 2> /dev/null
diff --git a/build_docker.sh b/build_docker.sh
deleted file mode 100755
index f7845c594..000000000
--- a/build_docker.sh
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-set -eu
-
-CMAKE_CMD=cmake
-CMAKE_BUILD_TYPE=Release
-NUM_THREADS=$(nproc)
-
-SRC_ROOT=/work
-BUILD_ROOT=/work/temp
-
-CUCIM_SDK_PATH=${BUILD_ROOT}/libcucim
-
-# Build libcucim
-${CMAKE_CMD} -S ${SRC_ROOT} -B ${BUILD_ROOT}/libcucim \
-    -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \
-    -DCMAKE_INSTALL_PREFIX=${CUCIM_SDK_PATH}
-${CMAKE_CMD} --build ${BUILD_ROOT}/libcucim --target cucim -- -j ${NUM_THREADS}
-${CMAKE_CMD} --build ${BUILD_ROOT}/libcucim --target install -- -j ${NUM_THREADS}
-
-# Build cuslide plugin
-${CMAKE_CMD} -S ${SRC_ROOT}/cpp/plugins/cucim.kit.cuslide -B ${BUILD_ROOT}/cuslide \
-    -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \
-    -DCMAKE_INSTALL_PREFIX=${BUILD_ROOT}/cuslide/install \
-    -DCUCIM_SDK_PATH=${CUCIM_SDK_PATH}
-${CMAKE_CMD} --build ${BUILD_ROOT}/cuslide --target cucim.kit.cuslide -- -j ${NUM_THREADS}
-${CMAKE_CMD} --build ${BUILD_ROOT}/cuslide --target install -- -j ${NUM_THREADS}
-
-# Build Python bind
-
-for PYBIN in /opt/python/*/bin; do
-    ${CMAKE_CMD} -S ${SRC_ROOT}/python -B ${BUILD_ROOT}/cucim \
-        -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \
-        -DCMAKE_INSTALL_PREFIX=${BUILD_ROOT}/cucim/install \
-        -DCUCIM_SDK_PATH=${CUCIM_SDK_PATH} \
-        -DPYTHON_EXECUTABLE=${PYBIN}/python
-    ${CMAKE_CMD} --build ${BUILD_ROOT}/cucim --target cucim -- -j ${NUM_THREADS}
-    ${CMAKE_CMD} --build ${BUILD_ROOT}/cucim --target install -- -j ${NUM_THREADS}
-done
-
-# Copy .so files to pybind's build folder
-# (it uses -P to copy symbolic links as they are)
-cp -P ${BUILD_ROOT}/libcucim/install/lib/lib* ${BUILD_ROOT}/cucim/lib/cucim/
-cp -P ${BUILD_ROOT}/cuslide/install/lib/cucim* ${BUILD_ROOT}/cucim/lib/cucim/
-
-# Copy .so files from pybind's build folder to cucim Python source folder
-cp -P ${BUILD_ROOT}/cucim/lib/cucim/* ${SRC_ROOT}/python/cucim/src/cucim/clara/
-
-
-
-
-set -e -u -x
-
-function repair_wheel {
-    wheel="$1"
-    if ! auditwheel show "$wheel"; then
-        echo "Skipping non-platform wheel $wheel"
-    else
-        auditwheel repair --plat "$PLAT" -w wheelhouse/ "$wheel"
-    fi
-}
-
-PLAT=manylinux2014_x86_64
-
-cd /work/python/cucim
-# Compile wheels (one python binary is enough)
-for PYBIN in /opt/python/cp36-cp36m/bin; do # /opt/python/*/bin
-    "${PYBIN}/python" setup.py bdist_wheel -p $PLAT
-done
-
-mkdir -p /work/python/cucim/wheelhouse
-
-# Bundle external shared libraries into the wheels
-for whl in dist/*.whl; do
-    repair_wheel "$whl"
-done
-
-# # Install packages and test
-# for PYBIN in /opt/python/*/bin/; do
-#     "${PYBIN}/pip" install python-manylinux-demo --no-index -f /io/wheelhouse
-#     (cd "$HOME"; "${PYBIN}/nosetests" pymanylinuxdemo)
-# done
-
-# python setup.py bdist_wheel -p manylinux2014-x86_64
diff --git a/ci/build_cpp.sh b/ci/build_cpp.sh
index b0ef4a446..0ecf3d5bb 100755
--- a/ci/build_cpp.sh
+++ b/ci/build_cpp.sh
@@ -3,7 +3,11 @@
 
 set -euo pipefail
 
-source rapids-env-update
+rapids-configure-conda-channels
+
+source rapids-configure-sccache
+
+source rapids-date-string
 
 export CMAKE_GENERATOR=Ninja
 
diff --git a/ci/build_docs.sh b/ci/build_docs.sh
index ee296fd5c..0df71c729 100755
--- a/ci/build_docs.sh
+++ b/ci/build_docs.sh
@@ -24,7 +24,7 @@ rapids-mamba-retry install \
     --channel "${PYTHON_CHANNEL}" \
     cucim libcucim
 
-export RAPIDS_VERSION_NUMBER="23.12"
+export RAPIDS_VERSION_NUMBER="24.02"
 export RAPIDS_DOCS_DIR="$(mktemp -d)"
 
 rapids-logger "Build Python docs"
diff --git a/ci/build_python.sh b/ci/build_python.sh
index 58d8a8e00..35d3ed08c 100755
--- a/ci/build_python.sh
+++ b/ci/build_python.sh
@@ -3,7 +3,11 @@
 
 set -euo pipefail
 
-source rapids-env-update
+rapids-configure-conda-channels
+
+source rapids-configure-sccache
+
+source rapids-date-string
 
 export CMAKE_GENERATOR=Ninja
 
diff --git a/ci/build_wheel.sh b/ci/build_wheel.sh
index a39ebf502..8d3fcf941 100755
--- a/ci/build_wheel.sh
+++ b/ci/build_wheel.sh
@@ -47,5 +47,6 @@ python -m pip wheel . -w dist -vvv --no-deps --disable-pip-version-check
 
 mkdir -p final_dist
 python -m auditwheel repair -w final_dist dist/*
+ls -1 final_dist | grep -vqz 'none'
 
 RAPIDS_PY_WHEEL_NAME="${package_name}_${RAPIDS_PY_CUDA_SUFFIX}" rapids-upload-wheels-to-s3 final_dist
diff --git a/ci/release/update-version.sh b/ci/release/update-version.sh
index e4ca4a8dd..d16562bf7 100755
--- a/ci/release/update-version.sh
+++ b/ci/release/update-version.sh
@@ -31,8 +31,8 @@ function sed_runner() {
 }
 
 # RTD update
-sed_runner 's/version = .*/version = '"'${NEXT_SHORT_TAG}'"'/g' docs/source/conf.py
-sed_runner 's/release = .*/release = '"'${NEXT_FULL_TAG}'"'/g' docs/source/conf.py
+sed_runner 's/version = .*/version = "'"${NEXT_SHORT_TAG}"'"/g' docs/source/conf.py
+sed_runner 's/release = .*/release = "'"${NEXT_FULL_TAG}"'"/g' docs/source/conf.py
 
 # Centralized version file update
 echo "${NEXT_FULL_TAG}" > VERSION
@@ -42,10 +42,10 @@ sed_runner "s/v${CURRENT_LONG_TAG}/v${NEXT_FULL_TAG}/g" python/cucim/docs/gettin
 sed_runner "s#cucim.kit.cuslide@${CURRENT_LONG_TAG}.so#cucim.kit.cuslide@${NEXT_FULL_TAG}.so#g" python/cucim/docs/getting_started/index.md
 sed_runner "s#cucim.kit.cuslide@${CURRENT_LONG_TAG}.so#cucim.kit.cuslide@${NEXT_FULL_TAG}.so#g" cucim.code-workspace
 sed_runner "s#branch-${CURRENT_MAJOR}.${CURRENT_MINOR}#branch-${NEXT_MAJOR}.${NEXT_MINOR}#g" README.md
-sed_runner "s#branch-${CURRENT_MAJOR}.${CURRENT_MINOR}#branch-${NEXT_MAJOR}.${NEXT_MINOR}#g" python/cucim/README.md
 sed_runner "s#branch-${CURRENT_MAJOR}.${CURRENT_MINOR}#branch-${NEXT_MAJOR}.${NEXT_MINOR}#g" python/cucim/pyproject.toml
 
 for FILE in .github/workflows/*.yaml; do
   sed_runner "/shared-workflows/ s/@.*/@branch-${NEXT_SHORT_TAG}/g" "${FILE}"
 done
 sed_runner "s/RAPIDS_VERSION_NUMBER=\".*/RAPIDS_VERSION_NUMBER=\"${NEXT_SHORT_TAG}\"/g" ci/build_docs.sh
+sed_runner "s/RAPIDS_VERSION_NUMBER=\".*/RAPIDS_VERSION_NUMBER=\"${NEXT_SHORT_TAG}\"/g" ci/test_python.sh
diff --git a/conda/environments/all_cuda-118_arch-x86_64.yaml b/conda/environments/all_cuda-118_arch-x86_64.yaml
index c038513af..31c5e6077 100644
--- a/conda/environments/all_cuda-118_arch-x86_64.yaml
+++ b/conda/environments/all_cuda-118_arch-x86_64.yaml
@@ -28,9 +28,9 @@ dependencies:
 - nbsphinx
 - ninja
 - numpy>=1.21.3
-- numpydoc
+- numpydoc>=1.5
 - nvcc_linux-64=11.8
-- openslide-python>=1.1.2
+- openslide-python>=1.3.0
 - pip
 - pooch>=1.6.0
 - pre-commit
@@ -39,10 +39,11 @@ dependencies:
 - pytest-cov>=2.12.1
 - pytest-lazy-fixture>=0.6.3
 - pytest-xdist
-- pytest>=6.2.4
+- pytest>=6.2.4,<8.0.0a0
 - python>=3.8,<3.11
+- pywavelets>=1.0
 - recommonmark
-- scikit-image>=0.19.0,<0.22.0a0
+- scikit-image>=0.19.0,<0.23.0a0
 - scipy
 - sphinx<6
 - sysroot_linux-64==2.17
diff --git a/conda/environments/all_cuda-120_arch-x86_64.yaml b/conda/environments/all_cuda-120_arch-x86_64.yaml
index 18f61bf9f..0f25face9 100644
--- a/conda/environments/all_cuda-120_arch-x86_64.yaml
+++ b/conda/environments/all_cuda-120_arch-x86_64.yaml
@@ -28,8 +28,8 @@ dependencies:
 - nbsphinx
 - ninja
 - numpy>=1.21.3
-- numpydoc
-- openslide-python>=1.1.2
+- numpydoc>=1.5
+- openslide-python>=1.3.0
 - pip
 - pooch>=1.6.0
 - pre-commit
@@ -38,10 +38,11 @@ dependencies:
 - pytest-cov>=2.12.1
 - pytest-lazy-fixture>=0.6.3
 - pytest-xdist
-- pytest>=6.2.4
+- pytest>=6.2.4,<8.0.0a0
 - python>=3.8,<3.11
+- pywavelets>=1.0
 - recommonmark
-- scikit-image>=0.19.0,<0.22.0a0
+- scikit-image>=0.19.0,<0.23.0a0
 - scipy
 - sphinx<6
 - sysroot_linux-64==2.17
diff --git a/conda/recipes/cucim/meta.yaml b/conda/recipes/cucim/meta.yaml
index dbb34a906..47606ab77 100644
--- a/conda/recipes/cucim/meta.yaml
+++ b/conda/recipes/cucim/meta.yaml
@@ -59,7 +59,7 @@ requirements:
     - libcucim ={{ version }}
     - numpy 1.21
     - python
-    - scikit-image >=0.19.0,<0.22.0a0
+    - scikit-image >=0.19.0,<0.23.0a0
     - scipy
   run:
     - {{ pin_compatible('cuda-version', max_pin='x', min_pin='x') }}
@@ -68,10 +68,11 @@ requirements:
     - cupy >=12.0.0
     - lazy_loader >=0.1
     - libcucim ={{ version }}
-    # - openslide # skipping here but benchmark binary would need openslide library
     - python
-    - scikit-image >=0.19.0,<0.22.0a0
+    - scikit-image >=0.19.0,<0.23.0a0
     - scipy
+  run_constrained:
+    - openslide-python >=1.3.0
 
 tests:
   requirements:
@@ -84,6 +85,8 @@ about:
   summary: cucim Python package
   license: Apache-2.0
   license_family: Apache
-  license_file: LICENSE
+  license_file:
+    - LICENSE
+    - LICENSE-3rdparty.md
   doc_url: https://docs.rapids.ai/api/cucim/stable/
   dev_url: https://github.com/rapidsai/cucim
diff --git a/conda/recipes/libcucim/meta.yaml b/conda/recipes/libcucim/meta.yaml
index 512ae3085..bd591c9e2 100644
--- a/conda/recipes/libcucim/meta.yaml
+++ b/conda/recipes/libcucim/meta.yaml
@@ -18,6 +18,7 @@ build:
   string: cuda{{ cuda_major }}_{{ date_string }}_{{ GIT_DESCRIBE_HASH }}_{{ GIT_DESCRIBE_NUMBER }}
   ignore_run_exports:
     - libwebp-base
+    - openslide
   ignore_run_exports_from:
     {% if cuda_major == "11" %}
     - {{ compiler('cuda11') }}
@@ -70,7 +71,7 @@ requirements:
     - jbig
     - libwebp-base
     - nvtx-c >=3.1.0
-    - openslide <4
+    - openslide
     - xz
     - zlib
     - zstd
@@ -82,16 +83,19 @@ requirements:
     {% endif %}
     - {{ pin_compatible('libwebp-base', max_pin='x.x') }}
     - jbig
-    # - openslide # skipping here but benchmark binary would need openslide library
     - xz
     - zlib
     - zstd
+  run_constrained:
+    - {{ pin_compatible('openslide') }}
 
 about:
   home: https://developer.nvidia.com/multidimensional-image-processing
   summary: libcucim C++ library
   license: Apache-2.0
   license_family: Apache
-  license_file: LICENSE
+  license_file:
+    - LICENSE
+    - LICENSE-3rdparty.md
   doc_url: https://docs.rapids.ai/api/cucim/stable/
   dev_url: https://github.com/rapidsai/cucim
diff --git a/cpp/plugins/cucim.kit.cuslide/cmake/deps/libopenjpeg.cmake b/cpp/plugins/cucim.kit.cuslide/cmake/deps/libopenjpeg.cmake
index 428b04f0f..b080554f9 100644
--- a/cpp/plugins/cucim.kit.cuslide/cmake/deps/libopenjpeg.cmake
+++ b/cpp/plugins/cucim.kit.cuslide/cmake/deps/libopenjpeg.cmake
@@ -18,7 +18,7 @@ if (NOT TARGET deps::libopenjpeg)
     FetchContent_Declare(
             deps-libopenjpeg
             GIT_REPOSITORY https://github.com/uclouvain/openjpeg.git
-            GIT_TAG v2.4.0
+            GIT_TAG v2.5.0
             GIT_SHALLOW TRUE
     )
     FetchContent_GetProperties(deps-libopenjpeg)
diff --git a/cucim.code-workspace b/cucim.code-workspace
index c8be5d588..000fd7483 100644
--- a/cucim.code-workspace
+++ b/cucim.code-workspace
@@ -33,7 +33,7 @@
 					"CUCIM_TESTDATA_FOLDER": "${workspaceDirectory}/test_data",
 					// Add cuslide plugin's library path to LD_LIBRARY_PATH
 					"LD_LIBRARY_PATH": "${workspaceDirectory}/build-debug/lib:${workspaceDirectory}/cpp/plugins/cucim.kit.cuslide/build-debug/lib:${workspaceDirectory}/temp/cuda/lib64:${os_env:LD_LIBRARY_PATH}",
-					"CUCIM_TEST_PLUGIN_PATH": "cucim.kit.cuslide@23.12.00.so"
+					"CUCIM_TEST_PLUGIN_PATH": "cucim.kit.cuslide@24.02.00.so"
 				},
 				"cwd": "${workspaceDirectory}",
 				"catch2": {
@@ -226,7 +226,7 @@
 					},
 					{
 						"name": "CUCIM_TEST_PLUGIN_PATH",
-						"value": "cucim.kit.cuslide@23.12.00.so"
+						"value": "cucim.kit.cuslide@24.02.00.so"
 					}
 				],
 				"console": "externalTerminal",
@@ -254,7 +254,7 @@
 					},
 					{
 						"name": "CUCIM_TEST_PLUGIN_PATH",
-						"value": "cucim.kit.cuslide@23.12.00.so"
+						"value": "cucim.kit.cuslide@24.02.00.so"
 					}
 				],
 				"console": "externalTerminal",
@@ -286,7 +286,7 @@
 					},
 					{
 						"name": "CUCIM_TEST_PLUGIN_PATH",
-						"value": "cucim.kit.cuslide@23.12.00.so"
+						"value": "cucim.kit.cuslide@24.02.00.so"
 					}
 				],
 				"console": "externalTerminal",
diff --git a/dependencies.yaml b/dependencies.yaml
index b7ceeef02..33f7c6a67 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -7,7 +7,8 @@ files:
       arch: [x86_64]
     includes:
       - build
-      - cudatoolkit
+      - cuda
+      - cuda_version
       - checks
       - docs
       - py_version
@@ -16,7 +17,7 @@ files:
   test_python:
     output: none
     includes:
-      - cudatoolkit
+      - cuda_version
       - py_version
       - test_python
   checks:
@@ -27,7 +28,7 @@ files:
   docs:
     output: none
     includes:
-      - cudatoolkit
+      - cuda_version
       - docs
       - py_version
   py_build:
@@ -140,7 +141,7 @@ dependencies:
       - output_types: [conda, requirements]
         packages:
           - pre-commit
-  cudatoolkit:
+  cuda_version:
     specific:
       - output_types: conda
         matrices:
@@ -148,26 +149,33 @@ dependencies:
               cuda: "11.2"
             packages:
               - cuda-version=11.2
-              - cudatoolkit
           - matrix:
               cuda: "11.4"
             packages:
               - cuda-version=11.4
-              - cudatoolkit
           - matrix:
               cuda: "11.5"
             packages:
               - cuda-version=11.5
-              - cudatoolkit
           - matrix:
               cuda: "11.8"
             packages:
               - cuda-version=11.8
-              - cudatoolkit
           - matrix:
               cuda: "12.0"
             packages:
               - cuda-version=12.0
+  cuda:
+    specific:
+      - output_types: conda
+        matrices:
+          - matrix:
+              cuda: "11.*"
+            packages:
+              - cudatoolkit
+          - matrix:
+              cuda: "12.*"
+            packages:
               - cuda-cudart-dev
               - libnvjpeg-dev
               - libcufile-dev
@@ -185,7 +193,7 @@ dependencies:
         packages:
           - ipython
           - nbsphinx
-          - numpydoc
+          - numpydoc>=1.5
           - pydata-sphinx-theme
           - recommonmark
           # TODO: sphinx upper version limit can likely be removed after pydata 0.13
@@ -215,7 +223,7 @@ dependencies:
       - output_types: [conda, requirements, pyproject]
         packages:
           - lazy_loader>=0.1
-          - scikit-image>=0.19.0,<0.22.0a0
+          - scikit-image>=0.19.0,<0.23.0a0
           - scipy
       - output_types: conda
         packages:
@@ -246,26 +254,30 @@ dependencies:
         packages:
           - GPUtil>=1.4.0
           - psutil>=5.8.0
+          - pytest>=6.2.4,<8.0.0a0
           - pytest-cov>=2.12.1
           - pytest-lazy-fixture>=0.6.3
           - pytest-xdist
-          - pytest>=6.2.4
           - tifffile>=2022.7.28
           - pooch>=1.6.0  # needed to download scikit-image sample data
+          - pywavelets>=1.0
       - output_types: [conda]
         packages:
           - imagecodecs>=2021.6.8
           - matplotlib-base
-          - openslide-python>=1.1.2
+          - openslide-python>=1.3.0
           - pip
           - pip:
             - opencv-python-headless>=4.6
       - output_types: [requirements, pyproject]
         packages:
-          # temporarily remove imagecodecs / openslide-python from wheel tests
-          # # skip packages on arm64 that don't provide a wheel
-          # - imagecodecs>=2021.6.8; platform_machine=='x86_64'
-          # - openslide-python>=1.1.2; platform_machine=='x86_64'
+          # skip packages on arm64 that don't provide a wheel
+          - imagecodecs>=2021.6.8; platform_machine=='x86_64'
+          - openslide-python>=1.3.0; platform_machine=='x86_64'
           - matplotlib
           - opencv-python-headless>=4.6
           - click
+      - output_types: [pyproject]
+        packages:
+          # Already added to requirements via docs. This is for tests.
+          - numpydoc>=1.5
diff --git a/dockcross-manylinux2014-x64 b/dockcross-manylinux2014-x64
deleted file mode 100755
index e6edf726e..000000000
--- a/dockcross-manylinux2014-x64
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env bash
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-DEFAULT_DOCKCROSS_IMAGE=gigony/manylinux2014-x64:cuda110
-
-#------------------------------------------------------------------------------
-# Helpers
-#
-err() {
-    echo -e >&2 ERROR: $@\\n
-}
-
-die() {
-    err $@
-    exit 1
-}
-
-has() {
-    # eg. has command update
-    local kind=$1
-    local name=$2
-
-    type -t $kind:$name | grep -q function
-}
-
-#------------------------------------------------------------------------------
-# Command handlers
-#
-command:update-image() {
-    docker pull $FINAL_IMAGE
-}
-
-help:update-image() {
-    echo Pull the latest $FINAL_IMAGE .
-}
-
-command:update-script() {
-    if cmp -s <( docker run --rm $FINAL_IMAGE ) $0; then
-        echo $0 is up to date
-    else
-        echo -n Updating $0 '... '
-        docker run --rm $FINAL_IMAGE > $0 && echo ok
-    fi
-}
-
-help:update-image() {
-    echo Update $0 from $FINAL_IMAGE .
-}
-
-command:update() {
-    command:update-image
-    command:update-script
-}
-
-help:update() {
-    echo Pull the latest $FINAL_IMAGE, and then update $0 from that.
-}
-
-command:help() {
-    if [[ $# != 0 ]]; then
-        if ! has command $1; then
-            err \"$1\" is not an dockcross command
-            command:help
-        elif ! has help $1; then
-            err No help found for \"$1\"
-        else
-            help:$1
-        fi
-    else
-        cat >&2 <<ENDHELP
-Usage: dockcross [options] [--] command [args]
-
-By default, run the given *command* in an dockcross Docker container.
-
-The *options* can be one of:
-
-    --args|-a           Extra args to the *docker run* command
-    --image|-i          Docker cross-compiler image to use
-    --config|-c         Bash script to source before running this script
-
-
-Additionally, there are special update commands:
-
-    update-image
-    update-script
-    update
-
-For update command help use: $0 help <command>
-ENDHELP
-        exit 1
-    fi
-}
-
-#------------------------------------------------------------------------------
-# Option processing
-#
-special_update_command=''
-while [[ $# != 0 ]]; do
-    case $1 in
-
-        --)
-            shift
-            break
-            ;;
-
-        --args|-a)
-            ARG_ARGS="$2"
-            shift 2
-            ;;
-
-        --config|-c)
-            ARG_CONFIG="$2"
-            shift 2
-            ;;
-
-        --image|-i)
-            ARG_IMAGE="$2"
-            shift 2
-            ;;
-        update|update-image|update-script)
-            special_update_command=$1
-            break
-            ;;
-        -*)
-            err Unknown option \"$1\"
-            command:help
-            exit
-            ;;
-
-        *)
-            break
-            ;;
-
-    esac
-done
-
-# The precedence for options is:
-# 1. command-line arguments
-# 2. environment variables
-# 3. defaults
-
-# Source the config file if it exists
-DEFAULT_DOCKCROSS_CONFIG=~/.dockcross
-FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}}
-
-[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG"
-
-# Set the docker image
-FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}}
-
-# Handle special update command
-if [ "$special_update_command" != "" ]; then
-    case $special_update_command in
-
-        update)
-            command:update
-            exit $?
-            ;;
-
-        update-image)
-            command:update-image
-            exit $?
-            ;;
-
-        update-script)
-            command:update-script
-            exit $?
-            ;;
-
-    esac
-fi
-
-# Set the docker run extra args (if any)
-FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}}
-
-# Bash on Ubuntu on Windows
-UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "")
-# MSYS, Git Bash, etc.
-MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "")
-
-if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" ]; then
-    USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )")
-fi
-
-# Change the PWD when working in Docker on Windows
-if [ -n "$UBUNTU_ON_WINDOWS" ]; then
-    WSL_ROOT="/mnt/"
-    CFG_FILE=/etc/wsl.conf
-	if [ -f "$CFG_FILE" ]; then
-		CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
-		eval "$CFG_CONTENT"
-		if [ -n "$root" ]; then
-			WSL_ROOT=$root
-		fi
-	fi
-    HOST_PWD=`pwd -P`
-    HOST_PWD=${HOST_PWD/$WSL_ROOT//}
-elif [ -n "$MSYS" ]; then
-    HOST_PWD=$PWD
-    HOST_PWD=${HOST_PWD/\//}
-    HOST_PWD=${HOST_PWD/\//:\/}
-else
-    HOST_PWD=$PWD
-    [ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD)
-fi
-
-# Mount Additional Volumes
-if [ -z "$SSH_DIR" ]; then
-    SSH_DIR="$HOME/.ssh"
-fi
-
-HOST_VOLUMES=
-if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then
-    HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh"
-fi
-
-#------------------------------------------------------------------------------
-# Now, finally, run the command in a container
-#
-TTY_ARGS=
-tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti
-CONTAINER_NAME=dockcross_$RANDOM
-docker run --runtime nvidia $TTY_ARGS --name $CONTAINER_NAME \
-    -v "$HOST_PWD":/work \
-    $HOST_VOLUMES \
-    "${USER_IDS[@]}" \
-    $FINAL_ARGS \
-    $FINAL_IMAGE "$@"
-run_exit_code=$?
-
-# Attempt to delete container
-rm_output=$(docker rm -f $CONTAINER_NAME 2>&1)
-rm_exit_code=$?
-if [[ $rm_exit_code != 0 ]]; then
-  if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then
-    : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/
-  else
-    echo "$rm_output"
-    exit $rm_exit_code
-  fi
-fi
-
-exit $run_exit_code
-
-################################################################################
-#
-# This image is not intended to be run manually.
-#
-# To create a dockcross helper script for the
-# gigony/manylinux2014-x64:cuda110 image, run:
-#
-# docker run --rm gigony/manylinux2014-x64:cuda110 > gigony-manylinux2014-x64-cuda111
-# chmod +x gigony-manylinux2014-x64-cuda111
-#
-# You may then wish to move the dockcross script to your PATH.
-#
-################################################################################
diff --git a/docker/Dockerfile-claratrain b/docker/Dockerfile-claratrain
deleted file mode 100644
index 4526ebbdd..000000000
--- a/docker/Dockerfile-claratrain
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-FROM nvcr.io/nvidian/dlmed/clara-train-sdk:v3.1-ga-qa-5
-
-RUN apt-get update \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        libopenslide0 \
-    && rm -rf /var/lib/apt/lists/*
-
-COPY ./docker/requirements-claratrain.txt ./
-COPY ./*.whl ./
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install --no-cache-dir -r requirements-claratrain.txt \
-    && python -m pip install cu*.whl
diff --git a/docker/Dockerfile-cmake b/docker/Dockerfile-cmake
deleted file mode 100644
index edf32abca..000000000
--- a/docker/Dockerfile-cmake
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-FROM nvidia/cuda:11.0-devel-ubuntu18.04
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Download and install Python3 PIP.
-RUN apt-get update --yes \
-    && apt-get upgrade --yes \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        software-properties-common \
-        ca-certificates \
-        python3-minimal \
-        python3-pip \
-    && add-apt-repository ppa:ubuntu-toolchain-r/test \
-    && rm -rf /var/lib/apt/lists/*
-
-RUN python3 --version
-
-# Set additional environment values that make usage more pleasant.
-ENV TERM=xterm-256color
-
-# Make /usr/bin/python point to the ${VERSION_PYTHON3} version of python
-RUN VERSION_PYTHON3=$(python3 --version | cut -c8-) && VERSION_PYTHON3=${VERSION_PYTHON3%.*} \
-    && rm -f /usr/bin/python \
-    && rm -f /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1` \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1`
-
-# Make /usr/bin/pip point to the ${VERSION_PIP3} version of python
-RUN rm -f /usr/bin/pip \
-    && ln -s /usr/bin/pip3 /usr/bin/pip
-
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        python3-dev \
-        gcc-9 \
-        g++-9 \
-        libopenslide-dev \
-        wget \
-        git \
-        curl \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-WORKDIR /workspace
-ENV HOME=/workspace
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install cmake
-
-# Setup gcc-9
-RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 10 \
-    && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 20 \
-    && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 10 \
-    && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 20
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64
-
-ENTRYPOINT ["/bin/bash"]
diff --git a/docker/Dockerfile-jupyter b/docker/Dockerfile-jupyter
deleted file mode 100644
index cc6a2403b..000000000
--- a/docker/Dockerfile-jupyter
+++ /dev/null
@@ -1,91 +0,0 @@
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-FROM nvidia/cuda:11.0-devel-ubuntu18.04
-
-ARG NODE_VERSION=v14.13.1
-ARG NODE_DISTRO=linux-x64
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Download and install Python3 PIP.
-RUN apt-get update --yes \
-    && apt-get upgrade --yes \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        ca-certificates \
-        python3-minimal \
-        python3-pip \
-    && rm -rf /var/lib/apt/lists/*
-
-RUN python3 --version
-
-# Set additional environment values that make usage more pleasant.
-ENV TERM=xterm-256color
-
-# Make /usr/bin/python point to the ${VERSION_PYTHON3} version of python
-RUN VERSION_PYTHON3=$(python3 --version | cut -c8-) && VERSION_PYTHON3=${VERSION_PYTHON3%.*} \
-    && rm -f /usr/bin/python \
-    && rm -f /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1` \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1`
-
-# Make /usr/bin/pip point to the ${VERSION_PIP3} version of python
-RUN rm -f /usr/bin/pip \
-    && ln -s /usr/bin/pip3 /usr/bin/pip
-
-# libgl1 is needed for opencv at `cucim convert` CLI command.
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        python3-dev \
-        gcc \
-        g++ \
-        libopenslide-dev \
-        libsm6 \
-        libxext6 \
-        libxrender-dev \
-        libglib2.0-0 \
-        libgl1 \
-        wget \
-        git \
-        xz-utils \
-        curl \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-WORKDIR /workspace
-ENV HOME=/workspace
-
-# Install nodejs
-RUN mkdir -p /usr/local/lib/nodejs \
-    && wget https://nodejs.org/dist/$NODE_VERSION/node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz \
-    && tar -xJvf node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz -C /usr/local/lib/nodejs \
-    && rm node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz
-ENV PATH=/usr/local/lib/nodejs/node-$NODE_VERSION-$NODE_DISTRO/bin:$PATH
-
-COPY ./docker/requirements-jupyter.txt ./
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install --no-cache-dir -r requirements-jupyter.txt
-
-# Install Jupyter Extensions
-RUN jupyter labextension install dask-labextension \
-    && jupyter serverextension enable dask_labextension
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64
-
-ENTRYPOINT ["/bin/bash"]
diff --git a/docker/Dockerfile-jupyter-dev b/docker/Dockerfile-jupyter-dev
deleted file mode 100644
index 5c7e7c2b1..000000000
--- a/docker/Dockerfile-jupyter-dev
+++ /dev/null
@@ -1,112 +0,0 @@
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-FROM nvidia/cuda:11.0-devel-ubuntu18.04
-
-ARG NODE_VERSION=v14.13.1
-ARG NODE_DISTRO=linux-x64
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV DEBIAN_FRONTEND=noninteractive
-
-RUN apt-get update \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        ca-certificates \
-    && rm -rf /var/lib/apt/lists/*
-
-# Download and install Python3 PIP.
-RUN apt-get update \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        python3-minimal \
-        python3-pip \
-    && rm -rf /var/lib/apt/lists/*
-
-RUN python3 --version
-
-# Set additional environment values that make usage more pleasant.
-ENV TERM=xterm-256color
-
-# Make /usr/bin/python point to the ${VERSION_PYTHON3} version of python
-RUN VERSION_PYTHON3=$(python3 --version | cut -c8-) && VERSION_PYTHON3=${VERSION_PYTHON3%.*} \
-    && rm -f /usr/bin/python \
-    && rm -f /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1` \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1`
-
-# Make /usr/bin/pip point to the ${VERSION_PIP3} version of python
-RUN rm -f /usr/bin/pip \
-    && ln -s /usr/bin/pip3 /usr/bin/pip
-
-# libgl1 is needed for opencv at `cucim convert` CLI command.
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        python3-dev \
-        gcc \
-        g++ \
-        libopenslide-dev \
-        libsm6 \
-        libxext6 \
-        libxrender-dev \
-        libglib2.0-0 \
-        libgl1 \
-        wget \
-        git \
-        xz-utils \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-WORKDIR /workspace
-ENV HOME=/workspace
-
-# Install nodejs
-RUN mkdir -p /usr/local/lib/nodejs \
-    && wget https://nodejs.org/dist/$NODE_VERSION/node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz \
-    && tar -xJvf node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz -C /usr/local/lib/nodejs \
-    && rm node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz
-ENV PATH=/usr/local/lib/nodejs/node-$NODE_VERSION-$NODE_DISTRO/bin:$PATH
-
-COPY ./docker/requirements-jupyter-dev.txt ./
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install --no-cache-dir -r requirements-jupyter-dev.txt
-
-# Install Jupyter Extensions
-RUN jupyter labextension install dask-labextension \
-    && jupyter serverextension enable dask_labextension
-
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        curl \
-#         build-essential \
-#         cmake \
-#         git \
-#         zlib1g-dev \
-#         libssl-dev \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/*
-
-# Download TRITON Client
-ARG TRITON_CLIENTS_URL=https://github.com/triton-inference-server/server/releases/download/v2.5.0/v2.5.0_ubuntu1804.clients.tar.gz
-RUN mkdir -p /opt/nvidia/triton-clients \
-    && curl -L ${TRITON_CLIENTS_URL} | tar xvz -C /opt/nvidia/triton-clients
-
-RUN pip install --no-cache-dir \
-        /opt/nvidia/triton-clients/python/*manylinux1_x86_64.whl
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64
-
-ENTRYPOINT ["/bin/bash"]
diff --git a/docker/Dockerfile-jupyter-gds b/docker/Dockerfile-jupyter-gds
deleted file mode 100644
index 1238c7265..000000000
--- a/docker/Dockerfile-jupyter-gds
+++ /dev/null
@@ -1,142 +0,0 @@
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-ARG UBUNTU_VER=18.04
-FROM nvidia/cuda:11.0-devel-ubuntu${UBUNTU_VER}
-
-ARG UBUNTU_VER=18.04
-ARG NODE_VERSION=v14.13.1
-ARG NODE_DISTRO=linux-x64
-ENV UBUNTU_VER=${UBUNTU_VER}
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Download and install Python3 PIP.
-RUN apt-get update --yes \
-    && apt-get upgrade --yes \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        ca-certificates \
-        python3-minimal \
-        python3-pip \
-    && rm -rf /var/lib/apt/lists/*
-
-RUN python3 --version
-
-# Set additional environment values that make usage more pleasant.
-ENV TERM=xterm-256color
-
-# Make /usr/bin/python point to the ${VERSION_PYTHON3} version of python
-RUN VERSION_PYTHON3=$(python3 --version | cut -c8-) && VERSION_PYTHON3=${VERSION_PYTHON3%.*} \
-    && rm -f /usr/bin/python \
-    && rm -f /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1` \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1`
-
-# Make /usr/bin/pip point to the ${VERSION_PIP3} version of python
-RUN rm -f /usr/bin/pip \
-    && ln -s /usr/bin/pip3 /usr/bin/pip
-
-# libgl1 is needed for opencv at `cucim convert` CLI command.
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        python3-dev \
-        gcc \
-        g++ \
-        libopenslide-dev \
-        libsm6 \
-        libxext6 \
-        libxrender-dev \
-        libglib2.0-0 \
-        libgl1 \
-        wget \
-        git \
-        xz-utils \
-        curl \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-WORKDIR /workspace
-ENV HOME=/workspace
-
-# Install nodejs
-RUN mkdir -p /usr/local/lib/nodejs \
-    && wget https://nodejs.org/dist/$NODE_VERSION/node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz \
-    && tar -xJvf node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz -C /usr/local/lib/nodejs \
-    && rm node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz
-ENV PATH=/usr/local/lib/nodejs/node-$NODE_VERSION-$NODE_DISTRO/bin:$PATH
-
-COPY ./docker/requirements-jupyter.txt ./
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install --no-cache-dir -r requirements-jupyter.txt
-
-# Install Jupyter Extensions
-RUN jupyter labextension install dask-labextension \
-    && jupyter serverextension enable dask_labextension
-
-# Supporting GDS
-
-ARG GDS_VER=0.9.0
-ARG MLNX_OFED_VER=5.1-2.5.8.0
-
-COPY ./temp/gds/tools/README /usr/local/cuda/gds/
-COPY ./temp/gds/samples/ /usr/local/cuda/gds/samples/
-COPY ./temp/gds/tools/ /usr/local/cuda/gds/tools/
-COPY ./temp/gds/lib64/cufile.h /usr/local/cuda/lib64/cufile.h
-COPY ./temp/gds/lib64/libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so.${GDS_VER}
-COPY ./temp/gds/lib64/libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so.${GDS_VER}
-
-# Somehow libcufile.so.0 and libcufile_rdma.so.0 are auto-generated during the copy
-    #&& ln -s libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so.0 \
-    #&& ln -s libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so.0
-RUN ln -sfn /usr/local/cuda/gds /usr/local/gds \
-    && ln -s libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so \
-    && ln -s libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so
-
-# dpkg: dependency problems prevent configuration of mlnx-iproute2:
-#  mlnx-iproute2 depends on libcap2 (>= 1:2.10); however:
-#   Package libcap2 is not installed.
-#
-#   liburcu-bp.so.6 => not found
-#   liburcu-cds.so.6 => not found
-#   libjsoncpp.so.1 => not found
-RUN apt-get update \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        libcap2 \
-        liburcu-dev \
-        libjsoncpp-dev \
-    && wget http://content.mellanox.com/ofed/MLNX_OFED-${MLNX_OFED_VER}/MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64.tgz \
-    && tar -xzvf MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64.tgz \
-    && MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64/mlnxofedinstall --user-space-only --without-fw-update --all -q --force \
-    && rm -rf MLNX_OFED_LINUX* \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-# Installation of MLNX_OFED would install python2, overwriting /usr/bin/python
-RUN ln -sf python3 /usr/bin/python \
-    && ln -sf pip3 /usr/bin/pip
-
-COPY ./docker/cufile.json /etc/cufile.json
-RUN sed -i 's/"allow_compat_mode": false,/"allow_compat_mode": true,/' /etc/cufile.json \
-    && echo "/usr/local/gds/lib/" > /etc/ld.so.conf.d/cufile.conf \
-    && ldconfig
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64
-
-ENTRYPOINT ["/bin/bash"]
diff --git a/docker/Dockerfile-jupyter-gds-dev b/docker/Dockerfile-jupyter-gds-dev
deleted file mode 100644
index cc7e2ef2c..000000000
--- a/docker/Dockerfile-jupyter-gds-dev
+++ /dev/null
@@ -1,160 +0,0 @@
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-ARG UBUNTU_VER=18.04
-FROM nvidia/cuda:11.0-devel-ubuntu${UBUNTU_VER}
-
-ARG UBUNTU_VER=18.04
-ARG NODE_VERSION=v14.13.1
-ARG NODE_DISTRO=linux-x64
-ENV UBUNTU_VER=${UBUNTU_VER}
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Download and install Python3 PIP.
-RUN apt-get update --yes \
-    && apt-get upgrade --yes \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        ca-certificates \
-        python3-minimal \
-        python3-pip \
-    && rm -rf /var/lib/apt/lists/*
-
-RUN python3 --version
-
-# Set additional environment values that make usage more pleasant.
-ENV TERM=xterm-256color
-
-# Make /usr/bin/python point to the ${VERSION_PYTHON3} version of python
-RUN VERSION_PYTHON3=$(python3 --version | cut -c8-) && VERSION_PYTHON3=${VERSION_PYTHON3%.*} \
-    && rm -f /usr/bin/python \
-    && rm -f /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1` \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python \
-    && ln -s /usr/bin/python${VERSION_PYTHON3} /usr/bin/python`echo ${VERSION_PYTHON3} | cut -c1-1`
-
-# Make /usr/bin/pip point to the ${VERSION_PIP3} version of python
-RUN rm -f /usr/bin/pip \
-    && ln -s /usr/bin/pip3 /usr/bin/pip
-
-# libgl1 is needed for opencv at `cucim convert` CLI command.
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        python3-dev \
-        gcc \
-        g++ \
-        libopenslide-dev \
-        libsm6 \
-        libxext6 \
-        libxrender-dev \
-        libglib2.0-0 \
-        libgl1 \
-        wget \
-        git \
-        xz-utils \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-WORKDIR /workspace
-ENV HOME=/workspace
-
-# Install nodejs
-RUN mkdir -p /usr/local/lib/nodejs \
-    && wget https://nodejs.org/dist/$NODE_VERSION/node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz \
-    && tar -xJvf node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz -C /usr/local/lib/nodejs \
-    && rm node-${NODE_VERSION}-${NODE_DISTRO}.tar.xz
-ENV PATH=/usr/local/lib/nodejs/node-$NODE_VERSION-$NODE_DISTRO/bin:$PATH
-
-COPY docker/requirements-jupyter-dev.txt ./
-
-# Use `python -m pip` to avoid using an old script wrapper.
-RUN python -m pip install --no-cache-dir --upgrade pip setuptools wheel \
-    && python -m pip install --no-cache-dir -r requirements-jupyter-dev.txt
-
-# Install Jupyter Extensions
-RUN jupyter labextension install dask-labextension \
-    && jupyter serverextension enable dask_labextension
-
-RUN apt-get update \
-    && apt-get install -y --no-install-recommends \
-        curl \
-#         build-essential \
-#         cmake \
-#         git \
-#         zlib1g-dev \
-#         libssl-dev \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/*
-
-# Download TRITON Client
-ARG TRITON_CLIENTS_URL=https://github.com/triton-inference-server/server/releases/download/v2.5.0/v2.5.0_ubuntu1804.clients.tar.gz
-RUN mkdir -p /opt/nvidia/triton-clients \
-    && curl -L ${TRITON_CLIENTS_URL} | tar xvz -C /opt/nvidia/triton-clients
-
-RUN pip install --no-cache-dir \
-        /opt/nvidia/triton-clients/python/*manylinux1_x86_64.whl
-
-# Supporting GDS
-
-ARG GDS_VER=0.9.0
-ARG MLNX_OFED_VER=5.1-2.5.8.0
-
-COPY ./temp/gds/tools/README /usr/local/cuda/gds/
-COPY ./temp/gds/samples/ /usr/local/cuda/gds/samples/
-COPY ./temp/gds/tools/ /usr/local/cuda/gds/tools/
-COPY ./temp/gds/lib64/cufile.h /usr/local/cuda/lib64/cufile.h
-COPY ./temp/gds/lib64/libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so.${GDS_VER}
-COPY ./temp/gds/lib64/libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so.${GDS_VER}
-
-# Somehow libcufile.so.0 and libcufile_rdma.so.0 are auto-generated during the copy
-    #&& ln -s libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so.0 \
-    #&& ln -s libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so.0
-RUN ln -sfn /usr/local/cuda/gds /usr/local/gds \
-    && ln -s libcufile.so.${GDS_VER} /usr/local/cuda/lib64/libcufile.so \
-    && ln -s libcufile_rdma.so.${GDS_VER} /usr/local/cuda/lib64/libcufile_rdma.so
-
-# dpkg: dependency problems prevent configuration of mlnx-iproute2:
-#  mlnx-iproute2 depends on libcap2 (>= 1:2.10); however:
-#   Package libcap2 is not installed.
-#
-#   liburcu-bp.so.6 => not found
-#   liburcu-cds.so.6 => not found
-#   libjsoncpp.so.1 => not found
-RUN apt-get update \
-    && apt-get install --yes --fix-missing --no-install-recommends \
-        libcap2 \
-        liburcu-dev \
-        libjsoncpp-dev \
-    && wget http://content.mellanox.com/ofed/MLNX_OFED-${MLNX_OFED_VER}/MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64.tgz \
-    && tar -xzvf MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64.tgz \
-    && MLNX_OFED_LINUX-${MLNX_OFED_VER}-ubuntu${UBUNTU_VER}-x86_64/mlnxofedinstall --user-space-only --without-fw-update --all -q --force \
-    && rm -rf MLNX_OFED_LINUX* \
-    && apt-get autoremove -y \
-    && rm -rf /var/lib/apt/lists/* \
-    && rm -rf /var/cache/apt/archives/partial/*
-
-# Installation of MLNX_OFED would install python2, overwriting /usr/bin/python
-RUN ln -sf python3 /usr/bin/python \
-    && ln -sf pip3 /usr/bin/pip
-
-COPY ./docker/cufile.json /etc/cufile.json
-RUN sed -i 's/"allow_compat_mode": false,/"allow_compat_mode": true,/' /etc/cufile.json \
-    && echo "/usr/local/gds/lib/" > /etc/ld.so.conf.d/cufile.conf \
-    && ldconfig
-
-ENV LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda/nvvm/lib64
-
-ENTRYPOINT ["/bin/bash"]
diff --git a/docker/cufile.json b/docker/cufile.json
deleted file mode 100644
index 55930426c..000000000
--- a/docker/cufile.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-    // NOTE : Application can override custom configuration via export CUFILE_ENV_PATH_JSON=<filepath>
-    // e.g : export CUFILE_ENV_PATH_JSON="/home/<xxx>/cufile.json"
-
-            "logging": {
-                            // log directory, if not enabled will create log file under current working directory
-                            //"dir": "/home/<xxxx>",
-
-                            // ERROR|WARN|INFO|DEBUG|TRACE (in decreasing order of priority)
-                            "level": "ERROR"
-            },
-
-            "profile": {
-                            // nvtx profiling on/off
-                            "nvtx": false,
-                            // cufile stats level(0-3)
-                            "cufile_stats": 0
-            },
-
-            "properties": {
-                            // max IO chunk size (parameter should be 4K aligned) used by cuFileRead/Write internally per IO request
-                            "max_direct_io_size_kb" : 16384,
-                            // device memory size (parameter should be 4K aligned) for reserving bounce buffers for the entire GPU
-                            "max_device_cache_size_kb" : 131072,
-                            // limit on maximum device memory size (parameter should be 4K aligned) that can be pinned for a given process
-                            "max_device_pinned_mem_size_kb" : 33554432,
-                            // true or false (true will enable asynchronous io submission to nvidia-fs driver)
-                            // Note : currently the overall IO will still be synchronous
-                            "use_poll_mode" : false,
-                            // maximum IO request size (parameter should be 4K aligned) within or equal to which library will use polling for IO completion
-                            "poll_mode_max_size_kb": 4,
-                            // allow compat mode, this will enable use of cuFile posix read/writes
-                            "allow_compat_mode": false,
-                            // client-side rdma addr list for user-space file-systems(e.g ["10.0.1.0", "10.0.2.0"])
-                            "rdma_dev_addr_list": [ ],
-                            // load balancing policy for RDMA memory registration(MR), (RoundRobin, RoundRobinMaxMin)
-                            // In RoundRobin, MRs will be distributed uniformly across NICS closest to a GPU
-                            // In RoundRobinMaxMin, MRs will be distributed across NICS closest to a GPU
-                            // with minimal sharing of NICS acros GPUS
-                            "rdma_load_balancing_policy": "RoundRobin"
-            },
-
-            "fs": {
-                    "generic": {
-
-                            // for unaligned writes, setting it to true will, cuFileWrite use posix write internally instead of regular GDS write
-                            "posix_unaligned_writes" : false
-                    },
-
-                    "lustre": {
-
-                            // IO threshold for read/write (param should be 4K aligned)) equal to or below which cuFile will use posix read/write
-                            "posix_gds_min_kb" : 0
-                    },
-
-                    "weka": {
-
-                            // enable/disable RDMA write
-                            "rdma_write_support" : false
-                    }
-            },
-
-            "denylist": {
-                            // specify list of vendor driver modules to deny for nvidia-fs (e.g. ["nvme" , "nvme_rdma"])
-                            "drivers":  [ ],
-
-                            // specify list of block devices to prevent IO using cuFile (e.g. [ "/dev/nvme0n1" ])
-                            "devices": [ ],
-
-                            // specify list of mount points to prevent IO using cuFile (e.g. ["/mnt/test"])
-                            "mounts": [ ],
-
-                            // specify list of file-systems to prevent IO using cuFile (e.g ["lustre", "wekafs"])
-                            "filesystems": [ ]
-            },
-
-            "miscellaneous": {
-                            // enable only for enforcing strict checks at API level for debugging
-                            "api_check_aggressive": false
-	    }
-}
diff --git a/docker/requirements-claratrain.txt b/docker/requirements-claratrain.txt
deleted file mode 100644
index 485192268..000000000
--- a/docker/requirements-claratrain.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-openslide-python==1.1.2
-tifffile>=2022.7.28
-itk==5.1.2
-dask[array,delayed,distributed]==2021.2.0
-dask-cuda==0.17.0
-zarr==2.6.1
-fsspec==0.8.5
-numpy # 1.17.3 already exists in the image
-opencv-contrib-python==4.5.1.48
-imagecodecs>=2021.6.8
diff --git a/docker/requirements-jupyter-dev.txt b/docker/requirements-jupyter-dev.txt
deleted file mode 100644
index 57a46ed8b..000000000
--- a/docker/requirements-jupyter-dev.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-openslide-python==1.1.2
-tifffile>=2022.7.28
-itk==5.1.2
-dask[array,delayed,distributed]==2021.2.0
-dask-cuda==0.17.0
-zarr==2.6.1
-fsspec==0.8.5
-numpy==1.19.5
-opencv-contrib-python==4.5.1.48
-imagecodecs>=2021.6.8
-cupy-cuda110==8.4.0
-jupyterlab==3.0.7
-dask_labextension==5.0.0
-cmake>=3.18
---extra-index-url https://developer.download.nvidia.com/compute/redist
-nvidia-dali-cuda110
---find-links https://download.pytorch.org/whl/torch_stable.html
-torch==1.7.1+cu110
-torchvision==0.8.2+cu110
-torchaudio===0.7.2
diff --git a/docker/requirements-jupyter.txt b/docker/requirements-jupyter.txt
deleted file mode 100644
index 57a46ed8b..000000000
--- a/docker/requirements-jupyter.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-openslide-python==1.1.2
-tifffile>=2022.7.28
-itk==5.1.2
-dask[array,delayed,distributed]==2021.2.0
-dask-cuda==0.17.0
-zarr==2.6.1
-fsspec==0.8.5
-numpy==1.19.5
-opencv-contrib-python==4.5.1.48
-imagecodecs>=2021.6.8
-cupy-cuda110==8.4.0
-jupyterlab==3.0.7
-dask_labextension==5.0.0
-cmake>=3.18
---extra-index-url https://developer.download.nvidia.com/compute/redist
-nvidia-dali-cuda110
---find-links https://download.pytorch.org/whl/torch_stable.html
-torch==1.7.1+cu110
-torchvision==0.8.2+cu110
-torchaudio===0.7.2
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 084d85d70..572312f8e 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -72,9 +72,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = "23.12"
+version = "24.02"
 # The full version, including alpha/beta/rc tags.
-release = "23.12.00"
+release = "24.02.00"
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/python/cucim/.appveyor.yml b/python/cucim/.appveyor.yml
deleted file mode 100644
index 71d045008..000000000
--- a/python/cucim/.appveyor.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-version: '{branch}-{build}'
-build: off
-environment:
-  matrix:
-    - TOXENV: check
-      TOXPYTHON: C:\Python36\python.exe
-      PYTHON_HOME: C:\Python36
-      PYTHON_VERSION: '3.6'
-      PYTHON_ARCH: '32'
-    - TOXENV: py27,codecov
-      TOXPYTHON: C:\Python27\python.exe
-      PYTHON_HOME: C:\Python27
-      PYTHON_VERSION: '2.7'
-      PYTHON_ARCH: '32'
-    - TOXENV: py27,codecov
-      TOXPYTHON: C:\Python27-x64\python.exe
-      PYTHON_HOME: C:\Python27-x64
-      PYTHON_VERSION: '2.7'
-      PYTHON_ARCH: '64'
-      WINDOWS_SDK_VERSION: v7.0
-    - TOXENV: py35,codecov
-      TOXPYTHON: C:\Python35\python.exe
-      PYTHON_HOME: C:\Python35
-      PYTHON_VERSION: '3.5'
-      PYTHON_ARCH: '32'
-    - TOXENV: py35,codecov
-      TOXPYTHON: C:\Python35-x64\python.exe
-      PYTHON_HOME: C:\Python35-x64
-      PYTHON_VERSION: '3.5'
-      PYTHON_ARCH: '64'
-    - TOXENV: py36,codecov
-      TOXPYTHON: C:\Python36\python.exe
-      PYTHON_HOME: C:\Python36
-      PYTHON_VERSION: '3.6'
-      PYTHON_ARCH: '32'
-    - TOXENV: py36,codecov
-      TOXPYTHON: C:\Python36-x64\python.exe
-      PYTHON_HOME: C:\Python36-x64
-      PYTHON_VERSION: '3.6'
-      PYTHON_ARCH: '64'
-    - TOXENV: py37,codecov
-      TOXPYTHON: C:\Python37\python.exe
-      PYTHON_HOME: C:\Python37
-      PYTHON_VERSION: '3.7'
-      PYTHON_ARCH: '32'
-    - TOXENV: py37,codecov
-      TOXPYTHON: C:\Python37-x64\python.exe
-      PYTHON_HOME: C:\Python37-x64
-      PYTHON_VERSION: '3.7'
-      PYTHON_ARCH: '64'
-    - TOXENV: py38,codecov
-      TOXPYTHON: C:\Python38\python.exe
-      PYTHON_HOME: C:\Python38
-      PYTHON_VERSION: '3.8'
-      PYTHON_ARCH: '32'
-    - TOXENV: py38,codecov
-      TOXPYTHON: C:\Python38-x64\python.exe
-      PYTHON_HOME: C:\Python38-x64
-      PYTHON_VERSION: '3.8'
-      PYTHON_ARCH: '64'
-init:
-  - ps: echo $env:TOXENV
-  - ps: ls C:\Python*
-install:
-  - '%PYTHON_HOME%\python -mpip install --progress-bar=off tox -rci/requirements.txt'
-  - '%PYTHON_HOME%\Scripts\virtualenv --version'
-  - '%PYTHON_HOME%\Scripts\easy_install --version'
-  - '%PYTHON_HOME%\Scripts\pip --version'
-  - '%PYTHON_HOME%\Scripts\tox --version'
-test_script:
-  - cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd %PYTHON_HOME%\Scripts\tox
-on_failure:
-  - ps: dir "env:"
-  - ps: get-content .tox\*\log\*
-
-### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker):
-# on_finish:
-#   - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
diff --git a/python/cucim/.cookiecutterrc b/python/cucim/.cookiecutterrc
deleted file mode 100644
index 437fca81c..000000000
--- a/python/cucim/.cookiecutterrc
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file exists so you can easily regenerate your project.
-#
-# `cookiepatcher` is a convenient shim around `cookiecutter`
-# for regenerating projects (it will generate a .cookiecutterrc
-# automatically for any template). To use it:
-#
-#    pip install cookiepatcher
-#    cookiepatcher gh:ionelmc/cookiecutter-pylibrary cucim
-#
-# See:
-#    https://pypi.org/project/cookiepatcher
-#
-# Alternatively, you can run:
-#
-#    cookiecutter --overwrite-if-exists --config-file=cucim/.cookiecutterrc gh:ionelmc/cookiecutter-pylibrary
-
-default_context:
-
-    _extensions:               ['jinja2_time.TimeExtension']
-    _template:                 'https://github.com/ionelmc/cookiecutter-pylibrary'
-    allow_tests_inside_package: 'no'
-    appveyor:                  'yes'
-    c_extension_function:      'longest'
-    c_extension_module:        '_cucim'
-    c_extension_optional:      'no'
-    c_extension_support:       'no'
-    c_extension_test_pypi:     'no'
-    c_extension_test_pypi_username: ''
-    codacy:                    'no'
-    codacy_projectid:          '[Get ID from https://app.codacy.com/app/rapidsai/cucim/settings]'
-    codeclimate:               'no'
-    codecov:                   'yes'
-    command_line_interface:    'click'
-    command_line_interface_bin_name: 'cucim'
-    coveralls:                 'no'
-    coveralls_token:           '[Required for Appveyor, take it from https://coveralls.io/github/rapidsai/cucim]'
-    distribution_name:         'cucim'
-    email:                     ''
-    full_name:                 'cuCIM Developers'
-    landscape:                 'no'
-    license:                   'Apache Software License 2.0'
-    linter:                    'flake8'
-    package_name:              'cucim'
-    pre_commit:                'yes'
-    project_name:              'cucim'
-    project_short_description: 'A CUDA-accerlated image processing library'
-    pypi_badge:                'yes'
-    pypi_disable_upload:       'no'
-    release_date:              'today'
-    repo_hosting:              'github.com'
-    repo_hosting_domain:       'github.com'
-    repo_name:                 'cucim'
-    repo_username:             ''
-    requiresio:                'yes'
-    scrutinizer:               'no'
-    setup_py_uses_setuptools_scm: 'no'
-    setup_py_uses_test_runner: 'no'
-    sphinx_docs:               'yes'
-    sphinx_docs_hosting:       'https://cucim.readthedocs.io/'
-    sphinx_doctest:            'yes'
-    sphinx_theme:              'sphinx-rtd-theme'
-    test_matrix_configurator:  'no'
-    test_matrix_separate_coverage: 'no'
-    test_runner:               'pytest'
-    travis:                    'yes'
-    travis_osx:                'no'
-    version:                   '0.0.0'
-    website:                   'https://rapids.ai/'
-    year_from:                 '2021'
-    year_to:                   '2021'
diff --git a/python/cucim/.gitignore b/python/cucim/.gitignore
deleted file mode 100644
index dfe58380d..000000000
--- a/python/cucim/.gitignore
+++ /dev/null
@@ -1,71 +0,0 @@
-*.py[cod]
-__pycache__
-
-# C extensions
-*.so
-
-# Packages
-*.egg
-*.egg-info
-dist
-build
-eggs
-.eggs
-parts
-bin
-var
-sdist
-wheelhouse
-develop-eggs
-.installed.cfg
-lib
-lib64
-venv*/
-pyvenv*/
-pip-wheel-metadata/
-
-# Installer logs
-pip-log.txt
-
-# Unit test / coverage reports
-.coverage
-.tox
-.coverage.*
-.pytest_cache/
-nosetests.xml
-coverage.xml
-htmlcov
-
-# Translations
-*.mo
-
-# Mr Developer
-.mr.developer.cfg
-.project
-.pydevproject
-.idea
-*.iml
-*.komodoproject
-
-# Complexity
-output/*.html
-output/*/index.html
-
-# Sphinx
-docs/_build
-
-.DS_Store
-*~
-.*.sw[po]
-.build
-.ve
-.env
-.cache
-.pytest
-.benchmarks
-.bootstrap
-.appveyor.token
-*.bak
-
-# Mypy Cache
-.mypy_cache/
diff --git a/python/cucim/.readthedocs.yml b/python/cucim/.readthedocs.yml
deleted file mode 100644
index 59ff5c04f..000000000
--- a/python/cucim/.readthedocs.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
-version: 2
-sphinx:
-  configuration: docs/conf.py
-formats: all
-python:
-  install:
-    - requirements: docs/requirements.txt
-    - method: pip
-      path: .
diff --git a/python/cucim/.travis.yml b/python/cucim/.travis.yml
deleted file mode 100644
index 09858acea..000000000
--- a/python/cucim/.travis.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-language: python
-dist: xenial
-cache: false
-env:
-  global:
-    - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
-    - SEGFAULT_SIGNALS=all
-    - LANG=en_US.UTF-8
-matrix:
-  include:
-    - python: '3.6'
-      env:
-        - TOXENV=check
-    - python: '3.6'
-      env:
-        - TOXENV=docs
-    - env:
-        - TOXENV=py27,codecov
-      python: '2.7'
-    - env:
-        - TOXENV=py35,codecov
-      python: '3.5'
-    - env:
-        - TOXENV=py36,codecov
-      python: '3.6'
-    - env:
-        - TOXENV=py37,codecov
-      python: '3.7'
-    - env:
-        - TOXENV=py38,codecov
-      python: '3.8'
-    - env:
-        - TOXENV=pypy,codecov
-      python: 'pypy'
-    - env:
-        - TOXENV=pypy3,codecov
-        - TOXPYTHON=pypy3
-      python: 'pypy3'
-before_install:
-  - python --version
-  - uname -a
-  - lsb_release -a || true
-install:
-  - python -mpip install --progress-bar=off tox -rci/requirements.txt
-  - virtualenv --version
-  - easy_install --version
-  - pip --version
-  - tox --version
-script:
-  - tox -v
-after_failure:
-  - cat .tox/log/*
-  - cat .tox/*/log/*
-notifications:
-  email:
-    on_success: never
-    on_failure: always
diff --git a/python/cucim/AUTHORS.md b/python/cucim/AUTHORS.md
deleted file mode 100644
index c16398d00..000000000
--- a/python/cucim/AUTHORS.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Authors
-
-* Gigon Bae (gigony)
-* Gregory R. Lee (grlee77)
-* Benjamin Zaitlen (quasiben)
-* John Kirkham (jakirkham)
-* Ray Douglass (raydouglass)
diff --git a/python/cucim/CONTRIBUTING.md b/python/cucim/CONTRIBUTING.md
deleted file mode 100644
index 77f80ae8a..000000000
--- a/python/cucim/CONTRIBUTING.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Contributing
-
-Contributions are welcome, and they are greatly appreciated! Every
-little bit helps, and credit will always be given.
-
-# Bug reports
-
-When [reporting a bug](https://github.com/rapidsai/cucim/issues) please include:
-
-    * Your operating system name and version.
-    * Any details about your local setup that might be helpful in troubleshooting.
-    * Detailed steps to reproduce the bug.
-
-# Documentation improvements
-
-cucim could always use more documentation, whether as part of the
-official cucim docs, in docstrings, or even on the web in blog posts,
-articles, and such.
-
-# Feature requests and feedback
-
-The best way to send feedback is to file an issue at https://github.com/rapidsai/cucim/issues.
-
-If you are proposing a feature:
-
-* Explain in detail how it would work.
-* Keep the scope as narrow as possible, to make it easier to implement.
-* Remember that this is a volunteer-driven project, and that code contributions are welcome :)
-
-# Development
-
-To set up `cucim` for local development:
-
-1. Fork [cucim](https://github.com/rapidsai/cucim)
-    (look for the "Fork" button).
-
-2. Clone your fork locally:
-
-    ```bash
-    git clone git@github.com:YOURGITHUBNAME/cucim.git
-    ```
-
-3. Create a branch for local development::
-
-    ```bash
-    git checkout -b name-of-your-bugfix-or-feature
-    ```
-
-    Now you can make your changes locally.
-
-4. When you're done making changes run all the checks and docs builder with [tox](https://tox.readthedocs.io/en/latest/install.html) one command::
-
-    ```bash
-    tox
-    ```
-
-5. Commit your changes and push your branch to GitHub:
-
-    ```bash
-    git add .
-    git commit -m "Your detailed description of your changes."
-    git push origin name-of-your-bugfix-or-feature
-    ```
-
-6. Submit a pull request through the GitHub website.
-
-## Pull Request Guidelines
-
-If you need some code review or feedback while you're developing the code just make the pull request.
-
-For merging, you should:
-
-1. Include passing tests (run `tox`).
-
-    If you don't have all the necessary python versions available locally you can rely on Travis - it will [run the tests](https://travis-ci.org/rapidsai/cucim/pull_requests) for each change you add in the pull request.
-
-    It will be slower though ...
-2. Update documentation when there's new API, functionality etc.
-3. Add a note to `CHANGELOG.md`` about the changes.
-4. Add yourself to `AUTHORS.md`.
-
-
-## Tips
-
-
-To run a subset of tests::
-
-```bash
-tox -e envname -- pytest -k test_myfeature
-```
-
-To run all the test environments in *parallel*::
-
-```bash
-tox -p auto
-```
diff --git a/python/cucim/CONTRIBUTING.md b/python/cucim/CONTRIBUTING.md
new file mode 120000
index 000000000..f939e75f2
--- /dev/null
+++ b/python/cucim/CONTRIBUTING.md
@@ -0,0 +1,1 @@
+../../CONTRIBUTING.md
\ No newline at end of file
diff --git a/python/cucim/MANIFEST.in b/python/cucim/MANIFEST.in
index 756e96d3c..61881e2c1 100644
--- a/python/cucim/MANIFEST.in
+++ b/python/cucim/MANIFEST.in
@@ -1,24 +1,13 @@
 # https://packaging.python.org/guides/using-manifest-in/
-graft docs
-graft src
-graft ci
-graft tests
-
-include .bumpversion.cfg
-include .coveragerc
-include .cookiecutterrc
 include .editorconfig
 
-include VERSION
-include AUTHORS.md
+include src/cucim/VERSION
 include CHANGELOG.md
 include CONTRIBUTING.md
-include ../../LICENSE
-include ../../LICENSE-3rdparty.md
+include LICENSE
+include LICENSE-3rdparty.md
 include README.md
 
-include tox.ini .travis.yml .appveyor.yml .readthedocs.yml
-
 include src/cucim/clara/*.so*
 
 recursive-include src/cucim *.py *.pyi *.cu *.h *.npy *.txt *.md
diff --git a/python/cucim/README.md b/python/cucim/README.md
deleted file mode 100755
index 0fcb1bcee..000000000
--- a/python/cucim/README.md
+++ /dev/null
@@ -1,113 +0,0 @@
-# <div align="left"><img src="https://rapids.ai/assets/images/rapids_logo.png" width="90px"/>&nbsp;cuCIM</div>
-
-[RAPIDS](https://rapids.ai) cuCIM is an open-source, accelerated computer vision and image processing software library for multidimensional images used in biomedical, geospatial, material and life science, and remote sensing use cases.
-
-cuCIM offers:
-
-- Enhanced Image Processing Capabilities for large and n-dimensional tag image file format (TIFF) files
-- Accelerated performance through Graphics Processing Unit (GPU)-based image processing and computer vision primitives
-- A Straightforward Pythonic Interface with Matching Application Programming Interface (API) for Openslide
-
-cuCIM supports the following formats:
-
-- Aperio ScanScope Virtual Slide (SVS)
-- Philips TIFF
-- Generic Tiled, Multi-resolution RGB TIFF files with the following compression schemes:
-  - No Compression
-  - JPEG
-  - JPEG2000
-  - Lempel-Ziv-Welch (LZW)
-  - Deflate
-
-**NOTE:** For the latest stable [README.md](https://github.com/rapidsai/cucim/blob/main/README.md) ensure you are on the `main` branch.
-
-- [GTC 2022 Accelerating Storage IO to GPUs with Magnum IO [S41347]](https://events.rainfocus.com/widget/nvidia/gtcspring2022/sessioncatalog/session/1634960000577001Etxp)
-  - cuCIM's GDS API examples: <https://github.com/NVIDIA/MagnumIO/tree/main/gds/readers/cucim-gds>
-- [SciPy 2021 cuCIM - A GPU image I/O and processing library](https://www.scipy2021.scipy.org/)
-  - [video](https://youtu.be/G46kOOM9xbQ)
-- [GTC 2021 cuCIM: A GPU Image I/O and Processing Toolkit [S32194]](https://www.nvidia.com/en-us/on-demand/search/?facet.mimetype[]=event%20session&layout=list&page=1&q=cucim&sort=date)
-  - [video](https://www.nvidia.com/en-us/on-demand/session/gtcspring21-s32194/)
-
-**[Developer Page](https://developer.nvidia.com/multidimensional-image-processing)**
-
-**Blogs**
-- [Enhanced Image Analysis with Multidimensional Image Processing](https://developer.nvidia.com/blog/enhanced-image-analysis-with-multidimensional-image-processing/)
-- [Accelerating Scikit-Image API with cuCIM: n-Dimensional Image Processing and IO on GPUs](https://developer.nvidia.com/blog/cucim-rapid-n-dimensional-image-processing-and-i-o-on-gpus/)
-- [Accelerating Digital Pathology Pipelines with NVIDIA Clara™ Deploy](https://developer.nvidia.com/blog/accelerating-digital-pathology-pipelines-with-nvidia-clara-deploy-2/)
-
-**Webinars**
-
-- [cuCIM: a GPU Image IO and Processing Library](https://www.youtube.com/watch?v=G46kOOM9xbQ)
-
-**[Documentation](https://docs.rapids.ai/api/cucim/stable)**
-
-**Release notes** are available on our [wiki page](https://github.com/rapidsai/cucim/wiki/Release-Notes).
-
-## Install cuCIM
-
-### Conda
-
-#### [Conda (stable)](https://anaconda.org/rapidsai/cucim)
-
-> conda create -n cucim -c rapidsai -c conda-forge cucim cudatoolkit=`<CUDA version>`
-
-`<CUDA version>` should be 11.0+ (e.g., `11.0`, `11.2`, etc.)
-
-#### [Conda (nightlies)](https://anaconda.org/rapidsai-nightly/cucim)
-
-> conda create -n cucim -c rapidsai-nightly -c conda-forge cucim cudatoolkit=`<CUDA version>`
-
-`<CUDA version>` should be 11.0+ (e.g., `11.0`, `11.2`, etc)
-
-### [PyPI](https://pypi.org/project/cucim/)
-
-```bash
-pip install cucim
-
-# Install dependencies for `cucim.skimage` (assuming that CUDA 11.0 is used for CuPy)
-pip install scipy scikit-image cupy-cuda110
-```
-
-### Notebooks
-
-Please check out our [Welcome](notebooks/Welcome.ipynb) notebook ([NBViewer](https://nbviewer.jupyter.org/github/rapidsai/cucim/blob/branch-23.12/notebooks/Welcome.ipynb))
-
-#### Downloading sample images
-
-To download images used in the notebooks, please execute the following commands from the repository root folder to copy sample input images into `notebooks/input` folder:
-
-(You will need [Docker](https://www.docker.com/) installed in your system)
-
-```bash
-./run download_testdata
-```
-or
-
-```bash
-mkdir -p notebooks/input
-tmp_id=$(docker create gigony/svs-testdata:little-big)
-docker cp $tmp_id:/input notebooks
-docker rm -v ${tmp_id}
-```
-
-## Build/Install from Source
-
-See build [instructions](CONTRIBUTING.md#setting-up-your-build-environment).
-
-## Contributing Guide
-
-Contributions to cuCIM are more than welcome!
-Please review the [CONTRIBUTING.md](https://github.com/rapidsai/cucim/blob/main/CONTRIBUTING.md) file for information on how to contribute code and issues to the project.
-
-## Acknowledgments
-
-Without awesome third-party open source software, this project wouldn't exist.
-
-Please find [LICENSE-3rdparty.md](LICENSE-3rdparty.md) to see which third-party open source software
-is used in this project.
-
-## License
-
-Apache-2.0 License (see [LICENSE](LICENSE) file).
-
-Copyright (c) 2020-2022, NVIDIA CORPORATION.
diff --git a/python/cucim/README.md b/python/cucim/README.md
new file mode 120000
index 000000000..fe8400541
--- /dev/null
+++ b/python/cucim/README.md
@@ -0,0 +1,1 @@
+../../README.md
\ No newline at end of file
diff --git a/python/cucim/VERSION b/python/cucim/VERSION
new file mode 120000
index 000000000..558194c5a
--- /dev/null
+++ b/python/cucim/VERSION
@@ -0,0 +1,1 @@
+../../VERSION
\ No newline at end of file
diff --git a/python/cucim/ci/appveyor-with-compiler.cmd b/python/cucim/ci/appveyor-with-compiler.cmd
deleted file mode 100644
index 289585fc1..000000000
--- a/python/cucim/ci/appveyor-with-compiler.cmd
+++ /dev/null
@@ -1,23 +0,0 @@
-:: Very simple setup:
-:: - if WINDOWS_SDK_VERSION is set then activate the SDK.
-:: - disable the WDK if it's around.
-
-SET COMMAND_TO_RUN=%*
-SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
-SET WIN_WDK="c:\Program Files (x86)\Windows Kits\10\Include\wdf"
-ECHO SDK: %WINDOWS_SDK_VERSION% ARCH: %PYTHON_ARCH%
-
-IF EXIST %WIN_WDK% (
-    REM See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/
-    REN %WIN_WDK% 0wdf
-)
-IF "%WINDOWS_SDK_VERSION%"=="" GOTO main
-
-SET DISTUTILS_USE_SDK=1
-SET MSSdk=1
-"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
-CALL "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
-
-:main
-ECHO Executing: %COMMAND_TO_RUN%
-CALL %COMMAND_TO_RUN% || EXIT 1
diff --git a/python/cucim/ci/bootstrap.py b/python/cucim/ci/bootstrap.py
deleted file mode 100755
index 05dbf0b3f..000000000
--- a/python/cucim/ci/bootstrap.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import os
-import subprocess
-import sys
-from os.path import abspath, dirname, exists, join
-
-base_path = dirname(dirname(abspath(__file__)))
-
-
-def check_call(args):
-    print("+", *args)
-    subprocess.check_call(args)
-
-
-def exec_in_env():
-    env_path = join(base_path, ".tox", "bootstrap")
-    if sys.platform == "win32":
-        bin_path = join(env_path, "Scripts")
-    else:
-        bin_path = join(env_path, "bin")
-    if not exists(env_path):
-        import subprocess
-
-        print("Making bootstrap env in: {0} ...".format(env_path))
-        try:
-            check_call([sys.executable, "-m", "venv", env_path])
-        except subprocess.CalledProcessError:
-            try:
-                check_call([sys.executable, "-m", "virtualenv", env_path])
-            except subprocess.CalledProcessError:
-                check_call(["virtualenv", env_path])
-        print("Installing `jinja2` into bootstrap environment...")
-        check_call([join(bin_path, "pip"), "install", "jinja2", "tox"])
-    python_executable = join(bin_path, "python")
-    if not os.path.exists(python_executable):
-        python_executable += ".exe"
-
-    print("Re-executing with: {0}".format(python_executable))
-    print("+ exec", python_executable, __file__, "--no-env")
-    os.execv(python_executable, [python_executable, __file__, "--no-env"])
-
-
-def main():
-    import jinja2
-
-    print("Project path: {0}".format(base_path))
-
-    jinja = jinja2.Environment(
-        loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")),
-        trim_blocks=True,
-        lstrip_blocks=True,
-        keep_trailing_newline=True,
-    )
-
-    tox_environments = [
-        line.strip()
-        # 'tox' need not be installed globally, but must be importable
-        # by the Python that is running this script.
-        # This uses sys.executable the same way that the call in
-        # cookiecutter-pylibrary/hooks/post_gen_project.py
-        # invokes this bootstrap.py itself.
-        for line in subprocess.check_output(
-            [sys.executable, "-m", "tox", "--listenvs"], universal_newlines=True
-        ).splitlines()
-    ]
-    tox_environments = [
-        line for line in tox_environments if line.startswith("py")
-    ]
-
-    for name in os.listdir(join("ci", "templates")):
-        with open(join(base_path, name), "w") as fh:
-            fh.write(
-                jinja.get_template(name).render(
-                    tox_environments=tox_environments
-                )
-            )
-        print("Wrote {}".format(name))
-    print("DONE.")
-
-
-if __name__ == "__main__":
-    args = sys.argv[1:]
-    if args == ["--no-env"]:
-        main()
-    elif not args:
-        exec_in_env()
-    else:
-        print("Unexpected arguments {0}".format(args), file=sys.stderr)
-        sys.exit(1)
diff --git a/python/cucim/ci/requirements.txt b/python/cucim/ci/requirements.txt
deleted file mode 100644
index a0f53e12a..000000000
--- a/python/cucim/ci/requirements.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-virtualenv>=16.6.0
-pip>=19.1.1
-setuptools>=18.0.1
-six>=1.14.0
-lazy_loader>=0.1
diff --git a/python/cucim/ci/templates/.appveyor.yml b/python/cucim/ci/templates/.appveyor.yml
deleted file mode 100644
index bb4a05599..000000000
--- a/python/cucim/ci/templates/.appveyor.yml
+++ /dev/null
@@ -1,49 +0,0 @@
-version: '{branch}-{build}'
-build: off
-environment:
-  matrix:
-    - TOXENV: check
-      TOXPYTHON: C:\Python36\python.exe
-      PYTHON_HOME: C:\Python36
-      PYTHON_VERSION: '3.6'
-      PYTHON_ARCH: '32'
-{% for env in tox_environments %}
-{% if env.startswith(('py2', 'py3')) %}
-    - TOXENV: {{ env }},codecov{{ "" }}
-      TOXPYTHON: C:\Python{{ env[2:4] }}\python.exe
-      PYTHON_HOME: C:\Python{{ env[2:4] }}
-      PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}'
-      PYTHON_ARCH: '32'
-{% if 'nocov' in env %}
-      WHEEL_PATH: .tox/dist
-{% endif %}
-    - TOXENV: {{ env }},codecov{{ "" }}
-      TOXPYTHON: C:\Python{{ env[2:4] }}-x64\python.exe
-      PYTHON_HOME: C:\Python{{ env[2:4] }}-x64
-      PYTHON_VERSION: '{{ env[2] }}.{{ env[3] }}'
-      PYTHON_ARCH: '64'
-{% if 'nocov' in env %}
-      WHEEL_PATH: .tox/dist
-{% endif %}
-{% if env.startswith('py2') %}
-      WINDOWS_SDK_VERSION: v7.0
-{% endif %}
-{% endif %}{% endfor %}
-init:
-  - ps: echo $env:TOXENV
-  - ps: ls C:\Python*
-install:
-  - '%PYTHON_HOME%\python -mpip install --progress-bar=off tox -rci/requirements.txt'
-  - '%PYTHON_HOME%\Scripts\virtualenv --version'
-  - '%PYTHON_HOME%\Scripts\easy_install --version'
-  - '%PYTHON_HOME%\Scripts\pip --version'
-  - '%PYTHON_HOME%\Scripts\tox --version'
-test_script:
-  - cmd /E:ON /V:ON /C .\ci\appveyor-with-compiler.cmd %PYTHON_HOME%\Scripts\tox
-on_failure:
-  - ps: dir "env:"
-  - ps: get-content .tox\*\log\*
-
-### To enable remote debugging uncomment this (also, see: http://www.appveyor.com/docs/how-to/rdp-to-build-worker):
-# on_finish:
-#   - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
diff --git a/python/cucim/ci/templates/.travis.yml b/python/cucim/ci/templates/.travis.yml
deleted file mode 100644
index cb15bd09c..000000000
--- a/python/cucim/ci/templates/.travis.yml
+++ /dev/null
@@ -1,47 +0,0 @@
-language: python
-dist: xenial
-cache: false
-env:
-  global:
-    - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
-    - SEGFAULT_SIGNALS=all
-    - LANG=en_US.UTF-8
-matrix:
-  include:
-    - python: '3.6'
-      env:
-        - TOXENV=check
-    - python: '3.6'
-      env:
-        - TOXENV=docs
-{%- for env in tox_environments %}{{ '' }}
-    - env:
-        - TOXENV={{ env }},codecov
-{%- if env.startswith('pypy3') %}{{ '' }}
-        - TOXPYTHON=pypy3
-      python: 'pypy3'
-{%- elif env.startswith('pypy') %}{{ '' }}
-      python: 'pypy'
-{%- else %}{{ '' }}
-      python: '{{ '{0[2]}.{0[3]}'.format(env) }}'
-{%- endif %}{{ '' }}
-{%- endfor %}{{ '' }}
-before_install:
-  - python --version
-  - uname -a
-  - lsb_release -a || true
-install:
-  - python -mpip install --progress-bar=off tox -rci/requirements.txt
-  - virtualenv --version
-  - easy_install --version
-  - pip --version
-  - tox --version
-script:
-  - tox -v
-after_failure:
-  - cat .tox/log/*
-  - cat .tox/*/log/*
-notifications:
-  email:
-    on_success: never
-    on_failure: always
diff --git a/python/cucim/docs/_static/css/custom.css b/python/cucim/docs/_static/css/custom.css
deleted file mode 100644
index 87f612eaf..000000000
--- a/python/cucim/docs/_static/css/custom.css
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-https: //github.com/pandas-dev/pydata-sphinx-theme/blob/master/pydata_sphinx_theme/static/css/theme.css
-https: //pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/customizing.html#customizing-the-css
-*/
-
-/* To fix a bug: `.col-xl-2` and `.bd-toc` conflicts in the following HTML of right navbar in the theme.
-  - `.col-xl-2` has `position: relative`
-  - `.bd-toc` has `position: sticky`
-
-    <div class="d-none d-xl-block col-xl-2 bd-toc">
-
-*/
-div.bd-toc {
-    position: sticky;
-}
-
-/* Set max width of container */
-div.container-xl {
-    max-width: 1400px;
-}
diff --git a/python/cucim/docs/_static/images/RAPIDS_cuCIM.png b/python/cucim/docs/_static/images/RAPIDS_cuCIM.png
deleted file mode 100644
index aa7ed8cdc..000000000
Binary files a/python/cucim/docs/_static/images/RAPIDS_cuCIM.png and /dev/null differ
diff --git a/python/cucim/docs/api_reference/cucim.CuImage.rst b/python/cucim/docs/api_reference/cucim.CuImage.rst
deleted file mode 100644
index e66690f20..000000000
--- a/python/cucim/docs/api_reference/cucim.CuImage.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-cucim.CuImage
--------------
-
-.. autoclass:: cucim.CuImage
-    :members:
diff --git a/python/cucim/docs/api_reference/cucim.clara.filesystem.CuFileDriver.rst b/python/cucim/docs/api_reference/cucim.clara.filesystem.CuFileDriver.rst
deleted file mode 100644
index 9c7e0fa84..000000000
--- a/python/cucim/docs/api_reference/cucim.clara.filesystem.CuFileDriver.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-cucim.clara.filesystem.CuFileDriver
------------------------------------
-
-.. autoclass:: cucim.clara.filesystem.CuFileDriver
-    :members:
diff --git a/python/cucim/docs/api_reference/cucim.clara.filesystem.rst b/python/cucim/docs/api_reference/cucim.clara.filesystem.rst
deleted file mode 100644
index 995fc0860..000000000
--- a/python/cucim/docs/api_reference/cucim.clara.filesystem.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-cucim.clara.filesystem
-----------------------
-
-.. automodule:: cucim.clara.filesystem
-    :members:
diff --git a/python/cucim/docs/api_reference/cucim.clara.io.Device.rst b/python/cucim/docs/api_reference/cucim.clara.io.Device.rst
deleted file mode 100644
index 5e5cd0b3c..000000000
--- a/python/cucim/docs/api_reference/cucim.clara.io.Device.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-cucim.clara.io.Device
----------------------
-
-.. autoclass:: cucim.clara.io.Device
-    :members:
diff --git a/python/cucim/docs/api_reference/cucim.clara.io.rst b/python/cucim/docs/api_reference/cucim.clara.io.rst
deleted file mode 100644
index 230d12541..000000000
--- a/python/cucim/docs/api_reference/cucim.clara.io.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-cucim.clara.io
---------------
-
-.. autoclass:: cucim.clara.io.DeviceType
diff --git a/python/cucim/docs/api_reference/cucim.rst b/python/cucim/docs/api_reference/cucim.rst
deleted file mode 100644
index f67c1fc3a..000000000
--- a/python/cucim/docs/api_reference/cucim.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-cucim
------
-
-.. testsetup::
-
-    from cucim import *
-
-.. automodule:: cucim
-    :members:
diff --git a/python/cucim/docs/api_reference/index.md b/python/cucim/docs/api_reference/index.md
deleted file mode 100644
index 951c37970..000000000
--- a/python/cucim/docs/api_reference/index.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# API Reference
-
-
-```{toctree}
-:glob:
-:hidden:
-
-cucim
-cucim.CuImage
-cucim.clara.io
-cucim.clara.io.Device
-cucim.clara.filesystem
-cucim.clara.filesystem.CuFileDriver
-
-```
-
-## Python API
-
-```{toctree}
-:maxdepth: 2
-
-cucim
-cucim.CuImage
-cucim.clara.io
-cucim.clara.io.Device
-cucim.clara.filesystem
-cucim.clara.filesystem.CuFileDriver
-```
diff --git a/python/cucim/docs/conf.py b/python/cucim/docs/conf.py
deleted file mode 100644
index 0dbe8b296..000000000
--- a/python/cucim/docs/conf.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-import os
-
-# Versioning
-with open("../../../VERSION") as f:
-    version_long = f.readline().strip()
-
-extensions = [
-    "sphinx.ext.autodoc",
-    "sphinx.ext.autosummary",
-    "sphinx.ext.coverage",
-    "sphinx.ext.doctest",
-    "sphinx.ext.extlinks",
-    "sphinx.ext.ifconfig",
-    "sphinx.ext.napoleon",
-    "sphinx.ext.todo",
-    "sphinx.ext.viewcode",
-    "sphinx.ext.intersphinx",
-    "sphinxcontrib.bibtex",
-    "myst_nb",
-    "sphinx_copybutton",
-    "sphinx_togglebutton",
-    "sphinx_panels",
-    "ablog",
-    "sphinxemoji.sphinxemoji",
-]
-# source_suffix = {
-#     '.rst': 'restructuredtext',
-#     '.ipynb': 'myst-nb',
-#     '.myst': 'myst-nb',
-# }
-master_doc = "index"
-project = "cuCIM"
-year = "2020-2021"
-author = "NVIDIA"
-copyright = "{0}, {1}".format(year, author)
-version = release = version_long
-
-pygments_style = "trac"
-templates_path = ["."]
-extlinks = {
-    "issue": ("https://github.com/rapidsai/cucim/issues/%s", "#"),
-    "pr": ("https://github.com/rapidsai/cucim/pull/%s", "PR #"),
-}
-# on_rtd is whether we are on readthedocs.org
-on_rtd = os.environ.get("READTHEDOCS", None) == "True"
-
-if not on_rtd:  # only set the theme if we're building docs locally
-    html_theme = "pydata_sphinx_theme"  # 'sphinx_book_theme'
-    # https://github.com/pandas-dev/pydata-sphinx-theme
-    # https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/index.html
-
-html_use_smartypants = True
-html_last_updated_fmt = "%b %d, %Y"
-html_split_index = False
-# html_sidebars = {
-#     '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'],
-# }
-html_short_title = "%s-%s" % (project, version)
-
-napoleon_use_ivar = True
-napoleon_use_rtype = False
-napoleon_use_param = False
-
-html_show_sourcelink = True
-
-# Options for linkcheck builder
-#
-# Reference
-# : https://www.sphinx-doc.org/en/master/usage/configuration.html?highlight=linkcheck#options-for-the-linkcheck-builder)  # noqa
-linkcheck_ignore = [r"^\/", r"^\.\."]
-
-# Options for sphinx.ext.todo
-# (reference: https://www.sphinx-doc.org/en/master/usage/extensions/todo.html)
-
-todo_include_todos = True
-
-# Options for sphinxemoji.sphinxemoji
-# (reference: https://sphinxemojicodes.readthedocs.io/en/stable/#supported-codes)  # noqa
-
-
-# Options for myst
-# (reference: https://myst-parser.readthedocs.io/en/latest/index.html)
-
-# https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html#markdown-figures  # noqa
-myst_enable_extensions = ["colon_fence"]
-
-# Options for pydata-sphinx-theme
-# (reference: https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/configuring.html)  # noqa
-
-html_static_path = ["_static"]
-html_css_files = [
-    "css/custom.css",
-]
-
-html_theme_options = {
-    "external_links": [
-        {
-            "name": "Submit Issue",
-            "url": "https://github.com/rapidsai/cucim/issues/new/choose",  # noqa
-        }
-    ]
-}
-
-# Options for Sphinx Book Theme
-# (reference: https://github.com/executablebooks/sphinx-book-theme/blob/master/setup.py)  # noqa
-
-# html_theme_options = {
-#     "repository_url": "https://github.com/rapidsai/cucim",
-#     "use_repository_button": True,
-#     "use_issues_button": True,
-#     #"use_edit_page_button": True,
-#     "repository_branch": "dev",
-#     #"path_to_docs": "python/cucim/docs",
-#     "home_page_in_toc": True,
-# }
-
-# Options for myst-nb
-# (reference: https://myst-nb.readthedocs.io/en/latest/)
-
-# Prevent the following error
-#     MyST NB Configuration Error:
-#    `nb_render_priority` not set for builder: doctest
-nb_render_priority = {"doctest": ()}
-
-# Prevent creating jupyter_execute folder in dist
-#  https://myst-nb.readthedocs.io/en/latest/use/execute.html#executing-in-temporary-folders  # noqa
-execution_in_temp = True
-jupyter_execute_notebooks = "off"
diff --git a/python/cucim/docs/development/index.md b/python/cucim/docs/development/index.md
deleted file mode 100644
index 459110d34..000000000
--- a/python/cucim/docs/development/index.md
+++ /dev/null
@@ -1,1 +0,0 @@
-# Development
diff --git a/python/cucim/docs/getting_started/index.md b/python/cucim/docs/getting_started/index.md
deleted file mode 100644
index 5eff46f3f..000000000
--- a/python/cucim/docs/getting_started/index.md
+++ /dev/null
@@ -1,172 +0,0 @@
-# Getting Started
-
-```{toctree}
-:glob:
-:hidden:
-
-../notebooks/Basic_Usage.ipynb
-../notebooks/Accessing_File_with_GDS.ipynb
-../notebooks/File-access_Experiments_on_TIFF.ipynb
-../notebooks/Multi-thread_and_Multi-process_Tests.ipynb
-../notebooks/Working_with_DALI.ipynb
-../notebooks/Working_with_Albumentation.ipynb
-```
-
-## Installation
-
-Please download the latest SDK package (`cuCIM-v23.12.00-linux.tar.gz`).
-
-Untar the downloaded file.
-
-```bash
-mkdir -p cuCIM-v23.12.00
-tar -xzvf cuCIM-v23.12.00-linux.tar.gz -C cuCIM-v23.12.00
-
-cd cuCIM-v23.12.00
-```
-
-## Run command
-
-Executing `./run` command would show you available commands:
-
-```bash
-./run
-```
-```
-USAGE: ./run [command] [arguments]...
-
-Global Arguments
-
-Command List
-    help  ----------------------------  Print detailed description for a given argument (command name)
-  Example
-    download_testdata  ---------------  Download test data from Docker Hub
-    launch_notebooks  ----------------  Launch jupyter notebooks
-  Build
-    build_train  ---------------------  Build Clara Train Docker image with cuCIM (& OpenSlide)
-    build_examples  ------------------  Build cuCIM C++ examples
-```
-
-`./run help <command>` would show you detailed information about the command.
-
-```bash
-./run help build_train
-```
-```
-Build Clara Train Docker image with cuCIM (& OpenSlide)
-
-Build image from docker/Dockerfile-claratrain
-
-Arguments:
-  $1 - docker image name (default:cucim-train)
-```
-
-### download_testdata
-
-It downloads test data from DockerHub (`gigony/svs-testdata:little-big`) and make it available at `notebooks/input` folder.
-
-The folder has the following four files.
-
-- `TUPAC-TR-488.svs`
-- `TUPAC-TR-467.svs`
-- `image.tif`
-- `image2.tif`
-
-#### Test Dataset
-
-`TUPAC-TR-488.svs` and `TUPAC-TR-467.svs` are from the dataset
-of Tumor Proliferation Assessment Challenge 2016 (TUPAC16 | MICCAI Grand Challenge).
-
-- Website: <https://tupac.grand-challenge.org/>
-- Data link: <https://drive.google.com/drive/u/0/folders/0B--ztKW0d17XYlBqOXppQmw0M2M>
-
-#### Converted files
-
-- `image.tif` : 256x256 multi-resolution/tiled TIF conversion of TUPAC-TR-467.svs
-- `image2.tif` : 256x256 multi-resolution/tiled TIF conversion of TUPAC-TR-488.svs
-
-
-### launch_notebooks
-
-It launches a **Jupyter Lab** instance so that the user can experiment with cuCIM.
-
-After executing the command, type a password for the instance and open a web browser to access the instance.
-
-```bash
-./run launch_notebooks
-```
-
-```bash
-...
-Port 10001 would be used...(http://172.26.120.129:10001)
-2021-02-13 01:12:44 $ docker run --runtime nvidia --gpus all -it --rm -v /home/repo/cucim/notebooks:/notebooks -p 10001:10001 cucim-jupyter -c echo -n 'Enter New Password: '; jupyter lab --ServerApp.password="$(python3 -u -c "from jupyter_server.auth import passwd;pw=input();print(passwd(pw));" | egrep 'sha|argon')" --ServerApp.root_dir=/notebooks --allow-root --port=10001 --ip=0.0.0.0 --no-browser
-Enter New Password: <password>
-[I 2021-02-13 01:12:47.981 ServerApp] dask_labextension | extension was successfully linked.
-[I 2021-02-13 01:12:47.981 ServerApp] jupyter_server_proxy | extension was successfully linked.
-...
-```
-
-### build_train
-
-It builds an image from the Clara Deploy SDK image. The image would install other useful python package as well as cu
-CIM wheel file.
-
-`nvcr.io/nvidian/dlmed/clara-train-sdk:v3.1-ga-qa-5` is used and `docker/Dockerfile-claratrain` has the recipe of the image.
-
-You will need to have a permission to access `nvidian/dlmed` group in NGC.
-
-```bash
-./run build_train
-
-docker run -it --rm cucim-train /bin/bash
-```
-
-### build_examples
-
-It builds C++ examples at `examples/cpp` folder by using `cmake` in `cucim-cmake` image that is built in runtime.
-
-After the execution, it would copy built file into `bin` folder and show how to execute it.
-
-```bash
-./run build_examples
-```
-
-```bash
-...
-
-Execute the binary with the following commands:
-  # Set library path
-  export LD_LIBRARY_PATH=/ssd/repo/cucim/dist/install/lib:$LD_LIBRARY_PATH
-  # Execute
-  ./bin/tiff_image notebooks/input/image.tif .
-```
-
-Its execution would show some metadata information and create two files -- `output.ppm` and `output2.ppm`.
-
-`.ppm` file can be viewed by `eog` in Ubuntu.
-```
-$ ./bin/tiff_image notebooks/input/image.tif .
-[Plugin: cucim.kit.cuslide] Loading...
-[Plugin: cucim.kit.cuslide] Loading the dynamic library from: cucim.kit.cuslide@23.12.00.so
-[Plugin: cucim.kit.cuslide] loaded successfully. Version: 0
-Initializing plugin: cucim.kit.cuslide (interfaces: [cucim::io::IImageFormat v0.1]) (impl: cucim.kit.cuslide)
-is_loaded: true
-device: cpu
-metadata: {"key": "value"}
-dims: YXC
-shape: (26420, 19920, 3)
-size('XY'): (19920, 26420)
-channel_names: (R, G, B)
-
-is_loaded: true
-device: cpu
-metadata: {"key": "value"}
-dims: YXC
-shape: (1024, 1024, 3)
-size('XY'): (1024, 1024)
-channel_names: (R, G, B)
-[Plugin: cucim.kit.cuslide] Unloaded.
-
-$ eog output.ppm
-$ eog output2.ppm
-```
diff --git a/python/cucim/docs/index.md b/python/cucim/docs/index.md
deleted file mode 100644
index d78831377..000000000
--- a/python/cucim/docs/index.md
+++ /dev/null
@@ -1,86 +0,0 @@
-<!-- ```{eval-rst}
-:notoc:
-
-``` -->
-
-```{toctree}
-:maxdepth: 3
-:hidden:
-
-getting_started/index
-api_reference/index
-release_notes/index
-roadmap/index
-```
-<!-- user_guide/index
-development/index -->
-
-
-# cuCIM Documentation
-
-Current latest version is [Version 23.12.00](release_notes/v23.12.00.md).
-
-**cuCIM** a toolkit to provide GPU accelerated I/O, image  processing & computer vision primitives for N-Dimensional images with a focus on biomedical imaging.
-
-:::{figure-md} fig-cucim-architecture
-:class: myclass
-
-<img src="_static/images/RAPIDS_cuCIM.png" alt="cuCIM Architecture" class="bg-primary mb-1" width="600px">
-
-RAPIDS cuCIM Architecture
-:::
-
-<!-- .. raw:: html
-   <div> </div> -->
-
-<!-- ```{toctree}
-:maxdepth: 3
-:hidden:
-
-
-reference/index.md
-
-``` -->
-
-<!--
-```{include} readme.md
-```
-
-## Site contents
-
-```{toctree}
-:maxdepth: 2
-:caption: Main docs
-
-jupyter.md
-installation.md
-usage.md
-changelog.md
-Github repository <https://github.com/rapidsai/cucim>
-```
-
-## Reference pages
-
-```{toctree}
-:caption: Reference items
-:maxdepth: 2
-
-reference/index.md
-```
-
-## Development
-
-```{toctree}
-:caption: Development
-:maxdepth: 1
-
-contributing.md
-authors.md
-```
-
-## Indices and tables
-
-* {ref}`genindex`
-* {ref}`modindex`
-* {ref}`search`
- -->
diff --git a/python/cucim/docs/release_notes/index.md b/python/cucim/docs/release_notes/index.md
deleted file mode 100644
index 84183cc4d..000000000
--- a/python/cucim/docs/release_notes/index.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Release Notes
-
-```{toctree}
-:glob:
-:hidden:
-:maxdepth: 2
-
-v0.19.0
-v0.18.3
-v0.18.2
-v0.18.1
-v0.18.0
-v0.3.0
-v0.2.0
-v0.1.1
-v0.1.0
-```
-
-## Version 0.19
-
-```{toctree}
-:maxdepth: 2
-
-v0.19.0
-```
-
-## Version 0.18
-
-```{toctree}
-:maxdepth: 2
-
-v0.18.3
-v0.18.2
-v0.18.1
-v0.18.0
-```
-
-## Version 0.3
-
-```{toctree}
-:maxdepth: 2
-
-v0.3.0
-```
-
-## Version 0.2
-
-```{toctree}
-:maxdepth: 2
-
-v0.2.0
-```
-## Version 0.1
-
-```{toctree}
-:maxdepth: 2
-
-v0.1.1
-v0.1.0
-```
diff --git a/python/cucim/docs/release_notes/v0.1.0.md b/python/cucim/docs/release_notes/v0.1.0.md
deleted file mode 100644
index 0d2f40150..000000000
--- a/python/cucim/docs/release_notes/v0.1.0.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Version 0.1.0 (October 28, 2020)
-
-## What are provided in the package?
-
-- API Documents
-- C++ & Python library packages
-- Example project (using CMake. For C++)
-- Example code in a Jupyter notebook (with a docker image)
-
-## Features
-
-For v1, we have a limited feature focusing on generic tiled/multi-resolution TIFF file format (Jpeg-compressed RGB image).
-
-- Loading part of the image using read_region() API
-- Saving the loaded image in .ppm format (loadable by 'eog' viewer in Ubuntu or PIL library in Python)
-
-## Limitations
-
-- The following feature is not implemented yet
-  - Accessing image data through container() API (in C++) or as a numpy array (using `__array_interface__` in Python)
-- Errors are not handled properly yet (e.g., loading non-existing file would cause a crash)
-- Some metadata (e.g., physical size) is hard-coded for now
-- C++ library is forced to set `_GLIBCXX_USE_CXX11_ABI` to 0 due to [Dual ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html) problem
-  - Will package CXX11 ABI library separately later
diff --git a/python/cucim/docs/release_notes/v0.1.1.md b/python/cucim/docs/release_notes/v0.1.1.md
deleted file mode 100644
index 7ed9b5832..000000000
--- a/python/cucim/docs/release_notes/v0.1.1.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Version 0.1.1 (November 3, 2020)
-
-## What's new?
-
-The following features are implemented.
-- Access image data through `container()` API (in C++) or as a numpy array (using `__array_interface__` in Python)
-  - [Example](../notebooks/Basic_Usage.html#array-interface-support)
-- Remove hard-coded metadata for `resolutions`
-  - [Example](../notebooks/Basic_Usage.html#see-metadata)
-- Sort resolution levels (level 0: the largest resolution) for `CuImage::read_region()` method
-  - Add `TIFF::level_ifd(size_t level_index)` method
-- Pass SWIPAT
-
-## Fixes
-
-- Fix a crash that occurs when opening a non-existing file
-- Fix an error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag
-  - `Quantization table 0x00 was not defined` message can be shown
diff --git a/python/cucim/docs/release_notes/v0.18.0.md b/python/cucim/docs/release_notes/v0.18.0.md
deleted file mode 100644
index f4d16f682..000000000
--- a/python/cucim/docs/release_notes/v0.18.0.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Version 0.18.0 (March 16, 2021)
-
-## What's new?
-
-- The namespace of the project is changed from `cuimage` to `cucim` and project name is now `cuCIM`
-- Support Deflate(zlib) compression in Generic TIFF Format.
-  - [libdeflate](https://github.com/ebiggers/libdeflate) library is used to decode the deflate-compressed data.
diff --git a/python/cucim/docs/release_notes/v0.18.1.md b/python/cucim/docs/release_notes/v0.18.1.md
deleted file mode 100644
index 0a1d15001..000000000
--- a/python/cucim/docs/release_notes/v0.18.1.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Version 0.18.1 (March 17, 2021)
-
-## What's new?
-
-- Disable using cuFile
-  - Remove warning messages when libcufile.so is not available.
-    - `[warning] CuFileDriver cannot be open. Falling back to use POSIX file IO APIs.`
diff --git a/python/cucim/docs/release_notes/v0.18.2.md b/python/cucim/docs/release_notes/v0.18.2.md
deleted file mode 100644
index 44b81fba3..000000000
--- a/python/cucim/docs/release_notes/v0.18.2.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Version 0.18.2 (March 29, 2021)
-
-## What's new?
-
-- Use the white background only for Philips TIFF file.
-  - Generic TIFF file would have the black background by default.
-
-## Fixes
-
-- Fix upside-downed image for TIFF file if the image is not RGB & tiled image with JPEG/Deflate-compressed tiles.
-  - Use slow path if the image is not RGB & tiled image with JPEG/Deflate-compressed tiles.
-    - Show an error message if the out-of-boundary cases are requested with the slow path.
-    - `ValueError: Cannot handle the out-of-boundary cases for a non-RGB image or a non-Jpeg/Deflate-compressed image.`
diff --git a/python/cucim/docs/release_notes/v0.18.3.md b/python/cucim/docs/release_notes/v0.18.3.md
deleted file mode 100644
index c3dead3c1..000000000
--- a/python/cucim/docs/release_notes/v0.18.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Version 0.18.3 (April 16, 2021)
-
-## Fixes
-
-- Fix memory leaks that occur when reading completely out-of-boundary regions.
diff --git a/python/cucim/docs/release_notes/v0.19.0.md b/python/cucim/docs/release_notes/v0.19.0.md
deleted file mode 100644
index 00b2b5083..000000000
--- a/python/cucim/docs/release_notes/v0.19.0.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Version 0.19.0 (April 19, 2021)
-
-## What's new?
-
-- The first release of cuClaraImage + [cupyimg](https://github.com/mritools/cupyimg) as a single project `cuCIM`.
-  - `cucim.skimage` package is added from `cupyimg`.
-  - CuPy (>=9.0.0b3), scipy, scikit-image is required to use cuCIM's scikit-image-compatible API.
diff --git a/python/cucim/docs/release_notes/v0.2.0.md b/python/cucim/docs/release_notes/v0.2.0.md
deleted file mode 100644
index e5817c379..000000000
--- a/python/cucim/docs/release_notes/v0.2.0.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Version 0.2.0 (December 18, 2020)
-
-## What's new?
-
-The following features are implemented.
-- Make it work without CUDA runtime installed
-  - CUDA 11.0 runtime is embedded in the .whl file
-- Develop a wrapper for cufile API
-  - Refer to `Accessing File with GDS` (/notebooks/Accessing_File_with_GDS.html) notebook
-  - Did some experiments on accessing TIFF files (see `File-access Experiments on TIFF File` (/notebooks/File-access_Experiments_on_TIFF.html) notebook)
-- Support loading [Philips TIFF](https://openslide.org/formats/philips/) files
-  - Loading multi-resolution images and associated images (such as 'macro' and 'label') from TIFF Image File Directory (IFD) are available
-    - Please see `Basic Usage` (/notebooks/Basic_Usage.html#associated-images) notebook to know how to access the associated images.
-
-    ```{admonition} Characteristic of Philips TIFF format
-    As specified in [Philips format](https://openslide.org/formats/philips/),
-
-    "slides may omit pixel data for TIFF tiles not in an ROI; this is represented as a TileOffset of 0 and a TileByteCount of 0. When such tiles are downsampled into a tile that does contain pixel data, their contents are rendered as white pixels."
-
-    For the above reason, some Philips TIFF images can actually hold important information (‘tiles that are not ROIs or tissues’) which can expedite pre-processing by discarding unnecessarily tiles. Due to feature parity with Openslide, cuClaraImage also renders such tiles as white pixels. Please let us know and suggest APIs for getting the information if such non-ROI region information is useful to you.
-    ```
-  - The following tasks remain for feature-parity with OpenSlide
-    - Support Philips TIFF associated image from metadata
-    - Expose XML metadata of the Philips TIFF file as JSON
-- Provide an example/plan for the interoperability with DALI
-  - Created a notebook for the feasibility and plan (see `Working with DALI` (/notebooks/Working_with_DALI.html) notebook)
-
-## Fixes/Improvements
-
-- Fix again for the error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag
-  - `ERROR in line 126 while reading JPEG header tables: Not a JPEG file: starts with 0x01 0x00` message can be shown
-- Force-reinstall cucim Python package in the Tox environment whenever `gen_docs` or `gen_docs_dev` command is executed
diff --git a/python/cucim/docs/release_notes/v0.3.0.md b/python/cucim/docs/release_notes/v0.3.0.md
deleted file mode 100644
index bac97083b..000000000
--- a/python/cucim/docs/release_notes/v0.3.0.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# Version 0.3.0 (February 16, 2021)
-
-## What's new?
-
-- A new name and namespace (currently `cuClaraImage` and `cucim`) will be picked in `v0.4.0` once it's finalized
-- Add metadata and associated images for Philips TIFF Format
-  - Support Philips TIFF associated image from XML metadata
-- Expose metadata of the image as JSON
-  - `raw_metadata` property returns the image description of the first IFD in the TIFF image
-  - `resolution_dim_start` property of `CuImage` is removed
-  - `physical_pixel_size` property is renamed to `spacing`
-  - `ndim`/`origin`/`direction`/`coord_sys`/`spacing_units` properties are added
-  - Please see `Basic Usage` (/notebooks/Basic_Usage.html#see-metadata) notebook to know how to access metadata.
-- Support reading out of boundary region
-  - `read_region()` method now accepts a region that is out of the image boundary
-  - `size` parameter accepts values that are up to the size of the highest-resolution image
-  - The out of the boundary area would be filled with the white color
-- Showcase the interoperability with DALI
-  - Please see `Working with DALI` (/notebooks/Working_with_DALI.html) notebook
-
-## Fixes/Improvements
-
-- Fix wrong parameter interpretation (`size` in `read_region()` method). Now only `location` is level-0 based coordinates (using the level-0 reference frame). `size` is output image size. (Thanks `@Behrooz Hashemian`!)
-- Static link with cufile when [libcufile.a is available](https://docs.google.com/document/d/1DQ_T805dlTcDU9bGW32E2ak5InX8iUcNI7Tq_lXAtLc/edit?ts=5f90bc5f) -- Implemented but disabled for now
-- Fix a memory leak for cuslide::tiff::TIFF object (248 bytes) in CuImage class.
-- Fix incorrect method visibility in a plugin file (.so)
-- Replace malloc with better allocator for small-sized memory
-  - Use a custom allocator(pmr) for metadata data
-- Copy data using `std::vector::insert()` instead of `std::vector::push_back()`
-  - Small improvement (when opening TIFF file), but benchmark result showed that time for assigning 50000 tile offset/size (uint64_t) is reduced from 118 us to 8 us
-- Parameterize input library/image for testing
-- Update test input path
-  - Add test data under `test_data/private` : See `test_data/README.md` file.
-- Setup development environment with VSCode (in addition to CLion)
-- Use a VSCode plugin for local test execution
-  - Now it uses `matepek.vscode-catch2-test-adapter` extension
-    - <https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md>
-- Prevent relative path problem of .so with no DT_SONAME
-- Refactoring
-  - Add Development environment for VSCode
-    - Update run script
-    - Add settings for VSCode
-  - Refactor CMakeLists.txt
-    - Add definition `_GLIBCXX_USE_CXX11_ABI=0` to all sub directories
-    - Compile multiple architectures for CUDA Kernels
-  - Parameterize input files for tests
-    - Add `test_data` folder for test data
-    - plugin folder is from `CUCIM_TEST_PLUGIN_PATH` environment variable now (with static plugin name (cucim.kit.cuslide@0.3.0.so))
-  - Move cucim_malloc() to memory_manager.cu
-
-## Limitations
-
-- Some metadata (`origin`/`direction`/`coord_sys`/`spacing`/`spacing_units`) doesn't have correct values for now.
diff --git a/python/cucim/docs/requirements.txt b/python/cucim/docs/requirements.txt
deleted file mode 100644
index f211153ad..000000000
--- a/python/cucim/docs/requirements.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Sphinx==4.5.0
-sphinx-autobuild
-myst-parser
-sphinx-book-theme
-numpy
-matplotlib
-ipywidgets
-pandas
-nbclient
-myst-nb
-sphinx-togglebutton
-sphinx-copybutton
-plotly<5
-sphinxcontrib-bibtex<2.0.0 # https://github.com/executablebooks/jupyter-book/issues/1137
-sphinx-thebe
-sphinx-panels
-ablog
-docutils==0.16 # 0.17 causes error. https://github.com/executablebooks/MyST-Parser/issues/343
-pydata_sphinx_theme
-sphinxemoji
-cupy-cuda110
-scipy
-scikit-image
diff --git a/python/cucim/docs/roadmap/index.md b/python/cucim/docs/roadmap/index.md
deleted file mode 100644
index 7ac8596a0..000000000
--- a/python/cucim/docs/roadmap/index.md
+++ /dev/null
@@ -1,370 +0,0 @@
-# Roadmap
-
-<!-- https://fontawesome.com/icons?d=listing&m=free -->
-<!-- https://getbootstrap.com/docs/4.0/utilities/colors/ -->
-<!-- https://myst-parser.readthedocs.io/en/latest/using/syntax.html -->
-<!-- {fa}`cart-plus,text-info mr-1` -->
-
-```{eval-rst}
-The following list is on the road |:smile:|
-```
-
-## cuCIM
-
-### {fa}`calendar-alt,text-info mr-1` `v0.1`
-
-- {fa}`check,text-success mr-1` Abstract C++ API -- [v0.1.0](../release_notes/v0.1.0.md)
-- {fa}`check,text-success mr-1` Benchmark with openslide (for generic tiff file) : link -- [v0.1.0](../release_notes/v0.1.0.md)
-- {fa}`check,text-success mr-1` Usage with C++ API -- [v0.1.0](../release_notes/v0.1.0.md)
-- {fa}`check,text-success mr-1` Implement Python API -- [v0.1.0](../release_notes/v0.1.0.md)
-- {fa}`check,text-success mr-1` Usage with Python API -- [v0.1.0](../release_notes/v0.1.0.md)
-  1. Setup document/build system
-  1. Package it
-- {fa}`check,text-success mr-1` Sort resolution levels (level 0: the largest resolution) for `CuImage::read_region()` method -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Fix a crash that occurs when opening a non-existing file -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Fix an error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag -- [v0.1.1](../release_notes/v0.1.1.md)
-  - `Quantization table 0x00 was not defined` message can be shown
-- {fa}`check,text-success mr-1` Sort resolution levels (level 0: the largest resolution) for `CuImage::read_region()` method -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Pass SWIPAT -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Ignore link check for relative link with header that starts with `/` or `..` -- [v0.1.1](../release_notes/v0.1.1.md)
-
-### {fa}`calendar-alt,text-info mr-1` `v0.2`
-
-- {fa}`check,text-success mr-1` Make it work with various CUDA versions -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Develop a wrapper for cufile API -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Support loading [Philips TIFF](https://openslide.org/formats/philips/) files
-  - {fa}`check,text-success mr-1` Support Philips TIFF multi-resolution images -- [v0.2.0](../release_notes/v0.2.0.md)
-  - {fa}`check,text-success mr-1` Support Philips TIFF associated image from IFD -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Provide an example/plan for the interoperability with DALI -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Fix again for the error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Force-reinstall cucim Python package in the Tox environment whenever `gen_docs` or `gen_docs_dev` command is executed -- [v0.2.0](../release_notes/v0.2.0.md)
-
-### {fa}`calendar-alt,text-info mr-1` `v0.3`
-
-- {fa}`check,text-success mr-1` Add metadata and associated images for Philips TIFF Format
-  - {fa}`check,text-success mr-1` Support Philips TIFF associated image from XML metadata -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Expose metadata of the image as JSON -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Support reading out of boundary region -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Showcase the interoperability with DALI -- [v0.3.0](../release_notes/v0.3.0.md)
-
-
-### {fa}`calendar-alt,text-info mr-1` `v0.18`
-
-- {fa}`check,text-success mr-1` Support Deflate(zlib)-compressed RGB Tiff Image -- [v0.18.0](../release_notes/v0.18.0.md)
-- {fa}`check,text-success mr-1` Change the namespaces (`cuimage` to `cucim`) -- [v0.18.0](../release_notes/v0.18.0.md)
-
-### {fa}`calendar-alt,text-info mr-1` `v0.19`
-
-- Refactor the cupyimg package to incorporate it in the adaption layer of cuCIM. Change the namespaces
-- Support `__cuda_array_interface__` and DLPack object in Python API
-- Support loading data to CUDA memory
-- Implement cache mechanism for tile-based image formats
-
-### {fa}`calendar-alt,text-info mr-1` `v0.20`
-
-- Make use of nvJPEG to decode TIFF Files
-- Support .svs format with nvJPEG2000
-- Design a plug-in mechanism for developing CUDA based 2D/3D imaging filters
-- Implement a filter (example: Otsu Thresholding)
-- Support loading MHD files
-
-### {fa}`calendar-alt,text-info mr-1` `v0.21`
-
-- Support JPEG, Jpeg 2000, PNG, BMP formats
-- Support MIRAX/3DHISTECH (.mrxs) format
-- Support LEICA (.scn) format
-
-### {fa}`calendar-alt,text-info mr-1` `v0.22`
-
-- Design a CT bone segmentation filter
-- Provide a robust CI/CD system
-- Define KPIs and publish report
-- Update project to use the latest [Carbonite SDK](https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/carb/Framework.html) for supporting plug-in architecture
-
-## TODOs
-
-### Image Format
-
-#### Generic TIFF(.tif)
-
-- {fa}`check,text-success mr-1` Access image data through container() API (in C++) or as a numpy array (using `__array_interface__` in Python) -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Fix a crash that occurs when opening a non-existing file -- [v0.1.1](../release_notes/v0.1.1.md)
-- {fa}`check,text-success mr-1` Fix an error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag -- [v0.1.1](../release_notes/v0.1.1.md)
-  - `Quantization table 0x00 was not defined` message can be shown
-- {fa}`check,text-success mr-1` Fix again for the error that occurs when loading a TIFF image that has `TIFFTAG_JPEGTABLES` tag -- [v0.2.0](../release_notes/v0.2.0.md)
-  - `ERROR in line 126 while reading JPEG header tables: Not a JPEG file: starts with 0x01 0x00` message can be shown
-- {fa}`check,text-success mr-1` Expose metadata of the TIFF file as JSON -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Support reading out of boundary region -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Support Deflate(zlib)-compressed RGB Tiff Image -- [v0.18.0](../release_notes/v0.18.0.md)
-- Implement cache mechanism for tile-based image formats -- [v0.19.1](../release_notes/v0.19.1.md)
-- Use CuFileDriver class for reading files
-- Make use of nvJPEG to decode TIFF Files -- [v0.20.0](../release_notes/v0.20.0.md)
-
-- Remove hard-coded metadata (Fill correct values for `cucim::io::format::ImageMetadataDesc`)
-  - {fa}`check,text-success mr-1` `resolutions` -- [v0.1.1](../release_notes/v0.1.1.md)
-  - `metadata`
-- Check if the `tile_rester` memory is freed by jpeg-turbo or not
-  - {fa}`check,text-success mr-1` `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:365` in `IFD::read_region_tiles_libjpeg()` -- [v0.3.0](../release_notes/v0.3.0.md)
-    - `cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp:123` in `parser_parse` -- [v0.19.1](../release_notes/v0.19.1.md)
-- Fill correct metadata information for `CuImage::read_region()`
-  - `cpp/src/cucim.cpp:417` -- [v0.19.1](../release_notes/v0.19.1.md)
-- Check and use `ifd->samples_per_pixel()` once we can get RGB data instead of RGBA
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:280` in `IFD::read_region_tiles_libjpeg()` -- [v0.19.1](../release_notes/v0.19.1.md)
-- Consider endianness of the .tif file
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:329` in `IFD::read_region_tiles_libjpeg()`
-- Consider tile's depth tag
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:329` in `IFD::read_region_tiles_libjpeg()`
-- Make `file_handle_` object to pointer
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp:50` in `TIFF::TIFF()`
-- Remove assumption of sub-resolution dims to 2
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp:140` in `TIFF::read()`
-
-#### [Philips TIFF](https://openslide.org/formats/philips/) (.tif)
-
-- {fa}`check,text-success mr-1` Support Philips TIFF multi-resolution images -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Support Philips TIFF associated image from IFD -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Support Philips TIFF associated image from XML metadata -- [v0.3.0](../release_notes/v0.3.0.md)
-- {fa}`check,text-success mr-1` Expose XML metadata of the Philips TIFF file as JSON -- [v0.3.0](../release_notes/v0.3.0.md)
-
-#### .mhd
-
-- Support loading MHD files -- [v0.20.0](../release_notes/v0.20.0.md)
-
-#### .svs
-
-- Support .svs format with nvJPEG2000 -- [v0.20.0](../release_notes/v0.20.0.md)
-
-#### .png
-
-- Support .png with [libspng](https://github.com/randy408/libspng/) -- [v0.21.0](../release_notes/v0.21.0.md)
-  - **libspng** is faster than **libpng** (but doesn't support encoding)
-
-#### .jpg
-
-- Support .jpg with libjpeg-turbo and nvJPEG -- [v0.21.0](../release_notes/v0.21.0.md)
-
-#### .jp2/.j2k
-
-- Support .jp2/.j2k files with OpenJpeg and nvJPEG2000 -- [v0.21.0](../release_notes/v0.21.0.md)
-
-#### .bmp
-
-- Support .bmp file natively -- [v0.21.0](../release_notes/v0.21.0.md)
-
-#### .mrxs
-
-- Support MIRAX/3DHISTECH (.mrxs) format -- [v0.21.0](../release_notes/v0.21.0.md)
-
-#### .scn
-
-- Support LEICA (.scn) format -- [v0.21.0](../release_notes/v0.21.0.md)
-
-#### .dcm
-
-- Support DICOM format
-- Support reading segmentation image instead of main pixel array
-  - `examples/cpp/dicom_image/main.cpp:37`
-
-#### .iSyntax
-
-- Support Philips iSyntax format
-  - <https://thepathologist.com/fileadmin/issues/App_Notes/0016-024-app-note-Philips__iSyntax_for_Digital_Pathology.pdf>
-  - <https://www.usa.philips.com/healthcare/sites/pathology/about/sdk>
-
-### Image Filter
-
-#### Basic Filter
-
-- Design a plug-in mechanism for developing CUDA based 2D/3D imaging filters -- [v0.20.0](../release_notes/v0.20.0.md)
-- Implement a filter (example: Otsu Thresholding) -- [v0.20.0](../release_notes/v0.20.0.md)
-
-#### Medical-specific Filter
-
-- Design a CT bone segmentation filter -- [v0.22.0](../release_notes/v0.22.0.md)
-
-### Performance Improvements
-
-- {fa}`check,text-success mr-1` Copy data using `std::vector::insert()` instead of `std::vector::push_back()` -- [v0.3.0](../release_notes/v0.3.0.md)
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:78` in `IFD::IFD()`
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:98` in `IFD::IFD()`
-  - Benchmark result showed that time for assigning 50000 tile offset/size (uint64_t) is reduced from 118 us to 8 us.
-- {fa}`check,text-success mr-1` Replace malloc with better allocator for small-sized memory -- [v0.3.0](../release_notes/v0.3.0.md)
-  - Use a custom allocator(pmr) for metadata data.
-- Try to use `__array_struct__`. Access to array interface could be faster
-  - <https://numpy.org/doc/stable/reference/arrays.interface.html#c-struct-access>
-  - Check the performance difference between python int vs python long later
-  - `python/pybind11/cucim_py.cpp:234` in `get_array_interface()`
-- Check performance
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp:122` in `IFD::read()` : string concatenation
-
-### GPUDirect-Storage (GDS) Support
-
-- {fa}`check,text-success mr-1` Develop a wrapper for cufile API -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Static link with cufile when [libcufile.a is available](https://docs.google.com/document/d/1DQ_T805dlTcDU9bGW32E2ak5InX8iUcNI7Tq_lXAtLc/edit?ts=5f90bc5f) -- [v0.3.0](../release_notes/v0.3.0.md)
-
-### Interoperability
-
-- {fa}`check,text-success mr-1` Provide an example/plan for the interoperability with DALI -- [v0.2.0](../release_notes/v0.2.0.md)
-- {fa}`check,text-success mr-1` Showcase the interoperability with DALI -- [v0.3.0](../release_notes/v0.3.0.md)
-- Support `__cuda_array_interface__` and DLPack object in Python API -- [v0.19.1](../release_notes/v0.19.1.md)
-  - https://docs.cupy.dev/en/stable/reference/interoperability.html#dlpack
-  - https://github.com/pytorch/pytorch/pull/11984
-- Refactor the cupyimg package to incorporate it in the adaption layer of cuCIM. Change the namespaces -- [v0.19.0](../release_notes/v0.19.0.md)
-  - Implement/expose `scikit-image`-like image loading APIs (such as `imread`) and filtering APIs for cuCIM library by using cuCIM's APIs
-- Support DALI's CPU/GPU Tensor: <https://docs.nvidia.com/deeplearning/dali/user-guide/docs/data_types.html#tensor>
-- Support loading data to CUDA memory -- [v0.19.1](../release_notes/v0.19.1.md)
-- Consider adding `to_xxx()` methods in Python API
-  - `examples/python/tiff_image/main.py:125`
-- Support byte-like object for CuImage object so that the following method works -- [v0.19.1](../release_notes/v0.19.1.md)
-    ```python
-    from PIL import Image
-    ...
-    #np_img_arr = np.asarray(region)
-    #Image.fromarray(np_img_arr)
-
-    Image.fromarray(region)
-    # /usr/local/lib/python3.6/dist-packages/PIL/Image.py in frombytes(self, data, decoder_name, *args)
-    #     792         d = _getdecoder(self.mode, decoder_name, args)
-    #     793         d.setimage(self.im)
-    # --> 794         s = d.decode(data)
-    #     795
-    #     796         if s[0] >= 0:
-    # TypeError: a bytes-like object is required, not 'cucim._cucim.CuImage'
-    ```
-- Provide universal cucim adaptors for DALI (for cucim::io::format::IImageFormat and cucim::filter::IImageFilter interfaces)
-- Support pretty display for IPython(Jupyter Notebook)
-  - https://ipython.readthedocs.io/en/stable/config/integrating.html#integrating-your-objects-with-ipython
-
-### Pipeline
-
-- Use app_dp_sample pipeline to convert input image(.svs) of Nuclei segmentation pipeline(app_dp_nuclei) to .tif image
-  - Load .tif file using cuCIM for Nuclei segmentation pipeline
-
-### Python API
-
-- Feature parity with OpenSlide
-- Add context manager for CuImage class (for `close()` method) -- [v0.19.1](../release_notes/v0.19.1.md)
-
-### C++ API
-
-- Design filtering API (which can embrace CuPy/CVCore/CuPyImg/OpenCV/scikit-image/dask-image)
-- Feature parity with OpenSlide
-
-- {fa}`check,text-success mr-1` Sort resolution levels (level 0: the largest resolution) for `CuImage::read_region()` method -- [v0.1.1](../release_notes/v0.1.1.md)
-  - Add `TIFF::level_ifd(size_t level_index)` method
-- {fa}`check,text-success mr-1` Support `metadata` and `raw_metadata` properties/methods -- [v0.3.0](../release_notes/v0.3.0.md)
-  - Implement `CuImage::metadata()` with JSON library (Folly or Modern JSON)
-    - `cpp/src/cucim.cpp:238`
-- `ImageMetadataDesc` struct
-  - {fa}`check,text-success mr-1` `resolution_dim_start` field: Reconsider its use (may not be needed) -- [v0.3.0](../release_notes/v0.3.0.md)
-    - `cpp/include/cucim/io/format/image_format.h:53`
-  - `channel_names` field : `S`, `T`, and other dimension can have names so need to be generalized
-    - `cpp/include/cucim/io/format/image_format.h:51`
-- `numpy_dtype()` method
-  - Consider bfloat16: <https://github.com/dmlc/dlpack/issues/45>
-  - Consider other byte-order (currently, we assume `little-endian`)
-    - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/tiff.cpp:53)
-  - `cpp/include/cucim/memory/dlpack.h:41`
-- `checker_is_valid()` method
-  - Add `buf_size` parameter and implement the method
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/cuslide.cpp:68`
-
-- Consider default case (how to handle -1 index?)
-  - `cpp/src/io/device.cpp` in `Device::Device()`
-- Implement `Device::parse_type()`
-  - `cpp/src/io/device.cpp:81`
-- Implement `Device::validate_device()`
-  - `cpp/src/io/device.cpp:116`
-
-- Check illegal characters for `DimIndices::DimIndices()`
-  - `cpp/src/cucim.cpp:35`
-  - `cpp/src/cucim.cpp:46`
-
-- Implement `detect_format()` method
-  - `cpp/src/cucim.cpp:103`
-- Detect available format for the file path
-  - Also consider if the given file path is folder path (DICOM case)
-  - `cpp/src/cucim.cpp:117` in `CuImage::CuImage()`
-- Implement `CuImage::CuImage(const filesystem::Path& path, const std::string& plugin_name)`
-  - `cpp/src/cucim.cpp:128`
-- Implement `CuImage::dtype()`
-  - Support string conversion like Device class
-  - `cpp/src/cucim.cpp:283`
-
-### Build
-
-- Check if `CMAKE_EXPORT_PACKAGE_REGISTRY` is duplicate and remove it
-  - `cucim/cpp/plugins/cucim.kit.cuslide/CMakeLists.txt:255`
-- Install other dependencies for libtiff so that other compression methods are available
-  - `cucim/Dockerfile:32`
-- {fa}`check,text-success mr-1` Setup development environment with VSCode (in addition to CLion) -- [v0.3.0](../release_notes/v0.3.0.md)
-- Use prebuilt libraries for dependencies
-
-### Test
-
-- {fa}`check,text-success mr-1` Parameterize input library/image -- [v0.3.0](../release_notes/v0.3.0.md)
-  - `/ssd/repo/cucim/cpp/tests/test_read_region.cpp:69` in `Verify read_region`
-  - `/ssd/repo/cucim/cpp/tests/test_cufile.cpp:79` in `Verify libcufile usage`
-- {fa}`check,text-success mr-1` Use a VSCode plugin for local test execution -- [v0.3.0](../release_notes/v0.3.0.md)
-  - `matepek.vscode-catch2-test-adapter` extension
-    - <https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md>
-
-### Platform
-
-- Support Windows (currently only Linux package is available)
-
-### Package & CI/CD
-
-- {fa}`check,text-success mr-1` Make it work with various CUDA versions -- [v0.2.0](../release_notes/v0.2.0.md)
-  - Currently, it is linked to CUDA 11.0 library
-  - Refer to PyTorch's PyPi package
-    - The PyPi package embeds CUDA runtime library.
-    - https://github.com/pytorch/pytorch/issues/47268#issuecomment-721996861
-- Move to Github Project
-- Move `tox` setup from python folder to the project root folder
-- Setup Conda recipe
-- Setup automated test cases
-- Provide a robust CI/CD system -- [v0.22.0](../release_notes/v0.22.0.md)
-- Define KPIs and publish report -- [v0.22.0](../release_notes/v0.22.0.md)
-
-- Add license files to the package
-- Package a separate CXX11 ABI library
-  - Currently, C++ library is forced to set `_GLIBCXX_USE_CXX11_ABI` to 0 due to [Dual ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html) problem
-  - `cpp/CMakeLists.txt:98`
-- Support CPack
-  - `CMakeLists.txt:177`
-
-### Documentation
-
-- {fa}`check,text-success mr-1` Pass SWIPAT -- [v0.1.1](../release_notes/v0.1.1.md)
-- Refine README.md and relevant documents for the project
-- Move Sphinx docs to the project root folder
-- Add C++ API document
-- Add C++ examples to Jupyter Notebook
-  - Can install C++ Kernel: <https://xeus-cling.readthedocs.io/en/latest/installation.html#from-source-with-cmake>
-- {fa}`check,text-success mr-1` Ignore link check for relative link with header that starts with `/` or `..` -- [v0.1.1](../release_notes/v0.1.1.md)
-  - `python/cucim/docs/conf.py:71`
-  - <https://www.sphinx-doc.org/en/master/usage/configuration.html?highlight=linkcheck#options-for-the-linkcheck-builder>
-- {fa}`check,text-success mr-1` Force-reinstall cucim Python package in the Tox environment whenever `gen_docs` or `gen_docs_dev` command is executed -- [v0.2.0](../release_notes/v0.2.0.md)
-  - <https://tox.readthedocs.io/en/latest/config.html>
-- Simplify method signatures in Python API Docs
-  - `cucim._cucim.CuImage` -> `cucim.CuImage`
-- Use new feature to reference a cross-link with header (from v0.13.0 of [myst-parser](https://pypi.org/project/myst-parser/))
-  - <https://github.com/executablebooks/MyST-Parser/issues/149>
-  - <https://myst-parser.readthedocs.io/en/v0.13.5/using/howto.html#automatically-create-targets-for-section-headers>
-  - <https://myst-parser.readthedocs.io/en/v0.13.5/using/syntax-optional.html#auto-generated-header-anchors>
-
-### Plugin-system (Carbonite)
-
-- Update project to use the latest [Carbonite SDK](https://docs.omniverse.nvidia.com/kit/docs/carbonite/latest/docs/carb/Framework.html) for supporting plug-in architecture -- [v0.22.0](../release_notes/v0.22.0.md)
-  - Migrate to use Carbonite SDK as it is
-  - Update to use Minimal Carbonite SDK
-
-- Handle errors and log error message once switched to use Carbonite SDK's built-in error routine
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp` : when reading field info
-  - `cpp/plugins/cucim.kit.cuslide/src/cuslide/tiff/ifd.cpp` in `IFD::read()` : memory size check if `out_buf->data` has high-enough memory
-- Get plugin name from file_path
-  - `cpp/src/core/cucim_plugin.cpp:53` in `Plugin::Plugin()`
-- Generalize `CuImage::ensure_init()`
-  - 'LINUX' path separator is used. Need to make it generalize once filesystem library is available
-  - `cucim/cpp/src/cucim.cpp:520`
diff --git a/python/cucim/docs/spelling_wordlist.txt b/python/cucim/docs/spelling_wordlist.txt
deleted file mode 100644
index f95eb78d8..000000000
--- a/python/cucim/docs/spelling_wordlist.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-builtin
-builtins
-classmethod
-staticmethod
-classmethods
-staticmethods
-args
-kwargs
-callstack
-Changelog
-Indices
diff --git a/python/cucim/docs/user_guide/index.md b/python/cucim/docs/user_guide/index.md
deleted file mode 100644
index cd3d45227..000000000
--- a/python/cucim/docs/user_guide/index.md
+++ /dev/null
@@ -1,1 +0,0 @@
-# User Guide
diff --git a/python/cucim/pyproject.toml b/python/cucim/pyproject.toml
index ce9dc87e5..3d4aa443c 100644
--- a/python/cucim/pyproject.toml
+++ b/python/cucim/pyproject.toml
@@ -22,12 +22,12 @@ authors = [
     { name = "NVIDIA Corporation" },
 ]
 license = { text = "Apache 2.0" }
-requires-python = ">=3.8"
+requires-python = ">=3.9"
 dependencies = [
     "cupy-cuda11x>=12.0.0",
     "lazy_loader>=0.1",
     "numpy",
-    "scikit-image>=0.19.0,<0.22.0a0",
+    "scikit-image>=0.19.0,<0.23.0a0",
     "scipy",
 ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.
 classifiers = [
@@ -39,22 +39,18 @@ classifiers = [
     "Topic :: Scientific/Engineering",
     "Operating System :: POSIX :: Linux",
     "Environment :: Console",
-    "Environment :: GPU :: NVIDIA CUDA :: 11.0",
-    "Environment :: GPU :: NVIDIA CUDA :: 12.0",
+    "Environment :: GPU :: NVIDIA CUDA :: 11",
+    "Environment :: GPU :: NVIDIA CUDA :: 12",
     "License :: OSI Approved :: Apache Software License",
     "Programming Language :: C++",
     "Programming Language :: Python",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-    "Programming Language :: Python :: 3.11",
 ]
 
 [project.urls]
 Homepage = "https://developer.nvidia.com/multidimensional-image-processing"
 Documentation = "https://docs.rapids.ai/api/cucim/stable/"
-Changelog = "https://github.com/rapidsai/cucim/blob/branch-23.12/CHANGELOG.md"
+Changelog = "https://github.com/rapidsai/cucim/blob/branch-24.02/CHANGELOG.md"
 Source = "https://github.com/rapidsai/cucim"
 Tracker = "https://github.com/rapidsai/cucim/issues"
 
@@ -62,14 +58,18 @@ Tracker = "https://github.com/rapidsai/cucim/issues"
 test = [
     "GPUtil>=1.4.0",
     "click",
+    "imagecodecs>=2021.6.8; platform_machine=='x86_64'",
     "matplotlib",
+    "numpydoc>=1.5",
     "opencv-python-headless>=4.6",
+    "openslide-python>=1.3.0; platform_machine=='x86_64'",
     "pooch>=1.6.0",
     "psutil>=5.8.0",
     "pytest-cov>=2.12.1",
     "pytest-lazy-fixture>=0.6.3",
     "pytest-xdist",
-    "pytest>=6.2.4",
+    "pytest>=6.2.4,<8.0.0a0",
+    "pywavelets>=1.0",
     "tifffile>=2022.7.28",
 ] # This list was generated by `rapids-dependency-file-generator`. To make changes, edit ../../dependencies.yaml and run `rapids-dependency-file-generator`.
 developer = [
@@ -81,7 +81,7 @@ developer = [
 docs = [
     "ipython",
     "nbsphinx",
-    "numpydoc",
+    "numpydoc>=1.5",
     "pydata-sphinx-theme",
     "recommonmark",
     "sphinx<6",
diff --git a/python/cucim/src/cucim/py.typed b/python/cucim/src/cucim/py.typed
new file mode 100644
index 000000000..e69de29bb
diff --git a/python/cucim/src/cucim/skimage/_shared/filters.py b/python/cucim/src/cucim/skimage/_shared/filters.py
index 2892050d5..fe4c000ec 100644
--- a/python/cucim/src/cucim/skimage/_shared/filters.py
+++ b/python/cucim/src/cucim/skimage/_shared/filters.py
@@ -10,26 +10,7 @@
 
 import cucim.skimage._vendored.ndimage as ndi
 
-from .._shared.utils import _supported_float_type, convert_to_float, warn
-
-
-class _PatchClassRepr(type):
-    """Control class representations in rendered signatures."""
-
-    def __repr__(cls):
-        return f"<{cls.__name__}>"
-
-
-class ChannelAxisNotSet(metaclass=_PatchClassRepr):
-    """Signal that the `channel_axis` parameter is not set.
-    This is a proxy object, used to signal to `skimage.filters.gaussian` that
-    the `channel_axis` parameter has not been set, in which case the function
-    will determine whether a color channel is present. We cannot use ``None``
-    for this purpose as it has its own meaning which indicates that the given
-    image is grayscale.
-    This automatic behavior was broken in v0.19, recovered but deprecated in
-    v0.20 and will be removed in v0.21.
-    """
+from .._shared.utils import _supported_float_type, convert_to_float
 
 
 def gaussian(
@@ -41,7 +22,7 @@ def gaussian(
     preserve_range=False,
     truncate=4.0,
     *,
-    channel_axis=ChannelAxisNotSet,
+    channel_axis=None,
 ):
     """Multi-dimensional Gaussian filter.
 
@@ -77,12 +58,10 @@ def gaussian(
         to channels.
 
         .. warning::
-            Automatic detection of the color channel based on the old deprecated
-            ``multichannel=None`` was broken in version 0.19. In 0.20 this
-            behavior is recovered. The last axis of an `image` with dimensions
-            (M, N, 3) is interpreted as a color channel if `channel_axis` is
-            not set. Starting with release 23.04.02, ``channel_axis=None`` will
-            be used as the new default value.
+            In versions prior to 24.02, the last axis of an `image` with
+            dimensions (M, N, 3) was interpreted as a color channel if
+            `channel_axis` was not set. Starting with release 24.02,
+            ``channel_axis=None`` will be used as the new default value.
 
     Returns
     -------
@@ -133,21 +112,7 @@ def gaussian(
     >>> from skimage.data import astronaut
     >>> image = cp.array(astronaut())
     >>> filtered_img = gaussian(image, sigma=1, channel_axis=-1)
-
     """
-    if channel_axis is ChannelAxisNotSet:
-        if image.ndim == 3 and image.shape[-1] == 3:
-            warn(
-                "Automatic detection of the color channel was deprecated in "
-                "v0.19, and `channel_axis=None` will be the new default in "
-                "v0.21. Set `channel_axis=-1` explicitly to silence this "
-                "warning.",
-                FutureWarning,
-                stacklevel=2,
-            )
-            channel_axis = -1
-        else:
-            channel_axis = None
 
     # CuPy Backend: refactor to avoid overhead of cp.any(cp.asarray(sigma))
     sigma_msg = "Sigma values less than zero are not valid"
diff --git a/python/cucim/src/cucim/skimage/_vendored/_internal.py b/python/cucim/src/cucim/skimage/_vendored/_internal.py
index 9ac4cef9a..f87e07744 100644
--- a/python/cucim/src/cucim/skimage/_vendored/_internal.py
+++ b/python/cucim/src/cucim/skimage/_vendored/_internal.py
@@ -3,7 +3,14 @@
 from operator import mul
 
 import cupy
-import numpy
+
+# TODO: when minimum numpy dependency is 1.25 use:
+# np.exceptions.AxisError instead of AxisError
+# and remove this try-except
+try:
+    from numpy import AxisError
+except ImportError:
+    from numpy.exceptions import AxisError
 
 try:
     # try importing Cython-based private axis handling functions from CuPy
@@ -37,7 +44,7 @@ def _normalize_axis_index(axis, ndim):  # NOQA
         if axis < 0:
             axis += ndim
         if not (0 <= axis < ndim):
-            raise numpy.AxisError("axis out of bounds")
+            raise AxisError("axis out of bounds")
         return axis
 
     def _normalize_axis_indices(axes, ndim):  # NOQA
diff --git a/python/cucim/src/cucim/skimage/_vendored/_ndimage_filters_core.py b/python/cucim/src/cucim/skimage/_vendored/_ndimage_filters_core.py
index e1c8ade57..13cccd6b7 100644
--- a/python/cucim/src/cucim/skimage/_vendored/_ndimage_filters_core.py
+++ b/python/cucim/src/cucim/skimage/_vendored/_ndimage_filters_core.py
@@ -190,7 +190,6 @@ def _call_kernel(
 
 template<> struct std::is_floating_point<float16> : std::true_type {};
 template<> struct std::is_signed<float16> : std::true_type {};
-template<class T> struct std::is_signed<complex<T>> : std::is_signed<T> {};
 """
 
 
diff --git a/python/cucim/src/cucim/skimage/color/colorconv.py b/python/cucim/src/cucim/skimage/color/colorconv.py
index 0b18aa910..89eeffabb 100644
--- a/python/cucim/src/cucim/skimage/color/colorconv.py
+++ b/python/cucim/src/cucim/skimage/color/colorconv.py
@@ -63,6 +63,14 @@
 )
 from ..util import dtype, dtype_limits
 
+# TODO: when minimum numpy dependency is 1.25 use:
+# np.exceptions.AxisError instead of AxisError
+# and remove this try-except
+try:
+    from numpy import AxisError
+except ImportError:
+    from numpy.exceptions import AxisError
+
 
 def convert_colorspace(arr, fromspace, tospace, *, channel_axis=-1):
     """Convert an image array to a new color space.
@@ -173,7 +181,7 @@ def _validate_channel_axis(channel_axis, ndim):
     if not isinstance(channel_axis, int):
         raise TypeError("channel_axis must be an integer")
     if channel_axis < -ndim or channel_axis >= ndim:
-        raise np.AxisError("channel_axis exceeds array dimensions")
+        raise AxisError("channel_axis exceeds array dimensions")
 
 
 @cp.memoize(for_each_device=True)
diff --git a/python/cucim/src/cucim/skimage/feature/__init__.py b/python/cucim/src/cucim/skimage/feature/__init__.py
index 04b53fbfc..62d86f776 100644
--- a/python/cucim/src/cucim/skimage/feature/__init__.py
+++ b/python/cucim/src/cucim/skimage/feature/__init__.py
@@ -1,48 +1,3 @@
-from ._basic_features import multiscale_basic_features
-from ._canny import canny
-from ._daisy import daisy
-from .blob import blob_dog, blob_doh, blob_log
-from .corner import (
-    corner_foerstner,
-    corner_harris,
-    corner_kitchen_rosenfeld,
-    corner_peaks,
-    corner_shi_tomasi,
-    hessian_matrix,
-    hessian_matrix_det,
-    hessian_matrix_eigvals,
-    shape_index,
-    structure_tensor,
-    structure_tensor_eigenvalues,
-)
-from .match import match_descriptors
-from .peak import peak_local_max
-from .template import match_template
+import lazy_loader as lazy
 
-__all__ = [
-    "canny",
-    "daisy",
-    "multiscale_basic_features",
-    "peak_local_max",
-    "structure_tensor",
-    "structure_tensor_eigenvalues",
-    "structure_tensor_eigvals",
-    "hessian_matrix",
-    "hessian_matrix_det",
-    "hessian_matrix_eigvals",
-    "shape_index",
-    "corner_kitchen_rosenfeld",
-    "corner_harris",
-    "corner_shi_tomasi",
-    "corner_foerstner",
-    # 'corner_subpix',
-    "corner_peaks",
-    # 'corner_moravec',
-    # 'corner_fast',
-    # 'corner_orientations',
-    "match_template",
-    "match_descriptors",
-    "blob_dog",
-    "blob_log",
-    "blob_doh",
-]
+__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
diff --git a/python/cucim/src/cucim/skimage/feature/__init__.pyi b/python/cucim/src/cucim/skimage/feature/__init__.pyi
new file mode 100644
index 000000000..22519324e
--- /dev/null
+++ b/python/cucim/src/cucim/skimage/feature/__init__.pyi
@@ -0,0 +1,47 @@
+# Explicitly setting `__all__` is necessary for type inference engines
+# to know which symbols are exported. See
+# https://peps.python.org/pep-0484/#stub-files
+
+__all__ = [
+    "canny",
+    "daisy",
+    "peak_local_max",
+    "structure_tensor",
+    "structure_tensor_eigenvalues",
+    "hessian_matrix",
+    "hessian_matrix_det",
+    "hessian_matrix_eigvals",
+    "shape_index",
+    "corner_kitchen_rosenfeld",
+    "corner_harris",
+    "corner_shi_tomasi",
+    "corner_foerstner",
+    "corner_peaks",
+    "match_template",
+    "match_descriptors",
+    "blob_dog",
+    "blob_doh",
+    "blob_log",
+    "multiscale_basic_features",
+]
+
+from ._basic_features import multiscale_basic_features
+from ._canny import canny
+from ._daisy import daisy
+from .blob import blob_dog, blob_doh, blob_log
+from .corner import (
+    corner_foerstner,
+    corner_harris,
+    corner_kitchen_rosenfeld,
+    corner_peaks,
+    corner_shi_tomasi,
+    hessian_matrix,
+    hessian_matrix_det,
+    hessian_matrix_eigvals,
+    shape_index,
+    structure_tensor,
+    structure_tensor_eigenvalues,
+)
+from .match import match_descriptors
+from .peak import peak_local_max
+from .template import match_template
diff --git a/python/cucim/src/cucim/skimage/feature/peak.py b/python/cucim/src/cucim/skimage/feature/peak.py
index 84965b328..58e0f1899 100644
--- a/python/cucim/src/cucim/skimage/feature/peak.py
+++ b/python/cucim/src/cucim/skimage/feature/peak.py
@@ -23,7 +23,7 @@ def _get_high_intensity_peaks(image, mask, num_peaks, min_distance, p_norm):
     coord = cp.nonzero(mask)
     intensities = image[coord]
     # Highest peak first
-    idx_maxsort = cp.argsort(-intensities)
+    idx_maxsort = cp.argsort(-intensities, kind="stable")
     coord = cp.column_stack(coord)[idx_maxsort]
 
     if np.isfinite(num_peaks):
diff --git a/python/cucim/src/cucim/skimage/filters/ridges.py b/python/cucim/src/cucim/skimage/filters/ridges.py
index 0a929641e..34bd008d3 100644
--- a/python/cucim/src/cucim/skimage/filters/ridges.py
+++ b/python/cucim/src/cucim/skimage/filters/ridges.py
@@ -58,7 +58,7 @@ def meijering(
     wrinkles, rivers. It can be used to calculate the fraction of the
     whole image containing such objects.
 
-    Calculates the eigenvectors of the Hessian to compute the similarity of
+    Calculates the eigenvalues of the Hessian to compute the similarity of
     an image region to neurites, according to the method described in [1]_.
 
     Parameters
@@ -151,7 +151,7 @@ def sato(
     wrinkles, rivers. It can be used to calculate the fraction of the
     whole image containing such objects.
 
-    Defined only for 2-D and 3-D images. Calculates the eigenvectors of the
+    Defined only for 2-D and 3-D images. Calculates the eigenvalues of the
     Hessian to compute the similarity of an image region to tubes, according to
     the method described in [1]_.
 
@@ -334,7 +334,7 @@ def frangi(
     wrinkles, rivers. It can be used to calculate the fraction of the
     whole image containing such objects.
 
-    Defined only for 2-D and 3-D images. Calculates the eigenvectors of the
+    Defined only for 2-D and 3-D images. Calculates the eigenvalues of the
     Hessian to compute the similarity of an image region to vessels, according
     to the method described in [1]_.
 
diff --git a/python/cucim/src/cucim/skimage/filters/thresholding.py b/python/cucim/src/cucim/skimage/filters/thresholding.py
index 53e8b8d55..76127e52a 100644
--- a/python/cucim/src/cucim/skimage/filters/thresholding.py
+++ b/python/cucim/src/cucim/skimage/filters/thresholding.py
@@ -902,6 +902,8 @@ def threshold_triangle(image, nbins=256):
 
     Examples
     --------
+    >>> import cupy as cp
+    >>> from cucim.skimage.filters import threshold_triangle
     >>> from skimage.data import camera
     >>> image = cp.array(camera())
     >>> thresh = threshold_triangle(image)
@@ -910,12 +912,25 @@ def threshold_triangle(image, nbins=256):
     # nbins is ignored for integer arrays
     # so, we recalculate the effective nbins.
     hist, bin_centers = histogram(image.ravel(), nbins, source_range="image")
-    nbins = len(hist)
+    if hist.size == 1:
+        # integer-valued image with constant intensity will have just 1 bin
+        return image.ravel()[0]
 
+    # In most cases, nbins is small so it is better to process hist on the CPU
+    if nbins > 100000:
+        xp = cp
+    else:
+        xp = np
+        hist = cp.asnumpy(hist)
+
+    nbins = len(hist)
     # Find peak, lowest and highest gray levels.
-    arg_peak_height = cp.argmax(hist)
+    arg_peak_height = xp.argmax(hist)
+    arg_low_level, arg_high_level = xp.flatnonzero(hist)[[0, -1]]
+    if arg_low_level == arg_high_level:
+        # Image has constant intensity.
+        return image.ravel()[0]
     peak_height = hist[arg_peak_height]
-    arg_low_level, arg_high_level = cp.flatnonzero(hist)[[0, -1]]
 
     # Flip is True if left tail is shorter.
     flip = arg_peak_height - arg_low_level < arg_high_level - arg_peak_height
@@ -930,11 +945,11 @@ def threshold_triangle(image, nbins=256):
 
     # Set up the coordinate system.
     width = arg_peak_height - arg_low_level
-    x1 = cp.arange(width)
+    x1 = xp.arange(width)
     y1 = hist[x1 + arg_low_level]
 
     # Normalize.
-    norm = cp.sqrt(peak_height**2 + width**2)
+    norm = xp.sqrt(peak_height**2 + width**2)
     try:
         peak_height /= norm
         width /= norm
@@ -952,7 +967,7 @@ def threshold_triangle(image, nbins=256):
     # the length, but here we omit it as it does not affect the location of the
     # minimum.
     length = peak_height * x1 - width * y1
-    arg_level = cp.argmax(length) + arg_low_level
+    arg_level = xp.argmax(length) + arg_low_level
 
     if flip:
         arg_level = nbins - arg_level - 1
diff --git a/python/cucim/src/cucim/skimage/measure/__init__.py b/python/cucim/src/cucim/skimage/measure/__init__.py
index 4f32c7980..62d86f776 100644
--- a/python/cucim/src/cucim/skimage/measure/__init__.py
+++ b/python/cucim/src/cucim/skimage/measure/__init__.py
@@ -1,56 +1,3 @@
-from ._blur_effect import blur_effect
-from ._colocalization import (
-    intersection_coeff,
-    manders_coloc_coeff,
-    manders_overlap_coeff,
-    pearson_corr_coeff,
-)
-from ._label import label
-from ._moments import (
-    centroid,
-    inertia_tensor,
-    inertia_tensor_eigvals,
-    moments,
-    moments_central,
-    moments_coords,
-    moments_coords_central,
-    moments_hu,
-    moments_normalized,
-)
-from ._polygon import approximate_polygon, subdivide_polygon
-from ._regionprops import (
-    euler_number,
-    perimeter,
-    perimeter_crofton,
-    regionprops,
-    regionprops_table,
-)
-from .block import block_reduce
-from .entropy import shannon_entropy
-from .profile import profile_line
+import lazy_loader as lazy
 
-__all__ = [
-    "blur_effect",
-    "regionprops",
-    "regionprops_table",
-    "perimeter",
-    "approximate_polygon",
-    "subdivide_polygon",
-    "block_reduce",
-    "centroid",
-    "moments",
-    "moments_central",
-    "moments_coords",
-    "moments_coords_central",
-    "moments_normalized",
-    "moments_hu",
-    "inertia_tensor",
-    "inertia_tensor_eigvals",
-    "profile_line",
-    "label",
-    "shannon_entropy",
-    "intersection_coeff",
-    "manders_coloc_coeff",
-    "manders_overlap_coeff",
-    "pearson_corr_coeff",
-]
+__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
diff --git a/python/cucim/src/cucim/skimage/measure/__init__.pyi b/python/cucim/src/cucim/skimage/measure/__init__.pyi
new file mode 100644
index 000000000..4ae693f16
--- /dev/null
+++ b/python/cucim/src/cucim/skimage/measure/__init__.pyi
@@ -0,0 +1,62 @@
+# Explicitly setting `__all__` is necessary for type inference engines
+# to know which symbols are exported. See
+# https://peps.python.org/pep-0484/#stub-files
+
+__all__ = [
+    "regionprops",
+    "regionprops_table",
+    "perimeter",
+    "perimeter_crofton",
+    "euler_number",
+    "approximate_polygon",
+    "subdivide_polygon",
+    "block_reduce",
+    "centroid",
+    "moments",
+    "moments_central",
+    "moments_coords",
+    "moments_coords_central",
+    "moments_normalized",
+    "moments_hu",
+    "inertia_tensor",
+    "inertia_tensor_eigvals",
+    "profile_line",
+    "label",
+    "shannon_entropy",
+    "blur_effect",
+    "pearson_corr_coeff",
+    "manders_coloc_coeff",
+    "manders_overlap_coeff",
+    "intersection_coeff",
+]
+
+from ._blur_effect import blur_effect
+from ._colocalization import (
+    intersection_coeff,
+    manders_coloc_coeff,
+    manders_overlap_coeff,
+    pearson_corr_coeff,
+)
+from ._label import label
+from ._moments import (
+    centroid,
+    inertia_tensor,
+    inertia_tensor_eigvals,
+    moments,
+    moments_central,
+    moments_coords,
+    moments_coords_central,
+    moments_hu,
+    moments_normalized,
+)
+from ._polygon import approximate_polygon, subdivide_polygon
+from ._regionprops import (
+    euler_number,
+    perimeter,
+    perimeter_crofton,
+    regionprops,
+    regionprops_table,
+)
+from .block import block_reduce
+from .entropy import shannon_entropy
+from .profile import profile_line
diff --git a/python/cucim/src/cucim/skimage/measure/_blur_effect.py b/python/cucim/src/cucim/skimage/measure/_blur_effect.py
index e3ba81d1f..6fc77774c 100644
--- a/python/cucim/src/cucim/skimage/measure/_blur_effect.py
+++ b/python/cucim/src/cucim/skimage/measure/_blur_effect.py
@@ -5,6 +5,14 @@
 from ..color import rgb2gray
 from ..util import img_as_float
 
+# TODO: when minimum numpy dependency is 1.25 use:
+# np.exceptions.AxisError instead of AxisError
+# and remove this try-except
+try:
+    from numpy import AxisError
+except ImportError:
+    from numpy.exceptions import AxisError
+
 __all__ = ["blur_effect"]
 
 
@@ -56,7 +64,7 @@ def blur_effect(image, h_size=11, channel_axis=None, reduce_func=max):
         try:
             # ensure color channels are in the final dimension
             image = cp.moveaxis(image, channel_axis, -1)
-        except cp.AxisError:
+        except AxisError:
             print("channel_axis must be one of the image array dimensions")
             raise
         except TypeError:
diff --git a/python/cucim/src/cucim/skimage/measure/_regionprops.py b/python/cucim/src/cucim/skimage/measure/_regionprops.py
index fb1da9dfa..6246798ee 100644
--- a/python/cucim/src/cucim/skimage/measure/_regionprops.py
+++ b/python/cucim/src/cucim/skimage/measure/_regionprops.py
@@ -34,6 +34,7 @@
     "ConvexImage": "image_convex",
     "convex_image": "image_convex",
     "Coordinates": "coords",
+    "coords_scaled": "coords_scaled",
     "Eccentricity": "eccentricity",
     "EquivDiameter": "equivalent_diameter_area",
     "equivalent_diameter": "equivalent_diameter_area",
@@ -67,6 +68,7 @@
     "minor_axis_length": "axis_minor_length",
     "Moments": "moments",
     "NormalizedMoments": "moments_normalized",
+    "num_pixels": "num_pixels",
     "Orientation": "orientation",
     "Perimeter": "perimeter",
     "CroftonPerimeter": "perimeter_crofton",
@@ -102,6 +104,7 @@
     "centroid_weighted": float,
     "centroid_weighted_local": float,
     "coords": object,
+    "coords_scaled": object,
     "eccentricity": float,
     "equivalent_diameter_area": float,
     "euler_number": int,
@@ -125,6 +128,7 @@
     "moments_weighted_central": float,
     "moments_weighted_hu": float,
     "moments_weighted_normalized": float,
+    "num_pixels": int,
     "orientation": float,
     "perimeter": float,
     "perimeter_crofton": float,
@@ -192,18 +196,18 @@ def _infer_regionprop_dtype(func, *, intensity, ndim):
     dtype : NumPy data type
         The data type of the returned property.
     """
-    labels = [1, 2]
-    sample = cp.zeros((3,) * ndim, dtype=np.intp)
-    sample[(0,) * ndim] = labels[0]
-    sample[(slice(1, None),) * ndim] = labels[1]
-    propmasks = [(sample == n) for n in labels]
+    mask_1 = np.ones((1,) * ndim, dtype=bool)
+    mask_1 = np.pad(mask_1, (0, 1), constant_values=False)
+    mask_2 = np.ones((2,) * ndim, dtype=bool)
+    mask_2 = np.pad(mask_2, (1, 0), constant_values=False)
+    propmasks = [cp.array(mask_1), cp.array(mask_2)]
 
     rng = cp.random.default_rng()
 
     if intensity and _infer_number_of_required_args(func) == 2:
 
         def _func(mask):
-            return func(mask, rng.random(sample.shape))
+            return func(mask, rng.random(mask.shape))
 
     else:
         _func = func
@@ -921,7 +925,7 @@ def _props_to_dict(regions, properties=("label", "bbox"), separator="-"):
             or prop in OBJECT_COLUMNS
             or dtype is np.object_
         ):
-            if prop in OBJECT_COLUMNS:
+            if prop in OBJECT_COLUMNS or dtype is np.object_:
                 # keep objects in a NumPy array
                 column_buffer = np.empty(n, dtype=dtype)
                 for i in range(n):
diff --git a/python/cucim/src/cucim/skimage/measure/block.py b/python/cucim/src/cucim/skimage/measure/block.py
index db8cbfeac..4c3c8dc8c 100644
--- a/python/cucim/src/cucim/skimage/measure/block.py
+++ b/python/cucim/src/cucim/skimage/measure/block.py
@@ -89,9 +89,10 @@ def block_reduce(image, block_size=2, func=cp.sum, cval=0, func_kwargs=None):
             after_width = 0
         pad_width.append((0, after_width))
 
-    image = pad(
-        image, pad_width=pad_width, mode="constant", constant_values=cval
-    )
+    if any(after_width > 0 for _, after_width in pad_width):
+        image = pad(
+            image, pad_width=pad_width, mode="constant", constant_values=cval
+        )
 
     blocked = view_as_blocks(image, block_size)
 
diff --git a/python/cucim/src/cucim/skimage/morphology/__init__.py b/python/cucim/src/cucim/skimage/morphology/__init__.py
index 2c3cbf114..eedc0bc77 100644
--- a/python/cucim/src/cucim/skimage/morphology/__init__.py
+++ b/python/cucim/src/cucim/skimage/morphology/__init__.py
@@ -1,3 +1,11 @@
+"""Utilities that operate on shapes in images.
+
+These operations are particularly suited for binary images,
+although some may be useful for images of other types as well.
+
+Basic morphological operations include dilation and erosion.
+"""
+
 from ._skeletonize import medial_axis, thin
 from .binary import (
     binary_closing,
diff --git a/python/cucim/src/cucim/skimage/registration/__init__.py b/python/cucim/src/cucim/skimage/registration/__init__.py
index 5734f266f..62d86f776 100644
--- a/python/cucim/src/cucim/skimage/registration/__init__.py
+++ b/python/cucim/src/cucim/skimage/registration/__init__.py
@@ -1,4 +1,3 @@
-from ._optical_flow import optical_flow_ilk, optical_flow_tvl1  # noqa
-from ._phase_cross_correlation import phase_cross_correlation  # noqa
+import lazy_loader as lazy
 
-__all__ = ["optical_flow_ilk", "optical_flow_tvl1", "phase_cross_correlation"]
+__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
diff --git a/python/cucim/src/cucim/skimage/registration/__init__.pyi b/python/cucim/src/cucim/skimage/registration/__init__.pyi
new file mode 100644
index 000000000..e6992c41e
--- /dev/null
+++ b/python/cucim/src/cucim/skimage/registration/__init__.pyi
@@ -0,0 +1,8 @@
+# Explicitly setting `__all__` is necessary for type inference engines
+# to know which symbols are exported. See
+# https://peps.python.org/pep-0484/#stub-files
+
+__all__ = ["optical_flow_ilk", "optical_flow_tvl1", "phase_cross_correlation"]
+
+from ._optical_flow import optical_flow_ilk, optical_flow_tvl1
+from ._phase_cross_correlation import phase_cross_correlation
diff --git a/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py b/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py
index 4fcc497a0..ba5b8935e 100644
--- a/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py
+++ b/python/cucim/src/cucim/skimage/registration/_phase_cross_correlation.py
@@ -5,13 +5,13 @@
 
 import itertools
 import math
-import warnings
 
 import cupy as cp
 import cupyx.scipy.ndimage as ndi
 import numpy as np
 
 from .._shared.fft import fftmodule as fft
+from .._shared.utils import remove_arg
 from ._masked_phase_cross_correlation import _masked_phase_cross_correlation
 
 
@@ -188,6 +188,7 @@ def _disambiguate_shift(reference_image, moving_image, shift):
     return real_shift
 
 
+@remove_arg("return_error", changed_version="24.06")
 def phase_cross_correlation(
     reference_image,
     moving_image,
@@ -234,10 +235,6 @@ def phase_cross_correlation(
         this parameter is set to ``True``, the *real* space cross-correlation
         is computed for each possible shift, and the shift with the highest
         cross-correlation within the overlapping area is returned.
-    return_error : bool, {"always"}, optional
-        Returns error and phase difference if "always" is given. If False, or
-        either ``reference_mask`` or ``moving_mask`` are given, only the shift
-        is returned.
     reference_mask : ndarray
         Boolean mask for ``reference_image``. The mask should evaluate
         to ``True`` (or 1) on valid pixels. ``reference_mask`` should
@@ -268,13 +265,11 @@ def phase_cross_correlation(
     error : float
         Translation invariant normalized RMS error between
         ``reference_image`` and ``moving_image``. For masked cross-correlation
-        this error is not available and NaN is returned if ``return_error``
-        is "always".
+        this error is not available and NaN is returned.
     phasediff : float
         Global phase difference between the two images (should be
         zero if images are non-negative). For masked cross-correlation
-        this phase difference is not available and NaN is returned if
-        ``return_error`` is "always".
+        this phase difference is not available and NaN is returned.
 
     Notes
     -----
@@ -312,15 +307,11 @@ def phase_cross_correlation(
            Pattern Recognition, pp. 2918-2925 (2010).
            :DOI:`10.1109/CVPR.2010.5540032`
     """
-
-    def warn_return_error():
-        warnings.warn(
-            "In scikit-image 0.22, phase_cross_correlation will start "
-            "returning a tuple or 3 items (shift, error, phasediff) always. "
-            "To enable the new return behavior and silence this warning, use "
-            "return_error='always'.",
-            category=FutureWarning,
-            stacklevel=3,
+    if not return_error:
+        raise ValueError(
+            "return_error must be True (or 'always'), False is no longer "
+            "supported as of cuCIM 24.02 and the `return_error` kwarg will be "
+            "removed in cuCIM 24.06."
         )
 
     if (reference_mask is not None) or (moving_mask is not None):
@@ -331,11 +322,7 @@ def warn_return_error():
             moving_mask,
             overlap_ratio,
         )
-        if return_error == "always":
-            return shift, np.nan, np.nan
-        else:
-            warn_return_error()
-            return shift
+        return shift, np.nan, np.nan
 
     # images must be the same shape
     if reference_image.shape != moving_image.shape:
@@ -373,14 +360,13 @@ def warn_return_error():
     )
 
     if upsample_factor == 1:
-        if return_error:
-            sabs = cp.abs(src_freq)
-            sabs *= sabs
-            tabs = cp.abs(target_freq)
-            tabs *= tabs
-            src_amp = np.sum(sabs) / src_freq.size
-            target_amp = np.sum(tabs) / target_freq.size
-            CCmax = cross_correlation[maxima]
+        sabs = cp.abs(src_freq)
+        sabs *= sabs
+        tabs = cp.abs(target_freq)
+        tabs *= tabs
+        src_amp = np.sum(sabs) / src_freq.size
+        target_amp = np.sum(tabs) / target_freq.size
+        CCmax = cross_correlation[maxima]
     # If upsampling > 1, then refine estimate with matrix multiply DFT
     else:
         # Initial shift estimate in upsampled grid
@@ -412,13 +398,12 @@ def warn_return_error():
         maxima = tuple(float(m) - dftshift for m in maxima)
         shift = tuple(s + m / upsample_factor for s, m in zip(shift, maxima))
 
-        if return_error:
-            src_amp = cp.abs(src_freq)
-            src_amp *= src_amp
-            src_amp = cp.sum(src_amp)
-            target_amp = cp.abs(target_freq)
-            target_amp *= target_amp
-            target_amp = cp.sum(target_amp)
+        src_amp = cp.abs(src_freq)
+        src_amp *= src_amp
+        src_amp = cp.sum(src_amp)
+        target_amp = cp.abs(target_freq)
+        target_amp *= target_amp
+        target_amp = cp.sum(target_amp)
 
     # If its only one row or column the shift along that dimension has no
     # effect. We set to zero.
@@ -432,22 +417,19 @@ def warn_return_error():
             moving_image = fft.ifftn(moving_image)
         shift = _disambiguate_shift(reference_image, moving_image, shift)
 
-    if return_error:
-        # Redirect user to masked_phase_cross_correlation if NaNs are observed
-        if cp.isnan(CCmax) or cp.isnan(src_amp) or cp.isnan(target_amp):
-            raise ValueError(
-                "NaN values found, please remove NaNs from your "
-                "input data or use the `reference_mask`/`moving_mask` "
-                "keywords, eg: "
-                "phase_cross_correlation(reference_image, moving_image, "
-                "reference_mask=~np.isnan(reference_image), "
-                "moving_mask=~np.isnan(moving_image))"
-            )
-
-        return (
-            shift,
-            _compute_error(CCmax, src_amp, target_amp),
-            _compute_phasediff(CCmax),
+    # Redirect user to masked_phase_cross_correlation if NaNs are observed
+    if cp.isnan(CCmax) or cp.isnan(src_amp) or cp.isnan(target_amp):
+        raise ValueError(
+            "NaN values found, please remove NaNs from your "
+            "input data or use the `reference_mask`/`moving_mask` "
+            "keywords, eg: "
+            "phase_cross_correlation(reference_image, moving_image, "
+            "reference_mask=~np.isnan(reference_image), "
+            "moving_mask=~np.isnan(moving_image))"
         )
-    else:
-        return shift
+
+    return (
+        shift,
+        _compute_error(CCmax, src_amp, target_amp),
+        _compute_phasediff(CCmax),
+    )
diff --git a/python/cucim/src/cucim/skimage/restoration/__init__.py b/python/cucim/src/cucim/skimage/restoration/__init__.py
index 07eaeb6b1..62d86f776 100644
--- a/python/cucim/src/cucim/skimage/restoration/__init__.py
+++ b/python/cucim/src/cucim/skimage/restoration/__init__.py
@@ -1,12 +1,3 @@
-from ._denoise import denoise_tv_chambolle
-from .deconvolution import richardson_lucy, unsupervised_wiener, wiener
-from .j_invariant import calibrate_denoiser, denoise_invariant
+import lazy_loader as lazy
 
-__all__ = [
-    "wiener",
-    "unsupervised_wiener",
-    "richardson_lucy",
-    "denoise_tv_chambolle",
-    "calibrate_denoiser",
-    "denoise_invariant",
-]
+__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
diff --git a/python/cucim/src/cucim/skimage/restoration/__init__.pyi b/python/cucim/src/cucim/skimage/restoration/__init__.pyi
new file mode 100644
index 000000000..89e9ec583
--- /dev/null
+++ b/python/cucim/src/cucim/skimage/restoration/__init__.pyi
@@ -0,0 +1,16 @@
+# Explicitly setting `__all__` is necessary for type inference engines
+# to know which symbols are exported. See
+# https://peps.python.org/pep-0484/#stub-files
+
+__all__ = [
+    "wiener",
+    "unsupervised_wiener",
+    "richardson_lucy",
+    "denoise_tv_chambolle",
+    "denoise_invariant",
+    "calibrate_denoiser",
+]
+
+from ._denoise import denoise_tv_chambolle
+from .deconvolution import richardson_lucy, unsupervised_wiener, wiener
+from .j_invariant import calibrate_denoiser, denoise_invariant
diff --git a/python/cucim/src/cucim/skimage/restoration/deconvolution.py b/python/cucim/src/cucim/skimage/restoration/deconvolution.py
index f30da5045..554232d62 100644
--- a/python/cucim/src/cucim/skimage/restoration/deconvolution.py
+++ b/python/cucim/src/cucim/skimage/restoration/deconvolution.py
@@ -76,7 +76,7 @@ def wiener(image, psf, balance, reg=None, is_real=True, clip=True):
     unknown original image, the Wiener filter is
 
     .. math::
-       \hat x = F^\dagger (|\Lambda_H|^2 + \lambda |\Lambda_D|^2)
+       \hat x = F^\dagger \left( |\Lambda_H|^2 + \lambda |\Lambda_D|^2 \right)^{-1}
        \Lambda_H^\dagger F y
 
     where :math:`F` and :math:`F^\dagger` are the Fourier and inverse
@@ -113,7 +113,7 @@ def wiener(image, psf, balance, reg=None, is_real=True, clip=True):
     .. [2] B. R. Hunt "A matrix theory proof of the discrete
            convolution theorem", IEEE Trans. on Audio and
            Electroacoustics, vol. au-19, no. 4, pp. 285-288, dec. 1971
-    """
+    """  # noqa: E501
     if reg is None:
         reg, _ = uft.laplacian(image.ndim, image.shape, is_real=is_real)
     if not cp.iscomplexobj(reg):
@@ -307,7 +307,7 @@ def unsupervised_wiener(
     prev_x_postmean = cp.zeros(trans_fct.shape, dtype=float_type)
 
     # Difference between two successive mean
-    delta = np.NAN
+    delta = np.nan
 
     # Initial state of the chain
     gn_chain, gx_chain = [1], [1]
diff --git a/python/cucim/src/cucim/skimage/restoration/j_invariant.py b/python/cucim/src/cucim/skimage/restoration/j_invariant.py
index ffc3cef91..10ec14d2f 100644
--- a/python/cucim/src/cucim/skimage/restoration/j_invariant.py
+++ b/python/cucim/src/cucim/skimage/restoration/j_invariant.py
@@ -141,7 +141,17 @@ def denoise_invariant(
     .. [1] J. Batson & L. Royer. Noise2Self: Blind Denoising by
        Self-Supervision, International Conference on Machine Learning,
        p. 524-533 (2019).
-    """
+
+    Examples
+    --------
+    >>> import cucim.skimage
+    >>> import cupy as cp
+    >>> import skimage
+    >>> from cucim.skimage.restoration import denoise_invariant, denoise_tv_chambolle
+    >>> image = cucim.skimage.util.img_as_float(cp.asarray(skimage.data.chelsea()))
+    >>> noisy = cucim.skimage.util.random_noise(image, var=0.2 ** 2)
+    >>> denoised = denoise_invariant(noisy, denoise_function=denoise_tv_chambolle)
+    """  # noqa: E501
     image = img_as_float(image)
 
     # promote float16->float32 if needed
@@ -273,7 +283,7 @@ def calibrate_denoiser(
     ...                                          calibrate_denoiser)
     >>> img = color.rgb2gray(cp.array(data.astronaut()[:50, :50]))
     >>> noisy = img + 0.5 * img.std() * cp.random.randn(*img.shape)
-    >>> parameters = {'weight': cp.arange(0.01, 0.5, 0.05)}
+    >>> parameters = {'weight': cp.arange(0.01, 0.3, 0.02)}
     >>> denoising_function = calibrate_denoiser(noisy, denoise_tv_chambolle,
     ...                                         denoise_parameters=parameters)
     >>> denoised_img = denoising_function(img)
diff --git a/python/cucim/src/cucim/skimage/segmentation/__init__.py b/python/cucim/src/cucim/skimage/segmentation/__init__.py
index 6d9544aa8..6e2969ae5 100644
--- a/python/cucim/src/cucim/skimage/segmentation/__init__.py
+++ b/python/cucim/src/cucim/skimage/segmentation/__init__.py
@@ -1,3 +1,6 @@
+"""Algorithms to partition images into meaningful regions or boundaries.
+"""
+
 from ._chan_vese import chan_vese
 from ._clear_border import clear_border
 from ._expand_labels import expand_labels
diff --git a/python/cucim/src/cucim/skimage/transform/__init__.py b/python/cucim/src/cucim/skimage/transform/__init__.py
index 81fe7c6e8..62d86f776 100644
--- a/python/cucim/src/cucim/skimage/transform/__init__.py
+++ b/python/cucim/src/cucim/skimage/transform/__init__.py
@@ -1,58 +1,3 @@
-from ._geometric import (
-    AffineTransform,
-    EssentialMatrixTransform,
-    EuclideanTransform,
-    FundamentalMatrixTransform,
-    PiecewiseAffineTransform,
-    PolynomialTransform,
-    ProjectiveTransform,
-    SimilarityTransform,
-    estimate_transform,
-    matrix_transform,
-)
-from ._warps import (
-    downscale_local_mean,
-    rescale,
-    resize,
-    resize_local_mean,
-    rotate,
-    swirl,
-    warp,
-    warp_coords,
-    warp_polar,
-)
-from .integral import integral_image, integrate
-from .pyramids import (
-    pyramid_expand,
-    pyramid_gaussian,
-    pyramid_laplacian,
-    pyramid_reduce,
-)
+import lazy_loader as lazy
 
-__all__ = [
-    "integral_image",
-    "integrate",
-    "warp",
-    "warp_coords",
-    "warp_polar",
-    "estimate_transform",
-    "matrix_transform",
-    "EuclideanTransform",
-    "SimilarityTransform",
-    "AffineTransform",
-    "ProjectiveTransform",
-    "EssentialMatrixTransform",
-    "FundamentalMatrixTransform",
-    "PolynomialTransform",
-    "PiecewiseAffineTransform",
-    "swirl",
-    "resize",
-    "resize_local_mean",
-    "rotate",
-    "rescale",
-    "downscale_local_mean",
-    "pyramid_reduce",
-    "pyramid_expand",
-    "pyramid_gaussian",
-    "pyramid_laplacian",
-]
+__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
diff --git a/python/cucim/src/cucim/skimage/transform/__init__.pyi b/python/cucim/src/cucim/skimage/transform/__init__.pyi
new file mode 100644
index 000000000..8f8dcaadb
--- /dev/null
+++ b/python/cucim/src/cucim/skimage/transform/__init__.pyi
@@ -0,0 +1,62 @@
+# Explicitly setting `__all__` is necessary for type inference engines
+# to know which symbols are exported. See
+# https://peps.python.org/pep-0484/#stub-files
+
+__all__ = [
+    "integral_image",
+    "integrate",
+    "warp",
+    "warp_coords",
+    "warp_polar",
+    "estimate_transform",
+    "matrix_transform",
+    "EuclideanTransform",
+    "SimilarityTransform",
+    "AffineTransform",
+    "ProjectiveTransform",
+    "EssentialMatrixTransform",
+    "FundamentalMatrixTransform",
+    "PolynomialTransform",
+    "PiecewiseAffineTransform",
+    "swirl",
+    "resize",
+    "resize_local_mean",
+    "rotate",
+    "rescale",
+    "downscale_local_mean",
+    "pyramid_reduce",
+    "pyramid_expand",
+    "pyramid_gaussian",
+    "pyramid_laplacian",
+]
+
+from ._geometric import (
+    AffineTransform,
+    EssentialMatrixTransform,
+    EuclideanTransform,
+    FundamentalMatrixTransform,
+    PiecewiseAffineTransform,
+    PolynomialTransform,
+    ProjectiveTransform,
+    SimilarityTransform,
+    estimate_transform,
+    matrix_transform,
+)
+from ._warps import (
+    downscale_local_mean,
+    rescale,
+    resize,
+    resize_local_mean,
+    rotate,
+    swirl,
+    warp,
+    warp_coords,
+    warp_polar,
+)
+from .integral import integral_image, integrate
+from .pyramids import (
+    pyramid_expand,
+    pyramid_gaussian,
+    pyramid_laplacian,
+    pyramid_reduce,
+)
diff --git a/python/cucim/src/cucim/skimage/transform/_geometric.py b/python/cucim/src/cucim/skimage/transform/_geometric.py
index 9b5644bd7..8f3758b37 100644
--- a/python/cucim/src/cucim/skimage/transform/_geometric.py
+++ b/python/cucim/src/cucim/skimage/transform/_geometric.py
@@ -1365,6 +1365,13 @@ class EuclideanTransform(ProjectiveTransform):
     translation parameters. The similarity transformation extends the Euclidean
     transformation with a single scaling factor.
 
+    In 2D and 3D, the transformation parameters may be provided either via
+    `matrix`, the homogeneous transformation matrix, above, or via the
+    implicit parameters `rotation` and/or `translation` (where `a1` is the
+    translation along `x`, `b1` along `y`, etc.). Beyond 3D, if the
+    transformation is only a translation, you may use the implicit parameter
+    `translation`; otherwise, you must use `matrix`.
+
     Parameters
     ----------
     matrix : (D+1, D+1) ndarray, optional
@@ -1375,7 +1382,7 @@ class EuclideanTransform(ProjectiveTransform):
         (single rotation) and 3D (Euler rotations) values are supported. For
         higher dimensions, you must provide or estimate the transformation
         matrix.
-    translation : sequence of float, length D, optional
+    translation : (x, y[, z, ...]) sequence of float, length D, optional
         Translation parameters for each axis.
     dimensionality : int, optional
         The dimensionality of the transform.
@@ -1510,7 +1517,7 @@ class SimilarityTransform(EuclideanTransform):
 
     where ``s`` is a scale factor and the homogeneous transformation matrix is::
 
-        [[a0  b0  a1]
+        [[a0  -b0  a1]
          [b0  a0  b1]
          [0   0    1]]
 
diff --git a/python/cucim/src/cucim/skimage/transform/pyramids.py b/python/cucim/src/cucim/skimage/transform/pyramids.py
index 3608c0de4..88c512691 100644
--- a/python/cucim/src/cucim/skimage/transform/pyramids.py
+++ b/python/cucim/src/cucim/skimage/transform/pyramids.py
@@ -4,7 +4,7 @@
 
 from .._shared.filters import gaussian
 from .._shared.utils import convert_to_float
-from ..transform import resize
+from ._warps import resize
 
 
 def _smooth(image, sigma, mode, cval, channel_axis):
diff --git a/python/cucim/src/cucim/skimage/util/dtype.py b/python/cucim/src/cucim/skimage/util/dtype.py
index 866d515ee..2ba6dc7bb 100644
--- a/python/cucim/src/cucim/skimage/util/dtype.py
+++ b/python/cucim/src/cucim/skimage/util/dtype.py
@@ -3,6 +3,7 @@
 from warnings import warn
 
 import cupy as cp
+import numpy as np
 
 from .._shared.utils import _supported_float_type
 
@@ -46,7 +47,6 @@
     bool: (False, True),
     cp.bool_: (False, True),
     float: (-1, 1),
-    cp.float_: (-1, 1),
     cp.float16: (-1, 1),
     cp.float32: (-1, 1),
     cp.float64: (-1, 1),
@@ -279,7 +279,7 @@ def _convert(image, dtype, force_copy=False, uniform=False):
     #   is a subclass of that type (e.g. `cp.floating` will allow
     #   `float32` and `float64` arrays through)
 
-    if cp.issubdtype(dtype_in, cp.obj2sctype(dtype)):
+    if cp.issubdtype(dtype_in, np.core.numerictypes.obj2sctype(dtype)):
         if force_copy:
             image = image.copy()
         return image
diff --git a/python/cucim/tox.ini b/python/cucim/tox.ini
deleted file mode 100644
index 04fe6475b..000000000
--- a/python/cucim/tox.ini
+++ /dev/null
@@ -1,111 +0,0 @@
-[testenv:bootstrap]
-deps =
-    jinja2
-    matrix
-    tox
-skip_install = true
-commands =
-    python ci/bootstrap.py --no-env
-passenv =
-    *
-; a generative tox configuration, see: https://tox.readthedocs.io/en/latest/config.html#generative-envlist
-
-[tox]
-envlist =
-    clean,
-    check,
-    docs,
-    docs-dev,
-    release,
-    {py35,py36,py37,py38,py39,pypy,pypy3},
-    report
-ignore_basepython_conflict = true
-
-[testenv]
-basepython =
-    pypy: {env:TOXPYTHON:pypy}
-    pypy3: {env:TOXPYTHON:pypy3}
-    py35: {env:TOXPYTHON:python3.5}
-    py36: {env:TOXPYTHON:python3.6}
-    py37: {env:TOXPYTHON:python3.7}
-    py38: {env:TOXPYTHON:python3.8}
-    py39: {env:TOXPYTHON:python3.9}
-    {bootstrap,clean,check,report,docs,docs-dev,release,codecov}: {env:TOXPYTHON:python3}
-setenv =
-    PYTHONPATH={toxinidir}/tests
-    PYTHONUNBUFFERED=yes
-passenv =
-    *
-usedevelop = false
-deps =
-    pytest
-    pytest-travis-fold
-    pytest-cov
-commands =
-    {posargs:pytest --cov --cov-report=term-missing -vv tests}
-
-[testenv:check]
-deps =
-    docutils
-    check-manifest
-    black
-    ruff
-    readme-renderer
-    pygments
-    isort
-    twine
-skip_install = true
-
-; https://packaging.python.org/guides/making-a-pypi-friendly-readme/#validating-restructuredtext-markup
-commands =
-    twine check dist/*.whl
-    check-manifest {toxinidir}
-    ruff .
-    black --check .
-    isort --verbose --check-only --diff --filter-files .
-
-[testenv:docs]
-; Installing from `sdist` package instead of `setup.py develop` (https://tox.readthedocs.io/en/latest/config.html#conf-usedevelop)
-usedevelop = false
-deps =
-    -r{toxinidir}/docs/requirements.txt
-commands =
-    sphinx-build -E -b doctest docs {posargs:-dist/docs}
-    sphinx-build -E -b html docs {posargs:-dist/docs}
-    sphinx-build -b linkcheck docs {posargs:-dist/docs}
-
-[testenv:docs-dev]
-; Installing from `sdist` package instead of `setup.py develop` (https://tox.readthedocs.io/en/latest/config.html#conf-usedevelop)
-usedevelop = false
-deps =
-    -r{toxinidir}/docs/requirements.txt
-commands =
-    ; https://pypi.org/project/sphinx-autobuild/
-    sphinx-autobuild {posargs:---host 0.0.0.0 --port 9999 docs dist/docs}
-
-[testenv:release]
-usedevelop = false
-allowlist_externals = /bin/bash
-commands =
-    /bin/bash -c "{posargs}"
-
-[testenv:codecov]
-deps =
-    codecov
-skip_install = true
-commands =
-    codecov []
-
-[testenv:report]
-deps =
-    coverage
-skip_install = true
-commands =
-    coverage report
-    coverage html
-
-[testenv:clean]
-commands = coverage erase
-skip_install = true
-deps =
-    coverage
diff --git a/run b/run
index b66c2f75a..c8bec742e 100755
--- a/run
+++ b/run
@@ -262,24 +262,6 @@ is_x86_64() {
 # Section: Build
 #==================================================================================
 
-build_manylinux2014_desc() { echo 'Build manylinux2014 image
-
-Arguments:
-  $1 - cuda version (e.g., 110, 111)
-'
-}
-build_manylinux2014() {
-    local cuda_version="${1:-110}"
-    run_command docker build -f ${TOP}/Dockerfile-cuda${cuda_version} -t gigony/manylinux2014-x64:cuda${cuda_version} ${TOP}
-
-    read -n 1 -r -p "$(c_str R "Do you want to update dockcross-manylinux2014-x64 with " G "cuda${cuda_version}" R " (y/n)?")"
-    echo
-    if [[ $REPLY =~ ^[Yy]$ ]]; then
-        sed -i -e "s/manylinux2014-x64:cuda.../manylinux2014-x64:cuda${cuda_version}/g" ${TOP}/dockcross-manylinux2014-x64
-        c_echo W "Done"
-    fi
-}
-
 build_local_libcucim_() {
     local source_folder=${1:-${TOP}}
     local build_type=${2:-debug}
@@ -626,11 +608,13 @@ install_python_test_deps_() {
         # (https://github.com/rapidsai/cucim/pull/433)
         run_command pip install -r ${TOP}/python/cucim/requirements-test.txt
     else
+        pushd "${TOP}/python/cucim"
         if [ -n "${VIRTUAL_ENV}" ]; then
-            run_command pip3 install -r ${TOP}/python/cucim/requirements-test.txt
+            run_command pip3 install -e .[test]
         else
-            run_command pip3 install --user -r ${TOP}/python/cucim/requirements-test.txt
+            run_command pip3 install --user -e .[test]
         fi
+	popd
     fi
     hash -r
 }
diff --git a/run_gds.sh b/run_gds.sh
deleted file mode 100644
index 74b0d235a..000000000
--- a/run_gds.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2020-2021, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-MNT_PATH=/nvme
-GDS_IMAGE=cucim-gds
-
-BUILD_VER=`uname -r`
-NV_DRIVER=`nvidia-smi -q -i 0 | sed -n 's/Driver Version.*: *\(.*\) *$/\1/p'`
-echo "using nvidia driver version $NV_DRIVER on kernel $BUILD_VER"
-
-
-ofed_version=$(ofed_info -s | grep MLNX)
-if [ $? -eq 0 ]; then
-    rdma_core=$(dpkg -s libibverbs-dev | grep "Source: rdma-core")
-    if [ $? -eq 0 ]; then
-        CONFIG_MOFED_VERSION=$(echo $ofed_version | cut -d '-' -f 2)
-        echo "Found MOFED version $CONFIG_MOFED_VERSION"
-    fi
-    MLNX_SRCS="--volume /usr/src/mlnx-ofed-kernel-${CONFIG_MOFED_VERSION}:/usr/src/mlnx-ofed-kernel-${CONFIG_MOFED_VERSION}:ro"
-    MOFED_DEVS="--net=host --volume /sys/class/infiniband_verbs:/sys/class/infiniband_verbs/ "
-fi
-
-docker run \
-    --ipc host \
-    -it
-    --rm
-    --gpus all \
-    --volume /run/udev:/run/udev:ro \
-    --volume /sys/kernel/config:/sys/kernel/config/ \
-    --volume /usr/src/nvidia-$NV_DRIVER:/usr/src/nvidia-$NV_DRIVER:ro  ${MLNX_SRCS}\
-    --volume /dev:/dev:ro \
-    --privileged \
-    --env NV_DRIVER=${NV_DRIVER} \
-    --volume 	/lib/modules/$BUILD_VER/:/lib/modules/$BUILD_VER \
-    --volume "${MNT_PATH}/data:/data:rw" \
-    --volume "${MNT_PATH}/results:/results:rw"  ${MOFED_DEVS} \
-    -itd ${REPO_URI}/${GDS_IMAGE} \
-    /bin/bash
diff --git a/scripts/auditwheel_repair.py b/scripts/auditwheel_repair.py
deleted file mode 100644
index 2581ea977..000000000
--- a/scripts/auditwheel_repair.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Apache License, Version 2.0
-# Copyright 2020 NVIDIA Corporation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import functools
-import re
-from unittest.mock import patch
-
-import auditwheel.elfutils
-from auditwheel.main import main
-from auditwheel.wheeltools import InWheelCtx
-
-# How auditwheel repair works?
-#
-# From https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/wheel_abi.py#L38
-# 1) Find a Python extension libraries(.so)
-#      if so ==> A, else ==> B
-# 2) `needed_libs` <== external libraries needed by A and B
-# 3) From b in B,
-#      if b is not in `needed_libs`, b is added to A
-# 4) Only external libraries in A are patched to use locally copied .so files
-#    - external libraries that exists under wheel path are discarded
-#      - https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/policy/external_references.py#L61
-#    - https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/repair.py#L62
-#
-# With current implementation,
-# - `cucim/_cucim.cpython-XX-x86_64-linux-gnu.so` files are in A by 1)
-# - `cucim/libcucim.so.??` is in B by 1)
-# - `cucim/libcucim.so.??` and `libcudart.so.11.0` are in `needed_libs` by 2)
-# - `cucim/cucim.kit.cuslide@??.??.??.so` is in A by 3)
-#
-# And only libz and libcudart are considered as external libraries.
-
-# To work with cuCIM, we need to
-# 1) make `cucim/libcucim.so.??` as Python extension library
-#   - Patch elf_is_python_extension : https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/elfutils.py#L81
-# 2) control how to copy external libraries
-#   - Patch copylib: https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/repair.py#L108
-#   - Need for libnvjpeg library
-# 3) preprocess wheel metadata
-#   - patch InWheelCtx.__enter__ : https://github.com/pypa/auditwheel/blob/3.2.0/auditwheel/wheeltools.py#L158
-#   - `Root-Is-Purelib: true` -> `Root-Is-Purelib: false` from WHEEL file
-
-
-# Parameters
-PYTHON_EXTENSION_LIBRARIES = [r"cucim/libcucim\.so\.\d{1,2}"]
-
-# 1) auditwheel.elfutils.elf_is_python_extension replacement
-orig_elf_is_python_extension = auditwheel.elfutils.elf_is_python_extension
-
-
-@functools.wraps(orig_elf_is_python_extension)
-def elf_is_python_extension(fn, elf):
-    if any(map(lambda x: re.fullmatch(x, fn), PYTHON_EXTENSION_LIBRARIES)):
-        print("[cuCIM] Consider {} as a python extension.".format(fn))
-        return True, 3
-    return orig_elf_is_python_extension(fn, elf)
-
-
-# 3) auditwheel.wheeltools.InWheelCtx.__enter__ replacement
-orig_inwheelctx_enter = InWheelCtx.__enter__
-
-
-@functools.wraps(orig_inwheelctx_enter)
-def inwheelctx_enter(self):
-    rtn = orig_inwheelctx_enter(self)
-
-    # `self.path` is a path that extracted files from the wheel file exists
-
-    # base_dir = glob.glob(join(self.path, '*.dist-info'))
-    # wheel_path = join(base_dir[0], 'WHEEL')
-    # with open(wheel_path, 'r') as f:
-    #     wheel_text = f.read()
-
-    # wheel_text = wheel_text.replace('Root-Is-Purelib: true', 'Root-Is-Purelib: false')  # noqa: E501
-
-    # with open(wheel_path, 'w') as f:
-    #     f.write(wheel_text)
-
-    return rtn
-
-
-# # sys.argv replacement
-# testargs = ["auditwheel_repair.py", "repair", "--plat", "manylinux2014_x86_64", "-w", "wherehouse", "cuclara_image-0.1.1-py3-none-manylinux2014_x86_64.whl"]  # noqa: E501
-# with patch.object(sys, 'argv', testargs):
-
-if __name__ == "__main__":
-    # Patch
-    with patch.object(
-        auditwheel.elfutils, "elf_is_python_extension", elf_is_python_extension
-    ):
-        with patch.object(InWheelCtx, "__enter__", inwheelctx_enter):
-            main()
diff --git a/scripts/run-dist b/scripts/run-dist
deleted file mode 100755
index 60ed771e0..000000000
--- a/scripts/run-dist
+++ /dev/null
@@ -1,500 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2020, NVIDIA CORPORATION.
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-init_globals() {
-    if [ "$0" != "/bin/bash" ]; then
-        SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
-        export RUN_SCRIPT_FILE="$(readlink -f "$0")"
-    else
-        export RUN_SCRIPT_FILE="$(readlink -f "${BASH_SOURCE[0]}")"
-    fi
-
-    export TOP=$(dirname "${RUN_SCRIPT_FILE}")
-}
-
-################################################################################
-# Utility functions
-################################################################################
-
-#######################################
-# Get list of available commands from a given input file.
-#
-# Available commands and command summary are extracted by checking a pattern
-# "_desc() { echo '".
-# Section title is extracted by checking a pattern "# Section: ".
-# This command is used for listing available commands in CLI.
-#
-# e.g.)
-#   "# Section: String/IO functions"
-#     => "# String/IO functions"
-#   "to_lower_desc() { echo 'Convert to lower case"
-#     => "to_lower ----------------- Convert to lower case"
-#
-# Arguments:
-#   $1 - input file that defines commands
-# Returns:
-#   Print list of available commands from $1
-#######################################
-get_list_of_available_commands() {
-    local file_name="$1"
-    if [ ! -e "$1" ]; then
-        echo "$1 doesn't exist!"
-    fi
-
-    local line_str='--------------------------------'
-    local IFS= cmd_lines="$(IFS= cat "$1" | grep -E -e "^(([[:alpha:]_[:digit:]]+)_desc\(\)|# Section: )" | sed "s/_desc() *{ *echo '/ : /")"
-    local line
-    while IFS= read -r line; do
-        local cmd=$(echo "$line" | cut -d":" -f1)
-        local desc=$(echo "$line" | cut -d":" -f2-)
-        if [ "$cmd" = "# Section" ]; then
-            c_echo B "${desc}"
-        else
-            # there is no substring operation in 'sh' so use 'cut'
-            local dash_line="$(echo "${line_str}" | cut -c ${#cmd}-)"  #  = "${line_str:${#cmd}}"
-             c_echo Y "   ${cmd}" w " ${dash_line} ${desc}"
-        fi
-        # use <<EOF, not '<<<"$cmd_lines"' to be executable in sh
-    done <<EOF
-$cmd_lines
-EOF
-}
-
-my_cat_prefix() {
-    local IFS
-    local prefix="$1"
-    local line
-    while IFS= read -r line; do
-        echo "${prefix}${line}" # -e option doesn't work in 'sh' so disallow escaped characters
-    done <&0
-}
-
-
-c_str() {
-    local old_color=39
-    local old_attr=0
-    local color=39
-    local attr=0
-    local text=""
-    #local no_change=0
-    for i in "$@"; do
-        case "$i" in
-            r|R)
-                color=31
-                ;;
-            g|G)
-                color=32
-                ;;
-            y|Y)
-                color=33
-                ;;
-            b|B)
-                color=34
-                ;;
-            p|P)
-                color=35
-                ;;
-            c|C)
-                color=36
-                ;;
-            w|W)
-                color=37
-                ;;
-
-            z|Z)
-                color=0
-                ;;
-        esac
-        case "$i" in
-            l|L|R|G|Y|B|P|C|W)
-                attr=1
-                ;;
-            n|N|r|g|y|b|p|c|w)
-                attr=0
-                ;;
-            z|Z)
-                attr=0
-                ;;
-            *)
-                text="${text}$i"
-        esac
-        if [ ${old_color} -ne ${color} ] || [ ${old_attr} -ne ${attr} ]; then
-            text="${text}\033[${attr};${color}m"
-            old_color=$color
-            old_attr=$attr
-        fi
-    done
-    /bin/echo -en "$text"
-}
-
-c_echo() {
-    local old_opt="$(shopt -op xtrace)" # save old xtrace option
-    set +x # unset xtrace
-    local text="$(c_str "$@")"
-    /bin/echo -e "$text\033[0m"
-    eval "${old_opt}" # restore old xtrace option
-}
-
-
-echo_err() {
-    >&2 echo "$@"
-}
-
-c_echo_err() {
-    >&2 c_echo "$@"
-}
-
-printf_err() {
-    >&2 printf "$@"
-}
-
-get_item_ranges() {
-    local indexes="$1"
-    local list="$2"
-    echo -n "$(echo "${list}" | xargs | cut -d " " -f "${indexes}")"
-    return $?
-}
-
-get_unused_ports() {
-    local num_of_ports=${1:-1}
-    local start=${2:-49152}
-    local end=${3:-61000}
-    comm -23 \
-    <(seq ${start} ${end} | sort) \
-    <(ss -tan | awk '{print $4}' | while read line; do echo ${line##*\:}; done | grep '[0-9]\{1,5\}' | sort -u) \
-    | shuf | tail -n ${num_of_ports} # use tail instead head to avoid broken pipe in VSCode terminal
-}
-
-newline() {
-    echo
-}
-
-info() {
-    c_echo W "$(date -u '+%Y-%m-%d %H:%M:%S') [INFO] " Z "$@"
-}
-
-error() {
-    echo R "$(date -u '+%Y-%m-%d %H:%M:%S') [ERROR] " Z "$@"
-}
-
-fatal() {
-    echo R "$(date -u '+%Y-%m-%d %H:%M:%S') [FATAL] " Z "$@"
-    echo
-    if [ -n "${SCRIPT_DIR}" ]; then
-        exit 1
-    fi
-}
-
-run_command() {
-    local status=0
-    local cmd="$*"
-
-    c_echo B "$(date -u '+%Y-%m-%d %H:%M:%S') " W "\$ " G "${cmd}"
-
-    [ "$(echo -n "$@")" = "" ] && return 1 # return 1 if there is no command available
-
-    "$@"
-    status=$?
-
-    unset IFS
-
-    return $status
-}
-
-retry() {
-    local retries=$1
-    shift
-
-    local count=0
-    until run_command "$@"; do
-        exit=$?
-        wait=$((2 ** count))
-        count=$((count + 1))
-        if [ $count -lt $retries ]; then
-            info "Retry $count/$retries. Exit code=$exit, Retrying in $wait seconds..."
-            sleep $wait
-        else
-            fatal "Retry $count/$retries. Exit code=$exit, no more retries left."
-            return 1
-        fi
-    done
-    return 0
-}
-
-#==================================================================================
-# Section: Example
-#==================================================================================
-
-download_testdata_desc() { echo 'Download test data from Docker Hub
-'
-}
-download_testdata() {
-    c_echo W "Downloading test data..."
-    run_command mkdir -p ${TOP}/notebooks/input
-    if [ ! -e ${TOP}/notebooks/input/README.md ]; then
-        run_command rm -rf ${TOP}/notebooks/input
-        id=$(docker create gigony/svs-testdata:little-big)
-        run_command docker cp $id:/input ${TOP}/notebooks
-        run_command docker rm -v $id
-        c_echo G "Test data is downloaded to ${TOP}/notebooks/input!"
-    else
-        c_echo G "Test data already exists at ${TOP}/notebooks/input!"
-    fi
-}
-
-copy_gds_files_() {
-    [ ! -d /usr/local/cuda/gds ] && c_echo_err R "GDS is not available at /usr/local/cuda/gds !" && return 1
-
-    rm -rf ${TOP}/temp/gds
-    mkdir -p ${TOP}/temp/gds/lib64
-    cp -P -r /usr/local/cuda/gds/* ${TOP}/temp/gds/
-    cp -P /usr/local/cuda/lib64/cufile.h /usr/local/cuda/lib64/libcufile* ${TOP}/temp/gds/lib64/
-}
-
-launch_notebooks_desc() { echo 'Launch jupyter notebooks
-
-Arguments:
-  -p <port> - port number
-  -h <host> - hostname to serve documentation on (default: 0.0.0.0)
-  -g        - launch GDS-enabled container
-'
-}
-launch_notebooks() {
-    local OPTIND
-    local port=$(get_unused_ports 1 10000 10030)
-    local host='0.0.0.0'
-    local gds_postfix=''
-    local gds_nvme_path=''
-
-    while getopts 'p:h:g:' option;
-    do
-        case "${option}" in
-            p)
-                port="$OPTARG"
-                ;;
-            h)
-                host="$OPTARG"
-                ;;
-            g)
-                gds_postfix='-gds'
-                echo "# OPTARG:$OPTARG"
-                [ -z "$OPTARG" ] && c_echo_err R "Please specify NVMe path!" && return 1
-                gds_nvme_path=$(readlink -f "$OPTARG")
-                [ ! -d "$gds_nvme_path" ] && c_echo_err R "Folder $gds_nvme_path doesn't exist!" && return 1
-
-                # Copy cufile SDK from host system to temp/gds
-                copy_gds_files_
-                ;;
-            *)
-                return 1
-       esac
-    done
-
-    download_testdata
-
-    run_command cp ${TOP}/*.whl ${TOP}/notebooks
-
-    run_command docker build --runtime nvidia -t cucim-jupyter${gds_postfix} -f ${TOP}/docker/Dockerfile-jupyter${gds_postfix} ${TOP}
-
-    [ $? -ne 0 ] && return 1
-
-    c_echo W "Port " G "$port" W " would be used...(" B "http://$(hostname -I | cut -d' ' -f 1):${port}" W ")"
-
-    if [ -z "${gds_postfix}" ]; then
-        run_command docker run --runtime nvidia --gpus all -it --rm \
-            -v ${TOP}/notebooks:/notebooks \
-            -p ${port}:${port} \
-            cucim-jupyter \
-            -c "echo -n 'Enter New Password: '; jupyter lab --ServerApp.password=\"\$(python3 -u -c \"from jupyter_server.auth import passwd;pw=input();print(passwd(pw));\" | egrep 'sha|argon')\" --ServerApp.root_dir=/notebooks --allow-root --port=${port} --ip=${host} --no-browser"
-    else
-        local MNT_PATH=/nvme
-        local GDS_IMAGE=cucim-jupyter${gds_postfix}
-
-        local BUILD_VER=`uname -r`
-        local NV_DRIVER=`nvidia-smi -q -i 0 | sed -n 's/Driver Version.*: *\(.*\) *$/\1/p'`
-        echo "using nvidia driver version $NV_DRIVER on kernel $BUILD_VER"
-
-        local ofed_version=$(ofed_info -s | grep MLNX)
-        if [ $? -eq 0 ]; then
-            local rdma_core=$(dpkg -s libibverbs-dev | grep "Source: rdma-core")
-            if [ $? -eq 0 ]; then
-                local CONFIG_MOFED_VERSION=$(echo $ofed_version | cut -d '-' -f 2)
-                echo "Found MOFED version $CONFIG_MOFED_VERSION"
-            fi
-            local MLNX_SRCS="--volume /usr/src/mlnx-ofed-kernel-${CONFIG_MOFED_VERSION}:/usr/src/mlnx-ofed-kernel-${CONFIG_MOFED_VERSION}:ro"
-            local MOFED_DEVS="--net=host --volume /sys/class/infiniband_verbs:/sys/class/infiniband_verbs/ "
-        fi
-
-        docker run \
-            --ipc host \
-            -it \
-            --rm \
-            --gpus all \
-            -v ${TOP}/notebooks:/notebooks \
-            -p ${port}:${port} \
-            --volume /run/udev:/run/udev:ro \
-            --volume /sys/kernel/config:/sys/kernel/config/ \
-            --volume /usr/src/nvidia-$NV_DRIVER:/usr/src/nvidia-$NV_DRIVER:ro  ${MLNX_SRCS}\
-            --volume /dev:/dev:ro \
-            --privileged \
-            --env NV_DRIVER=${NV_DRIVER} \
-            --volume /lib/modules/$BUILD_VER/:/lib/modules/$BUILD_VER \
-            --volume "${MNT_PATH}:/notebooks/nvme:rw" \
-            ${MOFED_DEVS} \
-            ${GDS_IMAGE} \
-            -c "echo -n 'Enter New Password: '; jupyter lab --ServerApp.password=\"\$(python3 -u -c \"from jupyter_server.auth import passwd;pw=input();print(passwd(pw));\" | egrep 'sha|argon')\" --ServerApp.root_dir=/notebooks --allow-root --port=${port} --ip=${host} --no-browser"
-    fi
-}
-
-#==================================================================================
-# Section: Build
-#==================================================================================
-
-build_train() {
-    local image_name=${1:-cucim-train}
-    run_command docker build -t ${image_name} -f ${TOP}/docker/Dockerfile-claratrain ${TOP}/docker
-}
-
-build_train_desc() { echo 'Build Clara Train Docker image with cuCIM (& OpenSlide)
-
-Build image from docker/Dockerfile-claratrain
-
-Arguments:
-  $1 - docker image name (default:cucim-train)
-'
-}
-build_train() {
-    local image_name=${1:-cucim-train}
-    run_command docker build -t ${image_name} -f ${TOP}/docker/Dockerfile-claratrain ${TOP}
-}
-
-build_examples_desc() { echo 'Build cuCIM C++ examples
-'
-}
-build_examples() {
-    local image_name=cucim-cmake
-    run_command docker build -t ${image_name} -f ${TOP}/docker/Dockerfile-cmake ${TOP}/docker
-    run_command docker run -it --rm \
-        -v ${TOP}:/workspace \
-        ${image_name} \
-            -c "
-                mkdir -p /workspace/examples/cpp/build;
-                rm -rf /workspace/examples/cpp/build/*;
-                cd /workspace/examples/cpp/build;
-                cmake .. && make"
-    c_echo W "Copying binary files to ${TOP}/bin folder..."
-    run_command mkdir -p ${TOP}/bin
-    run_command cp ${TOP}/examples/cpp/build/bin/* ${TOP}/bin
-
-    download_testdata
-
-    c_echo W "Execute the binary with the following commands:"
-    c_echo   "  # Set library path"
-    c_echo B "  export LD_LIBRARY_PATH=${TOP}/install/lib:\$LD_LIBRARY_PATH"
-    c_echo   "  # Execute"
-    c_echo B "  ./bin/tiff_image notebooks/input/image.tif ."
-}
-
-parse_args() {
-    local OPTIND
-    while getopts 'yh' option;
-    do
-        case "${option}" in
-            y)
-                ALWAYS_YES=true;
-                ;;
-            h)
-                print_usage
-                exit 1
-                ;;
-            *)
-                ;;
-        esac
-    done
-    shift $((OPTIND-1))
-
-    CMD="$1"
-    shift
-
-    ARGS=("$@")
-}
-
-print_usage() {
-    set +x
-    echo_err
-    echo_err "USAGE: $0 [command] [arguments]..."
-    echo_err ""
-    c_echo_err W "Global Arguments"
-    echo_err
-    c_echo_err W "Command List"
-    c_echo_err Y "    help  " w "----------------------------  Print detailed description for a given argument (command name)"
-    echo_err "$(get_list_of_available_commands "${RUN_SCRIPT_FILE}" | my_cat_prefix " ")"
-    echo_err
-}
-
-print_cmd_help_messages() {
-    local cmd="$1"
-    if [ -n "${cmd}" ]; then
-        if type ${cmd}_desc > /dev/null 2>&1; then
-            ${cmd}_desc
-            exit 0
-        else
-            c_echo_err R "Command '${cmd}' doesn't exist!"
-            exit 1
-        fi
-    fi
-    print_usage
-    return 0
-}
-
-main() {
-    local ret=0
-    parse_args "$@"
-
-    case "$CMD" in
-        help)
-            print_cmd_help_messages "${ARGS[@]}"
-            exit 0
-            ;;
-        build)
-            build_examples "${ARGS[@]}"
-            ;;
-        notebooks)
-            launch_notebooks "${ARGS[@]}"
-            ;;
-        ''|main)
-            print_usage
-            ;;
-        *)
-            if type ${CMD} > /dev/null 2>&1; then
-                "$CMD" "${ARGS[@]}"
-            else
-                print_usage
-                exit 1
-            fi
-            ;;
-    esac
-    ret=$?
-    if [ -n "${SCRIPT_DIR}" ]; then
-        exit $ret
-    fi
-}
-
-init_globals
-
-if [ -n "${SCRIPT_DIR}" ]; then
-    main "$@"
-fi


Test patch:
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 8ac82418e..6f55ce705 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -16,7 +16,7 @@ on:
 jobs:
   conda-python-tests:
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@branch-24.02
     with:
       build_type: nightly
       branch: ${{ inputs.branch }}
@@ -24,7 +24,7 @@ jobs:
       sha: ${{ inputs.sha }}
   wheel-tests:
     secrets: inherit
-    uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-23.12
+    uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@branch-24.02
     with:
       build_type: nightly
       branch: ${{ inputs.branch }}
diff --git a/ci/test_python.sh b/ci/test_python.sh
index 476671b19..3739acf2e 100755
--- a/ci/test_python.sh
+++ b/ci/test_python.sh
@@ -7,6 +7,8 @@ set -euo pipefail
 
 . /opt/conda/etc/profile.d/conda.sh
 
+export RAPIDS_VERSION_NUMBER="24.02"
+
 rapids-logger "Generate Python testing dependencies"
 rapids-dependency-file-generator \
   --output conda \
@@ -33,7 +35,8 @@ rapids-print-env
 rapids-mamba-retry install \
   --channel "${CPP_CHANNEL}" \
   --channel "${PYTHON_CHANNEL}" \
-  libcucim cucim
+  "libcucim=${RAPIDS_VERSION_NUMBER}" \
+  "cucim=${RAPIDS_VERSION_NUMBER}"
 
 rapids-logger "Check GPU usage"
 nvidia-smi
diff --git a/ci/test_wheel.sh b/ci/test_wheel.sh
index 2fe2c1fb9..81f7f53e5 100755
--- a/ci/test_wheel.sh
+++ b/ci/test_wheel.sh
@@ -9,10 +9,21 @@ RAPIDS_PY_WHEEL_NAME="cucim_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-fro
 # echo to expand wildcard before adding `[extra]` requires for pip
 python -m pip install $(echo ./dist/cucim*.whl)[test]
 
+CUDA_MAJOR_VERSION=${RAPIDS_CUDA_VERSION:0:2}
+
 # Run smoke tests for aarch64 pull requests
 if [[ "$(arch)" == "aarch64" && ${RAPIDS_BUILD_TYPE} == "pull-request" ]]; then
     python ./ci/wheel_smoke_test.py
 else
-    # TODO: revisit enabling imagecodecs package during testing
-    python -m pytest ./python/cucim
+
+    DEBIAN_FRONTEND=noninteractive apt update
+    DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends libopenslide0
+
+    if [[ ${CUDA_MAJOR_VERSION} == "11" ]]; then
+        # Omit I/O-related tests in ./python/cucim/tests due to known CUDA bug
+        # with dynamic loading of libcufile.
+        python -m pytest ./python/cucim/src/
+    else
+        python -m pytest ./python/cucim
+    fi
 fi
diff --git a/python/cucim/requirements-test.txt b/python/cucim/requirements-test.txt
deleted file mode 100644
index e8324ced4..000000000
--- a/python/cucim/requirements-test.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-GPUtil>=1.4.0
-imagecodecs>=2021.6.8
-openslide-python>=1.1.2
-opencv-python-headless>=4.6
-psutil>=5.8.0
-pytest>=6.2.4
-pytest-cov>=2.12.1
-pytest-lazy-fixture>=0.6.3
-tifffile>=2022.7.28
diff --git a/python/cucim/src/cucim/skimage/color/tests/test_colorconv.py b/python/cucim/src/cucim/skimage/color/tests/test_colorconv.py
index 7dfc80564..704e874df 100644
--- a/python/cucim/src/cucim/skimage/color/tests/test_colorconv.py
+++ b/python/cucim/src/cucim/skimage/color/tests/test_colorconv.py
@@ -63,6 +63,14 @@
 )
 from cucim.skimage.util import img_as_float, img_as_float32, img_as_ubyte
 
+# TODO: when minimum numpy dependency is 1.25 use:
+# np.exceptions.AxisError instead of AxisError
+# and remove this try-except
+try:
+    from numpy import AxisError
+except ImportError:
+    from numpy.exceptions import AxisError
+
 data_dir = os.path.join(os.path.dirname(__file__), "data")
 
 
@@ -133,7 +141,7 @@ def test_rgba2rgb_error_channel_axis_invalid(self, channel_axis):
 
     @pytest.mark.parametrize("channel_axis", [-4, 3])
     def test_rgba2rgb_error_channel_axis_out_of_range(self, channel_axis):
-        with pytest.raises(np.AxisError):
+        with pytest.raises(AxisError):
             rgba2rgb(self.img_rgba, channel_axis=channel_axis)
 
     def test_rgba2rgb_error_rgb(self):
diff --git a/python/cucim/src/cucim/skimage/filters/tests/test_gaussian.py b/python/cucim/src/cucim/skimage/filters/tests/test_gaussian.py
index 73ffe943d..ae3349f43 100644
--- a/python/cucim/src/cucim/skimage/filters/tests/test_gaussian.py
+++ b/python/cucim/src/cucim/skimage/filters/tests/test_gaussian.py
@@ -2,8 +2,6 @@
 import numpy as np
 import pytest
 
-from cucim.skimage._shared._warnings import expected_warnings
-from cucim.skimage._vendored import pad
 from cucim.skimage.filters._gaussian import difference_of_gaussians, gaussian
 
 
@@ -60,17 +58,12 @@ def test_multichannel(channel_axis):
     )
 
     if channel_axis % a.ndim == 2:
-        # Test legacy behavior equivalent to old (channel_axis = -1)
-        with expected_warnings(["Automatic detection of the color channel"]):
-            gaussian_rgb_a = gaussian(
-                a, sigma=1, mode="reflect", preserve_range=True
-            )
-
         # Check that the mean value is conserved in each channel
         # (color channels are not mixed together)
         assert cp.allclose(
             a.mean(axis=spatial_axes), gaussian_rgb_a.mean(axis=spatial_axes)
         )
+
     # Iterable sigma
     gaussian_rgb_a = gaussian(
         a,
@@ -189,34 +182,3 @@ def test_shared_mem_check_fix(dtype, sigma):
     # The exact range that fails depends on the shared memory limit
     # of the GPU, so we test with a range of sigmas here.
     gaussian(cp.ones((512, 512), dtype=dtype), sigma=sigma)
-
-
-def test_deprecated_automatic_channel_detection():
-    rgb = cp.zeros((5, 5, 3))
-    rgb[1, 1] = cp.arange(1, 4)
-    gray = pad(rgb, pad_width=((0, 0), (0, 0), (1, 0)))
-
-    # Warning is raised if channel_axis is not set and shape is (M, N, 3)
-    with pytest.warns(
-        FutureWarning,
-        match="Automatic detection .* was deprecated .* Set `channel_axis=-1`",
-    ):
-        filtered_rgb = gaussian(rgb, sigma=1, mode="reflect")
-    # Check that the mean value is conserved in each channel
-    # (color channels are not mixed together)
-    assert cp.allclose(filtered_rgb.mean(axis=(0, 1)), rgb.mean(axis=(0, 1)))
-
-    # No warning if channel_axis is not set and shape is not (M, N, 3)
-    filtered_gray = gaussian(gray, sigma=1, mode="reflect")
-
-    # No warning is raised if channel_axis is explicitly set
-    filtered_rgb2 = gaussian(rgb, sigma=1, mode="reflect", channel_axis=-1)
-    assert cp.array_equal(filtered_rgb, filtered_rgb2)
-    filtered_gray2 = gaussian(gray, sigma=1, mode="reflect", channel_axis=None)
-    assert cp.array_equal(filtered_gray, filtered_gray2)
-    assert not cp.array_equal(filtered_rgb, filtered_gray)
-
-    # Check how the proxy value shows up in the rendered function signature
-    from cucim.skimage._shared.filters import ChannelAxisNotSet
-
-    assert repr(ChannelAxisNotSet) == "<ChannelAxisNotSet>"
diff --git a/python/cucim/src/cucim/skimage/filters/tests/test_thresholding.py b/python/cucim/src/cucim/skimage/filters/tests/test_thresholding.py
index f08fe60b4..a454c9584 100644
--- a/python/cucim/src/cucim/skimage/filters/tests/test_thresholding.py
+++ b/python/cucim/src/cucim/skimage/filters/tests/test_thresholding.py
@@ -640,12 +640,28 @@ def test_mean():
     assert threshold_mean(img) == 1.0
 
 
-def test_triangle_uint_images():
-    text = cp.array(data.text())
-    assert threshold_triangle(cp.invert(text)) == 151
-    assert threshold_triangle(text) == 104
-    assert threshold_triangle(coinsd) == 80
-    assert threshold_triangle(cp.invert(coinsd)) == 175
+# also run cases with nbins > 100000 to also test CuPy-based code path.
+@pytest.mark.parametrize("kwargs", [{}, {"nbins": 300000}])
+@pytest.mark.parametrize("dtype", [cp.uint8, cp.int16, cp.float16, cp.float32])
+def test_triangle_uniform_images(dtype, kwargs):
+    assert threshold_triangle(cp.zeros((10, 10), dtype=dtype), **kwargs) == 0
+    assert threshold_triangle(cp.ones((10, 10), dtype=dtype), **kwargs) == 1
+    assert threshold_triangle(cp.full((10, 10), 2, dtype=dtype), **kwargs) == 2
+
+
+# also run cases with nbins > 100000 to also test CuPy-based code path.
+@pytest.mark.parametrize("kwargs", [{}, {"nbins": 300000}])
+@pytest.mark.parametrize(
+    "data, expected_value",
+    [
+        (cp.invert(cp.array(data.text())), 151),
+        (cp.array(data.text()), 104),
+        (coinsd, 80),
+        (cp.invert(coinsd), 175),
+    ],
+)
+def test_triangle_uint_images(data, expected_value, kwargs):
+    assert threshold_triangle(data, **kwargs) == expected_value
 
 
 def test_triangle_float_images():
diff --git a/python/cucim/src/cucim/skimage/measure/tests/test_regionprops.py b/python/cucim/src/cucim/skimage/measure/tests/test_regionprops.py
index 7ce1351a2..1ce3b841f 100644
--- a/python/cucim/src/cucim/skimage/measure/tests/test_regionprops.py
+++ b/python/cucim/src/cucim/skimage/measure/tests/test_regionprops.py
@@ -1,4 +1,5 @@
 import math
+import re
 
 import cupy as cp
 import cupyx.scipy.ndimage as ndi
@@ -1240,6 +1241,20 @@ def test_column_dtypes_correct():
             assert False, f"{col} dtype {t} {msg} {COL_DTYPES[col]}"
 
 
+def test_all_documented_items_in_col_dtypes():
+    numpydoc = pytest.importorskip("numpydoc")
+    docstring = numpydoc.docscrape.FunctionDoc(regionprops)
+    notes_lines = docstring["Notes"]
+    property_lines = filter(lambda line: line.startswith("**"), notes_lines)
+    pattern = r"\*\*(?P<property_name>[a-z_]+)\*\*.*"
+    property_names = {
+        re.search(pattern, property_line).group("property_name")
+        for property_line in property_lines
+    }
+    column_keys = set(COL_DTYPES.keys())
+    assert column_keys == property_names
+
+
 def pixelcount(regionmask):
     """a short test for an extra property"""
     return cp.sum(regionmask)
@@ -1249,6 +1264,11 @@ def intensity_median(regionmask, image_intensity):
     return cp.median(image_intensity[regionmask])
 
 
+def bbox_list(regionmask):
+    """Extra property whose output shape is dependent on mask shape."""
+    return [1] * regionmask.shape[1]
+
+
 def too_many_args(regionmask, image_intensity, superfluous):
     return 1
 
@@ -1314,11 +1334,15 @@ def test_extra_properties_table():
         SAMPLE_MULTIPLE,
         intensity_image=INTENSITY_SAMPLE_MULTIPLE,
         properties=("label",),
-        extra_properties=(intensity_median, pixelcount),
+        extra_properties=(intensity_median, pixelcount, bbox_list),
     )
     assert_array_almost_equal(out["intensity_median"], np.array([2.0, 4.0]))
     assert_array_equal(out["pixelcount"], np.array([10, 2]))
 
+    assert out["bbox_list"].dtype == np.object_
+    assert out["bbox_list"][0] == [1] * 10
+    assert out["bbox_list"][1] == [1] * 1
+
 
 def test_multichannel():
     """Test that computing multichannel properties works."""
diff --git a/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py b/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py
index da089ed67..7a853fb86 100644
--- a/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py
+++ b/python/cucim/src/cucim/skimage/registration/tests/test_phase_cross_correlation.py
@@ -141,7 +141,7 @@ def test_wrong_input():
     template = cp.ones((5, 5))
     with expected_warnings([r"invalid value encountered in true_divide|\A\Z"]):
         with pytest.raises(ValueError):
-            phase_cross_correlation(template, image, return_error=True)
+            phase_cross_correlation(template, image)
 
 
 def test_4d_input_pixel():
@@ -202,7 +202,9 @@ def test_disambiguate_2d(shift0, shift1):
     reference = image[slice0]
     moving = image[slice1]
     computed_shift, _, _ = phase_cross_correlation(
-        reference, moving, disambiguate=True, return_error="always"
+        reference,
+        moving,
+        disambiguate=True,
     )
     np.testing.assert_equal(shift, computed_shift)
 
@@ -215,6 +217,9 @@ def test_disambiguate_zero_shift():
     """
     image = cp.array(camera())
     computed_shift, _, _ = phase_cross_correlation(
-        image, image, disambiguate=True, return_error="always"
+        image,
+        image,
+        disambiguate=True,
+        return_error="always",
     )
     assert computed_shift == (0, 0)
diff --git a/python/cucim/src/cucim/skimage/registration/tests/test_tvl1.py b/python/cucim/src/cucim/skimage/registration/tests/test_tvl1.py
index fa706a9d3..20a70b039 100644
--- a/python/cucim/src/cucim/skimage/registration/tests/test_tvl1.py
+++ b/python/cucim/src/cucim/skimage/registration/tests/test_tvl1.py
@@ -11,8 +11,8 @@ def _sin_flow_gen(image0, max_motion=4.5, npics=5):
     """Generate a synthetic ground truth optical flow with a sinusoid as
       first component.
 
-    Parameters:
-    ----
+    Parameters
+    ----------
     image0: ndarray
         The base image to be warped.
     max_motion: float
diff --git a/python/cucim/src/cucim/skimage/restoration/tests/test_j_invariant.py b/python/cucim/src/cucim/skimage/restoration/tests/test_j_invariant.py
index 584e4a711..6057a92c8 100644
--- a/python/cucim/src/cucim/skimage/restoration/tests/test_j_invariant.py
+++ b/python/cucim/src/cucim/skimage/restoration/tests/test_j_invariant.py
@@ -3,9 +3,6 @@
 import pytest
 from skimage.data import camera, chelsea
 
-# from cucim.skimage.restoration import denoise_wavelet
-from skimage.restoration import denoise_wavelet
-
 from cucim.skimage._shared.utils import _supported_float_type
 from cucim.skimage.data import binary_blobs
 from cucim.skimage.metrics import mean_squared_error as mse
@@ -20,6 +17,10 @@
 noisy_img_color = random_noise(test_img_color, mode="gaussian", var=0.01)
 noisy_img_3d = random_noise(test_img_3d, mode="gaussian", var=0.1)
 
+# skip tests if skimage.restoration module cannot be imported
+skimage_restoration = pytest.importorskip("skimage.restoration")
+denoise_wavelet = skimage_restoration.denoise_wavelet
+
 
 # TODO: replace with CuPy version once completed
 def _denoise_wavelet(image, rescale_sigma=True, **kwargs):
diff --git a/python/cucim/tests/unit/clara/test_image_cache.py b/python/cucim/tests/unit/clara/test_image_cache.py
index 1b8987765..258e01da4 100644
--- a/python/cucim/tests/unit/clara/test_image_cache.py
+++ b/python/cucim/tests/unit/clara/test_image_cache.py
@@ -196,6 +196,7 @@ def test_reserve_more_cache_memory():
     assert cache.miss_count == 0
 
 
+@pytest.mark.skip(reason="currently fails (gh-626)")
 def test_cache_hit_miss(testimg_tiff_stripe_32x24_16_jpeg):
     from cucim import CuImage
     from cucim.clara.cache import preferred_memory_capacity