Skip to content

Commit

Permalink
Merge pull request #91 from rmnldwg/release-1.2.3
Browse files Browse the repository at this point in the history
Release 1.2.3
  • Loading branch information
rmnldwg authored Jul 26, 2024
2 parents 38ec139 + c1caba6 commit 27d5206
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 114 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
python3 -m pip install .[test]
- name: Run tests
run: |
coverage run --omit=tests/*,*/_*.py -m unittest discover -v -p *_test.py .
coverage run --omit=tests/*,*/_*.py -m pytest
coverage xml
- name: Upload to codecov
uses: codecov/codecov-action@v3
27 changes: 25 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

All notable changes to this project will be documented in this file.

<a name="1.2.3"></a>

## [1.2.3] - 2024-07-26

### Features

- (**mid**) Add missing `binary` constructor to `Midline` model. Now all models have a `binary` and `trinary` constructor.

### Styling

- Add rules to [ruff].

### Testing

- Make suite testable with [pytest].

### Ci

- Switch to [pytest] for testing.

<a name="1.2.2"></a>

## [1.2.2] - 2024-06-25
Expand All @@ -23,11 +43,11 @@ All notable changes to this project will be documented in this file.

### Styling

- Use ruff to fix lint and format code.
- Use [ruff] to fix lint and format code.

### Build

