csrlite 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- csrlite/__init__.py +110 -71
- csrlite/ae/__init__.py +1 -1
- csrlite/ae/ae_listing.py +494 -494
- csrlite/ae/ae_specific.py +483 -483
- csrlite/ae/ae_summary.py +401 -401
- csrlite/ae/ae_utils.py +62 -62
- csrlite/cm/cm_listing.py +497 -0
- csrlite/cm/cm_summary.py +327 -0
- csrlite/common/config.py +34 -34
- csrlite/common/count.py +293 -293
- csrlite/common/parse.py +308 -308
- csrlite/common/plan.py +365 -365
- csrlite/common/rtf.py +137 -137
- csrlite/common/utils.py +33 -33
- csrlite/common/yaml_loader.py +71 -71
- csrlite/disposition/__init__.py +2 -2
- csrlite/disposition/disposition.py +332 -332
- csrlite/ie/ie_listing.py +109 -0
- csrlite/ie/{ie.py → ie_summary.py} +292 -405
- csrlite/mh/mh_listing.py +209 -0
- csrlite/mh/mh_summary.py +333 -0
- csrlite/pd/pd_listing.py +461 -0
- {csrlite-0.2.1.dist-info → csrlite-0.3.0.dist-info}/METADATA +68 -68
- csrlite-0.3.0.dist-info/RECORD +26 -0
- csrlite-0.2.1.dist-info/RECORD +0 -20
- {csrlite-0.2.1.dist-info → csrlite-0.3.0.dist-info}/WHEEL +0 -0
- {csrlite-0.2.1.dist-info → csrlite-0.3.0.dist-info}/top_level.txt +0 -0
csrlite/ie/ie_listing.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# pyre-strict
|
|
2
|
+
"""
|
|
3
|
+
Inclusion/Exclusion (IE) Listing Analysis Functions
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import polars as pl
|
|
9
|
+
|
|
10
|
+
from ..common.parse import StudyPlanParser
|
|
11
|
+
from ..common.plan import StudyPlan
|
|
12
|
+
from ..common.rtf import create_rtf_listing
|
|
13
|
+
from ..common.utils import apply_common_filters
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def study_plan_to_ie_listing(
|
|
17
|
+
study_plan: StudyPlan,
|
|
18
|
+
) -> list[str]:
|
|
19
|
+
"""
|
|
20
|
+
Generate IE Listing outputs.
|
|
21
|
+
"""
|
|
22
|
+
# Meta data
|
|
23
|
+
analysis_type = "ie_listing"
|
|
24
|
+
output_dir = study_plan.output_dir
|
|
25
|
+
title = "Listing of Protocol Deviations"
|
|
26
|
+
|
|
27
|
+
# Ensure output directory exists
|
|
28
|
+
Path(output_dir).mkdir(parents=True, exist_ok=True)
|
|
29
|
+
|
|
30
|
+
# Initialize parser
|
|
31
|
+
parser = StudyPlanParser(study_plan)
|
|
32
|
+
|
|
33
|
+
# Get expanded plan (Manually expansion to avoid AttributeError)
|
|
34
|
+
plans = study_plan.study_data.get("plans", [])
|
|
35
|
+
all_specs = []
|
|
36
|
+
for plan_data in plans:
|
|
37
|
+
expanded = study_plan.expander.expand_plan(plan_data)
|
|
38
|
+
for p in expanded:
|
|
39
|
+
all_specs.append(study_plan.expander.create_analysis_spec(p))
|
|
40
|
+
|
|
41
|
+
plan_df = pl.DataFrame(all_specs)
|
|
42
|
+
|
|
43
|
+
if "analysis" in plan_df.columns:
|
|
44
|
+
listing_plans = plan_df.filter(pl.col("analysis") == analysis_type)
|
|
45
|
+
else:
|
|
46
|
+
listing_plans = pl.DataFrame()
|
|
47
|
+
|
|
48
|
+
generated_files = []
|
|
49
|
+
|
|
50
|
+
# If listing_plans is empty, create a dummy row to force generation
|
|
51
|
+
if listing_plans.height == 0:
|
|
52
|
+
listing_plans = pl.DataFrame([{"population": "enrolled", "analysis": analysis_type}])
|
|
53
|
+
|
|
54
|
+
for analysis in listing_plans.iter_rows(named=True):
|
|
55
|
+
# Load ADSL
|
|
56
|
+
pop_name = analysis.get("population", "enrolled")
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
(adsl_raw,) = parser.get_datasets("adsl")
|
|
60
|
+
pop_filter = parser.get_population_filter(pop_name)
|
|
61
|
+
|
|
62
|
+
adsl, _ = apply_common_filters(
|
|
63
|
+
population=adsl_raw,
|
|
64
|
+
observation=None,
|
|
65
|
+
population_filter=pop_filter,
|
|
66
|
+
observation_filter=None,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
except ValueError as e:
|
|
70
|
+
print(f"Error loading population: {e}")
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
# Output filename
|
|
74
|
+
filename = f"{analysis_type}_{pop_name}.rtf".lower()
|
|
75
|
+
output_path = f"{output_dir}/{filename}"
|
|
76
|
+
|
|
77
|
+
# Generate DF
|
|
78
|
+
df = ie_listing_df(adsl)
|
|
79
|
+
|
|
80
|
+
# Generate RTF
|
|
81
|
+
ie_listing_rtf(df, output_path, title=title)
|
|
82
|
+
|
|
83
|
+
generated_files.append(output_path)
|
|
84
|
+
|
|
85
|
+
return generated_files
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def ie_listing_df(adsl: pl.DataFrame) -> pl.DataFrame:
|
|
89
|
+
"""Select columns for Listing."""
|
|
90
|
+
# Check if DCSREAS exists
|
|
91
|
+
cols = ["USUBJID", "DCSREAS"]
|
|
92
|
+
available = [c for c in cols if c in adsl.columns]
|
|
93
|
+
return adsl.select(available)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def ie_listing_rtf(df: pl.DataFrame, output_path: str, title: str | list[str] = "") -> None:
|
|
97
|
+
"""Generate RTF Listing."""
|
|
98
|
+
col_widths = [1.5, 3.5] # Approximate ratio
|
|
99
|
+
|
|
100
|
+
rtf_doc = create_rtf_listing(
|
|
101
|
+
df=df,
|
|
102
|
+
col_header=list(df.columns),
|
|
103
|
+
col_widths=col_widths,
|
|
104
|
+
title=title,
|
|
105
|
+
footnote=[],
|
|
106
|
+
source=[],
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
rtf_doc.write_rtf(output_path)
|