Skip to content

Commit

Permalink
Add 'index_style' to Tables and allow styles to be combined.
Browse files Browse the repository at this point in the history
Also allow kwargs to be passed to xlsxwriter.Workbook constructor
when calling Workbook.to_xlsx.
  • Loading branch information
tonyroberts committed May 1, 2015
1 parent 27eef34 commit 6a66d53
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 21 deletions.
2 changes: 2 additions & 0 deletions xltable/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
.. autoclass:: CellStyle
.. autoclass:: Value
"""
from .expression import Column, Cell, Range, Formula, ConstExpr, Expression
from .style import CellStyle, TableStyle
Expand Down
61 changes: 50 additions & 11 deletions xltable/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
to direct how the tables and cells in the tables will be
written to Excel.
"""
from weakref import WeakKeyDictionary


class TableStyle(object):
Expand All @@ -24,6 +25,7 @@ class CellStyle(object):
:param int decimal_places: Number of decimal places to display the cell value to.
:param str date_format: Format to use for date values (use Python date format, e.g. '%Y-%m-%d').
:param bool thousands_sep: True to display numbers with thousand separator.
:param str excel_number_format: Excel number format; overrides other numeric settings (eg thousands_sep).
:param bool bold: True to make cells bold.
:param int size: Text size, or use one of the string size aliases x-small, small, normal, large, x-large
or xx-large.
Expand All @@ -40,22 +42,25 @@ class CellStyle(object):
}

