I have been trying to copy a cell from one workbook to another with formatting only to fail. I have tried numerous suggestion but nothing works.
I have tried:
def copyCellStyle(new_cell,cell):
new_cell.font = copy(cell.font)
new_cell.border = copy(cell.border)
new_cell.fill = copy(cell.fill)
new_cell.number_format = copy(cell.number_format)
new_cell.protection = copy(cell.protection)
new_cell.alignment = copy(cell.alignment)
then use it like:
new_cell.value=old_cell.value
copyCellStyle(new_cell,old_cell)
It runs without errors but the job is not done.
I get errors with the other methods in the styles class. When
new_cell._style = copy(old_cell._style)
this is used I get this error while I am saving the copied file.
Traceback (most recent call last):
File "C:\Python Programs\test\test2.py", line 40, in <module>
wb2.save("Test3.xlsx")
File "C:\Anaconda3\lib\site-packages\openpyxl\workbook\workbook.py", line 392, in save
save_workbook(self, filename)
File "C:\Anaconda3\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
writer.save()
File "C:\Anaconda3\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
self.write_data()
File "C:\Anaconda3\lib\site-packages\openpyxl\writer\excel.py", line 84, in write_data
stylesheet = write_stylesheet(self.workbook)
File "C:\Anaconda3\lib\site-packages\openpyxl\styles\stylesheet.py", line 240, in write_stylesheet
xf.alignment = wb._alignments[style.alignmentId]
IndexError: list index out of range
Also when I check if cell has style like:
Traceback (most recent call last)
File "C:\Python Programs\test\test2.py", line 37, in <module>
if cell.has_style:
AttributeError: module 'openpyxl.cell' has no attribute 'has_style'
I am using python 3.x.
Can anyone tell me a working proper method to achieve this.
Thanks in advance!
You need to understand what does copy(cell._style)
does to understand that exception. Behind the scenes each openpyxl
workbook has protected attributes for different styles. For example the attribute _alignments
will hold a list
with the alignments in the workbook, such as these:
_style
is a list that only refers to the mentioned attributes by their index, as such:
So, lets take for example a workbook with no alignment styles applied. in that case the _alignments
list attribute of the workbook will have only 1 item which is the defualt (empty) alignment so:
len(new_workbook._alignments) == 1
When you copy(cell._style)
to the new workbook it tries to get its new style by reffering to the protected attributes styles (alignments, borders, etc.). But, as the new workbook has no styles the reference _alignment[1]
will raise an IndexError
as the new workbook list has only one item on that list, the default one (which is stored in _alignments[0]
).
Your initial approach is the correct one. If you are copying to a new workbook you should iterate over the cells of the sheet copying the value and then the individual styles:
from openpyxl import load_workbook, Workbook
from copy import copy
original_wb = load_workbook('example.xlsx')
original_sheet = original_wb['Sheet1']
new_wb = Workbook()
new_ws = new_wb.active
for row in original_sheet.rows:
for cell in row:
new_ws[cell.coordinate] = cell.value
new_cell = new_ws[cell.coordinate]
if cell.has_style:
new_cell.font = copy(cell.font)
new_cell.border = copy(cell.border)
new_cell.fill = copy(cell.fill)
new_cell.number_format = copy(cell.number_format)
new_cell.protection = copy(cell.protection)
new_cell.alignment = copy(cell.alignment)
new_wb.save('new.xlsx')
The _style
method will not work when trying to copy to a new workbook and is not necessary within the same workbook as you can use workbook.copy_worksheet
(documentation).