Skip to main content

xls2xlsx

xls2xlsx converts Excel 97–2003 .xls workbooks to .xlsx or .xlsm directly from the published file-format specifications.

The distribution is named msxls2xlsx. The Python package and command-line program are both named xls2xlsx.

The converter uses only the Python standard library at runtime. It does not require xlrd, openpyxl, Pillow, olefile, Microsoft Excel, LibreOffice, COM, Java, or external processes.

Installation

python -m pip install msxls2xlsx

To install from source:

python -m pip install .

Python API

Import convert for normal conversions:

from xls2xlsx import convert

result = convert("input.xls", "output.xlsx")

print(result.output_path)
print(result.report.warnings)
print(result.report.statistics)

The converter does not overwrite existing files unless overwrite=True is set. It preserves styles, VBA, and an exact copy of the source workbook by default:

result = convert(
    "input.xls",
    "output.xlsx",
    overwrite=True,
    preserve_styles=True,
    preserve_vba=True,
    preserve_source=True,
)

When no destination is given, a regular workbook is written as .xlsx. A workbook containing VBA is written as .xlsm unless VBA preservation is disabled.

Inspect a workbook without converting it

inspect_xls is optional and independent of conversion. Use it when you need to examine the BIFF version, sheet list, VBA status, or container metadata without creating an output file:

from xls2xlsx import inspect_xls

info = inspect_xls("input.xls")
print(info.to_dict())

Command line

Convert one workbook

xls2xlsx input.xls
xls2xlsx input.xls -o output.xlsx --report report.json

Inspect a workbook

xls2xlsx inspect input.xls
xls2xlsx inspect input.xls --json

The inspect command is read-only and does not create an .xlsx or .xlsm file.

Convert a directory

xls2xlsx batch ./legacy -o ./converted
xls2xlsx batch ./legacy -o ./converted --recursive --report batch.json

Batch conversion:

  • ignores Excel ~$ lock files;
  • processes files in deterministic relative-path order;
  • preserves the input directory structure under the output directory;
  • isolates failures so one invalid workbook does not stop the batch;
  • checks for output and report-path collisions before conversion;
  • exits with status 1 when some files fail.

Recover the original XLS file

xls2xlsx recover converted.xlsx -o recovered.xls

Recovery verifies the embedded file's length and SHA-256 digest. The same operation is available through the Python API:

from xls2xlsx import read_original_source, recover_original_source

stored = read_original_source("converted.xlsx")
recover_original_source("converted.xlsx", "recovered.xls")

Common options

--overwrite          Replace existing output and report files
--no-styles          Skip style conversion
--no-vba             Discard VBA and write an .xlsx file
--no-source-archive  Do not embed the original XLS file
--report FILE        Write a structured JSON report atomically
--json               Print structured output as JSON
--quiet              Suppress success messages

Exit status 0 means success, 1 means conversion failure or partial batch failure, and 2 means invalid input or command usage.

Conversion reports

Reports use a stable top-level structure:

{
  "source": "/path/input.xls",
  "destination": "/path/output.xlsx",
  "diagnostics": [],
  "statistics": {
    "sheets": 1,
    "cells": 42,
    "vba_preserved": false,
    "source_archive_preserved": true
  }
}

Diagnostics have info, warning, or error severity. A diagnostic location may identify a worksheet, cell, OLE stream, or BIFF offset. JSON reports are written to a temporary file in the destination directory and then replaced atomically.

Source preservation and fidelity

The project provides two layers of preservation:

  1. Native conversion. BIFF and OfficeArt content that has an OOXML equivalent is converted to editable .xlsx or .xlsm content.
  2. Byte-for-byte source preservation. The complete original .xls file is embedded in a custom XML part by default, together with its file name, length, SHA-256 digest, and conversion report.

Recoverable source data does not mean that every runtime behavior can be reproduced in OOXML. ActiveX events, legacy OLE activation, some combined or 3D charts, and complex grouped shapes have no exact OOXML equivalent. The converter reports these cases and keeps the original bytes in the embedded source archive.

Using --no-source-archive or preserve_source=False disables byte-for-byte source recovery.

Supported content

  • Text, numbers, booleans, errors, dates, formulas, and cached formula values
  • Fonts, colors, fills, borders, alignment, number formats, and protection
  • Rich text, merged cells, row and column sizing, hiding, grouping, and outlines
  • Sheet order and visibility, active sheets, panes, and page breaks
  • Hyperlinks, comments, conditional formatting, data validation, filters, and print settings
  • JPEG, PNG, DIB/BMP, TIFF, WMF, and EMF images
  • Line, bar, area, pie, and scatter charts, including titles, legends, and series
  • Basic DrawingML shapes and the original payloads of embedded OLE objects
  • VBA projects and module streams in .xlsm output

Format references

The implementation is based primarily on Microsoft's published MS-CFB, MS-XLS, and MS-ODRAW documentation, together with the published ISO/IEC 29500 implementation notes.

xls2xlsx follows the same package and command conventions as doc2docx and ppt2pptx:

Distribution Python package / CLI Conversion
msdoc2docx doc2docx DOC to DOCX
msxls2xlsx xls2xlsx XLS to XLSX/XLSM
ppt2pptx ppt2pptx PPT to PPTX

The projects share a consistent API, CLI structure, report format, and exit status conventions. Their conversion engines remain separate because the Word, Excel, and PowerPoint binary formats use different data models.

Development

Run the test suite with:

PYTHONPATH=src python -m unittest discover -s tests -v

The tests cover protocol parsing, formulas, styles, objects, VBA, source recovery, structured reports, CLI workflows, isolated installation, and real .xls fixtures from Apache POI. Fixture licensing information is available in tests/fixtures/apache-poi/.

License

This project is licensed under the MIT License.

Metadata

Release files for msxls2xlsx 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for msxls2xlsx 0.1.2
File Size Uploaded Provenance Actions
msxls2xlsx-0.1.2.tar.gz 998.4 kB With provenance Details for msxls2xlsx-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for msxls2xlsx 0.1.2
File Interpreter ABI Platform Actions
msxls2xlsx-0.1.2-py3-none-any.whl Python 3 none any Details for msxls2xlsx-0.1.2-py3-none-any.whl

Total release size: 1.1 MB

Release files / msxls2xlsx-0.1.2.tar.gz

Download URL msxls2xlsx-0.1.2.tar.gz
Size 998.4 kB
Tags Source
SHA-256 checksum
How to use checksums
bb258a6783d5a1506d5416bcb03903ab0269b3ae22e22762f07df0d801780e12
BLAKE2b-256 checksum
How to use checksums
f0676e233289295c71696e40710170d72e64b1c3ea6bf414922d39324b16167f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.

Transparency log

Release files / msxls2xlsx-0.1.2-py3-none-any.whl

Download URL msxls2xlsx-0.1.2-py3-none-any.whl
Size 94.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
20042f5eabb67042b810967799bd2596e4271a53ccd763bb52c38a9d2f0b15f5
BLAKE2b-256 checksum
How to use checksums
49fc8b73111b1ea2382c92837f07fb6e3243fbb71b7415a8c98ab824f7c82fc1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.

Transparency log

Security for msxls2xlsx 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for msxls2xlsx-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page