I am using pywin32 for a project to automate a few excel files using python.
In the excel file, I want to protect all the cells that contain a formula.
So, I first unlock all the cells and then only lock those cells which has a formula.
When I protect the worksheet with a password, I also pass all the relevant protection properties such as;
AllowFormattingCells,
AllowFormattingColumns,
AllowFormattingRows,
AllowInsertingColumns,
AllowInsertingRows,
AllowSorting and
AllowFiltering
and set them to True. However, if I check what the properties are after I have protected the worksheet, they return as False.
When I open the file using Excel, the sheet is being protected and I am able to edit the contents of the unlocked cells but I am unable to format, filter, insert columns or rows or do anything else.
Relevant Information
Below is the python code for reproducibility
import win32com.client
excel_app = win32com.client.DispatchEx("Excel.Application")
excel_app.Visible = False
workbook = excel_app.Workbooks.Open("path_to_file.xlsx")
sheet = workbook.Sheets("Sheet1")
all_cells = sheet.Cells
merge_cells = sheet.Cells(1, 1).MergeArea
edited_cell = merge_cells.Cells(1, 1)
value = edited_cell.Formula if edited_cell.HasFormula else edited_cell.Value
edited_cell.Formula = "=1+1"
formula_cells = all_cells.SpecialCells(Type=-4123) # -4213 represent xlCellTypeFormulas
all_cells.Locked = False
formula_cells.Locked = True
if isinstance(value, str) and value.startswith("="):
edited_cell.Formula = value
else:
edited_cell.Value = value
merge_cells.Locked = False
sheet.Protect(
Password="random_password",
Contents=True,
UserInterfaceOnly=True,
AllowFormattingCells=True,
AllowFormattingColumns=True,
AllowFormattingRows=True,
AllowInsertingColumns=True,
AllowInsertingRows=True,
AllowSorting=True,
AllowFiltering=True,
)
print("AllowFormattingCells: ", sheet.Protection.AllowFormattingCells)
print("AllowFormattingColumns: ", sheet.Protection.AllowFormattingColumns)
print("AllowFormattingRows: ", sheet.Protection.AllowFormattingRows)
print("AllowInsertingColumns: ", sheet.Protection.AllowInsertingColumns)
print("AllowInsertingRows: ", sheet.Protection.AllowInsertingRows)
print("AllowSorting: ", sheet.Protection.AllowSorting)
print("AllowFiltering: ", sheet.Protection.AllowFiltering)
workbook.Save()
excel_app.Quit()
When I manually set the protection while using Excel, the protection is working as expected. However, when I am setting it using pywin32, protection is working, but the protections properties are not set, hence I am unable to add rows, use filters, etc.
I've tried all combinations for the 'Contents' and the 'UserInterfaceOnly' to see if that may cause it to change.
I tested originally on a Windows 10 PC with Excel 2013 and as stated your code worked.
I then tried a Windows 10 PC with Excel 2021 and it appeared to exhibit the same issue as you, the protections remained as False after being set to True. But another run later and it all worked fine on that Excel version.
I tested with older versions of pywin32 306, 307 and then upgraded to 308.
Anyway have applied the same protections using Xlwings (which also uses the Excel App and is similar to win32com) it works on both my systems so you can try it with your set up, assuming there is no issues using Xlwings.
import xlwings as xw
from xlwings import constants
in_excelfile = 'unprotected.xlsx'
out_excelfile = 'protected.xlsx'
with xw.App(visible=True) as xl:
wb = xw.Book(path_to_excel)
ws = wb.sheets["Sheet1"]
# Get range of used cells, this is the range of cells in the sheet with values
sheet_range = ws.used_range
# Set all cells in the sheet_range Locked status to False
ws.range(sheet_range).api.Locked = False
# Select all cells with formulas in the sheet_range and set Locked to True
ws.range(sheet_range).api.SpecialCells(constants.CellType.xlCellTypeFormulas, 23).Locked = True
# Set the protection states
ws.api.Protect(
Password='random_password',
Contents=True,
UserInterfaceOnly=True,
AllowFormattingCells=True,
AllowFormattingColumns=True,
AllowFormattingRows=True,
AllowInsertingColumns=True,
AllowInsertingRows=True,
AllowSorting=True,
AllowFiltering=True,
)
# Print the Status of the Protections
print(f"AllowFormattingCells: {ws.api.Protection.AllowFormattingCells}")
print(f"AllowFormattingColumns: {ws.api.Protection.AllowFormattingColumns}")
print(f"AllowFormattingRows: {ws.api.Protection.AllowFormattingRows}")
print(f"AllowInsertingColumns: {ws.api.Protection.AllowInsertingColumns}")
print(f"AllowInsertingRows: {ws.api.Protection.AllowInsertingRows}")
print(f"AllowSorting: {ws.api.Protection.AllowSorting}")
print(f"AllowFiltering: {ws.api.Protection.AllowFiltering}")
# Save file
wb.save(out_excelfile)
If Xlwings doesn't work for you there is also Openpyxl, which doesn't use the Excel App but rather edits the underlying XML files that make up the XLSX files, that might do the trick.