#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Timestamp: 2026-01-27 # File: src/scitex_writer/tables.py """Table management functions. Usage:: import scitex_writer as sw # List tables in project result = sw.tables.list("./my-paper") # Add a table sw.tables.add("./my-paper", "results", "col1,col2\\n1,2", "Results summary") # Convert CSV to LaTeX result = sw.tables.csv_to_latex("data.csv", "table.tex") """ from typing import Literal as _Literal from typing import Optional as _Optional from ._mcp.handlers import csv_to_latex as _csv_to_latex from ._mcp.handlers import latex_to_csv as _latex_to_csv from ._mcp.utils import resolve_project_path as _resolve_project_path def list( project_dir: str, doc_type: _Literal["manuscript", "supplementary", "revision"] = "manuscript", ) -> dict: """List all tables in a writer project. Args: project_dir: Path to scitex-writer project. doc_type: Document type to search. Returns: Dict with tables list and count. """ try: project_path = _resolve_project_path(project_dir) doc_dirs = { "manuscript": project_path / "01_manuscript", "supplementary": project_path / "02_supplementary", "revision": project_path / "03_revision", } doc_dir = doc_dirs.get(doc_type) if not doc_dir or not doc_dir.exists(): return { "success": False, "error": f"Document directory not found: {doc_type}", } table_dir = doc_dir / "contents" / "tables" / "caption_and_media" if not table_dir.exists(): return {"success": True, "tables": [], "count": 0} tables = [] for csv_file in sorted(table_dir.glob("*.csv")): caption_file = csv_file.with_suffix(".tex") tables.append( { "name": csv_file.stem, "csv_path": str(csv_file), "caption_path": str(caption_file) if caption_file.exists() else None, "has_caption": caption_file.exists(), } ) return {"success": True, "tables": tables, "count": len(tables)} except Exception as e: return {"success": False, "error": str(e)} def add( project_dir: str, name: str, csv_content: str, caption: str, label: _Optional[str] = None, doc_type: _Literal["manuscript", "supplementary"] = "manuscript", ) -> dict: """Add a new table (CSV + caption) to the project. Args: project_dir: Path to scitex-writer project. name: Table name (without extension). csv_content: CSV content as string. caption: Table caption text. label: LaTeX label (default: tab:). doc_type: Target document type. Returns: Dict with csv_path, caption_path, label. """ try: project_path = _resolve_project_path(project_dir) doc_dirs = { "manuscript": project_path / "01_manuscript", "supplementary": project_path / "02_supplementary", } doc_dir = doc_dirs.get(doc_type) if not doc_dir: return {"success": False, "error": f"Invalid doc_type: {doc_type}"} table_dir = doc_dir / "contents" / "tables" / "caption_and_media" table_dir.mkdir(parents=True, exist_ok=True) csv_path = table_dir / f"{name}.csv" csv_path.write_text(csv_content, encoding="utf-8") if label is None: label = f"tab:{name.replace(' ', '_')}" caption_content = f"\\caption{{{caption}}}\n\\label{{{label}}}\n" caption_path = table_dir / f"{name}.tex" caption_path.write_text(caption_content, encoding="utf-8") return { "success": True, "csv_path": str(csv_path), "caption_path": str(caption_path), "label": label, } except Exception as e: return {"success": False, "error": str(e)} def remove( project_dir: str, name: str, doc_type: _Literal["manuscript", "supplementary"] = "manuscript", ) -> dict: """Remove a table (CSV + caption) from the project. Args: project_dir: Path to scitex-writer project. name: Table name (without extension). doc_type: Document type. Returns: Dict with removed file paths. """ try: project_path = _resolve_project_path(project_dir) doc_dirs = { "manuscript": project_path / "01_manuscript", "supplementary": project_path / "02_supplementary", } doc_dir = doc_dirs.get(doc_type) if not doc_dir: return {"success": False, "error": f"Invalid doc_type: {doc_type}"} table_dir = doc_dir / "contents" / "tables" / "caption_and_media" csv_path = table_dir / f"{name}.csv" caption_path = table_dir / f"{name}.tex" removed = [] if csv_path.exists(): csv_path.unlink() removed.append(str(csv_path)) if caption_path.exists(): caption_path.unlink() removed.append(str(caption_path)) if not removed: return {"success": False, "error": f"Table not found: {name}"} return {"success": True, "removed": removed} except Exception as e: return {"success": False, "error": str(e)} def csv_to_latex( csv_path: str, output_path: _Optional[str] = None, caption: _Optional[str] = None, label: _Optional[str] = None, longtable: bool = False, ) -> dict: """Convert CSV file to LaTeX table format. Args: csv_path: Path to CSV file. output_path: Output .tex file path (optional). caption: Table caption. label: LaTeX label. longtable: Use longtable environment. Returns: Dict with latex_content and output_path. """ return _csv_to_latex(csv_path, output_path, caption, label, longtable) def latex_to_csv( latex_path: str, output_path: _Optional[str] = None, table_index: int = 0, ) -> dict: """Convert LaTeX table to CSV format. Args: latex_path: Path to LaTeX file. output_path: Output .csv file path (optional). table_index: Which table to extract (0-indexed). Returns: Dict with preview and output_path. """ return _latex_to_csv(latex_path, output_path, table_index) __all__ = ["list", "add", "remove", "csv_to_latex", "latex_to_csv"] # EOF