def __init__(self,
is_percentage=False,
is_percentage=None,
decimal_places=None,
date_format=None,
thousands_sep=False,
bold=False,
thousands_sep=None,
excel_number_format=None,
bold=None,
size=None,
text_color=None,
bg_color=None,
text_wrap=False,
text_wrap=None,
border=None,
align=None,
valign=None):
self.__derived_styles = WeakKeyDictionary()
self.is_percentage = is_percentage
self.decimal_places = decimal_places
self.date_format = date_format
self.thousands_sep = thousands_sep
self.__excel_number_format = excel_number_format
self.bold = bold
if isinstance(size, str):
size = self._sizes[size]
Expand All @@ -70,20 +75,25 @@ def __init__(self,
@property
def excel_number_format(self):
number_format = "0"
if self.thousands_sep:
number_format = "#,#00"
if self.__excel_number_format is not None:
number_format = self.__excel_number_format
else:
if self.thousands_sep:
number_format = "#,#00"

if self.decimal_places is not None:
if self.decimal_places > 0:
number_format = number_format + "." + ("0" * self.decimal_places)
if self.decimal_places is not None:
if self.decimal_places > 0:
number_format = number_format + "." + ("0" * self.decimal_places)

if self.is_percentage:
number_format = number_format + "%"
if self.is_percentage:
number_format = number_format + "%"

if self.date_format is not None:
number_format = self.date_format
number_format = number_format.replace("%Y", "yyyy")
number_format = number_format.replace("%y", "yy")
number_format = number_format.replace("%m", "mm")
number_format = number_format.replace("%b", "mmm")
number_format = number_format.replace("%d", "dd")
number_format = number_format.replace("%H", "hh")
number_format = number_format.replace("%M", "mm")
Expand All @@ -92,3 +102,32 @@ def excel_number_format(self):
if number_format == "0":
return None
return number_format

def __add__(self, other):
"""Apply a style on top of this one and return the new style"""
try:
return self.__derived_styles[other]
except KeyError:
pass

def _if_none(a, b):
"""return a if a is not None, else b"""
return a if a is not None else b

style = self.__class__(
is_percentage=_if_none(other.is_percentage, self.is_percentage),
decimal_places=_if_none(other.decimal_places, self.decimal_places),
date_format=_if_none(other.date_format, self.date_format),
thousands_sep=_if_none(other.thousands_sep, self.thousands_sep),
excel_number_format=_if_none(other.__excel_number_format, self.__excel_number_format),
bold=_if_none(other.bold, self.bold),
size=_if_none(other.size, self.size),
text_color=_if_none(other.text_color, self.text_color),
bg_color=_if_none(other.bg_color, self.bg_color),
text_wrap=_if_none(other.text_wrap, self.text_wrap),
border=_if_none(other.border, self.border),
align=_if_none(other.align, self.align),
valign=_if_none(other.valign, self.valign))

self.__derived_styles[other] = style
return style
14 changes: 11 additions & 3 deletions xltable/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@


class Value(object):
"""value wrapper that can be used in a table to add a style"""
"""
Value wrapper that can be used in a table to add a style.
:param value: Value that will be written to the cell.
:param xltable.CellStyle: Style to be applied to the cell.
"""
def __init__(self, value, style=None):
self.value = value
self.style = style
Expand All @@ -28,7 +33,8 @@ class Table(object):
:param xltable.TableStyle style: Table style, or one of the named styles 'default' or 'plain'.
:param xltable.CellStyle column_styles: Dictionary of column names to styles or named styles.
:param float column_widths: Dictionary of column names to widths.
:param xltable.CellStyle style: Style or named style to use for the cells in the header row.
:param xltable.CellStyle header_style: Style or named style to use for the cells in the header row.
:param xltable.CellStyle index_style: Style or named style to use for the cells in the index column.
Named table styles:
- default: blue stripes
Expand Down Expand Up @@ -60,7 +66,8 @@ def __init__(self,
style="default",
column_styles={},
column_widths={},
header_style=None):
header_style=None,
index_style=None):
self.__name = name
self.__df = dataframe
self.__position = None
Expand All @@ -81,6 +88,7 @@ def __init__(self,
self.__col_styles[col] = self._named_styles[style]

self.header_style = header_style
self.index_style = index_style

@property
def name(self):
Expand Down
7 changes: 5 additions & 2 deletions xltable/workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,16 @@ def itersheets(self):
finally:
self.active_worksheet = prev_ws

def to_xlsx(self):
def to_xlsx(self, **kwargs):
"""
Write workbook to a .xlsx file using xlsxwriter.
Return a xlsxwriter.workbook.Workbook.
:param kwargs: Extra arguments passed to the xlsxwriter.Workbook
constructor.
"""
from xlsxwriter.workbook import Workbook as _Workbook
self.workbook_obj = _Workbook()
self.workbook_obj = _Workbook(**kwargs)
self.workbook_obj.set_calc_mode(self.calc_mode)

for worksheet in self.itersheets():
Expand Down
13 changes: 8 additions & 5 deletions xltable/worksheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _get_all_styles(self):
_styles = {}
def _get_style(bold=False, bg_col=None, border=None):
if (bold, bg_col, border) not in _styles:
_styles[(bold, bg_col, border)] = CellStyle(bold,
_styles[(bold, bg_col, border)] = CellStyle(bold=bold,
bg_color=bg_col,
border=border)
return _styles[(bold, bg_col, border)]
Expand All @@ -175,8 +175,8 @@ def _get_style(bold=False, bg_col=None, border=None):
ws_styles[(r, c)] = table.header_style or _get_style(bold=True)

for c in range(col, col + table.row_labels_width):
for r in range(row, row + table.height):
ws_styles[(r, c)] = table.header_style or _get_style(bold=True)
for r in range(row + table.header_height, row + table.height):
ws_styles[(r, c)] = table.index_style or _get_style(bold=True)

bg_cols = None
num_bg_cols = 0
Expand All @@ -191,8 +191,11 @@ def _get_style(bold=False, bg_col=None, border=None):
table.height)):
for c in range(col, col + table.width):
bg_col = bg_cols[i % num_bg_cols] if bg_cols else None
ws_styles[(row + row_offset, c)] = _get_style(
bold=False, bg_col=bg_col, border=border)
style = _get_style(bold=None, bg_col=bg_col, border=border)
if (row + row_offset, c) in ws_styles:
ws_styles[(row + row_offset, c)] += style
else:
ws_styles[(row + row_offset, c)] = style

for col_name, col_style in table.column_styles.items():
try:
Expand Down

0 comments on commit 6a66d53

Please sign in to comment.