Skip to content

Commit 6ef70db

Browse files
Merge pull request #26 from DiogoRibeiro7/feat/add_citation
Feat/add citation
2 parents 7c84d2b + 944e7cb commit 6ef70db

File tree

16 files changed

+331
-41
lines changed

16 files changed

+331
-41
lines changed

CITATION.cff

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
cff-version: 1.2.0
2+
message: "If you use this software, please cite it using the metadata below."
3+
4+
# Basic information
5+
preferred-citation:
6+
type: software
7+
title: "gen_surv"
8+
version: "1.0.0"
9+
url: "https://github.com/DiogoRibeiro7/genSurvPy"
10+
authors:
11+
- family-names: Ribeiro
12+
given-names: Diogo
13+
orcid: "https://orcid.org/0009-0001-2022-7072"
14+
affiliation: "ESMAD - Instituto Politécnico do Porto"
15+
16+
license: "MIT"
17+
date-released: "2024-01-01"
18+

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ poetry install
2828
- Easy integration with `pandas` and `NumPy`
2929
- Suitable for benchmarking survival algorithms and teaching
3030
- Accelerated Failure Time (Log-Normal) model generator
31+
- Command-line interface powered by `Typer`
3132

3233
## 🧪 Example
3334

@@ -55,6 +56,15 @@ generate(model="thmm", n=100, qmat=[[0, 0.2, 0], [0.1, 0, 0.1], [0, 0.3, 0]],
5556
p0=[1.0, 0.0, 0.0], model_cens="exponential", cens_par=3.0)
5657
```
5758

59+
## ⌨️ Command-Line Usage
60+
61+
Install the package and use ``python -m gen_surv`` to generate datasets without
62+
writing Python code:
63+
64+
```bash
65+
python -m gen_surv dataset aft_ln --n 100 > data.csv
66+
```
67+
5868
## 🔧 Available Generators
5969

6070
| Function | Description |
@@ -115,3 +125,9 @@ expectations for participants in this project.
115125
## 🤝 Contributing
116126

117127
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on setting up your environment, running tests, and submitting pull requests.
128+
129+
## 📑 Citation
130+
131+
If you use **gen_surv** in your work, please cite it using the metadata in
132+
[`CITATION.cff`](CITATION.cff). Many reference managers can import this file
133+
directly.

TODO.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@ This document outlines future enhancements, features, and ideas for improving th
44

55
---
66

7+
## ✨ Priority Items
8+
9+
- [] Add property-based tests using Hypothesis to cover edge cases
10+
- [] Build a CLI for generating datasets from the terminal
11+
- [ ] Expand documentation with multilingual support and more usage examples
12+
- [ ] Implement Weibull and log-logistic AFT models and add visualization utilities
13+
- [] Provide CITATION metadata for proper referencing
14+
- [ ] Ensure all functions include Google-style docstrings with inline comments
15+
16+
---
17+
718
## 📦 1. Interface and UX
819

920
- [] Create a `generate(..., return_type="df" | "dict")` interface
10-
- [ ] Add `__version__` using `importlib.metadata` or `poetry-dynamic-versioning`
11-
- [ ] Build a CLI with `typer` or `click`
21+
- [] Add `__version__` using `importlib.metadata` or `poetry-dynamic-versioning`
22+
- [] Build a CLI with `typer` or `click`
1223
- [] Add example notebooks or scripts for each model (`examples/` folder)
1324

1425
---
@@ -25,7 +36,7 @@ This document outlines future enhancements, features, and ideas for improving th
2536
## 🧪 3. Testing and Quality
2637

2738
- [] Add tests for each model (e.g., `test_tdcm.py`, `test_thmm.py`, `test_aft.py`)
28-
- [ ] Add property-based tests with `hypothesis`
39+
- [] Add property-based tests with `hypothesis`
2940
- [ ] Cover edge cases (e.g., invalid parameters, n=0, negative censoring)
3041
- [ ] Run tests on multiple Python versions (CI matrix)
3142

docs/source/index.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ generate(model="thmm", n=100, qmat=[[0, 0.2, 0], [0.1, 0, 0.1], [0, 0.3, 0]],
4949
p0=[1.0, 0.0, 0.0], model_cens="exponential", cens_par=3.0)
5050
```
5151

52+
## ⌨️ Command-Line Usage
53+
54+
Generate datasets directly from the terminal:
55+
56+
```bash
57+
python -m gen_surv dataset aft_ln --n 100 > data.csv
58+
```
59+
5260
## 🔗 Project Links
5361

