pyexcel puts one API in front of a dozen spreadsheet formats
Single API for reading, manipulating and writing data in csv, ods, xls, xlsx and xlsm files
At a glance
- What is it?
- pyexcel is a BSD licensed Python library whose stated purpose is to let you focus on data instead of file formats, reading and writing csv, tsv, xls, xlsx, xlsm, ods and more through a single API, over a physical file, a memory file, a SQLAlchemy table, a Django model or plain Python data structures. Its own README states the two constraints up front: no fonts, colors or charts, and no password protected workbooks.
- Who is it for?
- pyexcel suits a Python codebase that has to read and write spreadsheet files without caring which format the user happens to have, especially one moving between csv exports and xlsx workbooks and one that needs to stream a large sheet rather than load it. It does not suit a project that needs to preserve formatting, charts or formulas, since none of that is supported, and it is the wrong tool for a password protected workbook.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 40 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem is the format, not the data
The title of the project is the argument for it: pyexcel, let you focus on data, instead of file formats.
The specific pain is that a spreadsheet format is a container choice that a user makes and a program has to cope with. A user sends a csv, then an xlsx exported from a legacy system, then an ods from a colleague using a different suite, and a pipeline that hardcodes one format either fails or needs three code paths. pyexcel's first feature highlight is one application programming interface to handle multiple data sources: a physical file, a memory file, a SQLAlchemy table, a Django model, or plain Python data structures such as a dictionary, records and an array.
The second highlight is one API to read and write data in the various Excel file formats, and the format table is longer than a typical reader expects. It includes csv, tsv, csvz, which is a zip file containing one or many csv files, tsvz, xls in the MS-Excel 97-2003 format, xlsx, xlsm which is a macro enabled workbook, ods and fods which are the OpenDocument spreadsheet and its flat variant, json, html as a table of the data structure, simple, rst as a reStructuredText presentation, and mediawiki as a table.
That last group is the interesting part of the design. The output formats are not only spreadsheets, and a data pipeline that can emit an HTML table, a wiki table or an rst table from the same in-memory records has one less conversion step in it. The architecture image in the README shows the same idea from the plugin side, with the core sitting between the caller and a set of format plugins.
Records or a two dimensional array, your choice
The one liners section of the README walks through the two ways you normally want tabular data out of a spreadsheet, and the difference between them is the difference between a list of dictionaries and a list of lists.
The first is records, where each row becomes a dictionary keyed by the header row:
>>> records = p.get_records(file_name="your_file.xls")The second is the array, where the rows keep their positions and you index them by number:
>>> for row in p.get_array(file_name="your_file.xls", start_row=1):
... print(f"{row[2]} are from {row[0]} period ({row[1]})")The start_row argument is the detail worth noticing. It skips the header row, which is what makes the array form usable at all, since the array form keeps the header as row zero unless you say otherwise.
Choosing between the two is a real decision rather than a preference. The records form is what you want when the columns are named, because the code survives a column being reordered in the source file. The array form is what you want when the columns are positional by contract, because it avoids building a dictionary per row for a large sheet, and because some data does not have meaningful headers at all.
The README's example runs against a table of composers by period, and the two loops produce the same output, which is a good way of showing that the choice of shape does not change the data.
Streaming is the answer for files that will not fit
The third feature highlight is the one that decides whether the library is usable in production: for large data sets, data streaming are supported, a generator can be returned to you, and the README points at iget_records, iget_array, isave_as and isave_book_as.
The naming convention is the API's clearest signal. A function prefixed with i returns an iterator rather than a list, so the same call shape works for a file with ten rows and a file with ten million, and the caller decides whether to materialise it. isave_as and isave_book_as are the write side, where a stream of records goes in and a file comes out.
This matters because spreadsheets are exactly the format people use for data that was too big for the thing they had. A pandas read_excel on a large workbook is a common way to run out of memory, and a generator based reader is the way out.
The dependency structure supports the same idea. The core package depends on three things: lml for the plugin loader, pyexcel-io for the actual reading and writing of files, and texttable for the textual presentation formats. The format handling is in separate packages, so a program that only needs csv does not need an Excel reader installed, and the plugin mechanism is how the format list can be that long without the core package becoming a dependency on every spreadsheet library in existence.
The constraints are stated before you find them
The README has a Known constraints section near the top, and it is short. Fonts, colors and charts are not supported. Nor to read password protected xls, xlsx and ods files.
Both limits are worth understanding properly rather than as a footnote. The first one is about the nature of the abstraction. pyexcel deals in records and arrays, that is, in values, and a spreadsheet file is much more than its values: it has fonts, fills, number formats, column widths, merged cells, charts, defined names and formulas. Preserving any of that means modelling a document rather than a table, and that is a different project. If your use case is moving data between systems, the constraint is free. If your use case is producing a formatted document for a human to read, it is the whole problem.
The second constraint is about encryption. A password protected workbook needs the password to be opened, and the library does not open them. That is an unusual thing to leave out of a spreadsheet reader, and the honest way to describe it is that pyexcel is for data extraction rather than for document handling, and a workflow that ends in a nicely formatted xlsx is going to need another tool at the end of it.
Not being able to read a protected workbook is also a security property worth noting in the other direction, since anything that does read protected files is handling credentials in memory.
The build is generated from templates, and the metadata shows it
The repository layout and the setup script explain a lot about the project, and not in the way you would guess.
The setup.py file says Template by pypi-mobans, and there is a .moban.yml file and a .moban.d/ directory in the tree. In other words, this project and a family of related ones are generated from a template system rather than scaffolded by hand, which is why the setup script carries a layer of compatibility code for Python 2 and for Python 3.3, with checks for PY2, PY26 and PY33 and a workaround for a distutils bug on Windows, and a locale fallback for platforms where the locale is unset.
That generation shows in the metadata too. The classifiers list Python 3.6, 3.7 and 3.8, python_requires says >=3.6, and the development status is classified as Alpha. The runtime dependencies are the three named above, and the package version is 0.7.6 under the name pyexcel with the author recorded as C.W.
The repository also has a batch of small build scripts in both Windows and shell form, test.sh and test.bat, lint.sh and lint.bat, format.sh and document.sh, and document.bat, and the Makefile has all, test, install_test, lint, format and a git-diff-check target that fails the build if the working tree is dirty. That is the shape of a project that is maintained by a small number of people on more than one operating system, and it explains both the file layout and the fact that the metadata has not been refreshed for recent Python versions.
Installing, and what a first run looks like
Installation is the standard one, with pip:
$ pip install pyexcelOr from a clone, with the classic setup script invocation:
$ git clone https://github.com/pyexcel/pyexcel.git
$ cd pyexcel
$ python setup.py installThe examples directory in the repository is organised the same way the documentation is, with basics, cookbook, database, formatting, memoryfile and simple subdirectories, so the path from a clone to a working call is short. The documentation lives at docs.pyexcel.org, the source at github.com/pyexcel/pyexcel, and the project is also on PyPI and on the conda-forge channel, which the README badges reflect.
The maintenance picture is a project on a 0.x line with an alpha classification, and the 2026 releases are frequent patch releases rather than feature versions: 0.7.6 at the end of June 2026, 0.7.5 a week earlier, and 0.7.4 in October 2025, whose release note is described as a minor fix on error messages. The repository is not archived, the last push was on 2026-09-13, and the default branch is dev rather than master, which tells you that the released tags and the working branch differ.
For a team, the practical adoption question is narrow. If your code reads a spreadsheet and gives the data to something else, this library removes the format branching and gives you streaming for free. If your code produces a spreadsheet for a person to read, with formatting, a chart and a formula, it is the wrong tool and you want a library that writes documents.
Editorial conclusion
pyexcel suits a Python codebase that has to read and write spreadsheet files without caring which format the user happens to have, especially one moving between csv exports and xlsx workbooks and one that needs to stream a large sheet rather than load it. It does not suit a project that needs to preserve formatting, charts or formulas, since none of that is supported, and it is the wrong tool for a password protected workbook. Verify first which format plugins you need, since the core package delegates the actual reading and writing to pyexcel-io and the lml plugin loader, and check the version you install, because the package metadata still classifies the project as alpha and the release cadence in 2026 has been frequent patch releases rather than feature versions.
Frequently asked questions
What file formats can pyexcel read and write?
The documented list includes csv, tsv, csvz and tsvz which are zip archives of csv or tsv files, xls, xlsx, xlsm, ods, fods, json, html as a table of the data structure, simple, rst and mediawiki, through one API.
How do I install pyexcel?
With pip install pyexcel, or by cloning the repository and running python setup.py install. The package is also published on PyPI and on the conda-forge channel.
What are pyexcel's known limitations?
The README states them directly: fonts, colors and charts are not supported, and password protected xls, xlsx and ods files cannot be read. The library is built for moving data rather than for producing formatted documents.
How does pyexcel handle large spreadsheets?
Data streaming is supported for large data sets, and a generator can be returned instead of a list. The functions iget_records, iget_array, isave_as and isave_book_as are the ones to look at for that path.
Can pyexcel read from a database or a Django model?
Yes. The first feature highlight is one API across multiple data sources, which the README lists as a physical file, a memory file, a SQLAlchemy table, a Django model, and Python data structures such as a dictionary, records and an array.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pyexcel-pyexcel)Was this useful?