tytable 0.6.0__tar.gz

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 (165) hide show
  1. tytable-0.6.0/.github/workflows/ci.yml +53 -0
  2. tytable-0.6.0/.github/workflows/docs-pages.yml +64 -0
  3. tytable-0.6.0/.github/workflows/docs-release.yml +34 -0
  4. tytable-0.6.0/.github/workflows/release.yml +57 -0
  5. tytable-0.6.0/.gitignore +21 -0
  6. tytable-0.6.0/.pre-commit-config.yaml +35 -0
  7. tytable-0.6.0/.python-version +1 -0
  8. tytable-0.6.0/AGENTS.md +75 -0
  9. tytable-0.6.0/LICENSE +595 -0
  10. tytable-0.6.0/Makefile +32 -0
  11. tytable-0.6.0/PKG-INFO +115 -0
  12. tytable-0.6.0/README.md +85 -0
  13. tytable-0.6.0/docs/build_examples.py +56 -0
  14. tytable-0.6.0/docs/examples/01_basic.py +15 -0
  15. tytable-0.6.0/docs/examples/02_format.py +21 -0
  16. tytable-0.6.0/docs/examples/03_style.py +26 -0
  17. tytable-0.6.0/docs/examples/04_group.py +22 -0
  18. tytable-0.6.0/docs/examples/05_theme.py +16 -0
  19. tytable-0.6.0/docs/examples/06_widths.py +24 -0
  20. tytable-0.6.0/docs/examples/07_images.py +40 -0
  21. tytable-0.6.0/docs/examples/08_full_report.py +36 -0
  22. tytable-0.6.0/docs/examples/09_widths_fixed.py +28 -0
  23. tytable-0.6.0/docs/examples/10_format_fn.py +33 -0
  24. tytable-0.6.0/docs/examples/11_format_polars.py +29 -0
  25. tytable-0.6.0/docs/examples/12_resize.py +26 -0
  26. tytable-0.6.0/docs/examples/13_list_selectors.py +36 -0
  27. tytable-0.6.0/docs/examples/14_data_driven.py +35 -0
  28. tytable-0.6.0/docs/examples/15_set_name.py +24 -0
  29. tytable-0.6.0/docs/examples/sparkline.py +24 -0
  30. tytable-0.6.0/docs/main.typ +595 -0
  31. tytable-0.6.0/docs/site/index.html +33 -0
  32. tytable-0.6.0/pyproject.toml +82 -0
  33. tytable-0.6.0/src/tytable/__init__.py +24 -0
  34. tytable-0.6.0/src/tytable/_colors.py +212 -0
  35. tytable-0.6.0/src/tytable/_constants.py +28 -0
  36. tytable-0.6.0/src/tytable/_directives.py +114 -0
  37. tytable-0.6.0/src/tytable/_escape.py +58 -0
  38. tytable-0.6.0/src/tytable/_format.py +282 -0
  39. tytable-0.6.0/src/tytable/_groups.py +158 -0
  40. tytable-0.6.0/src/tytable/_images.py +270 -0
  41. tytable-0.6.0/src/tytable/_indices.py +226 -0
  42. tytable-0.6.0/src/tytable/_render_ascii.py +60 -0
  43. tytable-0.6.0/src/tytable/_render_html.py +227 -0
  44. tytable-0.6.0/src/tytable/_render_typst.py +425 -0
  45. tytable-0.6.0/src/tytable/_renderer.py +19 -0
  46. tytable-0.6.0/src/tytable/_resolve.py +375 -0
  47. tytable-0.6.0/src/tytable/_style_markup.py +155 -0
  48. tytable-0.6.0/src/tytable/_styling.py +308 -0
  49. tytable-0.6.0/src/tytable/_themes.py +143 -0
  50. tytable-0.6.0/src/tytable/_tytable.py +1074 -0
  51. tytable-0.6.0/src/tytable/_utils.py +21 -0
  52. tytable-0.6.0/src/tytable/_version.py +24 -0
  53. tytable-0.6.0/src/tytable/py.typed +0 -0
  54. tytable-0.6.0/tests/__init__.py +0 -0
  55. tytable-0.6.0/tests/conftest.py +32 -0
  56. tytable-0.6.0/tests/helpers.py +33 -0
  57. tytable-0.6.0/tests/snapshots/.gitkeep +0 -0
  58. tytable-0.6.0/tests/snapshots/ascii_basic.txt +6 -0
  59. tytable-0.6.0/tests/snapshots/basic_3x3.txt +60 -0
  60. tytable-0.6.0/tests/snapshots/basic_typ.txt +59 -0
  61. tytable-0.6.0/tests/snapshots/caption_bold_color_fontsize.txt +63 -0
  62. tytable-0.6.0/tests/snapshots/caption_italic_smallcaps.txt +63 -0
  63. tytable-0.6.0/tests/snapshots/caption_present.txt +63 -0
  64. tytable-0.6.0/tests/snapshots/fmt_decimal.txt +62 -0
  65. tytable-0.6.0/tests/snapshots/fmt_full.txt +62 -0
  66. tytable-0.6.0/tests/snapshots/fmt_preformatted.txt +62 -0
  67. tytable-0.6.0/tests/snapshots/fmt_significant.txt +62 -0
  68. tytable-0.6.0/tests/snapshots/footnote_auto_marker.txt +66 -0
  69. tytable-0.6.0/tests/snapshots/footnote_auto_multiple.txt +67 -0
  70. tytable-0.6.0/tests/snapshots/footnote_labelled.txt +66 -0
  71. tytable-0.6.0/tests/snapshots/footnote_multiple.txt +67 -0
  72. tytable-0.6.0/tests/snapshots/footnote_single.txt +66 -0
  73. tytable-0.6.0/tests/snapshots/footnote_targeted.txt +66 -0
  74. tytable-0.6.0/tests/snapshots/group_col_by_name.txt +65 -0
  75. tytable-0.6.0/tests/snapshots/group_col_multiple_same_row.txt +65 -0
  76. tytable-0.6.0/tests/snapshots/group_col_single.txt +65 -0
  77. tytable-0.6.0/tests/snapshots/group_col_stacked_basic.txt +64 -0
  78. tytable-0.6.0/tests/snapshots/group_col_ungrouped.txt +65 -0
  79. tytable-0.6.0/tests/snapshots/group_combined.txt +67 -0
  80. tytable-0.6.0/tests/snapshots/group_delim.txt +65 -0
  81. tytable-0.6.0/tests/snapshots/group_groupi_background.txt +67 -0
  82. tytable-0.6.0/tests/snapshots/group_groupi_bold.txt +67 -0
  83. tytable-0.6.0/tests/snapshots/group_row_end.txt +63 -0
  84. tytable-0.6.0/tests/snapshots/group_row_multiple.txt +67 -0
  85. tytable-0.6.0/tests/snapshots/group_row_single.txt +63 -0
  86. tytable-0.6.0/tests/snapshots/html_basic_2x2.txt +9 -0
  87. tytable-0.6.0/tests/snapshots/html_basic_3x3.txt +10 -0
  88. tytable-0.6.0/tests/snapshots/html_caption.txt +9 -0
  89. tytable-0.6.0/tests/snapshots/html_caption_styled.txt +10 -0
  90. tytable-0.6.0/tests/snapshots/html_footnote.txt +12 -0
  91. tytable-0.6.0/tests/snapshots/html_group_col.txt +9 -0
  92. tytable-0.6.0/tests/snapshots/html_group_row.txt +12 -0
  93. tytable-0.6.0/tests/snapshots/html_no_colnames.txt +6 -0
  94. tytable-0.6.0/tests/snapshots/html_notes_bg_align.txt +12 -0
  95. tytable-0.6.0/tests/snapshots/html_notes_italic_color.txt +12 -0
  96. tytable-0.6.0/tests/snapshots/html_notes_marker_styled.txt +12 -0
  97. tytable-0.6.0/tests/snapshots/html_style_bold.txt +9 -0
  98. tytable-0.6.0/tests/snapshots/html_style_color.txt +9 -0
  99. tytable-0.6.0/tests/snapshots/html_style_rotate.txt +9 -0
  100. tytable-0.6.0/tests/snapshots/html_style_rotate_header.txt +9 -0
  101. tytable-0.6.0/tests/snapshots/images_sparkline.txt +59 -0
  102. tytable-0.6.0/tests/snapshots/line_bottom.txt +63 -0
  103. tytable-0.6.0/tests/snapshots/line_chunking.txt +64 -0
  104. tytable-0.6.0/tests/snapshots/line_color.txt +63 -0
  105. tytable-0.6.0/tests/snapshots/line_dedupe.txt +63 -0
  106. tytable-0.6.0/tests/snapshots/line_dedupe_tb_merge.txt +63 -0
  107. tytable-0.6.0/tests/snapshots/line_left.txt +63 -0
  108. tytable-0.6.0/tests/snapshots/line_right.txt +63 -0
  109. tytable-0.6.0/tests/snapshots/line_tblr.txt +66 -0
  110. tytable-0.6.0/tests/snapshots/line_top.txt +63 -0
  111. tytable-0.6.0/tests/snapshots/line_width.txt +63 -0
  112. tytable-0.6.0/tests/snapshots/no_colnames.txt +57 -0
  113. tytable-0.6.0/tests/snapshots/notes_align_center.txt +66 -0
  114. tytable-0.6.0/tests/snapshots/notes_italic_color.txt +66 -0
  115. tytable-0.6.0/tests/snapshots/notes_marker_styled.txt +66 -0
  116. tytable-0.6.0/tests/snapshots/set_name_full_list_empty.txt +58 -0
  117. tytable-0.6.0/tests/snapshots/set_name_per_column.txt +59 -0
  118. tytable-0.6.0/tests/snapshots/set_name_style_new_name.txt +63 -0
  119. tytable-0.6.0/tests/snapshots/set_name_then_group.txt +60 -0
  120. tytable-0.6.0/tests/snapshots/style_align.txt +64 -0
  121. tytable-0.6.0/tests/snapshots/style_align_combined.txt +64 -0
  122. tytable-0.6.0/tests/snapshots/style_align_per_column.txt +68 -0
  123. tytable-0.6.0/tests/snapshots/style_alignv.txt +64 -0
  124. tytable-0.6.0/tests/snapshots/style_background.txt +64 -0
  125. tytable-0.6.0/tests/snapshots/style_bold.txt +64 -0
  126. tytable-0.6.0/tests/snapshots/style_color.txt +64 -0
  127. tytable-0.6.0/tests/snapshots/style_fontsize.txt +64 -0
  128. tytable-0.6.0/tests/snapshots/style_header.txt +65 -0
  129. tytable-0.6.0/tests/snapshots/style_indent.txt +64 -0
  130. tytable-0.6.0/tests/snapshots/style_italic.txt +64 -0
  131. tytable-0.6.0/tests/snapshots/style_mono.txt +64 -0
  132. tytable-0.6.0/tests/snapshots/style_rotate.txt +64 -0
  133. tytable-0.6.0/tests/snapshots/style_rotate_header.txt +65 -0
  134. tytable-0.6.0/tests/snapshots/style_smallcaps.txt +64 -0
  135. tytable-0.6.0/tests/snapshots/style_strikeout.txt +64 -0
  136. tytable-0.6.0/tests/snapshots/style_underline.txt +64 -0
  137. tytable-0.6.0/tests/snapshots/theme_callable.txt +62 -0
  138. tytable-0.6.0/tests/snapshots/theme_default.txt +62 -0
  139. tytable-0.6.0/tests/snapshots/theme_default_no_colnames.txt +57 -0
  140. tytable-0.6.0/tests/snapshots/theme_default_with_groups.txt +64 -0
  141. tytable-0.6.0/tests/snapshots/theme_empty.txt +58 -0
  142. tytable-0.6.0/tests/snapshots/theme_grid.txt +66 -0
  143. tytable-0.6.0/tests/snapshots/theme_method.txt +66 -0
  144. tytable-0.6.0/tests/snapshots/theme_override.txt +63 -0
  145. tytable-0.6.0/tests/snapshots/theme_resize_default.txt +71 -0
  146. tytable-0.6.0/tests/snapshots/theme_resize_down.txt +71 -0
  147. tytable-0.6.0/tests/snapshots/theme_resize_height.txt +71 -0
  148. tytable-0.6.0/tests/snapshots/theme_rotate.txt +61 -0
  149. tytable-0.6.0/tests/snapshots/theme_striped.txt +62 -0
  150. tytable-0.6.0/tests/snapshots/theme_striped_3rows.txt +65 -0
  151. tytable-0.6.0/tests/test_basic.py +255 -0
  152. tytable-0.6.0/tests/test_colors.py +26 -0
  153. tytable-0.6.0/tests/test_compile.py +95 -0
  154. tytable-0.6.0/tests/test_format.py +234 -0
  155. tytable-0.6.0/tests/test_grouping.py +196 -0
  156. tytable-0.6.0/tests/test_html.py +470 -0
  157. tytable-0.6.0/tests/test_images.py +210 -0
  158. tytable-0.6.0/tests/test_indices.py +34 -0
  159. tytable-0.6.0/tests/test_perf.py +44 -0
  160. tytable-0.6.0/tests/test_resolve.py +280 -0
  161. tytable-0.6.0/tests/test_set_name.py +214 -0
  162. tytable-0.6.0/tests/test_styling.py +606 -0
  163. tytable-0.6.0/tests/test_themes.py +312 -0
  164. tytable-0.6.0/tests/test_utils.py +21 -0
  165. tytable-0.6.0/uv.lock +1993 -0
