Openpyxl Templates Documentation: Release 0.1.1
Openpyxl Templates Documentation: Release 0.1.1
Release 0.1.1
Sverker Sjöberg
1 Table of contents 3
1.1 Welcome to openpyxl-templates! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Quick start . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 TemplatedWorkbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 TemplatedWorksheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Working with styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.6 TableSheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.7 TableColumn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
i
ii
Openpyxl Templates Documentation, Release 0.1.1
Openpyxl-templates is an extention to openpyxl which simplifies reading and writing excelfiles by formalizing their
structure into templates. The package has two main components:
1. The TemplatedWorkbook which describe the excel file
2. The TemplatedSheets which describe the individual sheets within the file
The package is build for developers to be able to implement their own templates but also provides one useful templated
sheet. The TableSheet which makes it significantly easier to read and write data from excel data tabels such as this
one:
docs/examples/fruit_lovers.png
The TableSheet provides an easy way of defining columns and handles both styling and conversion to and from excel.
See quickstart for a demo.
Github https://github.com/SverkerSbrg/openpyxl-templates
Documentation http://openpyxl-templates.readthedocs.io/en/latest/
pypi https://pypi.python.org/pypi/openpyxl-templates
openpyxl https://openpyxl.readthedocs.io/en/default/
If you have any questions or ideas regarding the package feel free to reach out to me via GitHub.
Warning: This package is still in beta. The api may still be subject to change and the documentation is patchy.
Contents 1
Openpyxl Templates Documentation, Release 0.1.1
2 Contents
CHAPTER 1
Table of contents
Openpyxl-templates is an extention to openpyxl which simplifies reading and writing excelfiles by formalizing their
structure into templates. The package has two main components:
1. The TemplatedWorkbook which describe the excel file
2. The TemplatedSheets which describe the individual sheets within the file
The package is build for developers to be able to implement their own templates but also provides one useful templated
sheet. The TableSheet which makes it significantly easier to read and write data from excel data tabels such as this
one:
docs/examples/fruit_lovers.png
The TableSheet provides an easy way of defining columns and handles both styling and conversion to and from excel.
See quickstart for a demo.
Github https://github.com/SverkerSbrg/openpyxl-templates
Documentation http://openpyxl-templates.readthedocs.io/en/latest/
pypi https://pypi.python.org/pypi/openpyxl-templates
openpyxl https://openpyxl.readthedocs.io/en/default/
3
Openpyxl Templates Documentation, Release 0.1.1
If you have any questions or ideas regarding the package feel free to reach out to me via GitHub.
Warning: This package is still in beta. The api may still be subject to change and the documentation is patchy.
1.2.1 Installation
The first we create our TemplatedWorkbook, which describes the structure of our file using TemplatedWorksheets.
This template can then be used for both creating new files or reading existing ones. Below is an example using the
TableSheet (a TemplatedWorksheet) to describe a excel file of people and their favorite fruits.
class Fruits(Enum):
apple = 1
banana = 2
orange = 3
class PersonSheet(TableSheet):
first_name = CharColumn()
last_name = CharColumn()
date_of_birth = DateColumn()
favorite_fruit = ChoiceColumn(choices=(
(Fruits.apple, "Apple"),
(Fruits.banana, "Banana"),
(Fruits.orange, "Orange"),
))
class PersonsWorkbook(TemplatedWorkbook):
persons = PersonSheet()
1.2.3 Writing
To write create an instance of your templated workbook, supply data to the sheets and save to a file.
wb = PersonsWorkbook()
wb.persons.write(
title="List of fruit lovers",
objects=(
("John", "Doe", date(year=1992, month=7, day=17), Fruits.banana),
("Jane", "Doe", date(year=1986, month=3, day=2), Fruits.apple),
)
)
The TableSheet in this case will handle all formatting and produce the following sheet.
1.2.4 Reading
To utilize the openpyxl-templates to read from an existing excel file, initialize your TemplatedWorkbook with a file (or
a path to a file). Using the read method or simply itterating over a sheet will give you access to the data as namedtupels.
wb = PersonsWorkbook("fruit_lovers.xlsx")
1.3 TemplatedWorkbook
The TemplatedWorkbook is our representation of the excel file and describes the file as a whole. To create a
TemplatedWorkbook extend the base class and declare which sheets it includes using TemplatedWorksheets.
class DemoTemplatedWorkbook(TemplatedWorkbook):
sheet1 = TemplatedWorksheet()
sheet2 = TemplatedWorksheet()
To use your template to generate new excel files simply create an instance. . .
templated_workbook = DemoTemplatedWorkbook()
templated_workbook = DemoTemplatedWorkbook(file="my_excel.xlsx")
The TemplatedWorkbook will find all sheets which correspond to a TemplatedWorksheet. Once identified the Templat-
edWorksheets can be used to interact with the underlying excel sheets. The matching is done based on the sheetname.
1.3. TemplatedWorkbook 5
Openpyxl Templates Documentation, Release 0.1.1
The TemplatedWorkbook keeps track of the declaration order of the TemplatedWorksheets which enables it to make
sure the the sheets are always in the correct order once the file has been saved. The identified sheets can also be iterated
as illustrated below.
To save the workbook simply call the save method and provide a filename
templated_workbook.save("my_excel.xlsx")
1.4 TemplatedWorksheet
The TemplatedWorksheet describes a a sheet in an excel file and is the bare bone used for building useful sheet
templates such as the TableSheet. A TemplatedWorksheet is defined by following attributes:
• It’s sheetname which is used for identifying the sheets in the excel file
• It’s read() method which when implemented should return the relevant data contained in the sheet
• It’s write(data) method which when implemented should write the provided data to the sheet and make
sure that it is properly formatted
The TemplatedWorksheet will handle managing the openpyxl worksheet so you do not have to worry about whether
the sheet is created or not before you start writing.
To create a TemplatedWorksheet you should implement the read and write method. We’ll demonstrate this by creating
a DictSheet a TemplatedWorksheet which reads and writes simple key value pairs in a python dict.
class DictSheet(TemplatedWorksheet):
def write(self, data):
worksheet = self.worksheet
def read(self):
worksheet = self.worksheet
data = {}
return data
We can now add our DictSheet to a TemplatedWorkbook and use it to create an excel file.
class DictWorkbook(TemplatedWorkbook):
dict_sheet = DictSheet(sheetname="dict_sheet")
workbook = DictWorkbook()
workbook.dict_sheet.write({
"key1": "value1",
(continues on next page)
workbook.save("key_value_pairs.xlsx")
We can use the same TemplatedWorkbook to read the data from the file we just created.
print(workbook.dict_sheet.read())
Have a look at the TableSheet for a more advanced example. It includes type handling and plenty of styling.
Styling in openpyxl-templates is entirely reliant on the NamedStyle provided by openpyxl. Using NamedStyles
offers significantly better performance compared to styling each individual cells, as well as the benefits of making the
styles avaliable in the produced excel file.
To manage all named styles within a TemplatedWorkbook openpyxl-templates uses the StyleSet which is a dictio-
nary like collection of NamedStyles. Using the StyleSet when creating templates is entierly optional but offers several
advantages:
• Using a common colleciton of styles for all TemplatedSheets makes it easier to avoid duplicated styles and name
conflicts
• The StyleSet accepts ExtendedStyle s as well as NamedStyles which enables inheritance between styles
within the StyleSet
• Styles will only be added to the excel file when they are needed allowing the developer to use a single StyleSet
for multiple templates without having to worry about unused styles being included in the excel file.
• Using NamedStyles offers significantly better performance compared to styling each cell individually when
writing a large amout of data
demo_style = StyleSet(
NamedStyle(
name="Default",
font=Font(
name="Arial",
size=12
)
),
NamedStyle(
name="Header",
font=Font(
name="Arial",
size=12,
bold=True,
(continues on next page)
If we want to avoid having to redeclare the font we could refactor the above example using an ExtendedStyle
demo_style = StyleSet(
NamedStyle(
name="Default",
font=Font(
name="Arial",
size=12
)
),
ExtendedStyle(
base="Default", # Reference to the style defined above
name="Header",
font={
"bold": True,
}
)
)
The ExtendedStyle can be viewed as a NamedStyle factory. It accepts the same arguments as a NamedStyle with the
addition of the base which is the name of the intended parent. The StyleSet will make sure that the parent style is
found irregardless of declaration order.
The font, border, alignment and fill arguments of the NamedStyle are supplied as objects which (since they have
default values) prevent inheritance. To circomvent this limitation you can supply the kwarg dicts to the extended style
instead of the object itself, as we have done in the example above. If the openpyxl class is used instead of kwargs,
inheritance will be broken
bad_example = StyleSet(
NamedStyle(
name="Default",
font=Font(
name="Arial",
size=12
)
),
ExtendedStyle(
base="Default",
name="Header",
font=Font(
# Openpyxl will set name="Calibri" by default which will override name=
˓→"Arial and break inheritance.
bold=True
)
)
if a name is declared multiple times the last declaration will take precedence making it easy to modify an existing
StyleSet. One common usage for this is to modify the DefaultStyleSet. Which is demonstrated ModifyDefaultStyleSet.
TODO
1.5.3 DefaultStyleSet
Openpyxl-templates includes a DefaultStyleSet which is used as a fallback for all TemplatedWorkbook. Many
of the styles it declares (or their names) are required by the TableSheet. The DefaultStyleSet is defined like this
raise ValueError("StyleSet can only handle NamedStyles")
if style.name in self:
raise ValueError("Style already exists")
self._styles[style.name] = style
return style
@property
def names(self):
return tuple(style.name for style in self._styles.values())
class DefaultStyleSet(StyleSet):
def __init__(self, *styles):
super(DefaultStyleSet, self).__init__(
NamedStyle(
name="Default",
alignment=Alignment(vertical="top")
),
ExtendedStyle(
base="Default",
name="Empty",
),
ExtendedStyle(
base="Empty",
name="Title",
font={"size": 20}
),
ExtendedStyle(
base="Empty",
name="Description",
font={"color": "FF777777"},
alignment={"wrap_text": True}
(continues on next page)
),
ExtendedStyle(
base="Header",
name="Header, center",
alignment={"horizontal": "center"}
),
ExtendedStyle(
base="Default",
name="Row"
),
ExtendedStyle(
base="Row",
name="Row, string",
number_format="@",
),
ExtendedStyle(
base="Row",
If you which to modify the DefaultStyle you can easily replace any or all of the styles it contains by passing them as
arguments to the constructor. Below we utilize the heavy usage of ExtendedStyles in the DefaultStyleSet to change of
all styles.
1.6 TableSheet
The TableSheet is a TemplatedWorksheet making it easy for reading and write sheets with excel Data Tables.
It is made up of an ordered set of typed columns which support when converting to and from Excel. Read more about
what the columns do here.
class TableSheetElements(TableSheet):
column1 = CharColumn(header="Header 1")
column2 = CharColumn(header="Header 2")
column3 = CharColumn(header="Header 3")
column4 = CharColumn(header="Header 4")
class TableSheetElementsWorkook(TemplatedWorkbook):
table_sheet_elements = TableSheetElements()
wb = TableSheetElementsWorkook()
wb.table_sheet_elements.write(
title="Title",
description="This is the description, it can be a couple of sentences long.",
objects=(tuple(repeat("Row %d" % i, times=4)) for i in range(1, 4))
)
wb.save("table_sheet_elements.xlsx")
A TableSheet is created by extending the TableSheet class, declaring columns and optionally changing styling
and other settings. Once the TableSheet class has been created an instance of this class is be supplied to the
TemplatedWorkbook.
Declaring columns
The columns are declared as class variables on a TableSheet which will identify and register the columns (in order of
declaration). The columns are avaliable under the columns attribute.
A TableSheet must always have atleast one TableColumn.
1.6. TableSheet 11
Openpyxl Templates Documentation, Release 0.1.1
class DemoTableSheet(TableSheet):
column1 = CharColumn()
column2 = IntColumn()
The column declaration supports inheritance, the following declaration is perfectly legal.
class ExtendedDemoTableSheet(DemoTableSheet):
column3 = CharColumn()
Note that the columns of the parent class are always considered to have been declared before the columns of the child.
All columns must have a header and there must not be any duplicated headers within the same sheet. The TableSheet
will automatically use the attribute name used when declaring the column as header.
class DemoTableSheet(TableSheet):
column1 = CharColumn(header="Header 1")
column2 = IntColumn() # The header of column2 will be set automatically to
˓→"column2"
TODO: Describe the ability to pass additional columns to __init__ via columns=[...]
1.6.3 Writing
Simple usage
Writing is done by an iterable of objects to the write function and optionally a title and/or description. The write
function will then:
• Prepare the workbook by registering all required styles, data validation etc.
• Write title, and description if they are supplied
• Create the headers and rows
• Apply sheet level formatting such as creating the Data Table and setting the freeze pane
Writing will always recreate the entire sheet from scratch, so any preexisting data will be lost. If you want to preserve
your data you could read existing rows and combine them with the new data.
class DemoTableSheet(TableSheet):
column1 = CharColumn()
column2 = IntColumn()
class DemoTemplatedWorksheet(TemplatedWorkbook):
demo_sheet1 = DemoTableSheet()
demo_sheet2 = DemoTableSheet()
wb = DemoTemplatedWorksheet()
)
wb.save("read_write.xlsx")
Using objects
The write accepts rows iterable containing tuples or list as in the example above. If an other type is encoun-
tered the columns will try to get the attribute directly from the object using getattr(object, column.
object_attribute). The object_attribute can be defined explicitly and will default to the attribute name used
when adding the column to the sheet.
class DemoObject():
def __init__(self, column1, column2):
self.column1 = column1
self.column2 = column2
wb = DemoTemplatedWorksheet()
wb.demo_sheet1.write(
objects=(
DemoObject("Row 1", 1),
DemoObject("Row 2", 2),
DemoObject("Row 3", 3),
)
)
Styling
class PrettyDemoSheet(TableSheet):
def __init__(self):
super().__init__(
title_style="Bold & red, title",
(continues on next page)
1.6. TableSheet 13
Openpyxl Templates Documentation, Release 0.1.1
column1 = CharColumn()
column2 = IntColumn()
Additional settings
The write behaviour of the TableSheet can be modified with the following settings:
• format_as_table - Controlling whether the TableSheet will format the output as a DataTable, defaults
to True
• freeze_pane - Controlling whether the TableSheet will utilize the freeze pane feature, defaults to True
• hide_excess_columns - When enabled the TableSheet will hide all columns not used by columns,
defaults to True
1.6.4 Reading
Simple usage
The read method does two things. First it will verify the format of the file by looking for the header row. If the
headers cannot be found a en exception will be raised. Once the headers has been found all subsequent rows in the
excel will be treated as data and parsed to namedtuples automatically after the columns has transformed the data from
excel to python.
wb = DemoTemplatedWorksheet("read_write.xlsx")
for row in wb.demo_sheet1.read():
print(row)
Iterate directly
Exception handling
The way the TableSheet handles exceptions can be configured by setting the exception_policy. It can be set on the TableSh
• RaiseSheetException - All row exceptions will be collected and raised once reading has finished.
So that all valid rows will be read, and all exceptions will be recorded.
• IgnoreRow - Invalid rows will be ignored
The policy only applies to exceptions occuring when reading rows. Exceptions such as HeadersNotFound will be
raised irregardless.
Looking for headers can be disabled by setting look_for_headers to False or passing it as a named argument
directly to the read function. When this is done the TableSheet will start looking for valid rows at once. This will most
likely cause an exception if the title, description or header row is present since they will be treated as rows.
1.6.5 Customization
The TableSheet is built with customization in mind. If you want your table to yield something else then a
namedtuple for each row. It is easy to achieve by overriding the create_object method.
class IceCream:
def __init__(self, name, description, flavour, color, price):
self.name = name
self.description = description
self.flavour = flavour
self.color = color
self.price = price
class IceCreamSheet(TableSheet):
name = CharColumn()
description = TextColumn(width=32)
flavour = CharColumn()
color = CharColumn()
price = FloatColumn()
Feel free to explore the source code for additional possibilities. If you are missing hook or add a feature useful for
others, feel free to submit a push request.
1.7 TableColumn
1.7. TableColumn 15