79219195

Date: 2024-11-24 02:03:54
Score: 0.5
Natty:
Report link

The reason your code fails is due to the following;

On your 1st iteration it takes the list ["Entry 1", 1, 5] which translates to writing "Entry 1" into the merged cells from 1 to 5 (A to E) on the next row where these cells are tested as 'empty'. You start your checking from row 2 using cell row/column co-ordinates and given its a new Sheet this row will be empty and so A2:E2 is merged and the value written.
On the 2nd iteration you now have the list ["Entry 2", 2, 6] which translates to writing "Entry 2" into the merged cells from cols 2 to 6 (B to F) on the next row where these cells again test as 'empty'. You start with row 2 again but this time you are checking the cells from Column B. What I guess you dont realise is that the cell B2 still exists and can be referenced. Many of its usual attributes remain including .value and this attribute will be None, therefore passing your test.

I'll note here if the referenced cell or attribute did not exist your code would crash at this point anyway.

So all the cells you test in row 2 in the range B2 to F2 exist and all will have None as the value and pass your test.
Your code then tries to merge that range, which will execute but corrupt your workbook in the process and then try to write the text to cell 'B2' at which you code crashes as cell B2 is a merged cell resulting in the error
'AttributeError: 'MergedCell' object attribute 'value' is read-only'.

if you checked the cell types instead

        for count_column in range(entry[1], entry[2]+1):
            print(type(ws.cell(row=count_row, column=count_column)))  # <--- Add this line 
            if ws.cell(row=count_row, column=count_column).value is None:

you would see for each cell the type is
<class 'openpyxl.cell.cell.MergedCell'>
except for the last cell which is not part of the previous merge. It's type will be
<class 'openpyxl.cell.cell.Cell'>
which is the type you'll see for all the cells A2:E5 on the 1st iteration

So you can see your test does not cover every eventuality that can cause a problems writing your data.
I don't know how sophisticated you want the check to be but certainly you can include the cell type check if you think that is necessary.

However one simple thing you could also do is skip the row your know your already wrote data to.
In you code rather than hardcoding the start of the row range as 2, use a variable that starts at the next row after the last one you used so after the 1st iteration when you wrote to row 2 the next start row should be 3.

    for count_row in range(2, 5):  # <--- Modify this range on each list iteration

This obviously means the end value of the range would need to be adjusted too as the start could possibly eventually be larger.
However the method used here may not be the best anyway given your directive If so, I want Python to skip to the next row and write it there. What if rows 2, 3, 4 fail the test, do you want to stop there or keep going until you find a row for each of your list entries?

Reasons:
  • RegEx Blacklisted phrase (1): I want
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • High reputation (-1):
Posted by: moken