Openpyxl python3 - форматирование целых строк eellicits странное поведение

Я работаю с файлами XLSX с поворотными текстами и пишу script, чтобы проанализировать их на новый файл за вкладку.

Так как openpyxl не поддерживает сводные таблицы по умолчанию, мне нужно выполнить некоторую работу, чтобы повторно вставить "стиль" поворота, который теряется во время копирования.

Для этого я повторяю каждую строку и столбец, ища значение Total в столбце 0. После этого строка должна измениться на все bold=True.

Вместо этого я получаю неустойчивое поведение, которое иногда выделяет ВСЕ ячейки после первого None. Мое сообщение print('bolding totals') показывает, что он правильно оценивает каждую строку/ячейку. Могу ли я возглавить кость и прикрутить свои отступы на петлях, возможно?

from openpyxl import Workbook
from openpyxl import load_workbook
from copy import deepcopy

wb = load_workbook(filename=r'input.xlsx')

# Print 1
sheetlist = wb.get_sheet_names()
print(sheetlist)

for i in range(len(sheetlist)-1):
    dest_filename = r''+sheetlist[i]+'.xlsx'
    new_wb = Workbook()
    ws = wb.get_sheet_by_name(sheetlist[i])
    new_wb.add_sheet(ws, 0)

    for k in range(0, new_wb.worksheets[0].get_highest_row()):
        print(new_wb.worksheets[0].cell(row=k, column=0).value)
        # ignore empty cells
        if new_wb.worksheets[0].cell(row=k, column=0).value is not None:
            if 'Total' in new_wb.worksheets[0].cell(row=k, column=0).value:
                for j in range(0, new_wb.worksheets[0].get_highest_column()):
                    print('bolding totals, '+str(k), str(j))
                    new_wb.worksheets[0].cell(
                        row=k, column=j).style.font.bold = True
            elif 'Total' not in new_wb.worksheets[0].cell(row=k, column=0).value:
                for j in range(0, new_wb.worksheets[0].get_highest_column()):
                    print('not bolding anything')
                    new_wb.worksheets[0].cell(
                        row=k, column=j).style.font.bold = False

    # remove the blank sheet created in new_wb by openpyxl
    new_wb.remove_sheet(new_wb.get_sheet_by_name('Sheet'))
    print(new_wb.get_sheet_names())
    new_wb.save(dest_filename)
    break  # set to break after one sheet for testing

print('finished')

В этот момент я подозреваю, что это ошибка в обработке openpyxl стилей. Я запустил еще одно очень простое редактирование и получил странное поведение.

Если у нас есть простой макет с жирным/нежирным ячеек. Затем мы запускаем эту простую команду для изменения одной ячейки:

>>> new_wb.worksheets[0].cell(row=10,column=0).style.font.bold = False

Выход изменяется для всего столбца, а не только для ячейки.

Ответ 1

До opentyxl 2.0 стили ячеек были разделены между ячеями: это был отрыв от реализации с использованием указателей в исходном XML: две (или более) ячейки использовали бы стиль "1". Изменение этого стиля для одной ячейки означало бы его изменение для всех ячеек, что звучит как поведение, наблюдаемое здесь.

С тех пор, несмотря на различные изменения в реализации, больше нет побочных эффектов при изменении стиля для одной ячейки. Важным изменением является то, что объекты форматирования, такие как Font, доступны напрямую и не должны быть обернуты в стиле.

Были некоторые другие изменения: рабочие листы не могут быть скопированы между книгами, потому что они зависят от данных, хранящихся в родительской книге.

Без исходного файла трудно быть уверенным, но следующий код должен работать с openpyxl >= 2.2

from openpyxl import Workbook
from openpyxl import load_workbook

wb = load_workbook(filename='input.xlsx', read_only=True)

for sheet in wb.sheetnames:

    dest_filename = '{0}.xlsx'.format(sheet)
    new_wb = Workbook()
    del new_wb["Sheet"]

    ws1 = wb[sheet]
    ws2 = new_wb.create_sheet(sheet)

    for row in ws1:
        ws2.append([c.value for c in row])
        first = row[0]
        if first.data_type == "s" and "Total" in first.value:
            for idx in range(len(row)):
                cell = ws2.cell(row=ws2.max_row, column=idx+1)
                bolded = cell.font.copy(bold=True)
                cell.font = bolded

    new_wb.save(dest_filename)
    print("saving {0}".format(dest_filename))

print('finished')