Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Create, read, edit, and format Excel (.xlsx) spreadsheets with formulas, color coding, and financial model standards
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/office/pack.py
1"""Pack a directory into a DOCX, PPTX, or XLSX file.23Validates with auto-repair, condenses XML formatting, and creates the Office file.45Usage:6python pack.py <input_directory> <output_file> [--original <file>] [--validate true|false]78Examples:9python pack.py unpacked/ output.docx --original input.docx10python pack.py unpacked/ output.pptx --validate false11"""1213import argparse14import sys15import shutil16import tempfile17import zipfile18from pathlib import Path1920import defusedxml.minidom2122from validators import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator2324def pack(25input_directory: str,26output_file: str,27original_file: str | None = None,28validate: bool = True,29infer_author_func=None,30) -> tuple[None, str]:31input_dir = Path(input_directory)32output_path = Path(output_file)33suffix = output_path.suffix.lower()3435if not input_dir.is_dir():36return None, f"Error: {input_dir} is not a directory"3738if suffix not in {".docx", ".pptx", ".xlsx"}:39return None, f"Error: {output_file} must be a .docx, .pptx, or .xlsx file"4041if validate and original_file:42original_path = Path(original_file)43if original_path.exists():44success, output = _run_validation(45input_dir, original_path, suffix, infer_author_func46)47if output:48print(output)49if not success:50return None, f"Error: Validation failed for {input_dir}"5152with tempfile.TemporaryDirectory() as temp_dir:53temp_content_dir = Path(temp_dir) / "content"54shutil.copytree(input_dir, temp_content_dir)5556for pattern in ["*.xml", "*.rels"]:57for xml_file in temp_content_dir.rglob(pattern):58_condense_xml(xml_file)5960output_path.parent.mkdir(parents=True, exist_ok=True)61with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:62for f in temp_content_dir.rglob("*"):63if f.is_file():64zf.write(f, f.relative_to(temp_content_dir))6566return None, f"Successfully packed {input_dir} to {output_file}"676869def _run_validation(70unpacked_dir: Path,71original_file: Path,72suffix: str,73infer_author_func=None,74) -> tuple[bool, str | None]:75output_lines = []76validators = []7778if suffix == ".docx":79author = "Claude"80if infer_author_func:81try:82author = infer_author_func(unpacked_dir, original_file)83except ValueError as e:84print(f"Warning: {e} Using default author 'Claude'.", file=sys.stderr)8586validators = [87DOCXSchemaValidator(unpacked_dir, original_file),88RedliningValidator(unpacked_dir, original_file, author=author),89]90elif suffix == ".pptx":91validators = [PPTXSchemaValidator(unpacked_dir, original_file)]9293if not validators:94return True, None9596total_repairs = sum(v.repair() for v in validators)97if total_repairs:98output_lines.append(f"Auto-repaired {total_repairs} issue(s)")99100success = all(v.validate() for v in validators)101102if success:103output_lines.append("All validations PASSED!")104105return success, "\n".join(output_lines) if output_lines else None106107108def _condense_xml(xml_file: Path) -> None:109try:110with open(xml_file, encoding="utf-8") as f:111dom = defusedxml.minidom.parse(f)112113for element in dom.getElementsByTagName("*"):114if element.tagName.endswith(":t"):115continue116117for child in list(element.childNodes):118if (119child.nodeType == child.TEXT_NODE120and child.nodeValue121and child.nodeValue.strip() == ""122) or child.nodeType == child.COMMENT_NODE:123element.removeChild(child)124125xml_file.write_bytes(dom.toxml(encoding="UTF-8"))126except Exception as e:127print(f"ERROR: Failed to parse {xml_file.name}: {e}", file=sys.stderr)128raise129130131if __name__ == "__main__":132parser = argparse.ArgumentParser(133description="Pack a directory into a DOCX, PPTX, or XLSX file"134)135parser.add_argument("input_directory", help="Unpacked Office document directory")136parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")137parser.add_argument(138"--original",139help="Original file for validation comparison",140)141parser.add_argument(142"--validate",143type=lambda x: x.lower() == "true",144default=True,145metavar="true|false",146help="Run validation with auto-repair (default: true)",147)148args = parser.parse_args()149150_, message = pack(151args.input_directory,152args.output_file,153original_file=args.original,154validate=args.validate,155)156print(message)157158if "Error" in message:159sys.exit(1)160