pysofra 0.1.0a1__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.
Files changed (50) hide show
  1. pysofra/__init__.py +82 -0
  2. pysofra/core/__init__.py +14 -0
  3. pysofra/core/compose.py +167 -0
  4. pysofra/core/format.py +155 -0
  5. pysofra/core/frames.py +69 -0
  6. pysofra/core/schema.py +128 -0
  7. pysofra/core/table.py +924 -0
  8. pysofra/io/__init__.py +1 -0
  9. pysofra/models/__init__.py +6 -0
  10. pysofra/models/extract.py +249 -0
  11. pysofra/models/pool.py +119 -0
  12. pysofra/models/regression.py +507 -0
  13. pysofra/models/survival.py +395 -0
  14. pysofra/models/uvregression.py +438 -0
  15. pysofra/notebook/__init__.py +6 -0
  16. pysofra/plot/__init__.py +23 -0
  17. pysofra/plot/_backend.py +32 -0
  18. pysofra/plot/forest.py +159 -0
  19. pysofra/plot/inline.py +171 -0
  20. pysofra/plot/km.py +249 -0
  21. pysofra/render/__init__.py +28 -0
  22. pysofra/render/_zip_determinism.py +57 -0
  23. pysofra/render/base.py +22 -0
  24. pysofra/render/docx.py +286 -0
  25. pysofra/render/html.py +442 -0
  26. pysofra/render/image.py +130 -0
  27. pysofra/render/latex.py +253 -0
  28. pysofra/render/markdown.py +128 -0
  29. pysofra/render/pptx.py +340 -0
  30. pysofra/render/xlsx.py +226 -0
  31. pysofra/summary/__init__.py +6 -0
  32. pysofra/summary/calibrate.py +214 -0
  33. pysofra/summary/design.py +246 -0
  34. pysofra/summary/effect_size.py +187 -0
  35. pysofra/summary/extras.py +745 -0
  36. pysofra/summary/smd.py +133 -0
  37. pysofra/summary/stats.py +135 -0
  38. pysofra/summary/tbl_cross.py +339 -0
  39. pysofra/summary/tbl_one.py +1220 -0
  40. pysofra/summary/tbl_summary.py +51 -0
  41. pysofra/summary/tests.py +370 -0
  42. pysofra/summary/typing.py +129 -0
  43. pysofra/summary/weights.py +161 -0
  44. pysofra/themes/__init__.py +5 -0
  45. pysofra/themes/registry.py +272 -0
  46. pysofra-0.1.0a1.dist-info/METADATA +301 -0
  47. pysofra-0.1.0a1.dist-info/RECORD +50 -0
  48. pysofra-0.1.0a1.dist-info/WHEEL +4 -0
  49. pysofra-0.1.0a1.dist-info/licenses/LICENSE +674 -0
  50. pysofra-0.1.0a1.dist-info/licenses/NOTICE +18 -0
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: pysofra
3
+ Version: 0.1.0a1
4
+ Summary: Statistical reporting and table preparation framework for Python — the missing reporting layer.
5
+ Project-URL: Homepage, https://github.com/jturner-uofl/pysofra
6
+ Project-URL: Documentation, https://github.com/jturner-uofl/pysofra
7
+ Project-URL: Repository, https://github.com/jturner-uofl/pysofra
8
+ Project-URL: Issues, https://github.com/jturner-uofl/pysofra/issues
9
+ Author-email: Jason Turner <jason.s.turner@gmail.com>
10
+ License: GPL-3.0-or-later
11
+ License-File: LICENSE
12
+ License-File: NOTICE
13
+ Keywords: biostatistics,clinical-trials,epidemiology,flextable,gtsummary,publication,reporting,statistics,tableone,tables
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Healthcare Industry
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
24
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
25
+ Requires-Python: >=3.11
26
+ Requires-Dist: numpy>=1.24
27
+ Requires-Dist: pandas<3,>=2.0
28
+ Requires-Dist: python-docx>=1.1
29
+ Requires-Dist: scipy>=1.11
30
+ Requires-Dist: statsmodels>=0.14
31
+ Provides-Extra: all
32
+ Requires-Dist: lifelines<0.31,>=0.27; extra == 'all'
33
+ Requires-Dist: matplotlib>=3.8; extra == 'all'
34
+ Requires-Dist: polars>=0.20; extra == 'all'
35
+ Requires-Dist: pyarrow>=15; extra == 'all'
36
+ Requires-Dist: python-pptx>=1.0; extra == 'all'
37
+ Requires-Dist: scikit-learn>=1.3; extra == 'all'
38
+ Requires-Dist: xlsxwriter>=3.2; extra == 'all'
39
+ Provides-Extra: dev
40
+ Requires-Dist: hypothesis>=6.100; extra == 'dev'
41
+ Requires-Dist: mypy>=1.8; extra == 'dev'
42
+ Requires-Dist: openpyxl>=3.1; extra == 'dev'
43
+ Requires-Dist: pandas-stubs>=2.2; extra == 'dev'
44
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
45
+ Requires-Dist: pytest>=7.4; extra == 'dev'
46
+ Requires-Dist: ruff>=0.4; extra == 'dev'
47
+ Provides-Extra: docs
48
+ Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
49
+ Requires-Dist: mkdocs>=1.5; extra == 'docs'
50
+ Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
51
+ Provides-Extra: plot
52
+ Requires-Dist: matplotlib>=3.8; extra == 'plot'
53
+ Provides-Extra: polars
54
+ Requires-Dist: polars>=0.20; extra == 'polars'
55
+ Requires-Dist: pyarrow>=15; extra == 'polars'
56
+ Provides-Extra: pptx
57
+ Requires-Dist: python-pptx>=1.0; extra == 'pptx'
58
+ Provides-Extra: sklearn
59
+ Requires-Dist: scikit-learn>=1.3; extra == 'sklearn'
60
+ Provides-Extra: survival
61
+ Requires-Dist: lifelines<0.31,>=0.27; extra == 'survival'
62
+ Requires-Dist: matplotlib>=3.8; extra == 'survival'
63
+ Provides-Extra: xlsx
64
+ Requires-Dist: xlsxwriter>=3.2; extra == 'xlsx'
65
+ Description-Content-Type: text/markdown
66
+
67
+ <div align="center">
68
+
69
+ # PySofra
70
+
71
+ ### The missing statistical reporting layer for Python
72
+
73
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/jturner-uofl/pysofra)
74
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://www.python.org/downloads/)
75
+ [![License: GPL-3.0+](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](LICENSE)
76
+ [![Style: ruff](https://img.shields.io/badge/style-ruff-purple.svg)](https://github.com/astral-sh/ruff)
77
+ [![Types: mypy strict](https://img.shields.io/badge/types-mypy%20strict-blue.svg)](http://mypy-lang.org/)
78
+ [![Tests: 886](https://img.shields.io/badge/tests-886%20passing-brightgreen.svg)](#status)
79
+
80
+ </div>
81
+
82
+ > PySofra turns datasets, fitted models, and summary statistics into
83
+ > **publication-ready tables** — across HTML · Markdown · LaTeX · DOCX ·
84
+ > PPTX · XLSX · PNG — from a single immutable `SofraTable` object. It
85
+ > brings the practical workflows of R's `tableone`, `gtsummary`, and
86
+ > `flextable` into a single coherent Pythonic API.
87
+
88
+ <div align="center">
89
+ <img src="https://raw.githubusercontent.com/jturner-uofl/pysofra/main/assets/readme/table_one.png" alt="Baseline characteristics table by treatment arm — JAMA theme, with p-values, standardized mean differences, and Overall column" width="820">
90
+ <br>
91
+ <sub><em>Baseline characteristics, by treatment arm. <strong>One line of code.</strong></em></sub>
92
+ </div>
93
+
94
+ <table>
95
+ <tr>
96
+ <td width="50%" valign="top" align="center">
97
+ <img src="https://raw.githubusercontent.com/jturner-uofl/pysofra/main/assets/readme/regression_forest.png" alt="Adjusted odds ratios with inline forest plot" width="100%">
98
+ <br>
99
+ <sub><em>Adjusted ORs + inline forest plot</em><br><code>tbl_regression(fit).with_forest_plot()</code></sub>
100
+ </td>
101
+ <td width="50%" valign="top" align="center">
102
+ <img src="https://raw.githubusercontent.com/jturner-uofl/pysofra/main/assets/readme/survival_km.png" alt="Kaplan-Meier survival table with embedded KM curve" width="100%">
103
+ <br>
104
+ <sub><em>KM table + inline survival curve</em><br><code>tbl_survival(...).with_km_plot()</code></sub>
105
+ </td>
106
+ </tr>
107
+ </table>
108
+
109
+ ### Why PySofra
110
+
111
+ - **One immutable object, seven output formats** — build a `SofraTable` once, render to HTML / Markdown / LaTeX / DOCX / PPTX / XLSX / PNG, all byte-deterministic across processes
112
+ - **Auto-dispatched statistical tests** — Welch, Wilcoxon, ANOVA, Kruskal–Wallis, Fisher, χ², Rao–Scott, design-adjusted *t* — picked by variable kind, overridable per-row
113
+ - **Inline forest plots and KM curves** — embed matplotlib figures directly into the table; the same `SofraTable` renders them across every backend
114
+ - **Statistically correct** — every numeric output validated against `scipy` / `statsmodels` / `lifelines` at machine precision (and cross-checked against R's `gtsummary` for the JSS paper)
115
+ - **Method-chainable and immutable** — every modifier returns a new table; no in-place mutation, no global state, fully reproducible
116
+
117
+ <div align="center">
118
+
119
+ **[Showcase notebook](examples/pysofra_showcase.ipynb)** · [rendered HTML](examples/pysofra_showcase.html) — *47 cells, every section a side-by-side numeric proof. Start here if you have 60 seconds.*
120
+
121
+ **[End-to-end tutorial](examples/pysofra_tutorial.ipynb)** · [rendered HTML](examples/pysofra_tutorial.html) — *126 cells walking every public feature on a synthetic two-arm trial.*
122
+
123
+ </div>
124
+
125
+ ---
126
+
127
+ ## Quick start
128
+
129
+ ```python
130
+ import numpy as np
131
+ import pandas as pd
132
+ import pysofra as ps
133
+
134
+ # Toy two-arm trial; replace with your own DataFrame in real use.
135
+ rng = np.random.default_rng(0)
136
+ df = pd.DataFrame({
137
+ "arm": rng.choice(["Placebo", "Treatment"], 200),
138
+ "age": rng.normal(60, 10, 200).round(),
139
+ "bmi": rng.normal(28, 5, 200).round(1),
140
+ "event": rng.binomial(1, 0.3, 200),
141
+ })
142
+
143
+ # Table 1 — baseline characteristics by treatment arm
144
+ tbl = (
145
+ ps.tbl_one(df, by="arm")
146
+ .add_p()
147
+ .add_smd()
148
+ .add_overall()
149
+ .theme("clinical")
150
+ )
151
+
152
+ tbl # renders in Jupyter / Colab / VS Code
153
+ tbl.to_docx("table1.docx") # publication-quality Word
154
+ tbl.to_html() # standalone HTML fragment
155
+ tbl.to_markdown() # GitHub-flavored Markdown
156
+ ```
157
+
158
+ The same workflow handles regression tables:
159
+
160
+ ```python
161
+ import statsmodels.api as sm
162
+
163
+ X = sm.add_constant(df[["age", "bmi"]])
164
+ fit = sm.Logit(df["event"], X).fit(disp=False)
165
+
166
+ (
167
+ ps.tbl_regression(fit, exponentiate=True)
168
+ .bold_p()
169
+ .theme("jama")
170
+ .to_docx("table2.docx")
171
+ )
172
+ ```
173
+
174
+ The full worked example from the JSS paper — baseline table by
175
+ treatment arm, regression table with forest plot, and Kaplan-Meier
176
+ survival summary — is in
177
+ [`paper/replication/example_trial.py`](paper/replication/example_trial.py).
178
+
179
+ ---
180
+
181
+ ## What's in the box
182
+
183
+ | Feature | Function / object | Status |
184
+ |----------------------|---------------------------|--------|
185
+ | Baseline Table 1 | `ps.tbl_one` | MVP |
186
+ | Descriptive summary | `ps.tbl_summary` | MVP |
187
+ | Regression results | `ps.tbl_regression` | MVP |
188
+ | Side-by-side merge | `ps.tbl_merge` | MVP |
189
+ | Vertical stack | `ps.tbl_stack` | MVP |
190
+ | HTML / Markdown | `.to_html` / `.to_markdown` | MVP |
191
+ | DOCX export | `.to_docx` | MVP |
192
+ | LaTeX export | `.to_latex` | MVP |
193
+ | PPTX export | `.to_pptx` | MVP (extras) |
194
+ | Excel export | `.to_xlsx` | MVP |
195
+ | Inline forest plots | `tbl_regression(...).with_forest_plot()` | MVP |
196
+ | Inline KM curves | `tbl_survival(...).with_km_plot()` | MVP |
197
+ | Cross-backend plot embedding | DOCX/PPTX/LaTeX include the plot too | MVP |
198
+ | Rao–Scott chi-square | weighted Table 1 auto-route | MVP |
199
+ | `SurveyDesign` (strata + cluster + FPC) | Taylor-linearised variance | MVP |
200
+ | Themes | `clinical`, `jama`, `nejm`, `compact`, `minimal` | MVP |
201
+ | Auto test selection | t-test / ANOVA / Wilcoxon / Kruskal / χ² / Fisher | MVP |
202
+ | Per-variable test overrides | `tests={'age': 'wilcoxon', ...}` | MVP |
203
+ | Multiplicity adjustment | `.add_q()` — BH, BY, Bonferroni, Holm, Hommel, Šidák | MVP |
204
+ | Multi-model regression | `tbl_regression([m1, m2], model_labels=[...])` | MVP |
205
+ | lifelines (Cox / AFT) | `tbl_regression(cph)` | MVP |
206
+ | sklearn (linear models) | `tbl_regression(clf)` — point estimates only | MVP |
207
+ | Kaplan–Meier summary | `tbl_survival(df, time=, event=, by=, times=[...])` | MVP |
208
+ | Survey-weighted Table 1 | `tbl_one(..., weights='w')` | MVP |
209
+ | polars input | `tbl_one(pl.DataFrame(...))` | MVP |
210
+ | Conditional formatting | `.bold_if`, `.highlight_if`, `.style_if` | MVP |
211
+ | Sticky-header notebook tables | `.to_html(sticky_header=True)` | MVP |
212
+ | Standardised mean differences | continuous + categorical (Yang–Dalton) | MVP |
213
+ | Notebook rendering | `_repr_html_` / `_repr_markdown_` / `_repr_latex_` | MVP |
214
+
215
+ ---
216
+
217
+ ## Design principles
218
+
219
+ * **Backend-agnostic tables.** A `SofraTable` is the single source of truth;
220
+ every renderer (HTML, Markdown, DOCX, …) reads the same object.
221
+ * **Immutable method chaining.** Every modifier returns a new `SofraTable`.
222
+ No surprises, no global state.
223
+ * **Strong defaults, explicit overrides.** Sensible journal-style output
224
+ out of the box; per-variable type, label, and test overrides when you
225
+ need them.
226
+ * **Deterministic.** The same input always produces the same output —
227
+ critical for reproducible research.
228
+ * **No magic.** No nonstandard evaluation, no metaprogramming, no
229
+ network calls, no telemetry.
230
+
231
+ ---
232
+
233
+ ## Installation
234
+
235
+ ```bash
236
+ pip install pysofra
237
+ ```
238
+
239
+ PySofra requires Python ≥ 3.11. The core install only pulls `numpy`,
240
+ `pandas`, `scipy`, `statsmodels`, and `python-docx`. Domain extras unlock
241
+ the features that depend on heavier optional libraries:
242
+
243
+ ```bash
244
+ pip install "pysofra[survival]" # tbl_survival + KM curves (lifelines, matplotlib)
245
+ pip install "pysofra[plot]" # forest plots, table-as-image (matplotlib)
246
+ pip install "pysofra[pptx]" # PowerPoint export (python-pptx)
247
+ pip install "pysofra[xlsx]" # Excel export (xlsxwriter)
248
+ pip install "pysofra[polars]" # accept polars DataFrames as input
249
+ pip install "pysofra[sklearn]" # tbl_regression on scikit-learn models
250
+ pip install "pysofra[all]" # everything above
251
+ pip install "pysofra[dev]" # testing + linting (pytest, ruff, mypy, hypothesis)
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Status
257
+
258
+ PySofra is in **alpha** (`0.1.0a1`). The public API surface is pinned
259
+ by an explicit
260
+ [API-stability test](tests/test_joss_api_stability.py) so that any
261
+ unintended rename, removal, or signature change surfaces as a failed
262
+ test. Quality bar at this release:
263
+
264
+ * **More than 800 tests passing**, **100% line coverage**, mypy strict, ruff clean.
265
+ * Every numeric output is validated against `scipy`, `lifelines`,
266
+ `statsmodels`, or a hand-computed textbook formula
267
+ ([test_joss_statistical_correctness.py](tests/test_joss_statistical_correctness.py)).
268
+ * Universal invariants enforced via Hypothesis on 720 randomized
269
+ examples per CI run
270
+ ([test_joss_property_invariants.py](tests/test_joss_property_invariants.py)).
271
+ * Renderer output is byte-deterministic — identical input always
272
+ produces identical HTML/Markdown/LaTeX, required for reproducible
273
+ publication artifacts
274
+ ([test_joss_renderer_consistency.py](tests/test_joss_renderer_consistency.py)).
275
+
276
+ Bug reports and use-case feedback are very welcome.
277
+
278
+ A **Journal of Statistical Software** paper ([`paper/paper.tex`](paper/paper.tex),
279
+ bibliography in [`paper/paper.bib`](paper/paper.bib)) is in
280
+ preparation. The [`paper/replication/`](paper/replication/) directory
281
+ regenerates every numeric output and figure shown in the paper and
282
+ includes an R cross-check script (`example_trial.R`) using
283
+ `gtsummary` for digit-level verification. The
284
+ [`paper/figures/`](paper/figures/) directory holds the rendered PDF
285
+ and PNG embedded in the manuscript via `\includegraphics{}`.
286
+
287
+ ## Contributing
288
+
289
+ Bug reports, feature requests, and pull requests are all very welcome.
290
+ Please read [`CONTRIBUTING.md`](CONTRIBUTING.md) for the workflow, the
291
+ quality gates, and the
292
+ [Code of Conduct](CODE_OF_CONDUCT.md).
293
+
294
+ ## License
295
+
296
+ GPL-3.0-or-later. See [`LICENSE`](LICENSE).
297
+
298
+ ## Citation
299
+
300
+ If you use PySofra in academic work, please cite the project — see
301
+ [`CITATION.cff`](CITATION.cff).
@@ -0,0 +1,50 @@
1
+ pysofra/__init__.py,sha256=HTn-jcTecuoxnsB6JC6DXKYz3en8rhTnn72eupwieb8,2045
2
+ pysofra/core/__init__.py,sha256=ac1VAhSD79VagXG9r8PwdKzrLklnB__HAigkHD3ofk0,295
3
+ pysofra/core/compose.py,sha256=7FWe1rOaX05XknJdhY37Gz1nFWzcdiYJ49sq4AS-MDo,6151
4
+ pysofra/core/format.py,sha256=kVamfHh9n06iTx_Cg-kzI4M2ILYNAIRMaoiGlSh5b48,5112
5
+ pysofra/core/frames.py,sha256=YjzrjmKkwydz5V0nud48kYVVcvOiVZ0xSVQIImaB5G8,2581
6
+ pysofra/core/schema.py,sha256=OzAGpG1tHGJBD9nHP-RyYea0Qg1BwiEK_lYjlSouyOY,3501
7
+ pysofra/core/table.py,sha256=tiQVqdPVYcvVkfCmve0QW2xixTjR9DRRF26DHK281_g,37304
8
+ pysofra/io/__init__.py,sha256=wLrJPCvgALItN7--2eR0dXc0hbZhFnSzqqwVkgtU7yI,71
9
+ pysofra/models/__init__.py,sha256=v9bCNwAcXrAwKeEw8DX3taWh3i412Ef4vHePr6_TVOI,156
10
+ pysofra/models/extract.py,sha256=IOgZw-CYGo_bE9rQfNpoQavQZ2PWbV8HyIMFZYhD27Y,9671
11
+ pysofra/models/pool.py,sha256=gYmOJSFXnyOx05_IiiSyJCG2W3fqLJM62Dv7TKkFMBE,4720
12
+ pysofra/models/regression.py,sha256=rpTY7qr6TNIXqfDScvR5J2q_PaIJSk6YQl89dToZ6QY,19859
13
+ pysofra/models/survival.py,sha256=EMIxUWgLLGYtCPYbGX_M32zr_bMwdqU7eIp94BUcYAo,14374
14
+ pysofra/models/uvregression.py,sha256=KzCAFfOJkaQMYCzjyBd5KzlI1TXNniCWrNY1HooJfDo,16148
15
+ pysofra/notebook/__init__.py,sha256=VvfVu08lD0iiwmrUAvUmm1wlaQ-Gaq112MJdogMzA0M,199
16
+ pysofra/plot/__init__.py,sha256=rApXS8uvUL5eEJvNQdtzlVmw6S4OtRVBl00J6EVxDpI,681
17
+ pysofra/plot/_backend.py,sha256=RL_rNqC3OWdfI-dnAlI3pAz51gI-XcrJfmDa_1z4Pgc,1276
18
+ pysofra/plot/forest.py,sha256=zwYUF7zG8Ab-7xmKep1ju088voCNrQ6LBabMjE1vXdo,4944
19
+ pysofra/plot/inline.py,sha256=L6-yu6Y09zwsxtP8EZoKElPy4J9zChXIqbCwbKhdcAk,6090
20
+ pysofra/plot/km.py,sha256=LQAYhvChXYWCDQFoCLCOrBtOexUPbrcUdYthDxX9Tdo,8493
21
+ pysofra/render/__init__.py,sha256=lbW0WougRXnglAdca2LFXtRXatJDHtQpHsDGa-yypKQ,687
22
+ pysofra/render/_zip_determinism.py,sha256=ambrEGTzerGc0Udg3xXzMhBUiCYUp899QjwjAl_-_hg,2255
23
+ pysofra/render/base.py,sha256=eeleWMTlhWyv5C6eZvPGxQHl8BH3z1A8mWG6N7YVudY,533
24
+ pysofra/render/docx.py,sha256=VeYUI_5rDKKk8WkeAdvOwGpQSI8uYoV_f8i1Cv_mB_E,10713
25
+ pysofra/render/html.py,sha256=va7e6xYKR1K1ihZlQBMnhSMOGMzG98yZqYUMbLyrln8,15464
26
+ pysofra/render/image.py,sha256=cp6oYdPk_hGPaW5dfcd1uOiN0W2s1CLXAd7C7KfMQnE,4209
27
+ pysofra/render/latex.py,sha256=4LonwkmwMAvJwKcbbFgD6eWoWUR07vpVpKyX3OZeqrs,8279
28
+ pysofra/render/markdown.py,sha256=IzwwLV0lfCtZ5knuBKDvUD59f12WRQoDNLVJpBOIcsI,4158
29
+ pysofra/render/pptx.py,sha256=cKi8VLBZ2X0G_f_XSwW1aMD8dWiwCTGYBL9WA_bRwk4,13860
30
+ pysofra/render/xlsx.py,sha256=owTuhcwCBusJDHPgKpRp1M8YFrm4-N6CEbYrOd1zpGg,9019
31
+ pysofra/summary/__init__.py,sha256=CYpMewe1uyZKl_1Gol8qbgEqsSR4o8nkQZADnarSCks,135
32
+ pysofra/summary/calibrate.py,sha256=10ZL5tk0NtR-i6E_QN1TFyYtMJ9mROBZ0-1Uyybs8z4,7251
33
+ pysofra/summary/design.py,sha256=nmNnYHVrw6HiNkN6ClAOC5ETjBc6OldDNSr1Lez7snQ,9310
34
+ pysofra/summary/effect_size.py,sha256=mIoQzYRYeGtd4Kntsn4YNoy7xfV3A2UONRKmCZ4__ZU,7020
35
+ pysofra/summary/extras.py,sha256=8CjPsbMVMstoon8-4ZLztwepdw-EE7XHnd5NZfJZtxU,27764
36
+ pysofra/summary/smd.py,sha256=KOb4dmZcjGSrwv3TfAonm_a8ndcfIXmzyScBvJmlQw4,5307
37
+ pysofra/summary/stats.py,sha256=F6C9jtSwlpNa7M_jsrx7xrQ5Qp7GMAHSE-lcHw3Uirg,4247
38
+ pysofra/summary/tbl_cross.py,sha256=N7_G3a9-CGdOlnmLqXSKnNdl6BEKn1dT0GHdndRgFTA,12773
39
+ pysofra/summary/tbl_one.py,sha256=ewhSsfDKiZdxW0YtV2axi8vw6nq_O9erU_1cdxoffOw,47288
40
+ pysofra/summary/tbl_summary.py,sha256=1M8l4v5vhc7wE6PmQSPdFvaKsIDB-cWHTq1OVo9XOmM,1597
41
+ pysofra/summary/tests.py,sha256=Of_hGxfaEFZClRYvmB2pX35OfuDOBfCxkiaCG1uR0j0,12225
42
+ pysofra/summary/typing.py,sha256=AkdGEkm0U9BnLrebwsKEEKFv0yN1MTNYDWPpfJiSs_M,5059
43
+ pysofra/summary/weights.py,sha256=x2VsEQsWIrmEP8aodtOhm9rH5MUuAnWTEtgdDgfNo1M,5069
44
+ pysofra/themes/__init__.py,sha256=Uf2h6mM1fduI6i3udKBPJ9TwJqtBM5F5OHPH-DBGwRE,189
45
+ pysofra/themes/registry.py,sha256=SXPt7Obdp07aXYmqWzKgtTmVU3UpHyrvdZro-YI_dIs,9010
46
+ pysofra-0.1.0a1.dist-info/METADATA,sha256=dMGekVR9Xrw6DHYTeKvIGRhtOOVtPKncSqIdeK5Dmw8,13359
47
+ pysofra-0.1.0a1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
48
+ pysofra-0.1.0a1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
49
+ pysofra-0.1.0a1.dist-info/licenses/NOTICE,sha256=RfuuxugSgFLA2YBdLSF6FU_yn4Rc6Xjlmya3iE7soQE,754
50
+ pysofra-0.1.0a1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any