Integrate and Publish a Sleep Study
Distribute your study via HuggingFace, Docker, or PyPI
Once a study is trained and validated, SleePyPhases supports three complementary distribution channels depending on how consumers will use your work:
| Channel | Best for |
|---|---|
| HuggingFace | Sharing model weights — downloaded automatically at runtime |
| Docker | Reproducible execution — ship the full environment as a container |
| PyPI | Reusable plugin — lets other SleePyPhases projects load your study as a dependency |
These are not mutually exclusive. A typical study publishes model weights to HuggingFace, a Docker image to the GitLab container registry for batch inference, and a PyPI package so the broader ecosystem can extend it.
HuggingFace — publish model weights
Upload weights
Trained model weights are stored in a HuggingFace repository and pulled at runtime by ModelExporter.registerModel. To upload your weights, follow the HuggingFace model upload documentation.
The repository name (namespace/repo-name) is the identifier you reference in your plugin.
Register the model in your plugin
In your Plugin.py, call ModelExporter.registerModel with the HuggingFace repo and the data ID that corresponds to the saved model state:
from pyPhasesML.exporter.ModelExporter import ModelExporter
ModelExporter.registerModel(
dataId='modelState<hash>-<ModelName>-<hash>--current',
repository='your-namespace/your-repo'
)At runtime, SleePyPhases checks whether the model file is present locally. If not, it downloads it from HuggingFace automatically before the first inference.
The dataId is the filename (without path) under which the model state is saved. It is printed after training completes.
Docker — publish a container image
Dockerfile
A minimal Dockerfile installs dependencies and sets the phases CLI as the entrypoint:
FROM pytorch/pytorch:2.6.0-cuda12.6-cudnn9-runtime
ARG VERSION="0.0.0"
WORKDIR /app
COPY requirements.txt .
COPY src src
COPY configs configs
COPY project*.yaml ./
RUN echo $VERSION > ./VERSION && \
apt-get -qq update && \
apt-get -qq install -y build-essential libpq-dev && \
apt-get clean && \
pip install --upgrade pip setuptools wheel && \
pip install --user -r requirements.txt && \
mkdir data
ENTRYPOINT ["python", "-m", "phases"]GitLab CI — push to container registry
The pipeline builds and pushes the image on every commit, and tags stable on a Git tag:
image: docker:20.10.21
services:
- name: docker:20.10.21-dind
alias: docker
variables:
DOCKER_TLS_CERTDIR: "/certs"
stages:
- release
- publish
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- '[ "$CI_COMMIT_TAG" != "" ] && export VERSION=$CI_COMMIT_TAG || export VERSION=0.0.1-rc$CI_COMMIT_SHORT_SHA'
build-image:
stage: release
except:
- tags
script:
- docker build --build-arg VERSION=$VERSION -t $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
publish-stable:
stage: publish
only:
- tags
script:
- docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:stable
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
- docker push $CI_REGISTRY_IMAGE:stable
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAGPyPI — publish as a plugin package
When packaged on PyPI, your study becomes a first-class SleePyPhases plugin that anyone can install and reference by name.
GitLab CI — publish to PyPI
image: python:3.13-alpine
stages:
- test
- release
test:
stage: test
before_script:
- apk add --no-cache build-base
script:
- pip install -U -r requirements.txt coverage
- python -m coverage run -m unittest discover -s tests -p "test_*.py"
- python -m coverage report
- python -m coverage xml -o cov/coverage.xml
only:
- pushes
coverage: '/TOTAL.*\s+(\d+\%)/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: cov/coverage.xml
pypi:
stage: release
before_script:
- apk add --no-cache build-base
variables:
APP_VERSION: $CI_COMMIT_TAG
script:
- sed -i "s/v0.0.0/${APP_VERSION}/g" setup.py
- pip install -U twine setuptools
- python setup.py sdist
# for pyproject.toml-based projects, use:
# - pip install -U twine build
# - python -m build
- twine upload dist/*
rules:
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/'You need to create a PyPi project and add a trusted publisher. See the PyPI publishing guide.
Load the published plugin
Once on PyPI, any SleePyPhases project can use your study by name:
pip install YourStudyPackageConfig based:
plugins:
- YourStudyPackageOr flat workflow:
from SleePyPhases import SleePyPhases
project = SleePyPhases.create(plugins=["YourStudyPackage"])
prediction = project.predictFromFile("recording.edf")For full usage example see the Use a Published Study guide.