@@ -0,0 +1,53 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ci-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ lint:
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v5
20
+ with:
21
+ fetch-depth: 0
22
+ - uses: astral-sh/setup-uv@v8.2.0
23
+ with:
24
+ enable-cache: true
25
+ - run: uv sync --all-extras
26
+ - run: uv run ruff check src tests
27
+ - run: uv run ruff format --check src tests
28
+ - run: uv run mypy
29
+
30
+ test:
31
+ runs-on: ${{ matrix.os }}
32
+ env:
33
+ MPLBACKEND: Agg
34
+ strategy:
35
+ fail-fast: false
36
+ matrix:
37
+ os: [ubuntu-latest]
38
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
39
+ include:
40
+ - os: macos-latest
41
+ python-version: "3.11"
42
+ - os: windows-latest
43
+ python-version: "3.11"
44
+ steps:
45
+ - uses: actions/checkout@v5
46
+ with:
47
+ fetch-depth: 0
48
+ - uses: astral-sh/setup-uv@v8.2.0
49
+ with:
50
+ python-version: ${{ matrix.python-version }}
51
+ enable-cache: true
52
+ - run: uv sync --all-extras --python ${{ matrix.python-version }}
53
+ - run: uv run pytest
@@ -0,0 +1,64 @@
1
+ name: Docs site
2
+
3
+ # Builds the Typst documentation PDF on every push to main and deploys it to
4
+ # GitHub Pages, so the docs are always current without cutting a release.
5
+ # The versioned, per-release PDF is still attached to each GitHub Release by
6
+ # docs-release.yml.
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ paths:
11
+ - docs/**
12
+ - src/tytable/**
13
+ - pyproject.toml
14
+ - uv.lock
15
+ - .github/workflows/docs-pages.yml
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+ pages: write
21
+ id-token: write
22
+
23
+ # Only one in-flight Pages deploy at a time; newer runs cancel older ones.
24
+ concurrency:
25
+ group: pages
26
+ cancel-in-progress: true
27
+
28
+ jobs:
29
+ build:
30
+ runs-on: ubuntu-latest
31
+ steps:
32
+ - uses: actions/checkout@v5
33
+
34
+ - name: Install Typst
35
+ uses: typst-community/setup-typst@v5
36
+
37
+ - name: Install uv
38
+ uses: astral-sh/setup-uv@v8.2.0
39
+
40
+ - name: Sync dependencies
41
+ run: uv sync --all-extras
42
+
43
+ - name: Build documentation
44
+ run: make docs
45
+
46
+ - name: Assemble Pages site
47
+ run: |
48
+ mkdir -p _site
49
+ cp docs/tytable-docs.pdf _site/tytable-docs.pdf
50
+ cp docs/site/index.html _site/index.html
51
+
52
+ - name: Upload Pages artifact
53
+ uses: actions/upload-pages-artifact@v5
54
+
55
+ deploy:
56
+ needs: build
57
+ runs-on: ubuntu-latest
58
+ environment:
59
+ name: github-pages
60
+ url: ${{ steps.deployment.outputs.page_url }}
61
+ steps:
62
+ - name: Deploy to GitHub Pages
63
+ id: deployment
64
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,34 @@
1
+ name: Docs
2
+
3
+ # Builds the Typst documentation PDF and attaches it to the GitHub Release.
4
+ on:
5
+ release:
6
+ types: [published]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: write
11
+
12
+ jobs:
13
+ build-pdf:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v5
17
+
18
+ - name: Install Typst
19
+ uses: typst-community/setup-typst@v5
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v8.2.0
23
+
24
+ - name: Sync dependencies
25
+ run: uv sync --all-extras
26
+
27
+ - name: Build documentation
28
+ run: make docs
29
+
30
+ - name: Upload PDF to the release
31
+ if: github.event_name == 'release'
32
+ uses: softprops/action-gh-release@v2
33
+ with:
34
+ files: docs/tytable-docs.pdf
@@ -0,0 +1,57 @@
1
+ name: Release
2
+
3
+ # Cut a release by pushing a `v*` tag, e.g.:
4
+ # git tag -a v0.6.0 -m "Release v0.6.0"
5
+ # git push origin v0.6.0
6
+ #
7
+ # The job builds the wheel + sdist with `uv build`, attaches them to a
8
+ # GitHub Release with auto-generated notes, and publishes to PyPI via
9
+ # trusted publishing (no stored API token). Trusted publishing requires
10
+ # this workflow file to exist on the default branch *before* the first
11
+ # tagged run can publish — merge to main before cutting v0.6.0.
12
+ #
13
+ # One-time setup: on PyPI (and TestPyPI for dry runs) add a trusted
14
+ # publisher for EinMaulwurf/tytable, workflow filename `release.yml`,
15
+ # environment `release`.
16
+ on:
17
+ push:
18
+ tags:
19
+ - "v*"
20
+
21
+ permissions:
22
+ contents: write # create the GitHub Release and its notes
23
+ id-token: write # trusted publishing to PyPI
24
+
25
+ concurrency:
26
+ group: release-${{ github.ref }}
27
+ cancel-in-progress: false
28
+
29
+ jobs:
30
+ release:
31
+ runs-on: ubuntu-latest
32
+ environment: release # matches the trusted-publisher env on PyPI
33
+ steps:
34
+ - uses: actions/checkout@v5
35
+ with:
36
+ fetch-depth: 0 # hatch-vcs needs full history to derive version
37
+
38
+ - uses: astral-sh/setup-uv@v8.2.0
39
+ with:
40
+ enable-cache: true
41
+
42
+ - name: Build distributions
43
+ run: uv build
44
+
45
+ - name: Validate metadata
46
+ run: uvx twine check dist/*
47
+
48
+ - name: Create GitHub Release
49
+ uses: softprops/action-gh-release@v2
50
+ with:
51
+ files: dist/*
52
+ generate_release_notes: true
53
+ draft: false
54
+ prerelease: false
55
+
56
+ - name: Publish to PyPI
57
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,21 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .eggs/
5
+ *.egg-info/
6
+ src/tytable/_version.py
7
+ build/
8
+ dist/
9
+ .pytest_cache/
10
+ /pytest-of-*/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ htmlcov/
15
+ tytable_assets/
16
+ report_assets/
17
+ docs/tytable-docs.pdf
18
+ .DS_Store
19
+ TODO.md
20
+ AUDIT_SUGGESTIONS_FINAL.md
21
+ .opencode/
@@ -0,0 +1,35 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ exclude: ^tests/snapshots/
7
+ - id: end-of-file-fixer
8
+ exclude: ^tests/snapshots/
9
+ - id: check-yaml
10
+ - id: check-toml
11
+ - id: check-merge-conflict
12
+ - id: check-added-large-files
13
+ - repo: local
14
+ hooks:
15
+ - id: ruff-check
16
+ name: ruff check
17
+ description: Lint with ruff (autofixes staged issues).
18
+ entry: uv run ruff check --fix
19
+ language: system
20
+ types_or: [python, pyi, toml]
21
+ pass_filenames: false
22
+ - id: ruff-format
23
+ name: ruff format
24
+ description: Format with ruff.
25
+ entry: uv run ruff format
26
+ language: system
27
+ types_or: [python, pyi]
28
+ pass_filenames: false
29
+ - id: mypy
30
+ name: mypy
31
+ description: Type-check with mypy.
32
+ entry: uv run mypy
33
+ language: system
34
+ types_or: [python, pyi]
35
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,75 @@
1
+ # AGENTS.md
2
+
3
+ ## Project identity
4
+
5
+ **Package**: `tytable` — source: `src/tytable/`
6
+
7
+ A lightweight Python package for creating typst tables from (polars) dataframes. Inspired by the tinytable R package.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ make install # uv sync --all-extras
13
+ make lint # ruff check src tests
14
+ make format # ruff format src tests
15
+ make typecheck # mypy
16
+ make test # pytest -m "not images" (excludes images tests)
17
+ make test-images # pytest -m "images" (requires matplotlib/numpy)
18
+ ```
19
+
20
+ Pre-commit order: `lint` → `typecheck` → `test`.
21
+
22
+ ## Tooling quirks
23
+
24
+ - **ruff**: line-length 100, double-quotes, selects E/F/I/UP/B/SIM/C4; E501 ignored
25
+ - **mypy**: non-strict, ignores missing imports, only checks `src/tytable` (not tests)
26
+ - **Coverage**: 80% branch minimum
27
+
28
+ ## Testing
29
+
30
+ - Custom snapshot helper at `tests/helpers.py:assert_snapshot`. Set `SNAPSHOT_UPDATE=1` to regenerate.
31
+ - `conftest.py` monkeypatches `_new_image_id` for deterministic image tests.
32
+ - Performance gate: `test_perf.py` asserts a 120×30 table renders under 0.3 s.
33
+ - Pytest markers: `typst`, `html`, `images`. Default `make test` skips `images` (needs the `images` extra).
34
+ - The `pytest-snapshot` dep is in `pyproject.toml` but **not** the active snapshot mechanism — `tests/helpers.py` handles snapshots.
35
+
36
+ ## Architecture
37
+
38
+ ```text
39
+ tt(df, ...) # _tytable.py — factory + TinyTable class
40
+ .style() / .fmt() / ... # record directives (StyleDirective, FormatDirective, …)
41
+ .render() / .save() # resolve pipeline → render
42
+
43
+ build() # _resolve.py — resolve directives → BuiltTable
44
+ → TypstRenderer # _render_typst.py
45
+ → HtmlRenderer # _render_html.py
46
+ → AsciiRenderer # _render_ascii.py
47
+ ```
48
+
49
+ Styling, formatting, grouping, and plotting are recorded as **intent** and replayed in a fixed order at render time. Row indices always refer to the final, visible table.
50
+
51
+ ### Key modules
52
+
53
+ | File | Role |
54
+ | ------------------ | ------------------------------------------------------------------------------------------------- |
55
+ | `_tytable.py` | Public API: `TinyTable` class, `tt()` factory |
56
+ | `_directives.py` | Dataclasses: `StyleDirective`, `FormatDirective`, `PlotDirective`, `Note`, `RowGroup`, `ColGroup` |
57
+ | `_resolve.py` | `build()` pipeline and `BuiltTable` output dataclass |
58
+ | `_styling.py` | Style validation, style-grid construction |
59
+ | `_format.py` | Numeric formatting, replace, escape, fn transforms |
60
+ | `_groups.py` | Row/column group registration and merging |
61
+ | `_themes.py` | Theme registry (`default`, `striped`, `grid`, `empty`, `rotate`) |
62
+ | `_render_typst.py` | Typst output (primary output format) |
63
+ | `_render_html.py` | HTML preview (Jupyter `_repr_html_`) |
64
+ | `_render_ascii.py` | ASCII `__repr__` |
65
+ | `_images.py` | Plot/image embedding (requires `images` extra) |
66
+
67
+ ## Commit style
68
+
69
+ Conventional commits: `type(scope): description`. Types: `feat`, `fix`, `docs`, `test`, `ci`, `build`, `refactor`. Scope optional. Keep descriptions imperative and lowercase. Examples from history: `feat: wire up resize theme`, `fix: resolve all 20 mypy type-checking errors`, `docs: add docstrings to all public API`.
70
+
71
+ - All source modules start with `_` (private). Public API is only what `__init__.py` exports.
72
+ - **0-based row indexing**: `i=0` is first data row; `i="header"` for column-name row; negative ints for column-group header rows.
73
+ - Column selection by **name** (`j="Score"`) preferred over integer position.
74
+ - Method chaining: `.style()`, `.fmt()`, `.group()`, `.theme()` return `self`. `.render()` / `.save()` are terminal.
75
+ - Internal imports use `from tytable._resolve import build`, not relative paths (most files already use this pattern).