csrlite 0.1.0__py3-none-any.whl → 0.2.1__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/ae/ae_utils.py CHANGED
@@ -1,132 +1,62 @@
1
- # pyre-strict
2
- from typing import Any
3
-
4
- import polars as pl
5
- from rtflite import RTFBody, RTFColumnHeader, RTFDocument, RTFFootnote, RTFPage, RTFSource, RTFTitle
6
-
7
-
8
- def get_ae_parameter_title(param: Any, prefix: str = "Participants With") -> str:
9
- """
10
- Extract title from parameter for ae_* title generation.
11
-
12
- Args:
13
- param: Parameter object with terms attribute
14
- prefix: Prefix for the title (e.g. "Participants With", "Listing of Participants With")
15
-
16
- Returns:
17
- Title string for the analysis
18
- """
19
- default_suffix = "Adverse Events"
20
-
21
- if not param:
22
- return f"{prefix} {default_suffix}"
23
-
24
- # Check for terms attribute
25
- if hasattr(param, "terms") and param.terms and isinstance(param.terms, dict):
26
- terms = param.terms
27
-
28
- # Preprocess to empty strings (avoiding None)
29
- before = terms.get("before", "").title()
30
- after = terms.get("after", "").title()
31
-
32
- # Build title and clean up extra spaces
33
- title = f"{prefix} {before} {default_suffix} {after}"
34
- return " ".join(title.split()) # Remove extra spaces
35
-
36
- # Fallback to default
37
- return f"{prefix} {default_suffix}"
38
-
39
-
40
- def get_ae_parameter_row_labels(param: Any) -> tuple[str, str]:
41
- """
42
- Generate n_with and n_without row labels based on parameter terms.
43
-
44
- Returns:
45
- Tuple of (n_with_label, n_without_label)
46
- """
47
- # Default labels
48
- default_with = " with one or more adverse events"
49
- default_without = " with no adverse events"
50
-
51
- if not param or not hasattr(param, "terms") or not param.terms:
52
- return (default_with, default_without)
53
-
54
- terms = param.terms
55
- before = terms.get("before", "").lower()
56
- after = terms.get("after", "").lower()
57
-
58
- # Build dynamic labels with leading indentation
59
- with_label = f"with one or more {before} adverse events {after}"
60
- without_label = f"with no {before} adverse events {after}"
61
-
62
- # Clean up extra spaces and add back the 4-space indentation
63
- with_label = " " + " ".join(with_label.split())
64
- without_label = " " + " ".join(without_label.split())
65
-
66
- return (with_label, without_label)
67
-
68
-
69
- def create_ae_rtf_table(
70
- df: pl.DataFrame,
71
- col_header_1: list[str],
72
- col_header_2: list[str] | None,
73
- col_widths: list[float] | None,
74
- title: list[str] | str,
75
- footnote: list[str] | str | None,
76
- source: list[str] | str | None,
77
- borders_2: bool = True,
78
- orientation: str = "landscape",
79
- ) -> RTFDocument:
80
- """
81
- Create a standardized RTF table document with 1 or 2 header rows.
82
- """
83
- n_cols = len(df.columns)
84
-
85
- # Calculate column widths if None - simple default
86
- if col_widths is None:
87
- col_widths = [1] * n_cols
88
-
89
- # Normalize metadata
90
- title_list = [title] if isinstance(title, str) else title
91
- footnote_list = [footnote] if isinstance(footnote, str) else (footnote or [])
92
- source_list = [source] if isinstance(source, str) else (source or [])
93
-
94
- headers = [
95
- RTFColumnHeader(
96
- text=col_header_1,
97
- col_rel_width=col_widths,
98
- text_justification=["l"] + ["c"] * (n_cols - 1),
99
- )
100
- ]
101
-
102
- if col_header_2:
103
- h2_kwargs = {
104
- "text": col_header_2,
105
- "col_rel_width": col_widths,
106
- "text_justification": ["l"] + ["c"] * (n_cols - 1),
107
- }
108
- if borders_2:
109
- h2_kwargs["border_left"] = ["single"]
110
- h2_kwargs["border_top"] = [""]
111
-
112
- headers.append(RTFColumnHeader(**h2_kwargs))
113
-
114
- rtf_components: dict[str, Any] = {
115
- "df": df,
116
- "rtf_page": RTFPage(orientation=orientation),
117
- "rtf_title": RTFTitle(text=title_list),
118
- "rtf_column_header": headers,
119
- "rtf_body": RTFBody(
120
- col_rel_width=col_widths,
121
- text_justification=["l"] + ["c"] * (n_cols - 1),
122
- border_left=["single"] * n_cols,
123
- ),
124
- }
125
-
126
- if footnote_list:
127
- rtf_components["rtf_footnote"] = RTFFootnote(text=footnote_list)
128
-
129
- if source_list:
130
- rtf_components["rtf_source"] = RTFSource(text=source_list)
131
-
132
- return RTFDocument(**rtf_components)
1
+ from typing import Any
2
+
3
+
4
+ def get_ae_parameter_title(param: Any, prefix: str = "Participants With") -> str:
5
+ """
6
+ Extract title from parameter for ae_* title generation.
7
+
8
+ Args:
9
+ param: Parameter object with terms attribute
10
+ prefix: Prefix for the title (e.g. "Participants With", "Listing of Participants With")
11
+
12
+ Returns:
13
+ Title string for the analysis
14
+ """
15
+ default_suffix = "Adverse Events"
16
+
17
+ if not param:
18
+ return f"{prefix} {default_suffix}"
19
+
20
+ # Check for terms attribute
21
+ if hasattr(param, "terms") and param.terms and isinstance(param.terms, dict):
22
+ terms = param.terms
23
+
24
+ # Preprocess to empty strings (avoiding None)
25
+ before = terms.get("before", "").title()
26
+ after = terms.get("after", "").title()
27
+
28
+ # Build title and clean up extra spaces
29
+ title = f"{prefix} {before} {default_suffix} {after}"
30
+ return " ".join(title.split()) # Remove extra spaces
31
+
32
+ # Fallback to default
33
+ return f"{prefix} {default_suffix}"
34
+
35
+
36
+ def get_ae_parameter_row_labels(param: Any) -> tuple[str, str]:
37
+ """
38
+ Generate n_with and n_without row labels based on parameter terms.
39
+
40
+ Returns:
41
+ Tuple of (n_with_label, n_without_label)
42
+ """
43
+ # Default labels
44
+ default_with = " with one or more adverse events"
45
+ default_without = " with no adverse events"
46
+
47
+ if not param or not hasattr(param, "terms") or not param.terms:
48
+ return (default_with, default_without)
49
+
50
+ terms = param.terms
51
+ before = terms.get("before", "").lower()
52
+ after = terms.get("after", "").lower()
53
+
54
+ # Build dynamic labels with leading indentation
55
+ with_label = f"with one or more {before} adverse events {after}"
56
+ without_label = f"with no {before} adverse events {after}"
57
+
58
+ # Clean up extra spaces and add back the 4-space indentation
59
+ with_label = " " + " ".join(with_label.split())
60
+ without_label = " " + " ".join(without_label.split())
61
+
62
+ return (with_label, without_label)
@@ -0,0 +1,34 @@
1
+ # pyre-strict
2
+ """
3
+ Central configuration for csrlite.
4
+ """
5
+
6
+ from typing import Literal, Optional
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+
11
+ class CsrLiteConfig(BaseModel):
12
+ """
13
+ Global configuration for csrlite library.
14
+ """
15
+
16
+ # Column Name Defaults
17
+ id_col: str = Field(default="USUBJID", description="Subject Identifier Column")
18
+ group_col: Optional[str] = Field(default=None, description="Treatment Group Column")
19
+
20
+ # Missing Value Handling
21
+ missing_str: str = Field(
22
+ default="__missing__", description="String to represent missing string values"
23
+ )
24
+
25
+ # Logging
26
+ logging_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
27
+ default="INFO", description="Default logging level"
28
+ )
29
+
30
+ model_config = ConfigDict(validate_assignment=True)
31
+
32
+
33
+ # Global configuration instance
34
+ config = CsrLiteConfig()