Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve Openpyxl TypeError: expected <class 'str'> error in openpyxl-3.0.3

Tags:

openpyxl

When I upgraded from openpyxl-2.5.12 to openpyxl-3.0.3, I started getting the following error:

C:\workspace\venv_py37_64\lib\site-packages\openpyxl\descriptors\base.py", line 42, in __set__
    raise TypeError('expected ' + str(self.expected_type))
TypeError: expected <class 'str'>

How do I resolve this? I believe it is failing on the line:

    adjusted_width = (max_length + 2) * 1.2
    worksheet.column_dimensions[column].width = adjusted_width

My current resolution: I had to downgrade to openpyxl-2.5.12 to resolve the error for now. Please let me know if there is an alternative solution or what change I need to do for my code to work with the newest openpyxl version. Thank you.

Here's my full code fragment:

def format_excel_file(excel_file_path):
"""
Formats the provided excel file - autosize, colors cell and draws thin borders
:param excel_file_path:
:return:
"""
my_name = 'format_excel_file()'

logger.info("Entered: {}".format(my_name))
excel_file_path = os.path.abspath(excel_file_path)
logger.info("Excel File: {}".format(excel_file_path))

wb = openpyxl.load_workbook(filename=excel_file_path)

fail_fill = PatternFill(start_color='f2a7a7',
                        end_color='f2a7a7',
                        fill_type='solid')

warn_fill = PatternFill(start_color='f5da71',
                        end_color='f5da71',
                        fill_type='solid')

pass_fill = PatternFill(start_color='8adb8d',
                        end_color='8adb8d',
                        fill_type='solid')

header_fill = PatternFill(start_color='46b363',
                          end_color='46b363',
                          fill_type='solid')

thin_border = Border(left=Side(style='thin'),
                     right=Side(style='thin'),
                     top=Side(style='thin'),
                     bottom=Side(style='thin'))

for worksheet in wb.worksheets:
    for r, row in enumerate(worksheet.rows, start=1):
        if r == 1:
            for cell in row:
                cell.fill = header_fill

    for col in worksheet.columns:
        max_length = 0
        column = col[0].column  # Get the column name
        for cell in col:
            cell.border = thin_border
            if 'FAIL' in str(cell.value):
                cell.fill = fail_fill
            elif 'PASS' in str(cell.value):
                cell.fill = pass_fill
            elif 'WARN' in str(cell.value):
                cell.fill = warn_fill
            if cell.coordinate in worksheet.merged_cells:  # not check merge_cells
                continue
            try:  # Necessary to avoid error on empty cells
                if len(str(cell.value)) > max_length:
                    max_length = len(cell.value)
            except IOError as e:
                print(e)
                pass

        adjusted_width = (max_length + 2) * 1.2
        worksheet.column_dimensions[column].width = adjusted_width
wb.save(excel_file_path)
logger.info("Exited: {}".format(my_name))
like image 519
Keshav Prabhu Avatar asked Mar 02 '23 17:03

Keshav Prabhu


1 Answers

The issue is a change in 2.6.1, which now requires the column letter, not the column number, when setting the width.

Fortunately the change is quite straightforward. Change

column = col[0].column  # Get the column name

to

column = col[0].column_letter  # Get the column name
like image 137
xorsyst Avatar answered May 17 '23 07:05

xorsyst