From 1b6809ce30687562ed8c77e89cd628460a8ddddd Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Tue, 27 May 2025 11:59:25 +0200
Subject: [PATCH 01/12] docs: fix build badge in README
---
.github/workflows/release.yml | 2 +-
.github/workflows/testpypi.yml | 2 +-
README.md | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9345c75..3f47cab 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,4 +1,4 @@
-name: Build and release Python package on PyPI
+name: Build
on:
release:
diff --git a/.github/workflows/testpypi.yml b/.github/workflows/testpypi.yml
index b359283..9029f11 100644
--- a/.github/workflows/testpypi.yml
+++ b/.github/workflows/testpypi.yml
@@ -1,4 +1,4 @@
-name: Build and release Python package on TestPyPI
+name: Test Build
on:
push:
diff --git a/README.md b/README.md
index 6cf1815..9a279ff 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[](https://github.com/rmnldwg/lyscripts/blob/main/LICENSE)
[](https://github.com/rmnldwg/lyscripts)
-[](https://pypi.org/project/lyscripts/)
+[](https://pypi.org/project/lyscripts/)
[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
From ba1ff6624b58610fe3b811c905811f6da4fdb5c4 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Tue, 27 May 2025 12:03:17 +0200
Subject: [PATCH 02/12] docs: fix outdated links to rmnldwg
---
.chglog/config.yml | 2 +-
CHANGELOG.md | 114 +++++++++++++++++++++---------------------
README.md | 18 +++----
lyscripts/__init__.py | 2 +-
lyscripts/schema.py | 6 +--
pyproject.toml | 2 +-
6 files changed, 72 insertions(+), 72 deletions(-)
diff --git a/.chglog/config.yml b/.chglog/config.yml
index e3b7d9d..0ea5514 100755
--- a/.chglog/config.yml
+++ b/.chglog/config.yml
@@ -2,7 +2,7 @@ style: github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
- repository_url: https://github.com/rmnldwg/lyscripts
+ repository_url: https://github.com/lycosystem/lyscripts
options:
commits:
filters:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 071c764..fc5e40d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -819,63 +819,63 @@ returns `None` instead. Fixes [#11]
## [0.5.3] - 2022-08-22
-[1.0.0rc1]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a7...1.0.0rc1
-[1.0.0.a7]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a6...1.0.0.a7
-[1.0.0.a6]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a5...1.0.0.a6
-[1.0.0.a5]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a4...1.0.0.a5
-[1.0.0.a4]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a3...1.0.0.a4
-[1.0.0.a3]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a2...1.0.0.a3
-[1.0.0.a2]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a1...1.0.0.a2
-[1.0.0.a1]: https://github.com/rmnldwg/lyscripts/compare/1.0.0.a0...1.0.0.a1
-[1.0.0.a0]: https://github.com/rmnldwg/lyscripts/compare/0.7.3...1.0.0.a0
-[0.7.3]: https://github.com/rmnldwg/lyscripts/compare/0.7.2...0.7.3
-[0.7.2]: https://github.com/rmnldwg/lyscripts/compare/0.7.1...0.7.2
-[0.7.1]: https://github.com/rmnldwg/lyscripts/compare/0.7.0...0.7.1
-[0.7.0]: https://github.com/rmnldwg/lyscripts/compare/0.6.9...0.7.0
-[0.6.9]: https://github.com/rmnldwg/lyscripts/compare/0.6.8...0.6.9
-[0.6.8]: https://github.com/rmnldwg/lyscripts/compare/0.6.7...0.6.8
-[0.6.7]: https://github.com/rmnldwg/lyscripts/compare/0.6.6...0.6.7
-[0.6.6]: https://github.com/rmnldwg/lyscripts/compare/0.6.5...0.6.6
-[0.6.5]: https://github.com/rmnldwg/lyscripts/compare/0.6.4...0.6.5
-[0.6.4]: https://github.com/rmnldwg/lyscripts/compare/0.6.3...0.6.4
-[0.6.3]: https://github.com/rmnldwg/lyscripts/compare/0.6.2...0.6.3
-[0.6.2]: https://github.com/rmnldwg/lyscripts/compare/0.6.1...0.6.2
-[0.6.1]: https://github.com/rmnldwg/lyscripts/compare/0.6.0...0.6.1
-[0.6.0]: https://github.com/rmnldwg/lyscripts/compare/0.5.11...0.6.0
-[0.5.11]: https://github.com/rmnldwg/lyscripts/compare/0.5.10...0.5.11
-[0.5.10]: https://github.com/rmnldwg/lyscripts/compare/0.5.9...0.5.10
-[0.5.9]: https://github.com/rmnldwg/lyscripts/compare/0.5.8...0.5.9
-[0.5.8]: https://github.com/rmnldwg/lyscripts/compare/0.5.7...0.5.8
-[0.5.7]: https://github.com/rmnldwg/lyscripts/compare/0.5.6...0.5.7
-[0.5.6]: https://github.com/rmnldwg/lyscripts/compare/0.5.5...0.5.6
-[0.5.5]: https://github.com/rmnldwg/lyscripts/compare/0.5.4...0.5.5
-[0.5.4]: https://github.com/rmnldwg/lyscripts/compare/0.5.3...0.5.4
-[0.5.3]: https://github.com/rmnldwg/lyscripts/compare/0.5.2...0.5.3
-
-[#2]: https://github.com/rmnldwg/lyscripts/issues/2
-[#5]: https://github.com/rmnldwg/lyscripts/issues/5
-[#8]: https://github.com/rmnldwg/lyscripts/issues/8
-[#11]: https://github.com/rmnldwg/lyscripts/issues/11
-[#13]: https://github.com/rmnldwg/lyscripts/issues/13
-[#15]: https://github.com/rmnldwg/lyscripts/issues/15
-[#16]: https://github.com/rmnldwg/lyscripts/issues/16
-[#17]: https://github.com/rmnldwg/lyscripts/issues/17
-[#20]: https://github.com/rmnldwg/lyscripts/issues/20
-[#21]: https://github.com/rmnldwg/lyscripts/issues/21
-[#23]: https://github.com/rmnldwg/lyscripts/issues/23
-[#25]: https://github.com/rmnldwg/lyscripts/issues/25
-[#30]: https://github.com/rmnldwg/lyscripts/issues/30
-[#31]: https://github.com/rmnldwg/lyscripts/issues/31
-[#33]: https://github.com/rmnldwg/lyscripts/issues/33
-[#40]: https://github.com/rmnldwg/lyscripts/issues/40
-[#41]: https://github.com/rmnldwg/lyscripts/issues/41
-[#44]: https://github.com/rmnldwg/lyscripts/issues/44
-[#45]: https://github.com/rmnldwg/lyscripts/issues/45
-[#51]: https://github.com/rmnldwg/lyscripts/issues/51
-[#53]: https://github.com/rmnldwg/lyscripts/issues/53
-[#54]: https://github.com/rmnldwg/lyscripts/issues/54
-[#57]: https://github.com/rmnldwg/lyscripts/issues/57
-[#70]: https://github.com/rmnldwg/lyscripts/issues/70
+[1.0.0rc1]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a7...1.0.0rc1
+[1.0.0.a7]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a6...1.0.0.a7
+[1.0.0.a6]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a5...1.0.0.a6
+[1.0.0.a5]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a4...1.0.0.a5
+[1.0.0.a4]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a3...1.0.0.a4
+[1.0.0.a3]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a2...1.0.0.a3
+[1.0.0.a2]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a1...1.0.0.a2
+[1.0.0.a1]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a0...1.0.0.a1
+[1.0.0.a0]: https://github.com/lycosystem/lyscripts/compare/0.7.3...1.0.0.a0
+[0.7.3]: https://github.com/lycosystem/lyscripts/compare/0.7.2...0.7.3
+[0.7.2]: https://github.com/lycosystem/lyscripts/compare/0.7.1...0.7.2
+[0.7.1]: https://github.com/lycosystem/lyscripts/compare/0.7.0...0.7.1
+[0.7.0]: https://github.com/lycosystem/lyscripts/compare/0.6.9...0.7.0
+[0.6.9]: https://github.com/lycosystem/lyscripts/compare/0.6.8...0.6.9
+[0.6.8]: https://github.com/lycosystem/lyscripts/compare/0.6.7...0.6.8
+[0.6.7]: https://github.com/lycosystem/lyscripts/compare/0.6.6...0.6.7
+[0.6.6]: https://github.com/lycosystem/lyscripts/compare/0.6.5...0.6.6
+[0.6.5]: https://github.com/lycosystem/lyscripts/compare/0.6.4...0.6.5
+[0.6.4]: https://github.com/lycosystem/lyscripts/compare/0.6.3...0.6.4
+[0.6.3]: https://github.com/lycosystem/lyscripts/compare/0.6.2...0.6.3
+[0.6.2]: https://github.com/lycosystem/lyscripts/compare/0.6.1...0.6.2
+[0.6.1]: https://github.com/lycosystem/lyscripts/compare/0.6.0...0.6.1
+[0.6.0]: https://github.com/lycosystem/lyscripts/compare/0.5.11...0.6.0
+[0.5.11]: https://github.com/lycosystem/lyscripts/compare/0.5.10...0.5.11
+[0.5.10]: https://github.com/lycosystem/lyscripts/compare/0.5.9...0.5.10
+[0.5.9]: https://github.com/lycosystem/lyscripts/compare/0.5.8...0.5.9
+[0.5.8]: https://github.com/lycosystem/lyscripts/compare/0.5.7...0.5.8
+[0.5.7]: https://github.com/lycosystem/lyscripts/compare/0.5.6...0.5.7
+[0.5.6]: https://github.com/lycosystem/lyscripts/compare/0.5.5...0.5.6
+[0.5.5]: https://github.com/lycosystem/lyscripts/compare/0.5.4...0.5.5
+[0.5.4]: https://github.com/lycosystem/lyscripts/compare/0.5.3...0.5.4
+[0.5.3]: https://github.com/lycosystem/lyscripts/compare/0.5.2...0.5.3
+
+[#2]: https://github.com/lycosystem/lyscripts/issues/2
+[#5]: https://github.com/lycosystem/lyscripts/issues/5
+[#8]: https://github.com/lycosystem/lyscripts/issues/8
+[#11]: https://github.com/lycosystem/lyscripts/issues/11
+[#13]: https://github.com/lycosystem/lyscripts/issues/13
+[#15]: https://github.com/lycosystem/lyscripts/issues/15
+[#16]: https://github.com/lycosystem/lyscripts/issues/16
+[#17]: https://github.com/lycosystem/lyscripts/issues/17
+[#20]: https://github.com/lycosystem/lyscripts/issues/20
+[#21]: https://github.com/lycosystem/lyscripts/issues/21
+[#23]: https://github.com/lycosystem/lyscripts/issues/23
+[#25]: https://github.com/lycosystem/lyscripts/issues/25
+[#30]: https://github.com/lycosystem/lyscripts/issues/30
+[#31]: https://github.com/lycosystem/lyscripts/issues/31
+[#33]: https://github.com/lycosystem/lyscripts/issues/33
+[#40]: https://github.com/lycosystem/lyscripts/issues/40
+[#41]: https://github.com/lycosystem/lyscripts/issues/41
+[#44]: https://github.com/lycosystem/lyscripts/issues/44
+[#45]: https://github.com/lycosystem/lyscripts/issues/45
+[#51]: https://github.com/lycosystem/lyscripts/issues/51
+[#53]: https://github.com/lycosystem/lyscripts/issues/53
+[#54]: https://github.com/lycosystem/lyscripts/issues/54
+[#57]: https://github.com/lycosystem/lyscripts/issues/57
+[#70]: https://github.com/lycosystem/lyscripts/issues/70
[`emcee`]: https://emcee.readthedocs.io/en/stable/
[`rich`]: https://rich.readthedocs.io/en/latest/
diff --git a/README.md b/README.md
index 9a279ff..c5e8d6f 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,16 @@
-
+
-[](https://github.com/rmnldwg/lyscripts/blob/main/LICENSE)
-[](https://github.com/rmnldwg/lyscripts)
-[](https://pypi.org/project/lyscripts/)
+[](https://github.com/lycosystem/lyscripts/blob/main/LICENSE)
+[](https://github.com/lycosystem/lyscripts)
+[](https://pypi.org/project/lyscripts/)
[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
-[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
+[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
## What are these `lyscripts`?
-This package provides convenient scripts for performing inference and learning regarding the lymphatic spread of head & neck cancer. Essentially, it provides a *command line interface* (CLI) to the [lymph](https://github.com/rmnldwg/lymph) library and the [lydata](https://github.com/rmnldwg/lydata) repository that stores lymphatic progression data.
+This package provides convenient scripts for performing inference and learning regarding the lymphatic spread of head & neck cancer. Essentially, it provides a *command line interface* (CLI) to the [lymph](https://github.com/lycosystem/lymph) library and the [lydata](https://github.com/rmnldwg/lydata) repository that stores lymphatic progression data.
-We are making these "convenience" scripts public, because doing so is one necessary requirement to making our research easily and fully reproducible. There exists another repository, [lynference](https://github.com/rmnldwg/lynference), where we stored the pipelines that produced our published results in a persistent way.
+We are making these "convenience" scripts public, because doing so is one necessary requirement to making our research easily and fully reproducible. There exists another repository, [lynference](https://github.com/lycosystem/lynference), where we stored the pipelines that produced our published results in a persistent way.
## Installation
@@ -23,7 +23,7 @@ pip install lyscripts
or installed from source by cloning this repo
```bash
-git clone https://github.com/rmnldwg/lyscripts.git
+git clone https://github.com/lycosystem/lyscripts.git
cd lyscripts
pip install .
```
@@ -59,7 +59,7 @@ For these YAML files we provide a unified schema containing all possible fields
```json
{
"yaml.schemas": {
- "https://raw.githubusercontent.com/rmnldwg/lyscripts/main/schemas/ly.json": "*.ly.yaml"
+ "https://raw.githubusercontent.com/lycosystem/lyscripts/main/schemas/ly.json": "*.ly.yaml"
}
}
```
diff --git a/lyscripts/__init__.py b/lyscripts/__init__.py
index 0de3d58..f6b7de8 100644
--- a/lyscripts/__init__.py
+++ b/lyscripts/__init__.py
@@ -26,7 +26,7 @@
__description__ = "Package to interact with lymphatic progression data and models."
__author__ = "Roman Ludwig"
__email__ = "roman.ludwig@usz.ch"
-__uri__ = "https://github.com/rmnldwg/lyscripts"
+__uri__ = "https://github.com/lycosystem/lyscripts"
# activate copy on write in pandas.
# See https://pandas.pydata.org/docs/user_guide/copy_on_write.html
diff --git a/lyscripts/schema.py b/lyscripts/schema.py
index 4776afb..cab7c68 100644
--- a/lyscripts/schema.py
+++ b/lyscripts/schema.py
@@ -13,15 +13,15 @@
{
"yaml.schemas": {
- "https://raw.githubusercontent.com/rmnldwg/lyscripts/main/schemas/ly.json": "*.ly.yaml"
+ "https://raw.githubusercontent.com/lycosystem/lyscripts/main/schemas/ly.json": "*.ly.yaml"
},
}
Which would enable auto-completion and validation for all files with the extension
``.ly.yaml`` in the workspace.
-.. _source code repository: https://github.com/rmnldwg/lyscripts
-.. _URL for the schema: https://raw.githubusercontent.com/rmnldwg/lyscripts/main/schemas/ly.json
+.. _source code repository: https://github.com/lycosystem/lyscripts
+.. _URL for the schema: https://raw.githubusercontent.com/lycosystem/lyscripts/main/schemas/ly.json
""" # noqa: E501
import json
diff --git a/pyproject.toml b/pyproject.toml
index c3ecdfb..38f67e8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -56,7 +56,7 @@ dependencies = [
dynamic = ["version"]
[project.urls]
-source = "https://github.com/rmnldwg/lyscripts"
+source = "https://github.com/lycosystem/lyscripts"
documentation = "https://lyscripts.readthedocs.io"
[project.optional-dependencies]
From a1ec2bef2ded6a83e38c9a500d111a1d8465ce72 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Wed, 18 Jun 2025 10:56:37 +0200
Subject: [PATCH 03/12] chore: update pre-commit & ruff rules
---
.pre-commit-config.yaml | 11 ++++++++---
pyproject.toml | 8 ++++++--
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f6f627a..3b059e6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,17 +1,22 @@
+default_install_hook_types: [pre-commit, commit-msg]
+
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.6.0
+ rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
+ - id: check-toml
+ - id: check-yaml
+ - id: check-json
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.5.4
+ rev: v0.12.0
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
- repo: https://github.com/compilerla/conventional-pre-commit
- rev: v3.3.0
+ rev: v4.2.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
diff --git a/pyproject.toml b/pyproject.toml
index 38f67e8..1ea5847 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -72,6 +72,10 @@ test = [
"pytest",
"pytest-mpl",
]
+dev = [
+ "pre-commit",
+ "git-cliff",
+]
[project.scripts]
lyscripts = "lyscripts:main"
@@ -90,12 +94,12 @@ version = {attr = "lyscripts._version.version"}
testpaths = "."
[tool.ruff.lint]
-select = ["E", "F", "W", "B", "C", "R", "U", "D", "I", "S", "T", "A", "N"]
+select = ["E", "F", "W", "B", "C", "R", "U", "D", "I", "S", "T", "A", "N", "COM", "FURB", "NPY", "UP"]
ignore = ["D409"]
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["E402"]
-"**/{tests,docs}/*" = [
+"{tests,docs}/*" = [
"D103",
"E402",
"S101",
From 9ed130c1b9f69a1d14f0af59cae2e397f517f1d7 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 15:53:39 +0200
Subject: [PATCH 04/12] test: fix the dataset used for testing prevalences
---
tests/compute/prevalences_test.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/compute/prevalences_test.py b/tests/compute/prevalences_test.py
index 7ccdba3..471b78d 100644
--- a/tests/compute/prevalences_test.py
+++ b/tests/compute/prevalences_test.py
@@ -23,7 +23,7 @@ def scenario_config() -> ScenarioConfig:
@pytest.fixture
def data() -> pd.DataFrame:
"""Load one of the lyDATA datasets."""
- data = next(load_datasets())
+ data = next(load_datasets(year=2021, institution="usz"))
return infer_and_combine_levels(data)
From a89a8f15605e42b19987ccc29fbc5808f25f1eb2 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 15:55:00 +0200
Subject: [PATCH 05/12] fix: divide by midext prevalence
This fixes a bug I reintroduced bug where I didn't compute observed and
model prevalence in an analogous and comparable way.
Fixes: #72
---
lyscripts/compute/prevalences.py | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/lyscripts/compute/prevalences.py b/lyscripts/compute/prevalences.py
index 306013e..21c2548 100644
--- a/lyscripts/compute/prevalences.py
+++ b/lyscripts/compute/prevalences.py
@@ -78,13 +78,27 @@ def compute_prevalences(
if isinstance(model, models.Unilateral | models.HPVUnilateral):
involvement = involvement.get("ipsi")
- prevalences.append(
- model.marginalize(
+ prevalence = model.marginalize(
+ given_state_dist=obs_dist,
+ involvement=involvement,
+ **kwargs,
+ )
+
+ if isinstance(model, models.Midline):
+ # In this case, we need to renormalize the prevalence by the marginalized
+ # probability of all states with midline extension. We must do this, because
+ # we compute the analogous quantity for the data. In principle, we could
+ # also compute the prevalence of the diagnosis *and* midline extension, but
+ # we have decided to compute the diagnosis *given* midline extension.
+ # https://github.com/lycosystem/lyscripts/blob/ea49ec/lyscripts/compute/prevalences.py#L217-L225
+ midext_prob = model.marginalize(
+ involvement=None,
given_state_dist=obs_dist,
- involvement=involvement,
**kwargs,
)
- )
+ prevalence /= midext_prob
+
+ prevalences.append(prevalence)
return np.stack(prevalences)
@@ -132,6 +146,12 @@ def observe_prevalence(
has_midext = NoneQ()
else:
has_midext = C("midext") == scenario_config.midext
+
+ # Note that below we compute the prevalence of the diagnosis *given* midline
+ # extension. This means, that when computing the prevalence of the diagnosis in
+ # the model, we need to renormalize by diving by the probability of midline
+ # extension. For an older - but pretty surely correct - implementation see
+ # https://github.com/lycosystem/lyscripts/blob/ea49ec/lyscripts/compute/prevalences.py#L217-L225
return data.ly.portion(
query=generate_query_from_diagnosis(scenario_config.diagnosis),
given=has_t_stage & has_midext,
From ce620f13e65f94d0fb15f9a90b41edfb542ffe1f Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:02:26 +0200
Subject: [PATCH 06/12] ci: use tests action with coverage
---
.github/workflows/tests.yml | 66 +++++++++++++++++++++++--------------
1 file changed, 42 insertions(+), 24 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 75e34fd..24f4097 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,38 +1,56 @@
-# This is a workflow that runs test on the package
-name: Tests
+name: tests
-# Controls when the action will run.
on:
- # Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
- # Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
-# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
- # This workflow contains a single job called "build"
- build:
- # The type of runner that the job will run on
+ test:
+ name: Run tests & report coverage
runs-on: ubuntu-latest
-
- # Steps represent a sequence of tasks that will be executed as part of the job
+ permissions:
+ pull-requests: write
+ contents: write
steps:
- # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- - uses: actions/checkout@v3
- with:
- fetch-depth: 0
- - name: Install python 3
- uses: actions/setup-python@v4
+ - uses: actions/checkout@v4
+ - name: Set up Python
+ uses: actions/setup-python@v5
with:
- python-version: '3.10'
- - name: install dependencies
- run: |
- python3 -m pip install -U pip setuptools setuptools-scm wheel
- python3 -m pip install .[test]
- - name: Run tests
+ python-version: "3.10"
+
+ - name: Install dependencies
run: |
- python3 -m pytest --doctest-modules
+ python -m pip install --upgrade pip
+ python -m pip install .[tests]
+
+ # Below, we first run pytest in the `tests/` folder. Because we use a `src`
+ # layout, this will fail if the package is not installed correctly.
+ - name: Test package is installable
+ run: pytest --cov=lydata --cov-config=pyproject.toml tests
+ env:
+ COVERAGE_FILE: .coverage.is_installable
+
+ # Now, we execute all doctests in the `src` tree. This will NOT run with
+ # the installed code, but it doesn't matter, because we already know it is
+ # installable from the step above.
+ - name: Run doctests
+ if: success() || failure() # run these even if previous step fails
+ run: pytest --cov=lydata --cov-config=pyproject.toml --doctest-modules src
+ env:
+ COVERAGE_FILE: .coverage.doctests
+ GITHUB_TOKEN: ${{ secrets.LYCOSYSTEM_READALL }}
+
+ # Lastly, we collect all files that start with `.coverage` into one file and
+ # create a report either as a comment on the PR or in a separate branch if its
+ # a commit to the main branch. From that branch we can put badges and coverage
+ # reports into e.g. our main README.md
+ - name: Add coverage comment
+ if: success() || failure() # run these even if previous step fails
+ uses: py-cov-action/python-coverage-comment-action@v3
+ with:
+ GITHUB_TOKEN: ${{ github.token }}
+ MERGE_COVERAGE_FILES: true
From dfc8e41edf49c96655b602f493b696284089c151 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:09:05 +0200
Subject: [PATCH 07/12] build: switch to `src` layout
Fixes: #74
---
pyproject.toml | 7 ++----
{lyscripts => src/lyscripts}/__init__.py | 0
{lyscripts => src/lyscripts}/__main__.py | 0
{lyscripts => src/lyscripts}/cli.py | 0
.../lyscripts}/compute/__init__.py | 0
.../lyscripts}/compute/__main__.py | 0
.../lyscripts}/compute/posteriors.py | 4 ++--
.../lyscripts}/compute/prevalences.py | 0
.../lyscripts}/compute/priors.py | 2 +-
{lyscripts => src/lyscripts}/compute/risks.py | 2 +-
{lyscripts => src/lyscripts}/compute/utils.py | 2 +-
{lyscripts => src/lyscripts}/configs.py | 24 ++++++++++++-------
{lyscripts => src/lyscripts}/data/__init__.py | 6 +++--
{lyscripts => src/lyscripts}/data/__main__.py | 7 ++++--
{lyscripts => src/lyscripts}/data/enhance.py | 0
{lyscripts => src/lyscripts}/data/filter.py | 6 ++---
{lyscripts => src/lyscripts}/data/generate.py | 2 +-
{lyscripts => src/lyscripts}/data/join.py | 0
.../lyscripts}/data/lyproxify.py | 8 +++----
{lyscripts => src/lyscripts}/data/split.py | 0
{lyscripts => src/lyscripts}/data/utils.py | 0
{lyscripts => src/lyscripts}/decorators.py | 0
{lyscripts => src/lyscripts}/evaluate.py | 24 +++++++++++++------
{lyscripts => src/lyscripts}/plots.py | 2 +-
{lyscripts => src/lyscripts}/sample.py | 6 ++---
{lyscripts => src/lyscripts}/schedule.py | 0
{lyscripts => src/lyscripts}/schema.py | 0
{lyscripts => src/lyscripts}/utils.py | 0
28 files changed, 60 insertions(+), 42 deletions(-)
rename {lyscripts => src/lyscripts}/__init__.py (100%)
rename {lyscripts => src/lyscripts}/__main__.py (100%)
rename {lyscripts => src/lyscripts}/cli.py (100%)
rename {lyscripts => src/lyscripts}/compute/__init__.py (100%)
rename {lyscripts => src/lyscripts}/compute/__main__.py (100%)
rename {lyscripts => src/lyscripts}/compute/posteriors.py (98%)
rename {lyscripts => src/lyscripts}/compute/prevalences.py (100%)
rename {lyscripts => src/lyscripts}/compute/priors.py (99%)
rename {lyscripts => src/lyscripts}/compute/risks.py (99%)
rename {lyscripts => src/lyscripts}/compute/utils.py (99%)
rename {lyscripts => src/lyscripts}/configs.py (97%)
rename {lyscripts => src/lyscripts}/data/__init__.py (90%)
rename {lyscripts => src/lyscripts}/data/__main__.py (80%)
rename {lyscripts => src/lyscripts}/data/enhance.py (100%)
rename {lyscripts => src/lyscripts}/data/filter.py (96%)
rename {lyscripts => src/lyscripts}/data/generate.py (99%)
rename {lyscripts => src/lyscripts}/data/join.py (100%)
rename {lyscripts => src/lyscripts}/data/lyproxify.py (99%)
rename {lyscripts => src/lyscripts}/data/split.py (100%)
rename {lyscripts => src/lyscripts}/data/utils.py (100%)
rename {lyscripts => src/lyscripts}/decorators.py (100%)
rename {lyscripts => src/lyscripts}/evaluate.py (92%)
rename {lyscripts => src/lyscripts}/plots.py (99%)
rename {lyscripts => src/lyscripts}/sample.py (99%)
rename {lyscripts => src/lyscripts}/schedule.py (100%)
rename {lyscripts => src/lyscripts}/schema.py (100%)
rename {lyscripts => src/lyscripts}/utils.py (100%)
diff --git a/pyproject.toml b/pyproject.toml
index 1ea5847..b67f485 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -81,15 +81,12 @@ dev = [
lyscripts = "lyscripts:main"
[tool.setuptools.packages.find]
-include = ["lyscripts"]
+where = ["src"]
[tool.setuptools_scm]
-write_to = "lyscripts/_version.py"
+write_to = "src/lyscripts/_version.py"
local_scheme = "no-local-version"
-[tool.setuptools.dynamic]
-version = {attr = "lyscripts._version.version"}
-
[tool.pytest.ini_options]
testpaths = "."
diff --git a/lyscripts/__init__.py b/src/lyscripts/__init__.py
similarity index 100%
rename from lyscripts/__init__.py
rename to src/lyscripts/__init__.py
diff --git a/lyscripts/__main__.py b/src/lyscripts/__main__.py
similarity index 100%
rename from lyscripts/__main__.py
rename to src/lyscripts/__main__.py
diff --git a/lyscripts/cli.py b/src/lyscripts/cli.py
similarity index 100%
rename from lyscripts/cli.py
rename to src/lyscripts/cli.py
diff --git a/lyscripts/compute/__init__.py b/src/lyscripts/compute/__init__.py
similarity index 100%
rename from lyscripts/compute/__init__.py
rename to src/lyscripts/compute/__init__.py
diff --git a/lyscripts/compute/__main__.py b/src/lyscripts/compute/__main__.py
similarity index 100%
rename from lyscripts/compute/__main__.py
rename to src/lyscripts/compute/__main__.py
diff --git a/lyscripts/compute/posteriors.py b/src/lyscripts/compute/posteriors.py
similarity index 98%
rename from lyscripts/compute/posteriors.py
rename to src/lyscripts/compute/posteriors.py
index c52589a..c017ccd 100644
--- a/lyscripts/compute/posteriors.py
+++ b/src/lyscripts/compute/posteriors.py
@@ -69,7 +69,7 @@ def compute_posteriors(
given_diagnosis=diagnosis,
mode=mode,
**kwargs,
- )
+ ),
)
return np.stack(posteriors)
@@ -85,7 +85,7 @@ class PosteriorsCLI(BaseComputeCLI):
),
)
posteriors: HDF5FileStorage = Field(
- description="Storage for the computed posteriors."
+ description="Storage for the computed posteriors.",
)
def cli_cmd(self) -> None:
diff --git a/lyscripts/compute/prevalences.py b/src/lyscripts/compute/prevalences.py
similarity index 100%
rename from lyscripts/compute/prevalences.py
rename to src/lyscripts/compute/prevalences.py
diff --git a/lyscripts/compute/priors.py b/src/lyscripts/compute/priors.py
similarity index 99%
rename from lyscripts/compute/priors.py
rename to src/lyscripts/compute/priors.py
index 7b668f8..ae7307e 100644
--- a/lyscripts/compute/priors.py
+++ b/src/lyscripts/compute/priors.py
@@ -54,7 +54,7 @@ def compute_priors(
sum(
model.state_dist(t_stage=t, mode=mode) * p
for t, p in zip(t_stages, t_stages_dist, strict=False)
- )
+ ),
)
return np.stack(priors)
diff --git a/lyscripts/compute/risks.py b/src/lyscripts/compute/risks.py
similarity index 99%
rename from lyscripts/compute/risks.py
rename to src/lyscripts/compute/risks.py
index d12455a..4b3e224 100644
--- a/lyscripts/compute/risks.py
+++ b/src/lyscripts/compute/risks.py
@@ -59,7 +59,7 @@ def compute_risks(
console=console,
):
risks.append(
- model.marginalize(involvement=involvement, given_state_dist=posterior)
+ model.marginalize(involvement=involvement, given_state_dist=posterior),
)
return np.stack(risks)
diff --git a/lyscripts/compute/utils.py b/src/lyscripts/compute/utils.py
similarity index 99%
rename from lyscripts/compute/utils.py
rename to src/lyscripts/compute/utils.py
index d8d25c4..b3bed8a 100644
--- a/lyscripts/compute/utils.py
+++ b/src/lyscripts/compute/utils.py
@@ -116,7 +116,7 @@ class HDF5FileStorage(BaseModel):
"""HDF5 file storage for in- and outputs of computations."""
file: HasParentPath = Field(
- description="Path to the HDF5 file. Parent directories are created if needed."
+ description="Path to the HDF5 file. Parent directories are created if needed.",
)
dataset: str | None = Field(
default=None,
diff --git a/lyscripts/configs.py b/src/lyscripts/configs.py
similarity index 97%
rename from lyscripts/configs.py
rename to src/lyscripts/configs.py
index 11f0a50..f76726e 100644
--- a/lyscripts/configs.py
+++ b/src/lyscripts/configs.py
@@ -73,7 +73,7 @@ class DataConfig(BaseModel):
description=(
"Either a path to a CSV file or a config that specifies how and where "
"to fetch the data from."
- )
+ ),
)
side: Literal["ipsi", "contra"] | None = Field(
default=None,
@@ -129,14 +129,16 @@ class DistributionConfig(BaseModel):
"""Configuration defining a distribution over diagnose times."""
kind: Literal["frozen", "parametric"] = Field(
- default="frozen", description="Parametric distributions may be updated."
+ default="frozen",
+ description="Parametric distributions may be updated.",
)
func: FuncNameType = Field(
default="binomial",
description="Name of predefined function to use as distribution.",
)
params: dict[str, int | float] = Field(
- default={}, description="Parameters to pass to the predefined function."
+ default={},
+ description="Parameters to pass to the predefined function.",
)
@@ -228,14 +230,16 @@ class ModelConfig(BaseModel):
description="Path to a Python file that defines a model.",
)
class_name: Literal["Unilateral", "Bilateral", "Midline"] = Field(
- default="Unilateral", description="Name of the model class to use."
+ default="Unilateral",
+ description="Name of the model class to use.",
)
constructor: Literal["binary", "trinary"] = Field(
default="binary",
description="Trinary models differentiate btw. micro- and macroscopic disease.",
)
max_time: int = Field(
- default=10, description="Max. number of time-steps to evolve the model over."
+ default=10,
+ description="Max. number of time-steps to evolve the model over.",
)
named_params: Sequence[str] = Field(
default=None,
@@ -387,7 +391,7 @@ class SamplingConfig(BaseModel):
"""Settings to configure the MCMC sampling."""
storage_file: Path = Field(
- description="Path to HDF5 file store results or load last state."
+ description="Path to HDF5 file store results or load last state.",
)
history_file: Path | None = Field(
default=None,
@@ -433,7 +437,8 @@ class SamplingConfig(BaseModel):
description=("Number of steps to take in the MCMC sampling."),
)
thin_by: int = Field(
- default=10, description="How many samples to draw before for saving one."
+ default=10,
+ description="How many samples to draw before for saving one.",
)
inverse_temp: float = Field(
default=1.0,
@@ -674,14 +679,15 @@ def _read_file(self, file_path: Path) -> dict[str, Any]:
if data.get("version") != 1:
raise ValueError(
f"Config file {file_path} does not have a 'version: 1' key. "
- "For compatibility reasons, all config files must have this key."
+ "For compatibility reasons, all config files must have this key.",
)
return data
def __call__(self) -> dict[str, Any]:
"""Reload the config files from the paths in the current state."""
yaml_file_to_reload = self.current_state.get(
- self.yaml_file_path_field, self.yaml_file_path
+ self.yaml_file_path_field,
+ self.yaml_file_path,
)
logger.debug(f"Reloading YAML files from {yaml_file_to_reload} (if it exists).")
self.__init__(
diff --git a/lyscripts/data/__init__.py b/src/lyscripts/data/__init__.py
similarity index 90%
rename from lyscripts/data/__init__.py
rename to src/lyscripts/data/__init__.py
index 42f0e0e..7e4f54f 100644
--- a/lyscripts/data/__init__.py
+++ b/src/lyscripts/data/__init__.py
@@ -18,13 +18,15 @@
from lyscripts.data import ( # noqa: F401
enhance,
- filter,
generate,
join,
lyproxify,
split,
)
+# Avoid conflict with built-in `filter` function
+from lyscripts.data import filter as filter_
+
class DataCLI(BaseSettings):
"""Work with lymphatic progression data through this CLI."""
@@ -32,7 +34,7 @@ class DataCLI(BaseSettings):
lyproxify: CliSubCommand[lyproxify.LyproxifyCLI]
join: CliSubCommand[join.JoinCLI]
split: CliSubCommand[split.SplitCLI]
- filter: CliSubCommand[filter.FilterCLI]
+ filter: CliSubCommand[filter_.FilterCLI]
enhance: CliSubCommand[enhance.EnhanceCLI]
generate: CliSubCommand[generate.GenerateCLI]
diff --git a/lyscripts/data/__main__.py b/src/lyscripts/data/__main__.py
similarity index 80%
rename from lyscripts/data/__main__.py
rename to src/lyscripts/data/__main__.py
index 8d270aa..a78ddd1 100644
--- a/lyscripts/data/__main__.py
+++ b/src/lyscripts/data/__main__.py
@@ -4,7 +4,10 @@
from lyscripts import exit_cli
from lyscripts.cli import RichDefaultHelpFormatter
-from lyscripts.data import enhance, filter, generate, join, split
+from lyscripts.data import enhance, generate, join, split
+
+# Avoid conflict with built-in `filter` function
+from lyscripts.data import filter as filter_
def main(args: argparse.Namespace):
@@ -23,7 +26,7 @@ def main(args: argparse.Namespace):
generate._add_parser(subparsers, help_formatter=parser.formatter_class)
join._add_parser(subparsers, help_formatter=parser.formatter_class)
split._add_parser(subparsers, help_formatter=parser.formatter_class)
- filter._add_parser(subparsers, help_formatter=parser.formatter_class)
+ filter_._add_parser(subparsers, help_formatter=parser.formatter_class)
args = parser.parse_args()
args.run_main(args, parser)
diff --git a/lyscripts/data/enhance.py b/src/lyscripts/data/enhance.py
similarity index 100%
rename from lyscripts/data/enhance.py
rename to src/lyscripts/data/enhance.py
diff --git a/lyscripts/data/filter.py b/src/lyscripts/data/filter.py
similarity index 96%
rename from lyscripts/data/filter.py
rename to src/lyscripts/data/filter.py
index 73115aa..bf64566 100644
--- a/lyscripts/data/filter.py
+++ b/src/lyscripts/data/filter.py
@@ -30,10 +30,10 @@ class FilterCLI(BaseCLI):
"The column to filter by. May be a tuple of three strings, since data "
"has a three-level header. If it is only one string, the lydata package "
"tries to map that to a three-level header."
- )
+ ),
)
operator: Literal["==", "!=", ">", "<", ">=", "<=", "in", "contains"] = Field(
- description="The operator to use for comparison."
+ description="The operator to use for comparison.",
)
value: float | int | str = Field(description="The value to compare against.")
output_file: Path = Field(description="The path to save the filtered dataset to.")
@@ -48,7 +48,7 @@ def model_post_init(self, __context):
else:
raise ValueError(
"The column attribute must be an iterable of three strings or a "
- f"single string, but it is {self.column}."
+ f"single string, but it is {self.column}.",
)
try:
diff --git a/lyscripts/data/generate.py b/src/lyscripts/data/generate.py
similarity index 99%
rename from lyscripts/data/generate.py
rename to src/lyscripts/data/generate.py
index 486a9ba..8dadf03 100644
--- a/lyscripts/data/generate.py
+++ b/src/lyscripts/data/generate.py
@@ -42,7 +42,7 @@ class GenerateCLI(BaseCLI):
description=(
"Specify what fraction of generated patients should come from the "
"respective T-Stage."
- )
+ ),
)
modalities: dict[str, ModalityConfig]
params: dict[str, float]
diff --git a/lyscripts/data/join.py b/src/lyscripts/data/join.py
similarity index 100%
rename from lyscripts/data/join.py
rename to src/lyscripts/data/join.py
diff --git a/lyscripts/data/lyproxify.py b/src/lyscripts/data/lyproxify.py
similarity index 99%
rename from lyscripts/data/lyproxify.py
rename to src/lyscripts/data/lyproxify.py
index 63bebc3..02154f8 100644
--- a/lyscripts/data/lyproxify.py
+++ b/src/lyscripts/data/lyproxify.py
@@ -60,7 +60,7 @@ class LyproxifyCLI(BaseCLI):
description=(
"Location of Python file containing a `COLUMN_MAP` dictionary. It may also "
"contain an `EXCLUDE` list of tuples `(column, check)` to exclude patients."
- )
+ ),
)
drop_rows: list[int] = Field(
default=[],
@@ -165,7 +165,7 @@ def get_instruction_depth(nested_column_map: dict[tuple, dict[str, Any]]) -> int
return 1 + get_instruction_depth(value)
raise ValueError(
- "Leaf of column map must be a dictionary with 'func' or 'default' key."
+ "Leaf of column map must be a dictionary with 'func' or 'default' key.",
)
raise ValueError("Empty column map.")
@@ -268,12 +268,12 @@ def transform_to_lyprox(
]
except Exception as exc:
raise ParsingError(
- f"Exception encountered while parsing column {multi_idx_col}"
+ f"Exception encountered while parsing column {multi_idx_col}",
) from exc
else:
raise ParsingError(
f"Column {multi_idx_col} has neither a `default` value nor `func` "
- "describing how to fill this column."
+ "describing how to fill this column.",
)
logger.info("Transformed raw data to LyProX format.")
diff --git a/lyscripts/data/split.py b/src/lyscripts/data/split.py
similarity index 100%
rename from lyscripts/data/split.py
rename to src/lyscripts/data/split.py
diff --git a/lyscripts/data/utils.py b/src/lyscripts/data/utils.py
similarity index 100%
rename from lyscripts/data/utils.py
rename to src/lyscripts/data/utils.py
diff --git a/lyscripts/decorators.py b/src/lyscripts/decorators.py
similarity index 100%
rename from lyscripts/decorators.py
rename to src/lyscripts/decorators.py
diff --git a/lyscripts/evaluate.py b/src/lyscripts/evaluate.py
similarity index 92%
rename from lyscripts/evaluate.py
rename to src/lyscripts/evaluate.py
index 5f7f15e..d09c5dd 100644
--- a/lyscripts/evaluate.py
+++ b/src/lyscripts/evaluate.py
@@ -18,6 +18,8 @@
from lyscripts.utils import load_patient_data, load_yaml_params
+RNG = np.random.default_rng()
+
def _add_parser(
subparsers: argparse._SubParsersAction,
@@ -39,7 +41,9 @@ def _add_arguments(parser: argparse.ArgumentParser):
This is called by the parent module that is called via the command line.
"""
parser.add_argument(
- "data", type=Path, help="Path to the tables of patient data (CSV)."
+ "data",
+ type=Path,
+ help="Path to the tables of patient data (CSV).",
)
parser.add_argument("model", type=Path, help="Path to model output files (HDF5).")
@@ -51,10 +55,16 @@ def _add_arguments(parser: argparse.ArgumentParser):
help="Path to parameter file",
)
parser.add_argument(
- "--plots", default="./plots", type=Path, help="Directory for storing plots"
+ "--plots",
+ default="./plots",
+ type=Path,
+ help="Directory for storing plots",
)
parser.add_argument(
- "--metrics", default="./metrics.json", type=Path, help="Path to metrics file"
+ "--metrics",
+ default="./metrics.json",
+ type=Path,
+ help="Path to metrics file",
)
parser.set_defaults(run_main=main)
@@ -93,7 +103,7 @@ def compute_evidence(
"""
integrals = np.zeros(shape=num)
for i in range(num):
- rand_idx = np.random.choice(log_probs.shape[1], size=log_probs.shape[0])
+ rand_idx = RNG.choice(log_probs.shape[1], size=log_probs.shape[0])
drawn_accuracy = log_probs[np.arange(log_probs.shape[0]), rand_idx].copy()
integrals[i] = trapezoid(y=drawn_accuracy, x=temp_schedule)
return np.mean(integrals), np.std(integrals)
@@ -113,7 +123,7 @@ def compute_ti_results(
if num_temps != len(h5_file["ti"]):
raise RuntimeError(
f"Parameters suggest temp schedule of length {num_temps}, "
- f"but stored are {len(h5_file['ti'])}"
+ f"but stored are {len(h5_file['ti'])}",
)
nwalker = ndim * params["sampling"]["walkers_per_dim"]
@@ -152,7 +162,7 @@ def main(args: argparse.Namespace):
)
logger.info(
"Computed results of thermodynamic integration with "
- f"{len(temp_schedule)} steps"
+ f"{len(temp_schedule)} steps",
)
# store inverse temperatures and log-probs in CSV file
@@ -164,7 +174,7 @@ def main(args: argparse.Namespace):
temp_schedule,
np.mean(ti_log_probs, axis=1),
np.std(ti_log_probs, axis=1),
- ]
+ ],
).T,
columns=["β", "accuracy", "std"],
)
diff --git a/lyscripts/plots.py b/src/lyscripts/plots.py
similarity index 99%
rename from lyscripts/plots.py
rename to src/lyscripts/plots.py
index 2b31313..07335b0 100644
--- a/lyscripts/plots.py
+++ b/src/lyscripts/plots.py
@@ -184,7 +184,7 @@ def from_hdf5(
num_total = int(dataset.attrs["num_total"])
except KeyError as key_err:
raise KeyError(
- "Dataset does not contain observed prevalence data"
+ "Dataset does not contain observed prevalence data",
) from key_err
return cls(
diff --git a/lyscripts/sample.py b/src/lyscripts/sample.py
similarity index 99%
rename from lyscripts/sample.py
rename to src/lyscripts/sample.py
index 480499e..d154dfb 100644
--- a/lyscripts/sample.py
+++ b/src/lyscripts/sample.py
@@ -141,10 +141,10 @@ def ensure_initial_state(sampler: emcee.EnsembleSampler) -> np.ndarray:
state = sampler.backend.get_last_sample()
logger.info(
f"Resuming from {sampler.backend.filename} with {sampler.iteration} "
- "stored iterations."
+ "stored iterations.",
)
except AttributeError:
- state = np.random.uniform(size=(sampler.nwalkers, sampler.ndim))
+ state = np.random.uniform(size=(sampler.nwalkers, sampler.ndim)) # noqa: NPY002
logger.debug(f"No stored samples found. Starting from random state {state}.")
return state
@@ -395,7 +395,7 @@ def cli_cmd(self) -> None:
ndim = MODEL.get_num_dims()
# emcee does not support numpy's new random number generator yet.
- np.random.seed(self.sampling.seed)
+ np.random.seed(self.sampling.seed) # noqa: NPY002
with get_pool(self.sampling.cores) as pool:
sampler = init_sampler(settings=self, ndim=ndim, pool=pool)
diff --git a/lyscripts/schedule.py b/src/lyscripts/schedule.py
similarity index 100%
rename from lyscripts/schedule.py
rename to src/lyscripts/schedule.py
diff --git a/lyscripts/schema.py b/src/lyscripts/schema.py
similarity index 100%
rename from lyscripts/schema.py
rename to src/lyscripts/schema.py
diff --git a/lyscripts/utils.py b/src/lyscripts/utils.py
similarity index 100%
rename from lyscripts/utils.py
rename to src/lyscripts/utils.py
From 88c7f1203e845dc3a988752a4667867b97c7912a Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:18:37 +0200
Subject: [PATCH 08/12] chore: update changelog
---
CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc5e40d..abcb7d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,35 @@
All notable changes to this project will be documented in this file.
+## [1.0.0rc2] - 2025-06-26
+
+### Bug Fixes
+
+- Divide by midext prevalence. Fixes [#72].\
+ This fixes a bug we reintroduced where we didn't compute observed and
+ model prevalence in an analogous and comparable way.
+
+### Documentation
+
+- Fix build badge in README.
+- Fix outdated links to rmnldwg.
+
+### Miscellaneous Tasks
+
+- Update pre-commit & ruff rules.
+
+### Testing
+
+- Fix the dataset used for testing prevalences.
+
+### Build
+
+- Switch to `src` layout. Fixes [#74].
+
+### Ci
+
+- Use tests action with coverage.
+
## [1.0.0rc1] - 2025-05-27
### Bug Fixes
@@ -819,6 +848,7 @@ returns `None` instead. Fixes [#11]
## [0.5.3] - 2022-08-22
+[1.0.0rc2]: https://github.com/lycosystem/lyscripts/compare/1.0.0rc1...1.0.0rc2
[1.0.0rc1]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a7...1.0.0rc1
[1.0.0.a7]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a6...1.0.0.a7
[1.0.0.a6]: https://github.com/lycosystem/lyscripts/compare/1.0.0.a5...1.0.0.a6
@@ -876,6 +906,8 @@ returns `None` instead. Fixes [#11]
[#54]: https://github.com/lycosystem/lyscripts/issues/54
[#57]: https://github.com/lycosystem/lyscripts/issues/57
[#70]: https://github.com/lycosystem/lyscripts/issues/70
+[#72]: https://github.com/lycosystem/lyscripts/issues/72
+[#74]: https://github.com/lycosystem/lyscripts/issues/74
[`emcee`]: https://emcee.readthedocs.io/en/stable/
[`rich`]: https://rich.readthedocs.io/en/latest/
From ecb8b670d9e718e3eb62aefc08689be3e28f843d Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:20:08 +0200
Subject: [PATCH 09/12] docs: add coverage badge to readme
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index c5e8d6f..e757f19 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@
[](https://pypi.org/project/lyscripts/)
[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
[](https://lyscripts.readthedocs.io/en/latest/?badge=latest)
+[](https://htmlpreview.github.io/?https://github.com/lycosystem/lyscripts/blob/python-coverage-comment-action-data/htmlcov/index.html)
## What are these `lyscripts`?
From bc104bc8a1c2b6da8bd221784f14d672ed601400 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:27:56 +0200
Subject: [PATCH 10/12] ci: configure coverage correctly
---
pyproject.toml | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/pyproject.toml b/pyproject.toml
index b67f485..2b9e1a7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -70,6 +70,7 @@ docs = [
]
test = [
"pytest",
+ "pytest-cov",
"pytest-mpl",
]
dev = [
@@ -104,6 +105,14 @@ ignore = ["D409"]
"S607",
]
+[tool.coverage.paths]
+source = [
+ "src/",
+ "**/site-packages/",
+]
+
+[tool.coverage.run]
+relative_files = true
# git-cliff ~ default configuration file
# https://git-cliff.org/docs/configuration
From a8f43ee18e2afcac3fabdae3044975e56d5b39b7 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:31:13 +0200
Subject: [PATCH 11/12] ci: fix typo
---
.github/workflows/tests.yml | 2 +-
pyproject.toml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 24f4097..02f6f12 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -9,7 +9,7 @@ on:
workflow_dispatch:
jobs:
- test:
+ tests:
name: Run tests & report coverage
runs-on: ubuntu-latest
permissions:
diff --git a/pyproject.toml b/pyproject.toml
index 2b9e1a7..22eb330 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -68,7 +68,7 @@ docs = [
"myst_parser",
"autodoc_pydantic",
]
-test = [
+tests = [
"pytest",
"pytest-cov",
"pytest-mpl",
From 66e1d7956d7fb05b2bfc9e48b4d742b18d221860 Mon Sep 17 00:00:00 2001
From: Roman Ludwig <48687784+rmnldwg@users.noreply.github.com>
Date: Thu, 26 Jun 2025 16:41:03 +0200
Subject: [PATCH 12/12] ci: replace lydata with lyscripts in test action
---
.github/workflows/tests.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 02f6f12..84ebe00 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -30,7 +30,7 @@ jobs:
# Below, we first run pytest in the `tests/` folder. Because we use a `src`
# layout, this will fail if the package is not installed correctly.
- name: Test package is installable
- run: pytest --cov=lydata --cov-config=pyproject.toml tests
+ run: pytest --cov=lyscripts --cov-config=pyproject.toml tests
env:
COVERAGE_FILE: .coverage.is_installable
@@ -39,7 +39,7 @@ jobs:
# installable from the step above.
- name: Run doctests
if: success() || failure() # run these even if previous step fails
- run: pytest --cov=lydata --cov-config=pyproject.toml --doctest-modules src
+ run: pytest --cov=lyscripts --cov-config=pyproject.toml --doctest-modules src
env:
COVERAGE_FILE: .coverage.doctests
GITHUB_TOKEN: ${{ secrets.LYCOSYSTEM_READALL }}