csrlite 0.2.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/ie/ie.py ADDED
@@ -0,0 +1,405 @@
1
+ # pyre-strict
2
+ """
3
+ Inclusion/Exclusion (IE) Table Analysis Functions
4
+
5
+ This module provides a pipeline for IE summary analysis:
6
+ - ie_ard: Generate Analysis Results Data (ARD)
7
+ - ie_df: Transform ARD to display format
8
+ - ie_rtf: Generate formatted RTF output
9
+ - study_plan_to_ie_summary: Batch generation from StudyPlan
10
+ """
11
+
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ import polars as pl
16
+
17
+ from ..common.parse import StudyPlanParser
18
+ from ..common.plan import StudyPlan
19
+ from ..common.rtf import create_rtf_listing, create_rtf_table_n_pct
20
+ from ..common.utils import apply_common_filters
21
+
22
+
23
+ def study_plan_to_ie_summary(
24
+ study_plan: StudyPlan,
25
+ ) -> list[str]:
26
+ """
27
+ Generate IE Summary Table outputs for all analyses defined in StudyPlan.
28
+ """
29
+ # Meta data
30
+ analysis_type = "ie_summary"
31
+ output_dir = study_plan.output_dir
32
+ title = "Summary of Protocol Deviations (Inclusion/Exclusion)"
33
+ # footnote = ["Percentages are based on the number of enrolled participants."]
34
+
35
+ # Defaults
36
+ criteria_df_name = "adie"
37
+
38
+ # Ensure output directory exists
39
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
40
+
41
+ # Initialize parser
42
+ parser = StudyPlanParser(study_plan)
43
+
44
+ # Get expanded plan (Manually expansion to avoid AttributeError)
45
+ plans = study_plan.study_data.get("plans", [])
46
+ all_specs = []
47
+ for plan_data in plans:
48
+ expanded = study_plan.expander.expand_plan(plan_data)
49
+ for p in expanded:
50
+ all_specs.append(study_plan.expander.create_analysis_spec(p))
51
+
52
+ plan_df = pl.DataFrame(all_specs)
53
+
54
+ if "analysis" in plan_df.columns:
55
+ ie_plans = plan_df.filter(pl.col("analysis") == analysis_type)
56
+ else:
57
+ ie_plans = pl.DataFrame()
58
+
59
+ generated_files = []
60
+
61
+ # Iterate over analyses
62
+ for analysis in ie_plans.iter_rows(named=True):
63
+ # Load data
64
+ # Note: IE analysis needs both ADSL (for population/group) and ADIE (for criteria)
65
+ pop_name = analysis.get("population", "enrolled")
66
+ group_kw = analysis.get("group") # Can be None
67
+
68
+ try:
69
+ if group_kw:
70
+ # Load Filtered Population (ADSL) with Group
71
+ adsl, group_col = parser.get_population_data(pop_name, group_kw)
72
+ group_col = group_col.upper()
73
+ grp_suffix = group_col
74
+ else:
75
+ # Load Filtered Population (ADSL) without Group
76
+ # Manual load + filter since get_population_data requires group
77
+ (adsl_raw,) = parser.get_datasets("adsl")
78
+ pop_filter = parser.get_population_filter(pop_name)
79
+
80
+ adsl, _ = apply_common_filters(
81
+ population=adsl_raw,
82
+ observation=None,
83
+ population_filter=pop_filter,
84
+ observation_filter=None,
85
+ )
86
+
87
+ group_col = None
88
+ grp_suffix = "total"
89
+
90
+ except ValueError as e:
91
+ print(f"Error loading population: {e}")
92
+ continue
93
+
94
+ # Load ADIE
95
+ try:
96
+ (adie,) = parser.get_datasets(criteria_df_name)
97
+ except ValueError as e:
98
+ print(f"Error loading datasets: {e}")
99
+ continue
100
+
101
+ # Output filename
102
+ filename = f"{analysis_type}_{pop_name}_{grp_suffix}.rtf".lower()
103
+ output_path = f"{output_dir}/{filename}"
104
+
105
+ # Generate ARD
106
+ ard = ie_ard(adsl=adsl, adie=adie, group_col=group_col)
107
+
108
+ # Generate DF
109
+ df = ie_df(ard)
110
+
111
+ # Generate RTF
112
+ ie_rtf(df, output_path, title=title)
113
+
114
+ generated_files.append(output_path)
115
+
116
+ return generated_files
117
+
118
+
119
+ def ie_ard(adsl: pl.DataFrame, adie: pl.DataFrame, group_col: str | None = None) -> pl.DataFrame:
120
+ """
121
+ Generate Analysis Results Data (ARD) for IE Table.
122
+
123
+ Structure:
124
+ - Total Screening Failures
125
+ - Exclusion Criteria Met
126
+ - [Detail]
127
+ - Inclusion Criteria Not Met
128
+ - [Detail]
129
+ """
130
+ # If group_col is None, create a dummy group column
131
+ actual_group_col: str = group_col if group_col else "Total"
132
+
133
+ # 1. Prepare Data
134
+ # Join ADIE to ADSL to get treatment group info
135
+ df_joined: pl.DataFrame = adie.join(
136
+ adsl.select(["USUBJID"] + ([group_col] if group_col else [])), on="USUBJID", how="inner"
137
+ )
138
+
139
+ if not group_col:
140
+ # Add dummy Total column
141
+ df_joined = df_joined.with_columns(pl.lit("Total").alias("Total"))
142
+
143
+ # Define hierarchy
144
+ results: list[dict[str, Any]] = []
145
+
146
+ # Get distinct groups
147
+ groups: list[str]
148
+ if group_col:
149
+ groups_raw: list[str | None] = sorted(adsl.select(group_col).unique().to_series().to_list())
150
+ groups = [g for g in groups_raw if g is not None]
151
+ else:
152
+ groups = ["Total"]
153
+
154
+ # Helper to calculate n and pct (pct of what? usually pct of failures? or pct of screened?)
155
+ # Usually IE table % is based on Total Screening Failures.
156
+ # Let's count Total Screening Failures per Group first.
157
+
158
+ # Total Screening Failures (Subjects present in ADIE)
159
+ # Note: A subject can match multiple criteria.
160
+ total_failures_by_group = df_joined.group_by(actual_group_col).agg(
161
+ pl.col("USUBJID").n_unique().alias("count")
162
+ )
163
+
164
+ total_failures_map: dict[str, int] = {
165
+ row[actual_group_col]: row["count"] for row in total_failures_by_group.iter_rows(named=True)
166
+ }
167
+
168
+ # Helper for row generation
169
+ def add_row(
170
+ label: str, filter_expr: pl.Expr | None = None, is_header: bool = False, indent: int = 0
171
+ ) -> None:
172
+ row_data: dict[str, Any] = {"label": label, "indent": indent, "is_header": is_header}
173
+
174
+ for g in groups:
175
+ # Filter data for this group
176
+ g_df = df_joined.filter(pl.col(actual_group_col) == g)
177
+
178
+ if filter_expr is not None:
179
+ # Filter specific criteria
180
+ g_df = g_df.filter(filter_expr)
181
+
182
+ n = g_df.select("USUBJID").n_unique()
183
+
184
+ # Pct based on total failures in that group?
185
+ denom = total_failures_map.get(g, 0)
186
+ pct = (n / denom * 100) if denom > 0 else 0.0
187
+
188
+ row_data[f"count_{g}"] = n
189
+ row_data[f"pct_{g}"] = pct
190
+
191
+ results.append(row_data)
192
+
193
+ # 1. Total Screening Failures
194
+ add_row("Total Screening Failures")
195
+
196
+ # 2. Exclusion Criteria Met
197
+ excl_expr = pl.col("PARAMCAT") == "EXCLUSION CRITERIA MET"
198
+ add_row("Exclusion Criteria Met", excl_expr, is_header=True, indent=1)
199
+
200
+ # Details for Exclusion
201
+ excl_params = (
202
+ df_joined.filter(excl_expr).select("PARAM").unique().sort("PARAM").to_series().to_list()
203
+ )
204
+ for param in excl_params:
205
+ add_row(param, excl_expr & (pl.col("PARAM") == param), indent=2)
206
+
207
+ # 3. Inclusion Criteria Not Met
208
+ incl_expr = pl.col("PARAMCAT") == "INCLUSION CRITERIA NOT MET"
209
+ add_row("Inclusion Criteria Not Met", incl_expr, is_header=True, indent=1)
210
+
211
+ # Details for Inclusion
212
+ incl_params = (
213
+ df_joined.filter(incl_expr).select("PARAM").unique().sort("PARAM").to_series().to_list()
214
+ )
215
+ for param in incl_params:
216
+ add_row(param, incl_expr & (pl.col("PARAM") == param), indent=2)
217
+
218
+ return pl.DataFrame(results)
219
+
220
+
221
+ def ie_df(ard: pl.DataFrame) -> pl.DataFrame:
222
+ """Transform ARD to display DataFrame."""
223
+ # Find group columns
224
+ cols = ard.columns
225
+ group_cols = [c for c in cols if c.startswith("count_")]
226
+ groups = [c.replace("count_", "") for c in group_cols]
227
+
228
+ # Create valid Polars expressions for selecting columns
229
+ # Apply indentation: 3 spaces per indent level
230
+ # Note: Using \u00A0 (NBSP) might be safer for RTF if spaces get collapsed,
231
+ # but regular spaces usually work in table cells. Let's start with regular spaces.
232
+
233
+ select_exprs = [
234
+ (pl.lit(" ").repeat_by(pl.col("indent")).list.join("") + pl.col("label")).alias(
235
+ "Criteria"
236
+ )
237
+ ]
238
+
239
+ for g in groups:
240
+ # Format n (%)
241
+ # We need to construct the string.
242
+ # Polars string formatting
243
+ # format: "{n} ({pct:.1f})"
244
+
245
+ # Note: Polars doesn't have f-string strictly in expressions like python
246
+ # We use strict casting and concatenation
247
+
248
+ col_n = pl.col(f"count_{g}")
249
+ col_pct = pl.col(f"pct_{g}")
250
+
251
+ fmt = (
252
+ col_n.cast(pl.Utf8)
253
+ + " ("
254
+ + col_pct.map_elements(lambda x: f"{x:.1f}", return_dtype=pl.Utf8)
255
+ + ")"
256
+ ).alias(g)
257
+
258
+ select_exprs.append(fmt)
259
+
260
+ return ard.select(select_exprs)
261
+
262
+
263
+ def ie_rtf(df: pl.DataFrame, output_path: str, title: str = "") -> None:
264
+ """Generate RTF."""
265
+
266
+ # Rename Criteria column to empty string for display if needed or keep as is?
267
+ # Usually "Criteria".
268
+
269
+ # Calculate number of columns
270
+ n_cols = len(df.columns)
271
+
272
+ # Build first-level column headers (use actual column names)
273
+ col_header_1 = list(df.columns)
274
+
275
+ # Build second-level column headers (empty for first, "n (%)" for groups)
276
+ col_header_2 = [""] + ["n (%)"] * (n_cols - 1)
277
+
278
+ # Calculate column widths - auto-calculate
279
+ # [n_cols-1, 1, 1, 1, ...]
280
+ col_widths = [float(n_cols - 1)] + [1.0] * (n_cols - 1)
281
+
282
+ rtf_doc = create_rtf_table_n_pct(
283
+ df=df,
284
+ col_header_1=col_header_1,
285
+ col_header_2=col_header_2,
286
+ col_widths=col_widths,
287
+ title=[title],
288
+ footnote=None,
289
+ source=None,
290
+ )
291
+
292
+ rtf_doc.write_rtf(output_path)
293
+
294
+
295
+ def study_plan_to_ie_listing(
296
+ study_plan: StudyPlan,
297
+ ) -> list[str]:
298
+ """
299
+ Generate IE Listing outputs.
300
+ """
301
+ # Meta data
302
+ analysis_type = "ie_listing"
303
+ output_dir = study_plan.output_dir
304
+ title = "Listing of Protocol Deviations"
305
+
306
+ # Ensure output directory exists
307
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
308
+
309
+ # Initialize parser
310
+ parser = StudyPlanParser(study_plan)
311
+
312
+ # Get expanded plan (Manually expansion to avoid AttributeError)
313
+ plans = study_plan.study_data.get("plans", [])
314
+ all_specs = []
315
+ for plan_data in plans:
316
+ expanded = study_plan.expander.expand_plan(plan_data)
317
+ for p in expanded:
318
+ all_specs.append(study_plan.expander.create_analysis_spec(p))
319
+
320
+ plan_df = pl.DataFrame(all_specs)
321
+
322
+ # Filter for ie_listing if user specified it, otherwise we might trigger it manually
323
+ # But for now let's assume if this function is called, we want to run for "ie_listing"
324
+ # If the user only asked for "ie_listing", we might need to add it to the plan
325
+ # or just run it blindly for all?
326
+ # Usually we filter by analysis_type.
327
+ if "analysis" in plan_df.columns:
328
+ listing_plans = plan_df.filter(pl.col("analysis") == analysis_type)
329
+ else:
330
+ listing_plans = pl.DataFrame()
331
+
332
+ # If no specific listing plans are found, maybe we should just generate one
333
+ # default one for the whole study?
334
+ # But sticking to the pattern:
335
+ generated_files = []
336
+
337
+ # If listing_plans is empty, let's create a default one to ensure we generate
338
+ # something for the user
339
+ # since they explicitly asked for it.
340
+ if listing_plans.height == 0:
341
+ # Create a dummy row to force generation
342
+ listing_plans = pl.DataFrame([{"population": "enrolled", "analysis": analysis_type}])
343
+
344
+ for analysis in listing_plans.iter_rows(named=True):
345
+ # Load ADSL
346
+ pop_name = analysis.get("population", "enrolled")
347
+
348
+ try:
349
+ # Load Filtered Population (ADSL) without Group
350
+ # (Listings usually don't group by columns like tables)
351
+ # But if they did, we'd handle it. For now, just load raw ADSL.
352
+ (adsl_raw,) = parser.get_datasets("adsl")
353
+ # We could filter, but user just said "show USUBJID and DCSREAS from adsl".
354
+ # Applying population filter if possible.
355
+ pop_filter = parser.get_population_filter(pop_name)
356
+
357
+ adsl, _ = apply_common_filters(
358
+ population=adsl_raw,
359
+ observation=None,
360
+ population_filter=pop_filter,
361
+ observation_filter=None,
362
+ )
363
+
364
+ except ValueError as e:
365
+ print(f"Error loading population: {e}")
366
+ continue
367
+
368
+ # Output filename
369
+ filename = f"{analysis_type}_{pop_name}.rtf".lower()
370
+ output_path = f"{output_dir}/{filename}"
371
+
372
+ # Generate DF
373
+ df = ie_listing_df(adsl)
374
+
375
+ # Generate RTF
376
+ ie_listing_rtf(df, output_path, title=title)
377
+
378
+ generated_files.append(output_path)
379
+
380
+ return generated_files
381
+
382
+
383
+ def ie_listing_df(adsl: pl.DataFrame) -> pl.DataFrame:
384
+ """Select columns for Listing."""
385
+ # Check if DCSREAS exists
386
+ cols = ["USUBJID", "DCSREAS"]
387
+ available = [c for c in cols if c in adsl.columns]
388
+ return adsl.select(available)
389
+
390
+
391
+ def ie_listing_rtf(df: pl.DataFrame, output_path: str, title: str = "") -> None:
392
+ """Generate RTF Listing."""
393
+
394
+ col_widths = [1.5, 3.5] # Approximate ratio
395
+
396
+ rtf_doc = create_rtf_listing(
397
+ df=df,
398
+ col_header=list(df.columns),
399
+ col_widths=col_widths,
400
+ title=[title],
401
+ footnote=None,
402
+ source=None,
403
+ )
404
+
405
+ rtf_doc.write_rtf(output_path)
@@ -1,68 +1,68 @@
1
- Metadata-Version: 2.4
2
- Name: csrlite
3
- Version: 0.2.0
4
- Summary: A hierarchical YAML-based framework for generating Tables, Listings, and Figures in clinical trials
5
- Author-email: Clinical Biostatistics Team <biostat@example.com>
6
- License: MIT
7
- Project-URL: Homepage, https://github.com/elong0527/csrlite
8
- Project-URL: Documentation, https://elong0527.github.io/csrlite
9
- Project-URL: Repository, https://github.com/elong0527/csrlite.git
10
- Project-URL: Bug Tracker, https://github.com/elong0527/csrlite/issues
11
- Keywords: clinical-trials,biostatistics,yaml,tlf,tables,listings,figures
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Intended Audience :: Science/Research
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
19
- Requires-Python: >=3.10
20
- Description-Content-Type: text/markdown
21
- Requires-Dist: pydantic>=2.0.0
22
- Requires-Dist: pyyaml>=6.0
23
- Requires-Dist: polars>=0.20.0
24
- Requires-Dist: rtflite>=2.1.1
25
- Provides-Extra: rtf
26
- Requires-Dist: rtflite; extra == "rtf"
27
- Provides-Extra: plotting
28
- Requires-Dist: matplotlib>=3.5.0; extra == "plotting"
29
- Requires-Dist: plotly>=5.0.0; extra == "plotting"
30
- Provides-Extra: dev
31
- Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
- Requires-Dist: pytest>=9.0.1; extra == "dev"
33
- Requires-Dist: black>=22.0.0; extra == "dev"
34
- Requires-Dist: isort>=7.0.0; extra == "dev"
35
- Requires-Dist: ruff>=0.14.8; extra == "dev"
36
- Requires-Dist: mypy>=1.19.0; extra == "dev"
37
- Requires-Dist: quarto>=0.1.0; extra == "dev"
38
- Requires-Dist: pyre-check>=0.9.18; extra == "dev"
39
- Requires-Dist: jupyter>=1.1.1; extra == "dev"
40
- Requires-Dist: jupyter-cache>=1.0.1; extra == "dev"
41
- Requires-Dist: nbformat>=5.10.4; extra == "dev"
42
- Provides-Extra: all
43
- Requires-Dist: rtflite; extra == "all"
44
- Requires-Dist: matplotlib>=3.5.0; extra == "all"
45
- Requires-Dist: plotly>=5.0.0; extra == "all"
46
-
47
- # csrlite
48
-
49
- [![CI](https://github.com/elong0527/csrlite/actions/workflows/ci.yml/badge.svg)](https://github.com/elong0527/csrlite/actions/workflows/ci.yml)
50
- [![codecov](https://codecov.io/gh/elong0527/csrlite/branch/main/graph/badge.svg)](https://codecov.io/gh/elong0527/csrlite)
51
- [![PyPI version](https://badge.fury.io/py/csrlite.svg)](https://badge.fury.io/py/csrlite)
52
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
53
-
54
- A hierarchical YAML-based framework for generating Tables, Listings, and Figures in clinical trials.
55
-
56
- ## Installation
57
-
58
- ```bash
59
- pip install csrlite
60
- ```
61
-
62
- ## Documentation
63
-
64
- Visit [https://elong0527.github.io/csrlite](https://elong0527.github.io/csrlite) for full documentation.
65
-
66
- ## License
67
-
68
- MIT License - see [LICENSE](LICENSE) file for details.
1
+ Metadata-Version: 2.4
2
+ Name: csrlite
3
+ Version: 0.2.1
4
+ Summary: A hierarchical YAML-based framework for generating Tables, Listings, and Figures in clinical trials
5
+ Author-email: Clinical Biostatistics Team <biostat@example.com>, Ming-Chun Chen <hellomingchun@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/elong0527/csrlite
8
+ Project-URL: Documentation, https://elong0527.github.io/csrlite
9
+ Project-URL: Repository, https://github.com/elong0527/csrlite.git
10
+ Project-URL: Bug Tracker, https://github.com/elong0527/csrlite/issues
11
+ Keywords: clinical-trials,biostatistics,yaml,tlf,tables,listings,figures
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: pydantic>=2.0.0
22
+ Requires-Dist: pyyaml>=6.0
23
+ Requires-Dist: polars>=0.20.0
24
+ Requires-Dist: rtflite>=2.1.1
25
+ Provides-Extra: rtf
26
+ Requires-Dist: rtflite; extra == "rtf"
27
+ Provides-Extra: plotting
28
+ Requires-Dist: matplotlib>=3.5.0; extra == "plotting"
29
+ Requires-Dist: plotly>=5.0.0; extra == "plotting"
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
32
+ Requires-Dist: pytest>=9.0.1; extra == "dev"
33
+ Requires-Dist: black>=22.0.0; extra == "dev"
34
+ Requires-Dist: isort>=7.0.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.14.8; extra == "dev"
36
+ Requires-Dist: mypy>=1.19.0; extra == "dev"
37
+ Requires-Dist: quarto>=0.1.0; extra == "dev"
38
+ Requires-Dist: pyre-check>=0.9.18; extra == "dev"
39
+ Requires-Dist: jupyter>=1.1.1; extra == "dev"
40
+ Requires-Dist: jupyter-cache>=1.0.1; extra == "dev"
41
+ Requires-Dist: nbformat>=5.10.4; extra == "dev"
42
+ Provides-Extra: all
43
+ Requires-Dist: rtflite; extra == "all"
44
+ Requires-Dist: matplotlib>=3.5.0; extra == "all"
45
+ Requires-Dist: plotly>=5.0.0; extra == "all"
46
+
47
+ # csrlite
48
+
49
+ [![CI](https://github.com/elong0527/csrlite/actions/workflows/ci.yml/badge.svg)](https://github.com/elong0527/csrlite/actions/workflows/ci.yml)
50
+ [![codecov](https://codecov.io/gh/elong0527/csrlite/branch/main/graph/badge.svg)](https://codecov.io/gh/elong0527/csrlite)
51
+ [![PyPI version](https://badge.fury.io/py/csrlite.svg)](https://badge.fury.io/py/csrlite)
52
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
53
+
54
+ A hierarchical YAML-based framework for generating Tables, Listings, and Figures in clinical trials.
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install csrlite
60
+ ```
61
+
62
+ ## Documentation
63
+
64
+ Visit [https://elong0527.github.io/csrlite](https://elong0527.github.io/csrlite) for full documentation.
65
+
66
+ ## License
67
+
68
+ MIT License - see [LICENSE](LICENSE) file for details.
@@ -0,0 +1,20 @@
1
+ csrlite/__init__.py,sha256=zKceiP6Z47_o4GUjVLhIqPO6iMefyj6BGKffVHLUTjs,1729
2
+ csrlite/ae/__init__.py,sha256=Pp661SGbsoYoXLmd24dUQB_lx1jYKWEsCEPjgVg5UUU,15
3
+ csrlite/ae/ae_listing.py,sha256=fZWhYmi_Vzp974z-3o7EQ9joizEjF0mio2eB5_I8ghU,18883
4
+ csrlite/ae/ae_specific.py,sha256=P1glCd5K_ur_KexxbVaC79BmowgQSMI9K8xdzL6OmIM,17505
5
+ csrlite/ae/ae_summary.py,sha256=Vk4bUonnjAji2zeJkiPHW7nwgpwUG1UfbuzH4M0w1MM,14093
6
+ csrlite/ae/ae_utils.py,sha256=tOVOdsj-TRTw1w5T4JqFTYUwTfOppZWGlRHi6nkNWRA,2073
7
+ csrlite/common/config.py,sha256=qWFTNSaeWnqAagXM6FwACdQafXLG_nFWxFHEk5dAo-I,912
8
+ csrlite/common/count.py,sha256=T9nB9hYdc2jIIuV9HISK2ZS0wXNV_FUBDCKW_VVM1fQ,9078
9
+ csrlite/common/parse.py,sha256=J4UkmNlG10mrJ-O68-po1LlfLchK_kSvfdU1GOaAYgQ,9627
10
+ csrlite/common/plan.py,sha256=tYnK-5TVCoGWobxkqmasYYYkc9DJlHmOiTIcrP3MFRo,13293
11
+ csrlite/common/rtf.py,sha256=g1n765i2HPpwkh6aQOzlw4UmCC21-JMZEezFtUaO6U8,4440
12
+ csrlite/common/utils.py,sha256=XLUQqYtEm4SLNImvNDxAuj9OOu6Eogm3_uIp0vyfpfQ,1143
13
+ csrlite/common/yaml_loader.py,sha256=ZPgXw5X9eitMHCPEJBHzeYtcjesEQ8sP0hOFSYnzrgk,3142
14
+ csrlite/disposition/__init__.py,sha256=AiLW7Os7SBFrvvkaUMrxYEntK15_XXT0HYpZQxBx7ro,87
15
+ csrlite/disposition/disposition.py,sha256=W1Oik5hqDfalQ69NXullH7XYWP3oRw2x2nFuFWlE3Qo,10679
16
+ csrlite/ie/ie.py,sha256=9kEAe4aY3xfHe7O-o2ZD3LNfL5eTha2ZPkAflopjPYU,13544
17
+ csrlite-0.2.1.dist-info/METADATA,sha256=zstZU0eiNMFz4ICMeOf9VqCvUGywxMkXTg0hCqGe9HY,2911
18
+ csrlite-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ csrlite-0.2.1.dist-info/top_level.txt,sha256=59zJTvGH5zx2FY4vCl4kgnH8awT0cZrg21Mace7IFlU,8
20
+ csrlite-0.2.1.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- csrlite/__init__.py,sha256=w18H3dEZE_HZFdsr0Qqo0xmJPksx764BFAg8XPo9tGI,1417
2
- csrlite/ae/__init__.py,sha256=gZHPLATRF9f8QBwwQtEjQRtXMsqOJsUK2sbUMLjiE5U,14
3
- csrlite/ae/ae_listing.py,sha256=R4g8JnJRCx4u60xRC2IEu8EPzEIgxj8VgDhBaaQ5eZE,18389
4
- csrlite/ae/ae_specific.py,sha256=_CDAgF4vMmjpqFTppL2LgmExVsEhA57z4jYj4Y1zLfY,17022
5
- csrlite/ae/ae_summary.py,sha256=46IyuqHGdn0dLOrz7XffKNcNjscA0Y8OZFiZ6akisB4,13692
6
- csrlite/ae/ae_utils.py,sha256=ew5Mm_zNdflc_MRYvYSChXhRhGQ1oZcz7H_TZPVvFBk,2011
7
- csrlite/common/config.py,sha256=FUnUL1BtQO52U0ag1U_d2K3UP5L_vA_KifonANHLv_c,878
8
- csrlite/common/count.py,sha256=k1W-LdQv63s-B-Oeq2SvYsXctrT1YMVWs93CtIaGpVw,8785
9
- csrlite/common/parse.py,sha256=Vz9C7ljkDygT2qkP6TlY3T3p71D6BD5GtIwRKv6p8ps,9319
10
- csrlite/common/plan.py,sha256=XXUGpzNxC6oS66c7NYnDPmE0CwXMhIQzlJCga1nDktw,12928
11
- csrlite/common/rtf.py,sha256=gah-M-WdvMk52R-AEacM79P18jc2OFnCH7-I0B91Fhk,2825
12
- csrlite/common/utils.py,sha256=It0aHqPfXDmCte2uVAO2Lkb3U_jDLrjNihAL8gziTQk,1110
13
- csrlite/common/yaml_loader.py,sha256=_v9pkbAUVshTqVoMLqMiEn17awL2K0kFR4pdDArMSOM,3071
14
- csrlite/disposition/__init__.py,sha256=KMtGoBjN4aKNYvXHmZ0GX-f4RnmQ3coYbUrkFeU8Es0,85
15
- csrlite/disposition/disposition.py,sha256=r0R53ozVFYNXI0JBzR14sghQayLVUvXJBiS0wNLAtB0,10348
16
- csrlite-0.2.0.dist-info/METADATA,sha256=SzOst7_7EmNn6FB29KO-oFZpGZ93yZCQ9lGBhG-p9bE,2801
17
- csrlite-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
18
- csrlite-0.2.0.dist-info/top_level.txt,sha256=59zJTvGH5zx2FY4vCl4kgnH8awT0cZrg21Mace7IFlU,8
19
- csrlite-0.2.0.dist-info/RECORD,,