Skip to content

Add tests#5

Merged
nadjano merged 2 commits intomasterfrom
add-tests
Feb 27, 2026
Merged

Add tests#5
nadjano merged 2 commits intomasterfrom
add-tests

Conversation

@nadjano
Copy link
Collaborator

@nadjano nadjano commented Feb 27, 2026

Add tests for filtering and and allele_utils

Summary by Sourcery

Add comprehensive automated coverage for filtering utilities and allelic ratio calculations while fixing syntelog ratio lookup and preparing for tagged releases.

Bug Fixes:

  • Correct allelic ratio retrieval for a syntelog group to return per-cell ratios across matching transcripts instead of a 1D slice.

Enhancements:

  • Add extensive unit tests for filtering low-expressed genes, grouping logic, and allelic ratio calculation utilities to validate core behaviours and edge cases.
  • Bump project version from 1.3.2 to 1.3.3 to reflect the new tests and bug fix.

CI:

  • Introduce a GitHub Actions workflow to automatically create GitHub releases when new semantic version tags are pushed.

nadjano and others added 2 commits February 27, 2026 14:48
- Add tests/test_allele_utils.py and tests/test_filter.py
- Update polyase/allele_utils.py
- Bump version to 1.3.3 in __init__.py and pyproject.toml

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Automatically creates a GitHub Release with generated release notes
when a v*.*.* tag is pushed. This in turn triggers the existing
python-publish.yml workflow to publish to PyPI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@NIB-SI NIB-SI deleted a comment from sourcery-ai bot Feb 27, 2026
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 27, 2026

Reviewer's Guide

Adds extensive unit test coverage for the filtering and allele_utils functionality, fixes the AlleleRatioCalculator.get_ratios_for_synt_id orientation bug, bumps the package version, and introduces a GitHub Actions workflow for tagged release automation.

Class diagram for AlleleRatioCalculator get_ratios_for_synt_id change

classDiagram
    class AlleleRatioCalculator {
        - adata
        + get_ratios_for_synt_id(synt_id, ratio_layer)
    }

    class AnnData {
        + var
        + layers
    }

    class VarTable {
        + Synt_id
    }

    class Layers {
        + allelic_ratio_unique_counts
        + unique_counts
    }

    AlleleRatioCalculator --> AnnData : uses
    AnnData --> VarTable : has
    AnnData --> Layers : has

    note for AlleleRatioCalculator "get_ratios_for_synt_id now indexes layers as [:, mask] instead of [mask] to return ratios across all cells for a given Synt_id"
Loading

File-Level Changes

Change Details Files
Fix allelic ratio slice orientation so per-syntelog ratios are returned with all cells for the selected transcripts.
  • Change get_ratios_for_synt_id to slice the ratio layer by rows then columns, ensuring the full cell-by-transcript submatrix is returned for a given Synt_id.
  • Keep error handling when the requested ratio layer is missing or not yet computed.
polyase/allele_utils.py
Add comprehensive tests for filter_low_expressed_genes and its helper _get_group_mapping covering behavior, error conditions, and configuration options.
  • Create fixtures for small synthetic AnnData objects with known expression patterns and grouping metadata.
  • Test _get_group_mapping for var/obs/obsm/varm sources including valid tuples and error paths.
  • Validate filter_low_expressed_genes error handling for invalid modes, normalization options, and missing layers.
  • Exercise basic filtering semantics, group-based modes (any/all/mean), copy vs in-place behavior, return_dropped, layer selection (dense and sparse), filter_axis=0/1, CPM normalization, and multiple min_expression types (scalar, dict, callable).
tests/test_filter.py
Add a full test suite for AlleleRatioCalculator and calculate_allelic_ratios to lock in API behavior and numerical correctness across edge cases.
  • Introduce fixtures for multiple AnnData layouts: multiple-transcript groups, single-transcript groups, excluded and NaN Synt_id values, and all-zero matrices.
  • Test AlleleRatioCalculator initialization and set_data behavior including replacing existing adata.
  • Cover calculate_ratios error handling for missing adata, missing Synt_id, and missing counts layers.
  • Verify ratio layer naming (default and custom suffix), non-modification of source layers, shape, correct per-group ratios (including zero totals), behavior for single-transcript groups, and identical results for sparse vs dense counts.
  • Test calculate_multiple_ratios for explicit and auto-detected count layers and that non-count layers are skipped.
  • Validate get_ratios_for_synt_id return values and error conditions, plus the calculate_allelic_ratios convenience wrapper’s behavior and parity with the class method.
tests/test_allele_utils.py
Prepare the project for a new patch release and automate GitHub releases.
  • Bump polyase project version from 1.3.2 to 1.3.3 in pyproject metadata.
  • Add a GitHub Actions workflow that creates a GitHub Release with generated notes whenever a semantic version tag (v*..) is pushed.
pyproject.toml
.github/workflows/release.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@nadjano nadjano merged commit d43723b into master Feb 27, 2026
2 checks passed
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tests/test_allele_utils.py" line_range="314-323" />
<code_context>
+class TestGetRatiosForSyntId:
</code_context>
<issue_to_address>
**question (testing):** Add a test for get_ratios_for_synt_id when the requested Synt_id does not exist.