5462
- [Source Code](https://github.com/DiogoRibeiro7/genSurvPy)

gen_surv/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1-
from .interface import generate
1+
"""Top-level package for ``gen_surv``.
2+
3+
This module exposes the :func:`generate` function and provides access to the
4+
package version via ``__version__``.
5+
"""
6+
7+
from importlib.metadata import PackageNotFoundError, version
8+
9+
from .interface import generate
10+
11+
try:
12+
__version__ = version("gen_surv")
13+
except PackageNotFoundError: # pragma: no cover - fallback when package not installed
14+
__version__ = "0.0.0"
15+
16+
__all__ = ["generate", "__version__"]
17+

gen_surv/__main__.py

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,4 @@
1-
import argparse
2-
import pandas as pd
3-
from gen_surv.cphm import gen_cphm
4-
from gen_surv.cmm import gen_cmm
5-
from gen_surv.tdcm import gen_tdcm
6-
from gen_surv.thmm import gen_thmm
7-
8-
def run_example(model: str):
9-
if model == "cphm":
10-
df = gen_cphm(n=10, model_cens="uniform", cens_par=1.0, beta=0.5, covar=2.0)
11-
elif model == "cmm":
12-
df = gen_cmm(n=10, model_cens="exponential", cens_par=1.0,
13-
beta=[0.5, 0.2, -0.1], covar=2.0, rate=[0.1, 1.0, 0.2, 1.0, 0.3, 1.0])
14-
elif model == "tdcm":
15-
df = gen_tdcm(n=10, dist="weibull", corr=0.5, dist_par=[1, 2, 1, 2],
16-
model_cens="uniform", cens_par=0.5, beta=[0.1, 0.2, 0.3], lam=1.0)
17-
elif model == "thmm":
18-
df = gen_thmm(n=10, model_cens="uniform", cens_par=0.5,
19-
beta=[0.1, 0.2, 0.3], covar=1.0, rate=[0.5, 0.6, 0.7])
20-
else:
21-
raise ValueError(f"Unknown model: {model}")
22-
23-
print(df)
1+
from gen_surv.cli import app
242

253
if __name__ == "__main__":
26-
parser = argparse.ArgumentParser(description="Run gen_surv model example.")
27-
parser.add_argument("model", choices=["cphm", "cmm", "tdcm", "thmm"],
28-
help="Model to run (cphm, cmm, tdcm, thmm)")
29-
args = parser.parse_args()
30-
run_example(args.model)
4+
app()

gen_surv/cli.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import csv
2+
from typing import Optional
3+
import typer
4+
from gen_surv.interface import generate
5+
6+
app = typer.Typer(help="Generate synthetic survival datasets.")
7+
8+
@app.command()
9+
def dataset(
10+
model: str = typer.Argument(
11+
..., help="Model to simulate [cphm, cmm, tdcm, thmm, aft_ln]"
12+
),
13+
n: int = typer.Option(100, help="Number of samples"),
14+
output: Optional[str] = typer.Option(
15+
None, "-o", help="Output CSV file. Prints to stdout if omitted."
16+
),
17+
) -> None:
18+
"""Generate survival data and optionally save to CSV.
19+
20+
Args:
21+
model: Identifier of the generator to use.
22+
n: Number of samples to create.
23+
output: Optional path to save the CSV file.
24+
25+
Returns:
26+
None
27+
"""
28+
df = generate(model=model, n=n)
29+
if output:
30+
df.to_csv(output, index=False)
31+
typer.echo(f"Saved dataset to {output}")
32+
else:
33+
typer.echo(df.to_csv(index=False))
34+
35+
if __name__ == "__main__":
36+
app()

gen_surv/interface.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
>>> df = generate(model="cphm", n=100, model_cens="uniform", cens_par=1.0, beta=0.5, covar=2.0)
77
"""
88

9+
from typing import Any
10+
import pandas as pd
11+
912
from gen_surv.cphm import gen_cphm
1013
from gen_surv.cmm import gen_cmm
1114
from gen_surv.tdcm import gen_tdcm
@@ -22,13 +25,13 @@
2225
}
2326

2427

25-
def generate(model: str, **kwargs):
26-
"""
27-
Generic interface to generate survival data from various models.
28+
def generate(model: str, **kwargs: Any) -> pd.DataFrame:
29+
"""Generate survival data from a specific model.
2830
29-
Parameters:
30-
model (str): One of ["cphm", "cmm", "tdcm", "thmm"]
31-
**kwargs: Arguments forwarded to the selected model generator.
31+
Args:
32+
model: Name of the generator to run. Must be one of ``cphm``, ``cmm``,
33+
``tdcm``, ``thmm`` or ``aft_ln``.
34+
**kwargs: Arguments forwarded to the chosen generator.
3235
3336
Returns:
3437
pd.DataFrame: Simulated survival data.

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "gen_surv"
3-
version = "1.0.1"
3+
version = "1.0.0"
44
description = "A Python package for simulating survival data, inspired by the R package genSurv"
55
authors = ["Diogo Ribeiro <[email protected]>"]
66
license = "MIT"
@@ -16,12 +16,14 @@ numpy = "^1.26"
1616
pandas = "^2.2.3"
1717
pytest-cov = "^6.1.1"
1818
invoke = "^2.2.0"
19+
typer = "^0.12.3"
1920

2021
[tool.poetry.group.dev.dependencies]
2122
pytest = "^8.3.5"
2223
python-semantic-release = "^9.21.0"
2324
mypy = "^1.15.0"
2425
invoke = "^2.2.0"
26+
hypothesis = "^6.98"
2527

2628

2729
[tool.poetry.group.docs.dependencies]

tasks.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66

77

8+
89
@task
910
def test(c: Context) -> None:
1011
"""
@@ -49,6 +50,33 @@ def test(c: Context) -> None:
4950
print(stderr_output)
5051

5152

53+
@task
54+
def check_version(c: Context) -> None:
55+
"""Validate that ``pyproject.toml`` matches the latest git tag.
56+
57+
This task runs the ``scripts/check_version_match.py`` helper using Poetry
58+
and reports whether the version numbers are aligned.
59+
60+
Args:
61+
c: Invoke context used to run shell commands.
62+
63+
Returns:
64+
None
65+
"""
66+
if not isinstance(c, Context):
67+
raise TypeError(f"Expected Invoke Context, got {type(c).__name__!r}")
68+
69+
# Execute the version check script with Poetry.
70+
cmd = "poetry run python scripts/check_version_match.py"
71+
result = c.run(cmd, warn=True, pty=False)
72+
73+
# Report based on the exit code from the script.
74+
if result.ok:
75+
print("✔️ pyproject version matches the latest git tag.")
76+
else:
77+
print("❌ Version mismatch detected.")
78+
print(result.stderr)
79+
5280
@task
5381
def docs(c: Context) -> None:
5482
"""

0 commit comments

Comments
 (0)