Skip to main content

SHELL — SHELL Highlights Epithelium and Lumen Locations

Build Tests Lint PyPI - Version PyPI - Python Version


A whole-slide image segmentation pipeline for H&E-stained histopathology. SHELL uses Macenko colour deconvolution and a SegResNetVAE to segment epithelium and lumen/stroma regions.

Model weights are bundled with the package — no separate download required.

Label Map

Value Label
0 Background / White
1 Epithelium
2 Stroma

Quick Start

Installation

pip install shell

Python 3.10 – 3.12 is required (constrained by the OMERO dependency).

To use OMERO support (fetching images from an OMERO server):

pip install shell[omero]

CLI — Local WSI Inference

The bundled model is used automatically — no --model-path needed:

shell infer --input slide.tiff --output prediction.tiff

To use a specific bundled model version:

shell infer --input slide.tiff --output prediction.tiff --model-version v1

To use your own weights instead:

shell infer --input slide.tiff --output prediction.tiff --model-path /path/to/custom.pth

CLI — OMERO Inference

shell infer-omero \
    --host $OMERO_SERVER --port $OMERO_PORT \
    --username $OMERO_USERNAME --password $OMERO_PASSWORD \
    --image-id 12345 \
    --output pred_12345.tiff

As a Library

from shell.infer_wsi import infer_wsi

# Uses the bundled latest model automatically
label_map = infer_wsi(
    input_path="slide.tiff",
    output_path="prediction.tiff",
)

You can also load the model directly:

from shell.model import build_model

# Bundled latest
model = build_model(device="cuda")

# Specific bundled version
model = build_model(model_version="v1", device="cuda")

# Custom weights file
model = build_model("/path/to/custom.pth", device="cuda")

Model Versioning

Model weights live in src/shell/weights/ and are registered in shell.model.MODEL_REGISTRY. The LATEST_MODEL constant controls which version is loaded by default.

Version File Notes
v1 model_v1.pth Initial release — SegResNetVAE trained on H&E

Adding a New Model

  1. Place the new .pth file in src/shell/weights/.
  2. Add an entry to MODEL_REGISTRY in src/shell/model.py:
    MODEL_REGISTRY: dict[str, str] = {
        "v1": "model_v1.pth",
        "v2": "model_v2.pth",  # new
    }
    
  3. Update LATEST_MODEL:
    LATEST_MODEL: str = "v2"
    
  4. Bump the package version and release.

Development Setup

Prerequisites: Python 3.10–3.12 and Hatch.

git clone https://github.com/laviolette-lab/shell.git
cd shell
pip install hatch

Optionally install pre-commit hooks:

pip install pre-commit
pre-commit install

Common Commands

Task Command
Run tests hatch run test:test
Tests + coverage hatch run test:cov
Lint hatch run lint:check
Format hatch run lint:format
Auto-fix lint hatch run lint:fix
Format + fix + lint hatch run lint:all
Type check hatch run types:check
Build docs hatch run docs:build-docs
Serve docs hatch run docs:serve-docs
Build wheel hatch build
Clean artifacts make clean

Publishing

Releases are fully automated. Creating a GitHub Release triggers the publish.yml workflow, which:

  1. Builds a wheel and sdist and publishes them to PyPI via trusted publishing (OIDC — no API tokens needed).
  2. Builds standalone binaries for Linux (x86_64) and macOS (x86_64 + arm64) using Nuitka with Python 3.12.
  3. Uploads the binaries as release assets on the GitHub Release.

How to Release

# 1. Bump the version in src/shell/__about__.py
# 2. Commit and tag
git add -A
git commit -m "release: v0.2.0"
git tag v0.2.0
git push && git push --tags

# 3. Create a GitHub Release from the tag
gh release create v0.2.0 --generate-notes

One-Time Setup (PyPI)

  1. Go to https://pypi.org/manage/account/publishing/.
  2. Add a pending publisher:
    • PyPI project name: shell
    • Owner: laviolette-lab
    • Repository: shell
    • Workflow name: publish.yml
    • Environment name: pypi

One-Time Setup (GitHub)

  1. In repository Settings → Environments, create an environment named pypi (optionally with manual approval protection).

Project Structure

shell/
├── src/
│   └── shell/                   # Package source
│       ├── __init__.py          # Public API & version export
│       ├── __about__.py         # Version string
│       ├── cli.py               # CLI entry point
│       ├── model.py             # SegResNetVAE model helpers & registry
│       ├── preprocessing.py     # Macenko deconvolution & EHO transform
│       ├── inference.py         # Sliding-window inference
│       ├── infer_wsi.py         # Local WSI pipeline
│       ├── infer_omero_wsi.py   # OMERO WSI pipeline (tiled, pipelined)
│       ├── weights/             # Bundled model weight files
│       │   └── model_v1.pth
│       └── py.typed             # PEP 561 marker
├── tests/                       # pytest test suite
├── docs/                        # MkDocs source files
├── .github/
│   └── workflows/
│       ├── build.yml            # CI: build wheel on push/PR
│       ├── pytest.yml           # CI: run tests
│       ├── lint.yml             # CI: ruff lint + format check
│       └── publish.yml          # CD: PyPI publish + Nuitka binaries
├── pyproject.toml               # All project & tool configuration
├── Dockerfile                   # Multi-stage build (hatch / dev / prod)
├── Makefile                     # Dev shortcuts
└── README.md

Contributing

See CONTRIBUTING.md for development guidelines.

License

shell is distributed under the terms of the MIT license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lavlab_shell-0.7.0.tar.gz (30.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lavlab_shell-0.7.0-py3-none-any.whl (5.9 MB view details)

Uploaded Python 3

File details

Details for the file lavlab_shell-0.7.0.tar.gz.

File metadata

  • Download URL: lavlab_shell-0.7.0.tar.gz
  • Upload date:
  • Size: 30.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lavlab_shell-0.7.0.tar.gz
Algorithm Hash digest
SHA256 b77ea10fe2e3e3a7dba8893b717e594c1bf71677d93265f80da6b77245443bc6
MD5 8bdf5d37c97e2f21dd6834a910002520
BLAKE2b-256 92b53527968445f92fe8994c1f14ec08a64e078b1e6034b360a6b3be64a57915

See more details on using hashes here.

Provenance

The following attestation bundles were made for lavlab_shell-0.7.0.tar.gz:

Publisher: publish.yml on laviolette-lab/shell

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lavlab_shell-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: lavlab_shell-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 5.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lavlab_shell-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4dec609468396a7693a0f39e3a09e9263c2cdd5cb53bdf882acc188350342522
MD5 8c639b7f6803c3aa1cec8ce9134f4658
BLAKE2b-256 1e9687752e1f6089620db2f5b6a0d5c1ae41ee2894c69fdd1e9bcd4371cb166d

See more details on using hashes here.

Provenance

The following attestation bundles were made for lavlab_shell-0.7.0-py3-none-any.whl:

Publisher: publish.yml on laviolette-lab/shell

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.8.0

2 files

This release

0.7.0 This release

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page