Skip to main content

openpyxl-toolkit

PyPI Python versions CI License

openpyxl formatting without the boilerplate.

Purpose

It is our opinion that formatting and styling worksheets with openpyxl is clunky and non-intuitive. We wanted to build something to make the process less painful and the end result more readable.

For example, openpyxl stores a cell's style as an immutable object. This means changing one attribute results in building an entirely new Font object and assigning it, which drops the size, the color, and anything else that was set:

>>> from copy import copy
>>> from openpyxl import Workbook
>>> from openpyxl.styles import Font

>>> wb = Workbook()
>>> ws = wb.active
>>> ws["A1"] = "My cell text"

>>> ws["A1"].font = Font(size=14, color="FF1D3557") # openpyxl wants ARGB
>>> ws["A1"].font = Font(bold=True) # the size and the color are now gone

If you try ws["A1"].font.bold = True, you get Style objects are immutable and cannot be changed. Reassign the style with a copy. So if you wanted to modify just one part of a font, you would have to make a copy, modify it, and assign it:

>>> font = copy(ws["A1"].font)
>>> font.bold = True
>>> ws["A1"].font = font

This toolkit allows you to change attributes one by one without having to copy previously set attributes.

>>> from openpyxl_toolkit import WorksheetToolkit

>>> toolkit = WorksheetToolkit(ws)
>>> toolkit.set_font(cells="A1", size=14, color="#1d3557")
>>> toolkit.set_font(cells="A1", bold=True) # size and color are not discarded

Install

pip install openpyxl-toolkit

Python 3.10 or newer, and openpyxl 3.1 or newer.

Methods

Cell formatting

Method What it sets
set_alignment horizontal, vertical, text_rotation, wrap_text, shrink_to_fit, indent, reading_order
set_border style and color, on any of six sides
set_outside_border one border around the edge of a block, leaving the inside alone
set_fill fill_type, start_color, end_color
set_font name, size, bold, italic, underline, strike, color
set_number_format how a value is displayed: currency, percent, dates, decimal places

Row and column formatting

Method What it sets
set_column_width / set_row_height an explicit size; 0 hides the column or row
set_column_best_fit a column width that fits the widest cell
merge_cells / unmerge_cells a merged range

Sheet-level controls

Method What it sets
freeze_panes rows above and columns left of a cell stay visible
set_autofilter Excel's filter controls on a range
set_gridline_visibility whether the grid between cells is drawn on screen
set_sheet_visibility whether the sheet is shown, hidden, or hidden from the unhide list too
set_tab_color the color of the sheet's tab
set_zoom_scale the zoom level when the reader opens the file: 10 to 400
>>> toolkit.set_tab_color("#1d3557")
>>> toolkit.set_gridline_visibility(visible=False)
>>> toolkit.set_autofilter(cells="A1:C3")
>>> toolkit.set_sheet_visibility(state="hidden")

Each method returns the toolkit, so calls can chain. Most parameters are keyword-only.

Anything not named is left as is. None is not the same as leaving out an argument: set_font(color=None) clears the color, while omitting color keeps whatever was there.

Cell selection

On every method that formats cells, there are 2 methods of selecting which cells the action should be applied to:

  1. cells
  2. rows and columns
>>> toolkit.set_fill(cells="A1:C3", fill_type="solid", start_color="#f4f6f8")
>>> toolkit.set_fill(cells="A:C", fill_type="solid", start_color="#f4f6f8")
>>> toolkit.set_fill(rows=[1, 2], columns=[1, 2], intersections_only=True,
...                  fill_type="solid", start_color="#ffff00")

cells takes a block ("A1:C3"), whole columns ("B:D"), whole rows ("2:5") or one cell ("C3"). Case does not matter, a reversed range such as "C3:A1" is normalized, and an unbounded side is filled in from the used range, so "B:B" means column B as far as the sheet goes (rather than all 1,048,576 rows).

rows and columns take lists.

Given both rows and columns, intersections_only decides what they mean:

Cells formatted
intersections_only=True (default) where the rows and the columns cross — a block
intersections_only=False every cell in those rows and every cell in those columns — a cross

Giving both cells and rows/columns raises.

Column letters and numbers

Because column letters can be hard to work with, we have provided a pair of functions for conversion. openpyxl has its own versions in openpyxl.utils, but under names that are more difficult to remember.

>>> from openpyxl_toolkit import column_letter, column_index

>>> column_letter(3)    # 'C'
>>> column_index("C")   # 3
>>> toolkit.set_column_width(width=18, columns=[column_index("D")])

Type hints

The package ships py.typed. Alignment names, border styles, fill patterns and underline styles are Literal types, so an editor completes them and a checker catches a typo before the code runs:

error: Argument "horizontal" to "set_alignment" has incompatible type "Literal['centre']"

openpyxl rejects the same typo, but only once the call runs; the Literal types move it into the editor. Elsewhere the annotations really are stricter than openpyxl is at runtime, which matters more than it sounds: openpyxl accepts bold="no" and stores True, and name=42 and stores "42".

License

MIT.

Release files for openpyxl-toolkit 0.4.0

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

Source distribution (sdist)

Source distribution for openpyxl-toolkit 0.4.0
File Size Uploaded
openpyxl_toolkit-0.4.0.tar.gz 68.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openpyxl-toolkit 0.4.0
File Interpreter ABI Platform
openpyxl_toolkit-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 105.8 kB

Release files / openpyxl_toolkit-0.4.0.tar.gz

Download URL openpyxl_toolkit-0.4.0.tar.gz
Size 68.8 kB
Tags Source
SHA-256 checksum
How to use checksums
f0c83b72bcafc5e96959c223240b29475887cdb30b280d213877c6459d0d0050
BLAKE2b-256 checksum
How to use checksums
4b72057cf460b198ed90b6302b4a20879ffb56f3c237c9030ee619dcc0f6e3e3
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 Sep 24, 2026.

Transparency log

Release files / openpyxl_toolkit-0.4.0-py3-none-any.whl

Download URL openpyxl_toolkit-0.4.0-py3-none-any.whl
Size 37.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
018d92a0e420c066fe63881c6685616694e18d280f8389fad13eb9e2344504e1
BLAKE2b-256 checksum
How to use checksums
2a739a369b7211583720185062b6b69680de540597356addfdea97fb1bdd28d0
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 Sep 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

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