Skip to content

Commit 4c219ba

Browse files
DriesSchaumontgithub-actions[bot]
authored andcommitted
deploy: 173cbdf
1 parent ac02e97 commit 4c219ba

File tree

619 files changed

+7287
-4545
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

619 files changed

+7287
-4545
lines changed

.github/workflows/integration-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868

6969
- uses: viash-io/viash-actions/setup@v5
7070

71-
- uses: nf-core/setup-nextflow@v1.5.2
71+
- uses: nf-core/setup-nextflow@v2.0.0
7272

7373
# use cache
7474
- name: Cache resources data

.github/workflows/release-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161

6262
- uses: viash-io/viash-actions/setup@v5
6363

64-
- uses: nf-core/setup-nextflow@v1.5.2
64+
- uses: nf-core/setup-nextflow@v2.0.0
6565

6666
# use cache
6767
- name: Cache resources data

.github/workflows/viash-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
run: |
7878
echo "matrix=$(jq -c '[ .[] |
7979
{
80-
"name": .functionality.namespace,
80+
"name": .functionality.name,
8181
"namespace_separator": .platforms | map(select(.type == "docker"))[0].namespace_separator,
8282
"namespace": .functionality.namespace,
8383
"config": .info.config,

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
# openpipelines 1.0.0rc2
2+
3+
## BUG FIXES
4+
5+
* Cellranger multi: Fix using a relative input path for `--vdj_inner_enrichment_primers` (PR #717)
6+
7+
* `dataflow/split_modalities`: remove unused `compression` argument. Use `output_compression` instead (PR #714).
8+
9+
* `metadata/grep_annotation_column`: fix calculating fraction when an input observation has no counts, which caused
10+
the result to be out of bounds.
11+
12+
* Fix `--output` argument not working for several workflows (PR #740).
13+
14+
## MINOR CHANGES
15+
16+
* `metadata/grep_annotation_column`: Added more logging output (PR #697).
17+
18+
* `metadata/add_id` and `metadata/grep_annotation_column`: Bump python to 3.11 (PR #697).
19+
20+
* Bump viash to 0.8.5 (PR #697)
21+
22+
* `dataflow/split_modalities`: add more logging output and bump python to 3.12 (PR #714).
23+
24+
* `correction/cellbender`: Update nextflow resource labels from `singlecpu` and `lowmem` to `midcpu` and `midmem` (PR #736)
25+
126
# openpipelines 1.0.0rc1
227

328
## BREAKING CHANGES

_viash.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
viash_version: 0.8.4
1+
viash_version: 0.8.5
22

33
source: src
44
target: target
@@ -8,6 +8,7 @@ config_mods: |
88
.functionality.requirements.commands := ['ps']
99
.functionality.arguments[.multiple == true].multiple_sep := ";"
1010
.functionality.argument_groups[true].arguments[.multiple == true].multiple_sep := ";"
11+
.functionality.test_resources += {path: 'src/base/openpipelinetestutils', dest: 'openpipelinetestutils'}
1112
.platforms[.type == 'docker'].namespace_separator := '_'
1213
.platforms[.type == 'docker'].target_registry := 'ghcr.io'
1314
.platforms[.type == 'docker'].target_organization := 'openpipelines-bio'
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__pycache__/
2+
build
3+
eggs/
4+
*.egg
5+
*.egg-info/

src/base/openpipelinetestutils/__init__.py

Whitespace-only changes.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import mudata
2+
import anndata
3+
import pandas as pd
4+
import numpy as np
5+
from scipy.sparse import issparse
6+
from mudata import MuData
7+
from pathlib import Path
8+
from pandas.testing import assert_frame_equal
9+
from typing import Literal
10+
from .typing import AnnotationObjectOrPathLike
11+
12+
13+
def _read_if_needed(anndata_mudata_path_or_obj):
14+
if isinstance(anndata_mudata_path_or_obj, (str, Path)):
15+
return mudata.read(anndata_mudata_path_or_obj)
16+
if isinstance(anndata_mudata_path_or_obj, (mudata.MuData, anndata.AnnData)):
17+
return anndata_mudata_path_or_obj.copy()
18+
raise AssertionError("Expected 'Path', 'str' to MuData/AnnData "
19+
"file or MuData/AnnData object.")
20+
21+
def _assert_same_annotation_object_class(left, right):
22+
assert type(left) == type(right), (f"Two objects are not of the same class:"
23+
f"\n[Left]:{type(left)}\n[right]:{type(right)}")
24+
25+
26+
def assert_mudata_modality_keys_equal(left, right):
27+
left_keys = set(left.mod.keys())
28+
right_keys = set(right.mod.keys())
29+
if left_keys!= right_keys:
30+
raise AssertionError("MuData modalities differ:"
31+
f"\n[left]:{left_keys}\n[right]:{right_keys}")
32+
33+
def assert_shape_equal(left: AnnotationObjectOrPathLike, right: AnnotationObjectOrPathLike):
34+
left, right = _read_if_needed(left), _read_if_needed(right)
35+
_assert_same_annotation_object_class(left, right)
36+
if left.shape != right.shape:
37+
raise AssertionError(f"{type(left).__name__} shapes differ:"
38+
f"\n[left]:{left.shape}\n[right]:{right.shape}")
39+
if isinstance(left, MuData):
40+
assert_mudata_modality_keys_equal(left, right)
41+
for mod_name, modality in left.mod.items():
42+
assert_shape_equal(modality, right[mod_name])
43+
44+
45+
def assert_obs_names_equal(left: AnnotationObjectOrPathLike, right: AnnotationObjectOrPathLike,
46+
*args, **kwargs):
47+
left, right = _read_if_needed(left), _read_if_needed(right)
48+
_assert_same_annotation_object_class(left, right)
49+
pd.testing.assert_index_equal(left.obs_names, right.obs_names, *args, **kwargs)
50+
if isinstance(left, MuData):
51+
assert_mudata_modality_keys_equal(left, right)
52+
for mod_name, modality in left.mod.items():
53+
assert_obs_names_equal(modality, right[mod_name])
54+
55+
56+
def assert_var_names_equal(left: AnnotationObjectOrPathLike, right: AnnotationObjectOrPathLike,
57+
*args, **kwargs):
58+
left, right = _read_if_needed(left), _read_if_needed(right)
59+
_assert_same_annotation_object_class(left, right)
60+
pd.testing.assert_index_equal(left.var_names, right.var_names, *args, **kwargs)
61+
if isinstance(left, MuData):
62+
assert_mudata_modality_keys_equal(left, right)
63+
for mod_name, modality in left.mod.items():
64+
assert_var_names_equal(modality, right[mod_name])
65+
66+
67+
def assert_annotation_frame_equal(annotation_attr: Literal["obs", "var"],
68+
left: AnnotationObjectOrPathLike, right: AnnotationObjectOrPathLike,
69+
sort=False, *args, **kwargs):
70+
if not annotation_attr in ("obs", "var"):
71+
raise ValueError("annotation_attr should be 'obs', or 'var'")
72+
left, right = _read_if_needed(left), _read_if_needed(right)
73+
_assert_same_annotation_object_class(left, right)
74+
left_frame, right_frame = getattr(left, annotation_attr), getattr(right, annotation_attr)
75+
if sort:
76+
left_frame, right_frame = left_frame.sort_index(inplace=False), right_frame.sort_index(inplace=False)
77+
assert_frame_equal(left_frame, right_frame, *args, **kwargs)
78+
if isinstance(left, MuData):
79+
assert_mudata_modality_keys_equal(left, right)
80+
for mod_name, modality in left.mod.items():
81+
assert_annotation_frame_equal(annotation_attr, modality,
82+
right[mod_name], sort=sort, *args, **kwargs)
83+
84+
def _assert_layer_equal(left, right):
85+
if issparse(left):
86+
if not issparse(right):
87+
raise AssertionError("Layers differ:\n[left]: sparse\n[right]: not sparse")
88+
if left.getformat() != right.getformat():
89+
raise AssertionError("Layers format differ:"
90+
f"\n[left]:{left.getformat()}\n[right]: {right.getformat()}")
91+
assert np.all(left.indices == right.indices), "Layers differ: indices are not the same"
92+
assert np.all(left.indptr == right.indptr), "Layers differ: index pointers are not the same"
93+
np.testing.assert_allclose(left.data, right.data,
94+
err_msg="Layers data differs.", equal_nan=True)
95+
else:
96+
if issparse(right):
97+
raise AssertionError("Layers differ:\n[left]: not sparse\n[right]: sparse")
98+
np.testing.assert_allclose(left, right,
99+
err_msg="Layers data differs.", equal_nan=True)
100+
101+
102+
def assert_layers_equal(left: AnnotationObjectOrPathLike,
103+
right: AnnotationObjectOrPathLike):
104+
left, right = _read_if_needed(left), _read_if_needed(right)
105+
_assert_same_annotation_object_class(left, right)
106+
if left.raw is not None:
107+
_assert_layer_equal(left.raw, right.raw)
108+
else:
109+
if right.raw:
110+
raise AssertionError("Layer .raw differs: "
111+
f"\n[left]:{left.raw}\n[right]:{right}")
112+
if left.X is not None:
113+
_assert_layer_equal(left.X, right.X)
114+
if left.layers:
115+
assert right.layers and (left.layers.keys() == right.layers.keys()), \
116+
"Avaiable layers differ:" \
117+
f"\n[left]:{left.layers}\n[right]{right.layers}"
118+
for layer_name, layer in left.layers.items():
119+
_assert_layer_equal(layer, right.layers[layer_name])
120+
if isinstance(left, MuData):
121+
assert_mudata_modality_keys_equal(left, right)
122+
for mod_name, modality in left.mod.items():
123+
assert_layers_equal(modality, right[mod_name])
124+
125+
126+
def assert_annotation_objects_equal(left: AnnotationObjectOrPathLike,
127+
right: AnnotationObjectOrPathLike,
128+
check_data=True):
129+
left, right = _read_if_needed(left), _read_if_needed(right)
130+
_assert_same_annotation_object_class(left, right)
131+
assert_shape_equal(left, right)
132+
assert_annotation_frame_equal("obs", left, right)
133+
assert_annotation_frame_equal("var", left, right)
134+
if check_data:
135+
assert_layers_equal(left, right)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from uuid import uuid4
2+
import pytest
3+
4+
@pytest.fixture
5+
def random_path(tmp_path):
6+
def wrapper(extension=None):
7+
extension = "" if not extension else f".{extension}"
8+
return tmp_path / f"{uuid4()}{extension}"
9+
return wrapper
10+
11+
@pytest.fixture
12+
def random_h5mu_path(random_path):
13+
def wrapper():
14+
return random_path(extension="h5mu")
15+
return wrapper
16+
17+
@pytest.fixture
18+
def write_mudata_to_file(random_h5mu_path):
19+
def wrapper(mudata_obj):
20+
output_path = random_h5mu_path()
21+
mudata_obj.write(output_path)
22+
return output_path
23+
return wrapper
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[build-system]
2+
requires = [
3+
"setuptools >= 40.9.0",
4+
]
5+
build-backend = "setuptools.build_meta"

0 commit comments

Comments
 (0)