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.6.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.6.0-py3-none-any.whl (5.9 MB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: lavlab_shell-0.6.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.6.0.tar.gz
Algorithm Hash digest
SHA256 b30bdc0c6ce901c5d9f8cfac6067479498713eb7517cce6183984ddcaf190cab
MD5 e353afef4433b0e921bdbd216d4e2b62
BLAKE2b-256 e7f90fc913121a6f16e824f7fadd2d3ec2a4b26304879f0495e099e0b4fc42ce

See more details on using hashes here.

Provenance

The following attestation bundles were made for lavlab_shell-0.6.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.6.0-py3-none-any.whl.

File metadata

  • Download URL: lavlab_shell-0.6.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.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a7e95831cb4a5822350e85167ccb4d8a729307289d2f05f1c98e3c7279b5c756
MD5 404061c9cef12e2848f3c69db9b72089
BLAKE2b-256 f92a1366ee1a973f35c9476f4471ff992715490091a4a1faa9e2fd55d2202be1

See more details on using hashes here.

Provenance

The following attestation bundles were made for lavlab_shell-0.6.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

0.7.0

2 files

This release

0.6.0 This release

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