- Remove upper cap in deps.
- Remove upper cap in dependencies because of [this](https://iscinumpy.dev/post/bound-version-constraints/).

### Change

Expand Down Expand Up @@ -793,3 +813,6 @@ Almost the entire API has changed. I'd therefore recommend to have a look at the
[#41]: https://github.com/rmnldwg/lymph/issues/41
[#40]: https://github.com/rmnldwg/lymph/issues/40
[#38]: https://github.com/rmnldwg/lymph/issues/38

[ruff]: https://astral.sh/ruff
[pytest]: https://docs.pytest.org/en/stable/
56 changes: 38 additions & 18 deletions lymph/models/midline.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def __init__(
if is_symmetric["tumor_spread"]:
raise ValueError(
"If you want the tumor spread to be symmetric, consider using the "
"Bilateral class."
"Bilateral class.",
)
self.is_symmetric = is_symmetric

Expand All @@ -124,7 +124,7 @@ def __init__(
if self.use_midext_evo and use_central:
raise ValueError(
"Evolution to central tumor not yet implemented. Choose to use either "
"the central model or the midline extension evolution."
"the central model or the midline extension evolution.",
# Actually, this shouldn't be too hard, but we still need to think
# about it for a bit.
)
Expand Down Expand Up @@ -168,6 +168,13 @@ def __init__(
is_modality_leaf=False,
)

@classmethod
def binary(cls, *args, **kwargs) -> Midline:
"""Create a binary model."""
uni_kwargs = kwargs.pop("uni_kwargs", {})
uni_kwargs["allowed_states"] = [0, 1]
return cls(*args, uni_kwargs=uni_kwargs, **kwargs)

@classmethod
def trinary(cls, *args, **kwargs) -> Midline:
"""Create a trinary model."""
Expand Down Expand Up @@ -242,7 +249,7 @@ def unknown(self) -> models.Bilateral:
if self.marginalize_unknown:
return self._unknown
raise AttributeError(
"This instance does not marginalize over unknown midline extension."
"This instance does not marginalize over unknown midline extension.",
)

def get_tumor_spread_params(
Expand All @@ -262,15 +269,15 @@ def get_tumor_spread_params(

if self.use_mixing:
params["contra"] = self.noext.contra.get_tumor_spread_params(
as_flat=as_flat
as_flat=as_flat,
)
params["mixing"] = self.mixing_param
else:
params["noext"] = {
"contra": self.noext.contra.get_tumor_spread_params(as_flat=as_flat)
"contra": self.noext.contra.get_tumor_spread_params(as_flat=as_flat),
}
params["ext"] = {
"contra": self.ext.contra.get_tumor_spread_params(as_flat=as_flat)
"contra": self.ext.contra.get_tumor_spread_params(as_flat=as_flat),
}

if as_flat or not as_dict:
Expand All @@ -295,15 +302,15 @@ def get_lnl_spread_params(
if ext_lnl_params != noext_lnl_params:
raise ValueError(
"LNL spread params not synched between ext and noext models. "
"Returning the ext params."
"Returning the ext params.",
)

if self.use_central:
central_lnl_params = self.central.get_lnl_spread_params(as_flat=False)
if central_lnl_params != ext_lnl_params:
warnings.warn(
"LNL spread params not synched between central and ext models. "
"Returning the ext params."
"Returning the ext params.",
)

if as_flat or not as_dict:
Expand Down Expand Up @@ -412,7 +419,8 @@ def set_tumor_spread_params(
noext_contra_kwargs = global_kwargs.copy()
noext_contra_kwargs.update(kwargs.get("noext", {}).get("contra", {}))
args = self.noext.contra.set_tumor_spread_params(
*args, **noext_contra_kwargs
*args,
**noext_contra_kwargs,
)

ext_contra_kwargs = global_kwargs.copy()
Expand Down Expand Up @@ -521,7 +529,7 @@ def load_patient_data(
elif is_unknown.sum() > 0:
warnings.warn(
f"Discarding {is_unknown.sum()} patients where midline extension "
"is unknown."
"is unknown.",
)

def midext_evo(self) -> np.ndarray:
Expand Down Expand Up @@ -638,7 +646,9 @@ def obs_dist(
"""
if given_state_dist is None:
given_state_dist = self.state_dist(
t_stage=t_stage, mode=mode, central=central
t_stage=t_stage,
mode=mode,
central=central,
)

if given_state_dist.ndim == 2:
Expand All @@ -653,7 +663,9 @@ def obs_dist(
return np.stack(obs_dist)

def _hmm_likelihood(
self, log: bool = True, for_t_stage: str | None = None
self,
log: bool = True,
for_t_stage: str | None = None,
) -> float:
"""Compute the likelihood of the stored data under the hidden Markov model."""
llh = 0.0 if log else 1.0
Expand Down Expand Up @@ -771,7 +783,9 @@ def posterior_state_dist(
if given_state_dist is None:
utils.safe_set_params(self, given_params)
given_state_dist = self.state_dist(
t_stage=t_stage, mode=mode, central=central
t_stage=t_stage,
mode=mode,
central=central,
)

if given_state_dist.ndim == 2:
Expand Down Expand Up @@ -817,7 +831,9 @@ def marginalize(

if given_state_dist is None:
given_state_dist = self.state_dist(
t_stage=t_stage, mode=mode, central=central
t_stage=t_stage,
mode=mode,
central=central,
)

if given_state_dist.ndim == 2:
Expand Down Expand Up @@ -907,7 +923,7 @@ def draw_patients(

if self.use_central:
raise NotImplementedError(
"Drawing patients from the central model not yet supported."
"Drawing patients from the central model not yet supported.",
)

drawn_t_stages = rng.choice(
Expand All @@ -920,13 +936,16 @@ def draw_patients(
[
distributions[t_stage].draw_diag_times(rng=rng)
for t_stage in drawn_t_stages
]
],
)

if self.use_midext_evo:
midext_evo = self.midext_evo()
drawn_midexts = np.array(
[rng.choice(a=[False, True], p=midext_evo[t]) for t in drawn_diag_times]
[
rng.choice(a=[False, True], p=midext_evo[t])
for t in drawn_diag_times
],
)
else:
drawn_midexts = rng.choice(
Expand Down Expand Up @@ -956,7 +975,8 @@ def draw_patients(
seed=seed,
)
drawn_case_diags = np.concatenate(
[drawn_ipsi_diags, drawn_contra_diags], axis=1
[drawn_ipsi_diags, drawn_contra_diags],
axis=1,
)
drawn_diags[drawn_midexts == (case == "ext")] = drawn_case_diags

Expand Down
78 changes: 41 additions & 37 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
[build-system]
requires = [
"setuptools >= 61.0.0",
"setuptools_scm >= 7.0.0",
"wheel",
]
requires = ["setuptools >= 61.0.0", "setuptools_scm >= 7.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "lymph-model"
description = "Package for statistical modelling of lymphatic metastatic spread."
authors = [
{name = "Roman Ludwig", email = "roman.ludwig@usz.ch"}
]
authors = [{ name = "Roman Ludwig", email = "roman.ludwig@usz.ch" }]
readme = "README.rst"
requires-python = ">=3.10"
keywords = ["cancer", "metastasis", "lymphatic progression", "model"]
license = {text = "MIT"}
license = { text = "MIT" }
classifiers = [
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: MIT License",
Expand All @@ -26,24 +20,12 @@ classifiers = [
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering",
]
dependencies = [
"numpy",
"pandas",
"cachetools",
]
dependencies = ["numpy", "pandas", "cachetools"]
dynamic = ["version"]

[project.optional-dependencies]
test = [
"scipy",
"coverage",
"emcee",
]
dev = [
"pre-commit",
"pylint",
"git-cliff",
]
test = ["pytest", "scipy", "coverage", "emcee"]
dev = ["pre-commit"]
docs = [
"sphinx",
"sphinx-book-theme",
Expand All @@ -68,7 +50,12 @@ packages = ["lymph"]
include-package-data = true

[tool.setuptools.dynamic]
version = {attr = "lymph._version.version"}
version = { attr = "lymph._version.version" }


[tool.pytest.ini_options]
testpaths = ["tests"]
filterwarnings = ["ignore::pandas.errors.PerformanceWarning"]


[tool.isort]
Expand All @@ -87,7 +74,24 @@ all = true
exclude = ["tests", "docs"]

[tool.ruff.lint]
select = ["E", "F", "W", "B", "C", "R", "U", "D", "I", "S", "T", "A", "N", "NPY201"]
select = [
"E",
"F",
"W",
"B",
"C",
"R",
"U",
"D",
"I",
"S",
"T",
"A",
"N",
"COM",
"FURB",
"NPY201",
]
ignore = ["B028"]


Expand Down Expand Up @@ -141,20 +145,20 @@ filter_unconventional = true
split_commits = false
# regex for preprocessing the commit messages
commit_preprocessors = [
# { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, # replace issue numbers
# { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, # replace issue numbers
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^docs", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactor" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore", group = "Miscellaneous Tasks" },
{ body = ".*security", group = "Security" },
{ message = "^feat", group = "Features" },
{ message = "^fix", group = "Bug Fixes" },
{ message = "^docs", group = "Documentation" },
{ message = "^perf", group = "Performance" },
{ message = "^refactor", group = "Refactor" },
{ message = "^style", group = "Styling" },
{ message = "^test", group = "Testing" },
{ message = "^chore\\(release\\): prepare for", skip = true },
{ message = "^chore", group = "Miscellaneous Tasks" },
{ body = ".*security", group = "Security" },
]
# protect breaking changes from being skipped due to matching a skipping commit_parser
protect_breaking_commits = false
Expand Down
3 changes: 2 additions & 1 deletion tests/bayesian_unilateral_test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Test the Bayesian Unilateral Model."""
import unittest

import numpy as np

Expand All @@ -7,7 +8,7 @@

class BayesianUnilateralModelTestCase(
fixtures.BinaryUnilateralModelMixin,
fixtures.IgnoreWarningsTestCase,
unittest.TestCase,
):
"""Test the Bayesian Unilateral Model."""

Expand Down
Loading

0 comments on commit 27d5206

Please sign in to comment.