Skip to content

Commit

Permalink
Support saving and loading of SingleCellExperiment objects with the…
Browse files Browse the repository at this point in the history
… new takane specification (#1)

* Add readers and writer for SCE
* Add tests
* Update github action to run tests from Python 3.8 to 3.12
* Update docstrings
  • Loading branch information
jkanche authored Jan 26, 2024
1 parent 8d100cf commit 2920ca9
Show file tree
Hide file tree
Showing 9 changed files with 477 additions and 86 deletions.
40 changes: 0 additions & 40 deletions .github/workflows/build-docs.yml

This file was deleted.

34 changes: 24 additions & 10 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Publish to PyPI

on:
Expand All @@ -6,32 +9,43 @@ on:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- uses: actions/checkout@v2
- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest tox
pip install flake8 pytest tox
# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with tox
run: |
tox
- name: Build package
- name: Build docs
run: |
tox -e docs
- run: touch ./docs/_build/html/.nojekyll
- name: GH Pages Deployment
uses: JamesIves/[email protected]
with:
branch: gh-pages # The branch the action should deploy to.
folder: ./docs/_build/html
clean: true # Automatically remove deleted files from the deploy branch
- name: Build Project and Publish
run: |
python -m tox -e clean,build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_PASSWORD }}
password: ${{ secrets.PYPI_PASSWORD }}
45 changes: 26 additions & 19 deletions .github/workflows/pypi-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@ name: Test the library

on:
push:
branches:
- master
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]

name: Python ${{ matrix.python-version }}
steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox
- name: Test with tox
run: |
tox
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest tox
# - name: Lint with flake8
# run: |
# # stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with tox
run: |
tox
14 changes: 7 additions & 7 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

[metadata]
name = dolomite-sce
description = Add a short description here!
description = Save and load single-cell experiments in the dolomite framework!
author = LTLA
author_email = [email protected]
license = MIT
license_files = LICENSE.txt
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8; variant=GFM
url = https://github.com/pyscaffold/pyscaffold/
url = https://github.com/ArtifactDB/dolomite-sce
# Add here related links, for example:
project_urls =
Documentation = https://pyscaffold.org/
Documentation = https://github.com/ArtifactDB/dolomite-sce
# Source = https://github.com/pyscaffold/pyscaffold/
# Changelog = https://pyscaffold.org/en/latest/changelog.html
# Tracker = https://github.com/pyscaffold/pyscaffold/issues
Expand All @@ -41,17 +41,17 @@ package_dir =
=src

# Require a min/specific Python version (comma-separated conditions)
# python_requires = >=3.8
python_requires = >=3.8

# Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0.
# Version specifiers like >=2.2,<3.0 avoid problems due to API changes in
# new major versions. This works if the required packages follow Semantic Versioning.
# For more information, check out https://semver.org/.
install_requires =
importlib-metadata; python_version<"3.8"
dolomite_base
dolomite_se
SummarizedExperiment
dolomite_base==0.2.0-alpha6
dolomite_se==0.1.0-alpha2
SingleCellExperiment>=0.4.3,<0.5.0


[options.packages.find]
Expand Down
3 changes: 2 additions & 1 deletion src/dolomite_sce/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
del version, PackageNotFoundError


from .load_single_cell_experiment import load_single_cell_experiment
from .read_single_cell_experiment import read_single_cell_experiment
from .save_single_cell_experiment import save_single_cell_experiment
7 changes: 0 additions & 7 deletions src/dolomite_sce/load_single_cell_experiment.py

This file was deleted.

103 changes: 103 additions & 0 deletions src/dolomite_sce/read_single_cell_experiment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import json
import os

import dolomite_base as dl
from dolomite_base.read_object import read_object_registry
from dolomite_se import read_common_se_props
from singlecellexperiment import SingleCellExperiment

read_object_registry[
"single_cell_experiment"
] = "dolomite_sce.read_single_cell_experiment"


def read_single_cell_experiment(
path: str, metadata: dict, **kwargs
) -> SingleCellExperiment:
"""Load a
:py:class:`~singlecellexperiment.SingleCellExperiment.SingleCellExperiment`
from its on-disk representation.
This method should generally not be called directly but instead be invoked by
:py:meth:`~dolomite_base.read_object.read_object`.
Args:
path:
Path to the directory containing the object.
metadata:
Metadata for the object.
kwargs:
Further arguments, ignored.
Returns:
A
:py:class:`~singlecellexperiment.SingleCellExperiment.SingleCellExperiment`
with file-backed arrays in the assays.
"""

_row_data, _column_data, _assays = read_common_se_props(path)

_main_expt_name = None
if "main_experiment_name" in metadata["single_cell_experiment"]:
_main_expt_name = metadata["single_cell_experiment"]["main_experiment_name"]

sce = SingleCellExperiment(
assays=_assays,
row_data=_row_data,
column_data=_column_data,
main_experiment_name=_main_expt_name,
)

_meta_path = os.path.join(path, "other_data")
if os.path.exists(_meta_path):
_meta = dl.read_object(_meta_path)
sce = sce.set_metadata(_meta.as_dict())

_ranges_path = os.path.join(path, "row_ranges")
if os.path.exists(_ranges_path):
_ranges = dl.read_object(_ranges_path)
sce = sce.set_row_ranges(_ranges)

_rdim_path = os.path.join(path, "reduced_dimensions")
if os.path.exists(_rdim_path):
_rdims = {}

with open(os.path.join(_rdim_path, "names.json"), "r") as handle:
_rdim_names = json.load(handle)

for _aidx, _aname in enumerate(_rdim_names):
_rdim_read_path = os.path.join(_rdim_path, str(_aidx))

try:
_rdims[_aname] = dl.read_object(_rdim_read_path)
except Exception as ex:
raise RuntimeError(
f"failed to load reduced dimension '{_aname}' from '{path}'; "
+ str(ex)
)

sce = sce.set_reduced_dims(_rdims)

_alt_path = os.path.join(path, "alternative_experiments")
if os.path.exists(_alt_path):
_alts = {}

with open(os.path.join(_alt_path, "names.json"), "r") as handle:
_alt_names = json.load(handle)

for _aidx, _aname in enumerate(_alt_names):
_alt_read_path = os.path.join(_alt_path, str(_aidx))

try:
_alts[_aname] = dl.read_object(_alt_read_path)
except Exception as ex:
raise RuntimeError(
f"failed to load alternative experiment '{_aname}' from '{path}'; "
+ str(ex)
)

sce = sce.set_alternative_experiments(_alts)

return sce
Loading

0 comments on commit 2920ca9

Please sign in to comment.