Skip to main content

A Python library to build Excel cell borders with simple range syntax, like VBA

Project description

xl-borders

A Python library that simplifies applying cell borders to openpyxl worksheets using Excel-style range strings (e.g. "A1:D5"), inspired by VBA's Range.Borders API.

Installation

# pip
pip install git+https://github.com/jiez1812/xl_borders.git

# uv
uv add git+https://github.com/jiez1812/xl_borders.git

To pin a specific version:

# By tag
pip install git+https://github.com/jiez1812/xl_borders.git@v0.1.0

# By branch
pip install git+https://github.com/jiez1812/xl_borders.git@main

Requires Python 3.13+ and openpyxl.

Quick Start

from openpyxl import Workbook
from xl_borders import set_border

wb = Workbook()
ws = wb.active

# Thin borders on all sides (default)
set_border(ws, "A1:D5")

# Thick red borders everywhere
set_border(ws, "A1:D5", style="thick", color="FF0000")

# Thick outer edges, thin inner grid
set_border(ws, "A1:D5", outline="thick", inside="thin")

# Compact numeric shorthand: thick outer, thin inner grid
set_border(ws, "A1:D5", custom=(3, 3, 3, 3, 1, 1))

# Override a single edge with shorthand (no Side import needed)
set_border(ws, "A1:D5", outline="medium", left=("double", "FF0000"))

wb.save("output.xlsx")

API

set_border(ws, cell_range, **kwargs)

Apply borders to a rectangular cell range.

Positional arguments:

Argument Type Description
ws Worksheet The openpyxl worksheet to modify.
cell_range str Excel-style range string (e.g. "A1:D5", "B2").

Keyword-only arguments (in priority order, lowest to highest):

Layer Parameter Type Description
1 style str Base border style for all 6 sides. Default: "thin".
1 color str | None Base border color for all sides (hex, e.g. "FF0000").
2 custom tuple[int, ...] | None Weight tuple in CSS-like order (see below).
3 outline str | None Style for all 4 outer edges.
3 inside str | None Style for inner horizontal and vertical lines.
4 horizontal str | None Style for top, bottom, and inner horizontal.
4 vertical str | None Style for left, right, and inner vertical.
5 left SideSpec Left edge (see Side shorthand below).
5 right SideSpec Right edge.
5 top SideSpec Top edge.
5 bottom SideSpec Bottom edge.
5 inner_horizontal SideSpec Inner horizontal lines.
5 inner_vertical SideSpec Inner vertical lines.

Higher-layer parameters override lower ones. The color param is inherited by all layers unless a side specifies its own color.

Side shorthand (SideSpec)

Individual side parameters (left, right, top, bottom, inner_horizontal, inner_vertical) accept three forms:

Form Example Result
str left="thick" Side(style="thick"), inherits base color
(str, str) tuple left=("thick", "FF0000") Side(style="thick", color="FF0000")
Side left=Side(style="thick", ...) Used as-is (full control)

This eliminates the need to import Side for most use cases.

The custom tuple

A compact way to set all 6 border positions with numeric weights:

(top, right, bottom, left, inner_horizontal, inner_vertical)

Weight mapping: 0 = none, 1 = thin, 2 = medium, 3 = thick.

The tuple length must be 4 or 6. A 4-element tuple sets the outer edges only; inner borders default to 0 (none). The base color is applied to all sides created by custom.

# 6-element: thick outer, thin horizontal grid, medium vertical grid
set_border(ws, "A1:D5", custom=(3, 3, 3, 3, 1, 2))

# 4-element: medium outer edges, no inner grid
set_border(ws, "A1:D5", custom=(2, 2, 2, 2))

# With color: all red
set_border(ws, "A1:D5", custom=(3, 3, 3, 3, 1, 1), color="FF0000")

Examples

All borders in one color

set_border(ws, "A1:D5", style="thick", color="0000FF")

Box border (outline only, no inner grid)

set_border(
    ws, "A1:D5",
    outline="medium",
    inner_horizontal=Side(style=None),
    inner_vertical=Side(style=None),
)

Different horizontal and vertical weights

set_border(ws, "A1:D5", horizontal="thin", vertical="thick")

Override a single edge with shorthand

# String shorthand (inherits base color)
set_border(ws, "A1:D5", outline="medium", color="0000FF", left="double")

# Tuple shorthand (own color overrides base)
set_border(ws, "A1:D5", outline="medium", left=("double", "FF0000"))

Using custom with overrides

Higher-priority layers refine on top of custom:

set_border(
    ws, "A1:D5",
    custom=(3, 2, 3, 2, 1, 1),
    color="0000FF",
    left=("double", "FF0000"),  # override left: double red
)

Available border styles

Any style string accepted by openpyxl's Side(style=...):

thin, medium, thick, double, dashed, mediumDashed, dotted, mediumDashDot, dashDot, mediumDashDotDot, dashDotDot, hair, slantDashDot

Development

# Install dependencies
uv sync

# Run tests
uv run pytest Test/ -v

License

MIT - See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xl_borders-0.1.0.tar.gz (5.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xl_borders-0.1.0-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file xl_borders-0.1.0.tar.gz.

File metadata

  • Download URL: xl_borders-0.1.0.tar.gz
  • Upload date:
  • Size: 5.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for xl_borders-0.1.0.tar.gz
Algorithm Hash digest
SHA256 03f68622798b65cb8ae449ac8e872567031235a2bd0a18f5d36b17b9d602261f
MD5 91c1814ef765cfe906f3af92e698940f
BLAKE2b-256 3abfd09d977eabcca8d110e2195d3c768d94de93e1eadcd820f85579cd9abd33

See more details on using hashes here.

File details

Details for the file xl_borders-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: xl_borders-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for xl_borders-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 86014e491e0b9dec8091381320441342f30d02629510733d5cc065e1bf04d171
MD5 82f45ef87d6444dce5cbd3ab1134e879
BLAKE2b-256 d81bf15c81fb1f46b9c2a232394f763a8ee3c4cc3a413ed781ed134fcd9af98d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page