Files
bussines_case_automation/venv/lib/python3.12/site-packages/xlsxwriter/format.py
andrei 0e2e1bddba Add xlsxwriter-based Excel generation scripts with openpyxl implementation
- Created create_excel_xlsxwriter.py and update_excel_xlsxwriter.py
- Uses openpyxl exclusively to preserve Excel formatting and formulas
- Updated server.js to use new xlsxwriter scripts for form submissions
- Maintains all original functionality while ensuring proper Excel file handling

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 13:53:06 +00:00

1275 lines
32 KiB
Python

###############################################################################
#
# Format - A class for writing the Excel XLSX Worksheet file.
#
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org
#
# Package imports.
from typing import Literal, Union
from warnings import warn
from xlsxwriter.color import Color
from . import xmlwriter
class Format(xmlwriter.XMLwriter):
"""
A class for writing the Excel XLSX Format file.
"""
###########################################################################
#
# Public API.
#
###########################################################################
def __init__(self, properties=None, xf_indices=None, dxf_indices=None) -> None:
"""
Constructor.
"""
if properties is None:
properties = {}
super().__init__()
self.xf_format_indices = xf_indices
self.dxf_format_indices = dxf_indices
self.xf_index = None
self.dxf_index = None
self.num_format = "General"
self.num_format_index = 0
self.font_index = 0
self.has_font = False
self.has_dxf_font = False
self.bold = 0
self.underline = 0
self.italic = 0
self.font_name = "Calibri"
self.font_size = 11
self.font_color = None
self.font_strikeout = 0
self.font_outline = 0
self.font_shadow = 0
self.font_script = 0
self.font_family = 2
self.font_charset = 0
self.font_scheme = "minor"
self.font_condense = 0
self.font_extend = 0
self.theme = 0
self.hyperlink = False
self.xf_id = 0
self.hidden = 0
self.locked = 1
self.text_h_align = 0
self.text_wrap = 0
self.text_v_align = 0
self.text_justlast = 0
self.rotation = 0
self.fg_color = None
self.bg_color = None
self.pattern = 0
self.has_fill = False
self.has_dxf_fill = False
self.fill_index = 0
self.fill_count = 0
self.border_index = 0
self.has_border = False
self.has_dxf_border = False
self.border_count = 0
self.bottom = 0
self.bottom_color = None
self.diag_border = 0
self.diag_color = None
self.diag_type = 0
self.left = 0
self.left_color = None
self.right = 0
self.right_color = None
self.top = 0
self.top_color = None
self.indent = 0
self.shrink = 0
self.merge_range = 0
self.reading_order = 0
self.just_distrib = 0
self.color_indexed = 0
self.font_only = 0
self.quote_prefix = False
self.checkbox = False
# Convert properties in the constructor to method calls.
for key, value in properties.items():
getattr(self, "set_" + key)(value)
self._format_key = None
def __repr__(self) -> str:
"""
Return a string representation of the Format instance.
"""
return (
f"Format("
f"font_name={self.font_name!r}, "
f"font_size={self.font_size}, "
f"bold={self.bold}, "
f"italic={self.italic}, "
f"underline={self.underline}, "
f"font_color={self.font_color}, "
f"num_format={self.num_format!r}, "
f"text_h_align={self.text_h_align}, "
f"text_v_align={self.text_v_align}, "
f"fg_color={self.fg_color}, "
f"bg_color={self.bg_color}, "
f"pattern={self.pattern}, "
f"locked={self.locked}, "
f"hidden={self.hidden})"
)
###########################################################################
#
# Format properties.
#
###########################################################################
def set_font_name(self, font_name) -> None:
"""
Set the Format font_name property such as 'Time New Roman'. The
default Excel font is 'Calibri'.
Args:
font_name: String with the font name. No default.
Returns:
Nothing.
"""
self.font_name = font_name
def set_font_size(self, font_size: int = 11) -> None:
"""
Set the Format font_size property. The default Excel font size is 11.
Args:
font_size: Int with font size. No default.
Returns:
Nothing.
"""
self.font_size = font_size
def set_font_color(self, font_color: Union[str, Color]) -> None:
"""
Set the Format font_color property. The Excel default is black.
Args:
font_color: String with the font color. No default.
Returns:
Nothing.
"""
self.font_color = Color._from_value(font_color)
def set_bold(self, bold: bool = True) -> None:
"""
Set the Format bold property.
Args:
bold: Default is True, turns property on.
Returns:
Nothing.
"""
self.bold = bold
def set_italic(self, italic: bool = True) -> None:
"""
Set the Format italic property.
Args:
italic: Default is True, turns property on.
Returns:
Nothing.
"""
self.italic = italic
def set_underline(self, underline: Literal[1, 2, 33, 34] = 1) -> None:
"""
Set the Format underline property.
Args:
underline: Default is 1, single underline.
Returns:
Nothing.
"""
self.underline = underline
def set_font_strikeout(self, font_strikeout: bool = True) -> None:
"""
Set the Format font_strikeout property.
Args:
font_strikeout: Default is True, turns property on.
Returns:
Nothing.
"""
self.font_strikeout = font_strikeout
def set_font_script(self, font_script: Literal[1, 2] = 1) -> None:
"""
Set the Format font_script property.
Args:
font_script: Default is 1, superscript.
Returns:
Nothing.
"""
self.font_script = font_script
def set_font_outline(self, font_outline: bool = True) -> None:
"""
Set the Format font_outline property.
Args:
font_outline: Default is True, turns property on.
Returns:
Nothing.
"""
self.font_outline = font_outline
def set_font_shadow(self, font_shadow: bool = True) -> None:
"""
Set the Format font_shadow property.
Args:
font_shadow: Default is True, turns property on.
Returns:
Nothing.
"""
self.font_shadow = font_shadow
def set_num_format(self, num_format: str) -> None:
"""
Set the Format num_format property such as '#,##0'.
Args:
num_format: String representing the number format. No default.
Returns:
Nothing.
"""
self.num_format = num_format
def set_locked(self, locked: bool = True) -> None:
"""
Set the Format locked property.
Args:
locked: Default is True, turns property on.
Returns:
Nothing.
"""
self.locked = locked
def set_hidden(self, hidden: bool = True) -> None:
"""
Set the Format hidden property.
Args:
hidden: Default is True, turns property on.
Returns:
Nothing.
"""
self.hidden = hidden
def set_align(
self,
alignment: Literal[
"left",
"centre",
"center",
"right",
"fill",
"justify",
"center_across",
"centre_across",
"distributed",
"justify_distributed",
"justify_distributed",
"top",
"vcentre",
"vcenter",
"bottom",
"vjustify",
"vdistributed",
],
) -> None:
"""
Set the Format cell alignment.
Args:
alignment: String representing alignment. No default.
Returns:
Nothing.
"""
alignment = alignment.lower()
# Set horizontal alignment properties.
if alignment == "left":
self.set_text_h_align(1)
if alignment == "centre":
self.set_text_h_align(2)
if alignment == "center":
self.set_text_h_align(2)
if alignment == "right":
self.set_text_h_align(3)
if alignment == "fill":
self.set_text_h_align(4)
if alignment == "justify":
self.set_text_h_align(5)
if alignment == "center_across":
self.set_text_h_align(6)
if alignment == "centre_across":
self.set_text_h_align(6)
if alignment == "distributed":
self.set_text_h_align(7)
if alignment == "justify_distributed":
self.set_text_h_align(7)
if alignment == "justify_distributed":
self.just_distrib = 1
# Set vertical alignment properties.
if alignment == "top":
self.set_text_v_align(1)
if alignment == "vcentre":
self.set_text_v_align(2)
if alignment == "vcenter":
self.set_text_v_align(2)
if alignment == "bottom":
self.set_text_v_align(3)
if alignment == "vjustify":
self.set_text_v_align(4)
if alignment == "vdistributed":
self.set_text_v_align(5)
def set_center_across(self, align_type: None = None) -> None:
# pylint: disable=unused-argument
"""
Set the Format center_across property.
Returns:
Nothing.
"""
self.set_text_h_align(6)
def set_text_wrap(self, text_wrap: bool = True) -> None:
"""
Set the Format text_wrap property.
Args:
text_wrap: Default is True, turns property on.
Returns:
Nothing.
"""
self.text_wrap = text_wrap
def set_rotation(self, rotation: int) -> None:
"""
Set the Format rotation property.
Args:
rotation: Rotation angle. No default.
Returns:
Nothing.
"""
rotation = int(rotation)
# Map user angle to Excel angle.
if rotation == 270:
rotation = 255
elif -90 <= rotation <= 90:
if rotation < 0:
rotation = -rotation + 90
else:
warn("Rotation rotation outside range: -90 <= angle <= 90")
return
self.rotation = rotation
def set_indent(self, indent: int = 1) -> None:
"""
Set the Format indent property.
Args:
indent: Default is 1, first indentation level.
Returns:
Nothing.
"""
self.indent = indent
def set_shrink(self, shrink: bool = True) -> None:
"""
Set the Format shrink property.
Args:
shrink: Default is True, turns property on.
Returns:
Nothing.
"""
self.shrink = shrink
def set_text_justlast(self, text_justlast: bool = True) -> None:
"""
Set the Format text_justlast property.
Args:
text_justlast: Default is True, turns property on.
Returns:
Nothing.
"""
self.text_justlast = text_justlast
def set_pattern(self, pattern: int = 1) -> None:
"""
Set the Format pattern property.
Args:
pattern: Default is 1, solid fill.
Returns:
Nothing.
"""
self.pattern = pattern
def set_bg_color(self, bg_color: Union[str, Color]) -> None:
"""
Set the Format bg_color property.
Args:
bg_color: Background color. No default.
Returns:
Nothing.
"""
self.bg_color = Color._from_value(bg_color)
def set_fg_color(self, fg_color: Union[str, Color]) -> None:
"""
Set the Format fg_color property.
Args:
fg_color: Foreground color. No default.
Returns:
Nothing.
"""
self.fg_color = Color._from_value(fg_color)
# set_border(style) Set cells borders to the same style
def set_border(self, style: int = 1) -> None:
"""
Set the Format bottom property.
Args:
bottom: Default is 1, border type 1.
Returns:
Nothing.
"""
self.set_bottom(style)
self.set_top(style)
self.set_left(style)
self.set_right(style)
# set_border_color(color) Set cells border to the same color
def set_border_color(self, color: Union[str, Color]) -> None:
"""
Set the Format bottom property.
Args:
color: Color string. No default.
Returns:
Nothing.
"""
self.set_bottom_color(color)
self.set_top_color(color)
self.set_left_color(color)
self.set_right_color(color)
def set_bottom(self, bottom: int = 1) -> None:
"""
Set the Format bottom property.
Args:
bottom: Default is 1, border type 1.
Returns:
Nothing.
"""
self.bottom = bottom
def set_bottom_color(self, bottom_color: Union[str, Color]) -> None:
"""
Set the Format bottom_color property.
Args:
bottom_color: Color string. No default.
Returns:
Nothing.
"""
self.bottom_color = Color._from_value(bottom_color)
def set_diag_type(self, diag_type: Literal[1, 2, 3] = 1) -> None:
"""
Set the Format diag_type property.
Args:
diag_type: Default is 1, border type 1.
Returns:
Nothing.
"""
self.diag_type = diag_type
def set_left(self, left: int = 1) -> None:
"""
Set the Format left property.
Args:
left: Default is 1, border type 1.
Returns:
Nothing.
"""
self.left = left
def set_left_color(self, left_color: Union[str, Color]) -> None:
"""
Set the Format left_color property.
Args:
left_color: Color string. No default.
Returns:
Nothing.
"""
self.left_color = Color._from_value(left_color)
def set_right(self, right: int = 1) -> None:
"""
Set the Format right property.
Args:
right: Default is 1, border type 1.
Returns:
Nothing.
"""
self.right = right
def set_right_color(self, right_color: Union[str, Color]) -> None:
"""
Set the Format right_color property.
Args:
right_color: Color string. No default.
Returns:
Nothing.
"""
self.right_color = Color._from_value(right_color)
def set_top(self, top: int = 1) -> None:
"""
Set the Format top property.
Args:
top: Default is 1, border type 1.
Returns:
Nothing.
"""
self.top = top
def set_top_color(self, top_color: Union[str, Color]) -> None:
"""
Set the Format top_color property.
Args:
top_color: Color string. No default.
Returns:
Nothing.
"""
self.top_color = Color._from_value(top_color)
def set_diag_color(self, diag_color: Union[str, Color]) -> None:
"""
Set the Format diag_color property.
Args:
diag_color: Color string. No default.
Returns:
Nothing.
"""
self.diag_color = Color._from_value(diag_color)
def set_diag_border(self, diag_border: int = 1) -> None:
"""
Set the Format diag_border property.
Args:
diag_border: Default is 1, border type 1.
Returns:
Nothing.
"""
self.diag_border = diag_border
def set_quote_prefix(self, quote_prefix: bool = True) -> None:
"""
Set the Format quote prefix property.
Args:
quote_prefix: Default is True, turns property on.
Returns:
Nothing.
"""
self.quote_prefix = quote_prefix
def set_checkbox(self, checkbox: bool = True) -> None:
"""
Set the Format property to show a checkbox in a cell.
This format property can be used with a cell that contains a boolean
value to display it as a checkbox. This property isn't required very
often and it is generally easier to create a checkbox using the
``worksheet.insert_checkbox()`` method.
Args:
checkbox: Default is True, turns property on.
Returns:
Nothing.
"""
self.checkbox = checkbox
###########################################################################
#
# Internal Format properties. These aren't documented since they are
# either only used internally or else are unlikely to be set by the user.
#
###########################################################################
def set_has_font(self, has_font: bool = True) -> None:
"""
Set the property to indicate the format has a font.
Args:
has_font: Default is True, turns property on.
Returns:
Nothing.
"""
self.has_font = has_font
def set_has_fill(self, has_fill: bool = True) -> None:
"""
Set the property to indicate the format has a fill.
Args:
has_fill: Default is True, turns property on.
Returns:
Nothing.
"""
self.has_fill = has_fill
def set_font_index(self, font_index: int) -> None:
"""
Set the unique font index property.
Args:
font_index: The unique font index.
Returns:
Nothing.
"""
self.font_index = font_index
def set_xf_index(self, xf_index: int) -> None:
"""
Set the unique format index property.
Args:
xf_index: The unique Excel format index.
Returns:
Nothing.
"""
self.xf_index = xf_index
def set_dxf_index(self, dxf_index: int) -> None:
"""
Set the unique conditional format index property.
Args:
dxf_index: The unique Excel conditional format index.
Returns:
Nothing.
"""
self.dxf_index = dxf_index
def set_num_format_index(self, num_format_index: int) -> None:
"""
Set the number format_index property.
Args:
num_format_index: The unique number format index.
Returns:
Nothing.
"""
self.num_format_index = num_format_index
def set_text_h_align(self, text_h_align: int) -> None:
"""
Set the horizontal text alignment property.
Args:
text_h_align: Horizontal text alignment.
Returns:
Nothing.
"""
self.text_h_align = text_h_align
def set_text_v_align(self, text_v_align: int) -> None:
"""
Set the vertical text alignment property.
Args:
text_h_align: Vertical text alignment.
Returns:
Nothing.
"""
self.text_v_align = text_v_align
def set_reading_order(self, direction: int = 0) -> None:
# Set the reading_order property.
"""
Set the reading order property.
Args:
direction: Default is 0, left to right.
Returns:
Nothing.
"""
self.reading_order = direction
def set_valign(
self,
align: Literal[
"left",
"centre",
"center",
"right",
"fill",
"justify",
"center_across",
"centre_across",
"distributed",
"justify_distributed",
"justify_distributed",
"top",
"vcentre",
"vcenter",
"bottom",
"vjustify",
"vdistributed",
],
) -> None:
# Set vertical cell alignment. This is required by the constructor
# properties dict to differentiate between the vertical and horizontal
# properties.
"""
Set vertical cell alignment property.
This is required by the constructor properties dict to differentiate
between the vertical and horizontal properties.
Args:
align: Alignment property.
Returns:
Nothing.
"""
self.set_align(align)
def set_font_family(self, font_family: int) -> None:
"""
Set the font family property.
Args:
font_family: Font family number.
Returns:
Nothing.
"""
self.font_family = font_family
def set_font_charset(self, font_charset: int) -> None:
"""
Set the font character set property.
Args:
font_charset: The font character set number.
Returns:
Nothing.
"""
self.font_charset = font_charset
def set_font_scheme(self, font_scheme: int) -> None:
"""
Set the font scheme property.
Args:
font_scheme: The font scheme.
Returns:
Nothing.
"""
self.font_scheme = font_scheme
def set_font_condense(self, font_condense: int) -> None:
"""
Set the font condense property.
Args:
font_condense: The font condense property.
Returns:
Nothing.
"""
self.font_condense = font_condense
def set_font_extend(self, font_extend: int) -> None:
"""
Set the font extend property.
Args:
font_extend: The font extend property.
Returns:
Nothing.
"""
self.font_extend = font_extend
def set_theme(self, theme: int) -> None:
"""
Set the theme property.
Args:
theme: Format theme.
Returns:
Nothing.
"""
self.theme = theme
def set_hyperlink(self, hyperlink: bool = True) -> None:
"""
Set the properties for the hyperlink style.
Args:
hyperlink: Default is True, turns property on.
Returns:
Nothing.
"""
self.xf_id = 1
self.set_underline(1)
self.set_theme(10)
self.hyperlink = hyperlink
def set_color_indexed(self, color_index: Literal[0, 1]) -> None:
"""
Set the color index property. Some fundamental format properties use an
indexed color instead of a rbg or theme color.
Args:
color_index: Generally 0 or 1.
Returns:
Nothing.
"""
self.color_indexed = color_index
def set_font_only(self, font_only: bool = True) -> None:
"""
Set property to indicate that the format is used for fonts only.
Args:
font_only: Default is True, turns property on.
Returns:
Nothing.
"""
self.font_only = font_only
# Compatibility methods. These versions of the method names were added in an
# initial version for compatibility testing with Excel::Writer::XLSX and
# leaked out into production code. They are deprecated and will be removed
# in a future after a suitable deprecation period.
def set_font(self, font_name: str) -> None:
"""Deprecated: Use set_font_name() instead."""
self.font_name = font_name
def set_size(self, font_size: int) -> None:
"""Deprecated: Use set_font_size() instead."""
self.font_size = font_size
def set_color(self, font_color: Union[Color, str]) -> None:
"""Deprecated: Use set_font_color() instead."""
self.font_color = Color._from_value(font_color)
###########################################################################
#
# Private API.
#
###########################################################################
def _get_align_properties(self):
# pylint: disable=too-many-boolean-expressions
# Return properties for an Style xf <alignment> sub-element.
changed = 0
align = []
# Check if any alignment options in the format have been changed.
if (
self.text_h_align
or self.text_v_align
or self.indent
or self.rotation
or self.text_wrap
or self.shrink
or self.reading_order
):
changed = 1
else:
return changed, align
# Indent is only allowed for some alignment properties. If it is
# defined for any other alignment or no alignment has been set then
# default to left alignment.
if (
self.indent
and self.text_h_align != 1
and self.text_h_align != 3
and self.text_h_align != 7
and self.text_v_align != 1
and self.text_v_align != 3
and self.text_v_align != 5
):
self.text_h_align = 1
# Check for properties that are mutually exclusive.
if self.text_wrap:
self.shrink = 0
if self.text_h_align == 4:
self.shrink = 0
if self.text_h_align == 5:
self.shrink = 0
if self.text_h_align == 7:
self.shrink = 0
if self.text_h_align != 7:
self.just_distrib = 0
if self.indent:
self.just_distrib = 0
continuous = "centerContinuous"
if self.text_h_align == 1:
align.append(("horizontal", "left"))
if self.text_h_align == 2:
align.append(("horizontal", "center"))
if self.text_h_align == 3:
align.append(("horizontal", "right"))
if self.text_h_align == 4:
align.append(("horizontal", "fill"))
if self.text_h_align == 5:
align.append(("horizontal", "justify"))
if self.text_h_align == 6:
align.append(("horizontal", continuous))
if self.text_h_align == 7:
align.append(("horizontal", "distributed"))
if self.just_distrib:
align.append(("justifyLastLine", 1))
# Property 'vertical' => 'bottom' is a default. It sets applyAlignment
# without an alignment sub-element.
if self.text_v_align == 1:
align.append(("vertical", "top"))
if self.text_v_align == 2:
align.append(("vertical", "center"))
if self.text_v_align == 4:
align.append(("vertical", "justify"))
if self.text_v_align == 5:
align.append(("vertical", "distributed"))
if self.rotation:
align.append(("textRotation", self.rotation))
if self.indent:
align.append(("indent", self.indent))
if self.text_wrap:
align.append(("wrapText", 1))
if self.shrink:
align.append(("shrinkToFit", 1))
if self.reading_order == 1:
align.append(("readingOrder", 1))
if self.reading_order == 2:
align.append(("readingOrder", 2))
return changed, align
def _get_protection_properties(self):
# Return properties for an Excel XML <Protection> element.
attributes = []
if not self.locked:
attributes.append(("locked", 0))
if self.hidden:
attributes.append(("hidden", 1))
return attributes
def _get_format_key(self):
# Returns a unique hash key for a format. Used by Workbook.
if self._format_key is None:
self._format_key = ":".join(
str(x)
for x in (
self._get_font_key(),
self._get_border_key(),
self._get_fill_key(),
self._get_alignment_key(),
self.num_format,
self.locked,
self.checkbox,
self.quote_prefix,
self.hidden,
)
)
return self._format_key
def _get_font_key(self):
# Returns a unique hash key for a font. Used by Workbook.
key = ":".join(
str(x)
for x in (
self.bold,
self.font_color,
self.font_charset,
self.font_family,
self.font_outline,
self.font_script,
self.font_shadow,
self.font_strikeout,
self.font_name,
self.italic,
self.font_size,
self.underline,
self.theme,
)
)
return key
def _get_border_key(self):
# Returns a unique hash key for a border style. Used by Workbook.
key = ":".join(
str(x)
for x in (
self.bottom,
self.bottom_color,
self.diag_border,
self.diag_color,
self.diag_type,
self.left,
self.left_color,
self.right,
self.right_color,
self.top,
self.top_color,
)
)
return key
def _get_fill_key(self):
# Returns a unique hash key for a fill style. Used by Workbook.
key = ":".join(str(x) for x in (self.pattern, self.bg_color, self.fg_color))
return key
def _get_alignment_key(self):
# Returns a unique hash key for alignment formats.
key = ":".join(
str(x)
for x in (
self.text_h_align,
self.text_v_align,
self.indent,
self.rotation,
self.text_wrap,
self.shrink,
self.reading_order,
)
)
return key
def _get_xf_index(self):
# Returns the XF index number used by Excel to identify a format.
if self.xf_index is not None:
# Format already has an index number so return it.
return self.xf_index
# Format doesn't have an index number so assign one.
key = self._get_format_key()
if key in self.xf_format_indices:
# Format matches existing format with an index.
return self.xf_format_indices[key]
# New format requiring an index. Note. +1 since Excel
# has an implicit "General" format at index 0.
index = 1 + len(self.xf_format_indices)
self.xf_format_indices[key] = index
self.xf_index = index
return index
def _get_dxf_index(self):
# Returns the DXF index number used by Excel to identify a format.
if self.dxf_index is not None:
# Format already has an index number so return it.
return self.dxf_index
# Format doesn't have an index number so assign one.
key = self._get_format_key()
if key in self.dxf_format_indices:
# Format matches existing format with an index.
return self.dxf_format_indices[key]
# New format requiring an index.
index = len(self.dxf_format_indices)
self.dxf_format_indices[key] = index
self.dxf_index = index
return index
###########################################################################
#
# XML methods.
#
###########################################################################