Files
2026-05-30 16:22:29 +08:00

5.6 KiB

pubtab architecture (source-driven)

This guide explains pubtab from the actual package layout under pubtab/src/pubtab.

Core files:

  • __init__.py
  • cli.py
  • models.py
  • reader.py
  • renderer.py
  • config.py
  • _preview.py
  • tex_reader.py
  • backends/
  • themes/

1. Start at pubtab.__init__

The public contract is defined in __init__.py.

Public exports are intentionally small:

  • xlsx2tex
  • preview
  • compile_pdf
  • tex_to_excel
  • SpacingConfig

This is the key architectural signal: pubtab exposes a compact API, while the real complexity is pushed into reader/renderer/preview internals.

2. Core data model layer

models.py defines the structured table representation.

Important dataclasses:

  • CellStyle
  • Cell
  • TableData
  • SpacingConfig
  • ThemeConfig
  • BackendConfig

Source fact:

  • the shared structured representation is TableData, not raw Excel cells or raw LaTeX text.

Forward and reverse conversions both pass through this structured table model.

3. Forward pipeline: Excel to LaTeX

The main forward path is:

  1. xlsx2tex(...) in __init__.py
  2. read_excel(...) in reader.py
  3. render(...) in renderer.py
  4. optional preview through _preview.py

This gives a clean source-driven decomposition:

  • reader.py = file ingestion and structure recovery
  • renderer.py = LaTeX generation
  • _preview.py = compile and raster preview

4. Reverse pipeline: LaTeX to Excel

The reverse path is:

  1. tex_to_excel(...) in __init__.py
  2. read_tex_multi(...) from tex_reader.py
  3. writer functions to .xlsx

So roundtrip support is not an afterthought. It is a real architecture branch.

5. reader.py is richer than a plain spreadsheet loader

From the source, reader.py does much more than “read cells”:

  • supports .xlsx and .xls
  • extracts rich text segments
  • reconstructs merged cells and spans
  • reads styling information
  • trims only trailing globally empty columns
  • reads pubtab metadata sheets
  • restores group separators, multicolumn alignment hints, and math-script hints

Interpretation from source:

  • pubtab is optimized for publication table semantics, rather than for plain tabular text dumping.

6. renderer.py is the central logic hub

renderer.py turns TableData into backend-specific LaTeX.

From the source, it handles:

  • style/theme loading
  • backend template loading
  • spacing resolution
  • column spec construction or projection
  • tabular vs tabularray differences
  • merged cells, row/column spans, header rules, vertical rules
  • background colors and grouped separators
  • final template rendering

This file is where most of the difficult publication logic lives.

For skill design, that means:

  • backend choice is not a cosmetic toggle
  • column spec and rule behavior are structural concerns
  • preview/render bugs usually require reading renderer.py

7. Theme vs backend is a real split

The codebase separates:

  • themes in themes/
  • LaTeX backends in backends/

That is reflected in two dataclasses:

  • ThemeConfig
  • BackendConfig

And in two loaders:

  • load_theme(...)
  • load_backend(...)

This is a major architectural point for the skill:

  • theme decides stylistic defaults,
  • backend decides LaTeX environment/template behavior.

Do not explain them as if they were the same thing.

8. Config precedence is explicit

In xlsx2tex(...), the source implements a clear precedence order:

  1. hardcoded defaults
  2. YAML config loaded by config.py
  3. explicit function kwargs
  4. in some roundtrip cases, values recovered from TableData

This is why user-facing guidance should say “CLI flags or function kwargs override YAML config.”

9. Multi-file and multi-sheet support are first-class

From __init__.py:

  • directory input is supported for both forward and reverse paths
  • sheet enumeration is supported when sheet=None
  • multi-sheet export produces *_sheetNN.tex

The default skill guidance can therefore recommend batch/file-driven workflows, not only one-table-at-a-time usage.

10. Preview is a real compilation layer

preview(...) and compile_pdf(...) in __init__.py delegate into _preview.py.

That layer:

  • finds or installs pdflatex
  • builds a standalone document
  • compiles the output
  • retries missing packages through tlmgr
  • converts PDF to PNG when requested

Preview is not a fake HTML-like snapshot. It is a real LaTeX compile pipeline.

11. tex_reader.py closes the roundtrip loop

tex_reader.py is substantial, not decorative.

From the source it supports parsing of:

  • tabular
  • tblr
  • longtblr
  • talltblr

It also handles:

  • color parsing
  • rule parsing
  • multirow/multicolumn reconstruction
  • metadata extraction
  • grouped rows and placeholder cleanup

This makes pubtab suitable for source-aware roundtrip and migration tasks, rather than only one-way Excel export.

12. Reading order for source debugging

When you need source-level certainty, use this order:

  1. pubtab/src/pubtab/__init__.py
  2. pubtab/src/pubtab/models.py
  3. pubtab/src/pubtab/reader.py
  4. pubtab/src/pubtab/renderer.py
  5. pubtab/src/pubtab/_preview.py
  6. pubtab/src/pubtab/tex_reader.py
  7. pubtab/src/pubtab/backends/ and themes/
  8. pubtab/src/pubtab/cli.py for flag-to-API mapping only

13. Implications for this skill

The source says the most faithful default workflow is:

  • use xlsx2tex(...) or CLI xlsx2tex for forward generation,
  • use preview(...) to verify actual compile output,
  • use tex_to_excel(...) for roundtrip or migration tasks,
  • explain theme/backend separately,
  • escalate into renderer/source debugging only when table structure or LaTeX behavior is the real problem.