There’s no test for how `get_ratios_for_synt_id` behaves when the requested `synt_id` is missing from `adata.var['Synt_id']`. Please add a test that locks in the expected behaviour (e.g. raising a clear `ValueError` vs returning an empty array) so this edge case is covered against future regressions.
</issue_to_address>

### Comment 2
<location path="tests/test_filter.py" line_range="460-141" />
<code_context>
+class TestMinExpressionTypes:
</code_context>
<issue_to_address>
**suggestion (testing):** Add coverage for library_size_dependent combined with non-callable thresholds.

You already cover scalar, dict, and callable `min_expression` values, plus `library_size_dependent=True` for the callable case. Please also add a test for `library_size_dependent=True` with a non-callable threshold (scalar or dict), asserting either the expected behaviour or a clear error. This will document and fix the intended semantics of that parameter combination.

Suggested implementation:

```python
class TestMinExpressionTypes:
    def test_float_threshold(self, adata):
        result = filter_low_expressed_genes(
            adata, min_expression=10.0, lib_size_normalization=None, verbose=False
        )
        assert result.n_vars == 2

    def test_scalar_threshold_with_library_size_dependent_raises(self, adata):
        # Non-callable thresholds are not compatible with library_size_dependent=True
        with pytest.raises(ValueError):
            filter_low_expressed_genes(
                adata,
                min_expression=10.0,
                lib_size_normalization=None,
                library_size_dependent=True,
                verbose=False,
            )

    def test_dict_threshold_with_library_size_dependent_raises(self, adata):
        # Non-callable dict thresholds are not compatible with library_size_dependent=True
        threshold = {"A": 10.0, "B": 5.0}
        with pytest.raises(ValueError):
            filter_low_expressed_genes(
                adata,
                min_expression=threshold,
                lib_size_normalization=None,
                library_size_dependent=True,
                verbose=False,
            )

    def test_dict_threshold_per_sample(self, adata):
        """
        Per-sample thresholds.
        Group A sums: s1=300, s2=250, s3=250.

```

1. Ensure `pytest` is imported at the top of `tests/test_filter.py` if it is not already:
   - `import pytest`
2. Update the implementation of `filter_low_expressed_genes` (where it lives) so that when `library_size_dependent=True` and `min_expression` is not callable (i.e. scalar or dict), it raises a `ValueError` matching these tests’ expectations.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +314 to +323
class TestGetRatiosForSyntId:
def test_raises_when_ratio_layer_missing(self, adata_two_groups):
calc = AlleleRatioCalculator(adata_two_groups)
with pytest.raises(ValueError, match="not found"):
calc.get_ratios_for_synt_id(1)

def test_returns_correct_values_for_synt_id(self, adata_two_groups):
calc = AlleleRatioCalculator(adata_two_groups)
calc.calculate_ratios('unique_counts')
ratios = calc.get_ratios_for_synt_id(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question (testing): Add a test for get_ratios_for_synt_id when the requested Synt_id does not exist.

There’s no test for how get_ratios_for_synt_id behaves when the requested synt_id is missing from adata.var['Synt_id']. Please add a test that locks in the expected behaviour (e.g. raising a clear ValueError vs returning an empty array) so this edge case is covered against future regressions.

result = filter_low_expressed_genes(
adata, min_expression=10, lib_size_normalization=None, verbose=False
)
assert 't3' not in result.var_names
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add coverage for library_size_dependent combined with non-callable thresholds.

You already cover scalar, dict, and callable min_expression values, plus library_size_dependent=True for the callable case. Please also add a test for library_size_dependent=True with a non-callable threshold (scalar or dict), asserting either the expected behaviour or a clear error. This will document and fix the intended semantics of that parameter combination.

Suggested implementation:

class TestMinExpressionTypes:
    def test_float_threshold(self, adata):
        result = filter_low_expressed_genes(
            adata, min_expression=10.0, lib_size_normalization=None, verbose=False
        )
        assert result.n_vars == 2

    def test_scalar_threshold_with_library_size_dependent_raises(self, adata):
        # Non-callable thresholds are not compatible with library_size_dependent=True
        with pytest.raises(ValueError):
            filter_low_expressed_genes(
                adata,
                min_expression=10.0,
                lib_size_normalization=None,
                library_size_dependent=True,
                verbose=False,
            )

    def test_dict_threshold_with_library_size_dependent_raises(self, adata):
        # Non-callable dict thresholds are not compatible with library_size_dependent=True
        threshold = {"A": 10.0, "B": 5.0}
        with pytest.raises(ValueError):
            filter_low_expressed_genes(
                adata,
                min_expression=threshold,
                lib_size_normalization=None,
                library_size_dependent=True,
                verbose=False,
            )

    def test_dict_threshold_per_sample(self, adata):
        """
        Per-sample thresholds.
        Group A sums: s1=300, s2=250, s3=250.
  1. Ensure pytest is imported at the top of tests/test_filter.py if it is not already:
    • import pytest
  2. Update the implementation of filter_low_expressed_genes (where it lives) so that when library_size_dependent=True and min_expression is not callable (i.e. scalar or dict), it raises a ValueError matching these tests’ expectations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant