Skip to content

Releases

v0.9.0

Choose a tag to compare

@harumiWeb harumiWeb released this 04 Oct 02:40
9cdf9aa

ExStruct v0.9.0

ExStruct v0.9.0 is a major performance-focused release that substantially reduces extraction latency, memory usage, repeated workbook parsing, and unnecessary heavy dependency loading.

The biggest change is a new direct OOXML extraction path for light mode. Supported .xlsx and .xlsm files can now be read directly from the workbook ZIP package without loading openpyxl, xlwings, pandas, or SciPy on the normal path.

This release also significantly improves verbose color extraction by avoiding thousands of unnecessary per-cell Excel COM calls while preserving Excel-rendered conditional formatting semantics.

Highlights

Direct OOXML extraction for light mode

light mode now uses a shared direct OOXML extraction session for supported .xlsx and .xlsm workbooks.

The new path extracts:

  • cells and shared strings
  • formulas
  • hyperlinks
  • merged cells
  • print areas
  • explicit and heuristic table candidates
  • shapes and connectors
  • charts

A normal light extraction now opens the workbook archive once and does not import:

  • openpyxl
  • xlwings
  • pandas
  • SciPy

If the direct OOXML reader encounters unsupported workbook content, ExStruct safely discards the partial result and restarts extraction through the existing openpyxl compatibility path.

Much faster light extraction

Representative local Windows benchmarks showed substantial improvements while producing identical serialized output.

Fixture Previous light v0.9.0
24-sheet workbook 4102 ms 120 ms
Large workbook 1596 ms 596 ms
Style-heavy workbook 535 ms 178 ms
Table-heavy workbook 242 ms 72 ms

After switching the default light path fully to direct OOXML, additional cold-start improvements were observed:

Fixture openpyxl path OOXML path
Small 983 ms 428 ms
Sparse 823 ms 254 ms
24 sheets 840 ms 333 ms
Large / 60,000 cells 1626 ms 1060 ms

Peak Python memory usage was also lower across all measured light-mode fixtures.

These are local benchmark results and should not be interpreted as universal timing guarantees.

Faster verbose color extraction

Previously, rendered background-color extraction queried Excel's DisplayFormat separately for every cell in the used range.

v0.9.0 introduces a hybrid strategy:

  • ordinary saved RGB fills are read directly from workbook styles
  • Excel COM is used only for conditional-formatting candidates and ambiguous cases
  • unsupported or unsafe cases fall back to the previous full COM scan

On the measured 300 × 20-cell fixtures:

Fixture DisplayFormat calls Legacy v0.9.0
Static fills 6,000 → 0 15.5–18.7 s 0.084–0.100 s
Sparse conditional formatting 6,000 → 30 12.8–17.0 s 0.144–0.208 s

All 24 paired color-map comparisons in the benchmark matched exactly.

Excel remains the source of truth for rendered conditional-formatting colors; ExStruct does not attempt to reimplement Excel's conditional-formatting engine.

Other performance improvements

Removed pandas from production extraction

Cell extraction no longer converts worksheets through pandas DataFrames.

The production path now reads worksheet data directly while preserving existing:

  • value normalization
  • dates
  • cached formula values
  • hyperlinks
  • sparse-row behavior
  • serialized output

pandas is now a development/benchmark dependency rather than a production extraction dependency.

Shared openpyxl extraction sessions

Compatibility extraction now reuses an extraction-scoped openpyxl workbook instead of repeatedly reopening the same file.

For multi-sheet workbooks, this removes a major source of redundant ZIP parsing and workbook object construction.

Formula extraction still opens a separate data_only=False workbook only when required.

SciPy is now optional

SciPy has moved out of the mandatory dependency set.

Install the optional accelerator with:

pip install "exstruct[fast]"

Without SciPy, ExStruct continues to use its Python border-clustering implementation.

Lighter backend imports

COM and rendering implementations are now loaded lazily.

Light extraction no longer pays the import cost for Excel automation backends that it does not use.

Reliability improvements

  • Fixed a lifecycle issue where a newly created Excel instance could remain running if workbook opening failed.
  • Existing/borrowed Excel applications and workbooks remain under caller ownership.
  • OOXML fallback restarts the complete compatibility extraction rather than mixing partial results from multiple backends.
  • Sparse worksheets no longer materialize large numbers of blank cells during extraction.
  • Improved handling of relocated OOXML workbook/drawing parts.
  • Preserved rich/plain shared-string segment ordering.
  • Reduced repeated merge and hyperlink scans for sparse worksheets.

COM-first evaluation

As part of this release, a bulk COM-based cell extraction path was prototyped and benchmarked for standard and verbose modes.

It was not adopted as the public default.

The experiment showed no consistent performance advantage and introduced semantic differences for:

  • Excel dates represented through Value2
  • formula recalculation
  • missing formula caches
  • unsaved workbook edits

ExStruct therefore continues to use the current saved-file-first architecture for standard and verbose extraction.

Compatibility

v0.9.0 is intended to preserve the existing public extraction output contract.

Performance work was validated with output-parity tests across representative workbooks, including cells, formulas, links, tables, merged ranges, shapes, charts, and color maps.

Unsupported direct OOXML cases continue to use the existing compatibility backend automatically.

Installation

pip install -U exstruct

Optional SciPy acceleration:

pip install -U "exstruct[fast]"

Summary

v0.9.0 changes ExStruct's extraction architecture from:

repeated workbook parsing
+ heavyweight intermediate readers
+ eager backend imports
+ per-cell COM formatting calls

to:

shared extraction sessions
+ direct OOXML where possible
+ lazy compatibility backends
+ targeted COM only where Excel rendering is required

The result is significantly faster and lighter extraction while retaining compatibility with the existing ExStruct output model.

v0.8.2

Choose a tag to compare

@harumiWeb harumiWeb released this 26 Sep 10:04
563da66

Updated project dependencies to resolve the reported Dependabot vulnerability alerts.

v0.8.1

Choose a tag to compare

@harumiWeb harumiWeb released this 14 May 06:52
b871aa3

Applied security updates for dependent packages.

v0.8.0

Choose a tag to compare

@harumiWeb harumiWeb released this 22 Apr 13:36
91777b0

v0.8.0 Release Notes

This release publishes the April 2026 extraction work: stronger pure-Python rich
extraction in light mode, corrected print-area defaults across public
entrypoints, and LibreOffice / OOXML resilience hardening.

Highlights

  • light now acts as the pure-Python OOXML-rich baseline for .xlsx /
    .xlsm, so non-COM environments can emit best-effort:
    • shapes
    • connectors / arrows
    • charts
  • light now keeps print_areas by default across:
    • extract(...)
    • process_excel(...)
    • ExStructEngine
    • CLI extraction and --print-areas-dir
  • libreoffice now seeds the same OOXML baseline first and then applies UNO
    enrichment when available, so fallback paths preserve already recovered rich
    artifacts where safe.
  • LibreOffice workbook lifecycle handling is more robust for custom
    session_factory integrations via typed workbook handles and session-owned
    close semantics.
  • OOXML drawing parsing is more resilient and more efficient:
    • malformed or corrupt drawing parts now fail per sheet instead of dropping
      healthy workbook siblings
    • worksheet metrics are read with streaming XML parsing
    • row/column offset lookups now use cached cumulative offsets

Compatibility Notes

  • No new extraction CLI commands were added in v0.8.0.
  • light mode behavior changed intentionally:
    • previous releases treated light as cells + table candidates only
    • v0.8.0 adds best-effort OOXML shapes / connectors / charts for OOXML
      workbooks and keeps print areas by default
  • .xls remains outside the new OOXML-rich baseline; the new non-COM rich path
    applies to .xlsx / .xlsm.
  • Serialized backend metadata may now report python_ooxml provenance when
    backend metadata output is enabled.
  • MCP tool names and payload shapes remain compatible; the release changes the
    extraction content available behind existing interfaces rather than adding a
    new transport contract.

Notes

  • The repository docs/build path still has a pre-existing mkdocstrings
    failure in docs/api.md; this issue was already reproducible before the
    v0.8.0 extraction work and is not introduced by this release.
  • Review-driven hardening after the initial implementation also restored
    process_excel() auto-filter behavior, corrected stale README / architecture
    wording, and prevented OOXML baseline seeding failures from crashing the
    LibreOffice pipeline.

v0.7.1

Choose a tag to compare

@harumiWeb harumiWeb released this 21 Mar 09:40
04a7eb1

v0.7.1 Release Notes

This patch release publishes the CLI and package import startup optimization work
completed under issues #107, #108, and #109.

Highlights

  • The extraction CLI now always shows --auto-page-breaks-dir in help output
    and validates support only when the option is actually used at runtime.
  • Lightweight CLI paths now avoid unnecessary heavy imports:
    • exstruct --help
    • extraction-style argv that do not route to edit commands
    • exstruct ops list
  • Public package imports are lighter:
    • import exstruct
    • import exstruct.engine
    • exported names from exstruct and exstruct.edit remain compatible while
      loading implementation modules lazily
  • Regression coverage now locks the startup boundary and validates that
    lightweight import paths do not eagerly load extraction, edit, MCP, render,
    or pydantic dependencies.

Startup impact

Compared with v0.7.0, local median startup timings on the same Python
environment improved by approximately:

  • python -m exstruct.cli.main --help: 2195 ms -> 64 ms (34.4x faster)
  • import exstruct: 1039 ms -> 55 ms (19.0x faster)
  • python -m exstruct.cli.main ops list: 1143 ms -> 207 ms (5.5x faster)
  • import exstruct.engine: 1005 ms -> 223 ms (4.5x faster)

These measurements were taken locally against v0.7.0 and the current
v0.7.1 code using the same virtual environment and direct source imports, so
exact numbers will vary by machine and startup conditions.

Notes

  • No new CLI commands were added in v0.7.1.
  • MCP tool names and payload shapes remain compatible in v0.7.1.
  • Backend selection policy remains auto / com / openpyxl.
  • The edit CLI validate subcommand once again propagates RuntimeError
    instead of converting it into handled CLI error output.

v0.7.0

Choose a tag to compare

@harumiWeb harumiWeb released this 19 Mar 10:56
ee3d44f

v0.7.0 Release Notes

This release publishes the workbook editing work completed under issue #99,
including the new exstruct.edit API surface, the editing CLI, compatibility
follow-ups, and maintainer-facing documentation needed to keep the layering
clear for future changes.

Next steps

Currently, the CLI startup is slow due to issues with the initial implementation,
so we plan to release an update in the near future to improve its performance.

Highlights

  • Added a first-class workbook editing API under exstruct.edit, including:
    • public patch_workbook() / make_workbook() entrypoints
    • public request/result models
    • shared patch-op schema discovery helpers
  • Added public editing CLI commands under exstruct:
    • patch
    • make
    • ops
    • validate
  • Clarified the editing architecture split so exstruct.edit is the canonical
    core and MCP remains the host-managed integration / compatibility layer.
  • Updated public docs to explain canonical usage across Python, CLI, and MCP,
    including the recommended dry_run -> inspect -> apply workflow and the
    backend="auto" caveat for same-engine comparisons.
  • Added maintainer-facing documentation coverage for editing architecture,
    specs, ADR alignment, and agent workflow expectations used during the issue
    #99 closeout.
  • Fixed release-significant review follow-ups, including:
    • top-level sheet fallback while preserving op.sheet precedence
    • legacy monkeypatch compatibility across compatibility shims
    • rename-reservation cleanup on openpyxl failure paths
    • dry-run / backend / CLI failure wording drift in docs

Notes

  • The legacy extraction CLI invocation (exstruct INPUT.xlsx ...) is unchanged.
  • MCP tool names and payload shapes remain compatible in v0.7.0.
  • Patch backend policy remains auto / com / openpyxl; this release does
    not change backend selection semantics.

v0.6.1

Choose a tag to compare

@harumiWeb harumiWeb released this 12 Mar 13:56
10a9cd0

v0.6.1 Release Notes

This patch release hardens Windows LibreOffice smoke coverage and runtime
resolution for the libreoffice extraction path.

Highlights

  • Added a dedicated Windows GitHub Actions LibreOffice smoke job:
    • runs on windows-2025
    • installs libreoffice-fresh
    • discovers EXSTRUCT_LIBREOFFICE_PATH and bundled LibreOffice Python
    • runs tests/core/test_libreoffice_smoke.py -m libreoffice with
      RUN_LIBREOFFICE_SMOKE=1
  • Improved Windows runtime discovery:
    • soffice.com is now preferred over soffice.exe when available
    • bundled LibreOffice Python detection now covers python-core-* layouts
  • Hardened LibreOffice bridge subprocess startup on Windows:
    • bridge probe, handshake, and extraction now run from the runtime Python
      directory
    • the runtime directory is prepended to PATH for UNO import and DLL
      resolution
  • Reduced smoke-gate false negatives:
    • slow soffice --version probes are retried with a longer timeout
    • if version probing still times out, the smoke gate falls back to a
      short-lived LibreOffice session probe before marking the runtime
      unavailable
  • Added regression tests for Windows runtime normalization, bundled Python
    discovery, bridge subprocess environment handling, and timeout fallback.

Notes

  • This is a reliability-focused patch release for Windows LibreOffice CI and
    runtime detection.
  • No public API or output schema changes were introduced in this release.

v0.6.0

Choose a tag to compare

@harumiWeb harumiWeb released this 10 Mar 12:38
1b1853b

v0.6.0 Release Notes

logo

This release adds a new best-effort libreoffice extraction mode for
non-COM environments and extends shape/chart metadata with provenance fields.

Highlights

  • Added mode="libreoffice" across the Python API, CLI, and MCP server.
  • Added early validation for .xls + mode="libreoffice" with a clear error.
  • Added extraction-only validation for mode="libreoffice":
    • rejects PDF/PNG rendering
    • rejects auto page-break export
  • Added FallbackReason.LIBREOFFICE_UNAVAILABLE and
    FallbackReason.LIBREOFFICE_PIPELINE_FAILED.
  • Added backend metadata to shapes/charts:
    • provenance
    • approximation_level
    • confidence
    • serialized output now keeps these fields opt-in via include_backend_metadata
  • Added OOXML-based best-effort reconstruction for:
    • shapes
    • connectors
    • charts
  • Added a LibreOffice runtime helper so server/Linux/macOS environments can
    opt into rich extraction without Excel COM.
  • Added bundled bridge compatibility probing for LibreOffice Python runtime
    selection, including fail-fast handling for incompatible
    EXSTRUCT_LIBREOFFICE_PYTHON_PATH overrides.
  • Added a required Linux GitHub Actions smoke job that installs LibreOffice
    • python3-uno and runs the pytest.mark.libreoffice sample smoke test.

Notes

  • libreoffice is available for .xlsx/.xlsm only.
  • libreoffice is best-effort and not a strict subset of COM output.
  • v1 does not add LibreOffice PDF/PNG rendering or auto page-break extraction.

v0.5.3

Choose a tag to compare

@harumiWeb harumiWeb released this 06 Mar 03:56
2ed74ef

v0.5.3 Release Notes

This patch release improves capture_sheet_images subprocess reliability and
observability, and updates MCP guidance for safe production rollout.

Highlights

  • Added dedicated subprocess worker entrypoint:
    • python -m exstruct.render.subprocess_worker is now used for
      capture_sheet_images subprocess mode.
    • worker bootstrap is decoupled from parent __main__ restoration.
  • Updated default runtime behavior:
    • MCP now defaults EXSTRUCT_RENDER_SUBPROCESS=1 based on profile-comparison
      runs showing stable behavior in both modes.
    • EXSTRUCT_RENDER_SUBPROCESS=0 remains available to force in-process mode.
  • Improved timeout and failure diagnostics:
    • wait ordering now prioritizes result receipt before join wait to reduce
      false timeout failures after successful worker output.
    • stage-aware error reporting (startup / join / result / worker) now
      includes actionable context and stderr snippets when available.
  • Documentation updates:
    • MCP exstruct_capture_sheet_images is marked Experimental.
    • README/MCP docs now include subprocess timeout tuning guidance, including
      EXSTRUCT_RENDER_SUBPROCESS_STARTUP_TIMEOUT_SEC.

Notes

  • No new patch operations were added in this release.
  • MCP tools include the experimental exstruct_capture_sheet_images path updated in this release.
  • This is a reliability-focused patch release for image-capture execution paths.

v0.5.2

Choose a tag to compare

@harumiWeb harumiWeb released this 28 Feb 02:25
fd47bfe

v0.5.2 Release Notes

This patch release restores mixed chart/table patch workflows on COM-backed
execution and clarifies error behavior for non-COM environments.

Highlights

  • Restored mixed-op support:
    • create_chart and apply_table_style can be executed in one request when
      the backend resolves to COM (backend="com" or COM-available
      backend="auto").
  • Improved error behavior:
    • when COM is unavailable, mixed create_chart + apply_table_style
      requests now return a clear COM-required error.
  • Added and updated regression coverage:
    • mixed request succeeds on COM
    • mixed request fails clearly when COM is unavailable
    • backend="openpyxl" continues to reject create_chart requests

Notes

  • This release does not add new MCP tools or patch operations.
  • Documentation (README and MCP guide) has been aligned with the restored
    mixed-op behavior.