6

I havent found much of the topic of creating a password protected Excel file using Python.

In Openpyxl, I did find a SheetProtection module using:

from openpyxl.worksheet import SheetProtection

However, the problem is I'm not sure how to use it. It's not an attribute of Workbook or Worksheet so I can't just do this:

wb = Workbook()
ws = wb.worksheets[0]
ws_encrypted = ws.SheetProtection()
ws_encrypted.password = 'test'
...

Does anyone know if such a request is even possible with Python? Thanks!

jmcnamara
  • 38,196
  • 6
  • 90
  • 108
dyao
  • 983
  • 3
  • 12
  • 25

5 Answers5

10

Here's a workaround I use. It generates a VBS script and calls it from within your python script.

def set_password(excel_file_path, pw):

    from pathlib import Path

    excel_file_path = Path(excel_file_path)

    vbs_script = \
    f"""' Save with password required upon opening

    Set excel_object = CreateObject("Excel.Application")
    Set workbook = excel_object.Workbooks.Open("{excel_file_path}")

    excel_object.DisplayAlerts = False
    excel_object.Visible = False

    workbook.SaveAs "{excel_file_path}",, "{pw}"

    excel_object.Application.Quit
    """

    # write
    vbs_script_path = excel_file_path.parent.joinpath("set_pw.vbs")
    with open(vbs_script_path, "w") as file:
        file.write(vbs_script)

    #execute
    subprocess.call(['cscript.exe', str(vbs_script_path)])

    # remove
    vbs_script_path.unlink()

    return None
Michał Zawadzki
  • 695
  • 6
  • 14
7

Looking at the docs for openpyxl, I noticed there is indeed a openpyxl.worksheet.SheetProtection class. However, it seems to be already part of a worksheet object:

>>> wb = Workbook()
>>> ws = wb.worksheets[0]
>>> ws.protection
<openpyxl.worksheet.protection.SheetProtection object at 0xM3M0RY>

Checking dir(ws.protection) shows there is a method set_password that when called with a string argument does indeed seem to set a protected flag.

>>> ws.protection.set_password('test')
>>> wb.save('random.xlsx')

I opened random.xlsx in LibreOffice and the sheet was indeed protected. However, I only needed to toggle an option to turn off protection, and not enter any password, so I might be doing it wrong still...

icedwater
  • 4,701
  • 3
  • 35
  • 50
  • Thanks for taking the time to respond. The `protection` attribute doesn't require a password to open a Excel, it instead it adds a password to the sheet option under Review. So if I ever want to change user permissions to the worksheet, I would have to enter 'test' – dyao Mar 21 '16 at 05:59
  • Ah, so I guess that was the thing you were looking for after all. Good to know, anyway, I'll be poking more into excel-writing with python soon. – icedwater Mar 21 '16 at 06:27
  • I have used `openpyxl.writer.excel.save_virtual_workbook` instead of `wb.save` in my code. It doesn't ask for password when I unprotect it (tools > protection > unprotect sheet). I tried it with `save` and it actually asks for the password. Why is the behaviour different? I really have to use `save_virtual_workbook` – Hussain Jan 02 '18 at 09:16
  • @Hussain thanks for your question. Would you consider asking it separately? I think there are details you could add that don't fit in the comment limit. – icedwater Jan 08 '18 at 04:45
  • @dyao as fate would have it, I haven't had the bandwidth to look into Excel files and Python recently. Have you? – icedwater Jan 08 '18 at 04:47
  • It was char length issue of the password. Have raised an issue https://bitbucket.org/openpyxl/openpyxl/issues/945/36-character-length-password-doesnt. Thanks – Hussain Jan 08 '18 at 07:51
4

You can use python win32com to save an excel file with a password.

import win32com.client as win32

excel = win32.gencache.EnsureDispatch('Excel.Application')
#Before saving the file set DisplayAlerts to False to suppress the warning dialog:
excel.DisplayAlerts = False
wb = excel.Workbooks.Open(your_file_name)
# refer https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2007/bb214129(v=office.12)?redirectedfrom=MSDN
# FileFormat = 51 is for .xlsx extension
wb.SaveAs(your_file_name, 51, 'your password')                                               
wb.Close() 
excel.Application.Quit()
liu quan
  • 41
  • 1
4

Here is a rework of Michał Zawadzki's solution that doesn't require creating and executing a separate vbs file:

def PassProtect(Path, Pass):

    from win32com.client.gencache import EnsureDispatch
    
    xlApp = EnsureDispatch("Excel.Application")
    
    xlwb = xlApp.Workbooks.Open(Path)
    
    xlApp.DisplayAlerts = False
    xlwb.Visible = False
    
    xlwb.SaveAs(Path, Password = Pass)
    
    xlwb.Close()
    
    xlApp.Quit()
    
PassProtect(FullExcelWorkbookPathGoesHere, DesiredPasswordGoesHere)

If you wanted to choose a file name that's in your project's folder, you could also do:

from os.path import abspath

PassProtect(abspath(FileNameInsideProjectFolderGoesHere), DesiredPasswordGoesHere)
3

openpyxl is unlikely ever to provide workbook encryption. However, you can add this yourself because Excel files (xlsx format version >= 2010) are zip-archives: create a file in openpyxl and add a password to it using standard utilities.

Steve Rossiter
  • 2,624
  • 21
  • 29
Charlie Clark
  • 18,477
  • 4
  • 49
  • 55
  • "All Excel files are zip-archives"? Just tried to write an old Excel 97-2003 format file, rename it to `.zip` and tried opening the zip file. No dice. – Eric Smith Jun 24 '16 at 15:38
  • Read Excel >= 2010 files. Older versions are not supported by openpyxl as the docs make clearer. You'll xlrd and xlwt for those. – Charlie Clark Jun 24 '16 at 18:59
  • 2
    Thanks for the insight, @CharlieClark, I'm assuming you're that Charlie Clark who's also one of the main authors of `openpyxl`. Has anyone offered to add workbook encryption, and is the zip-password added in this manner normally recognisable by Excel as a document password? – icedwater Jan 08 '18 at 05:00
  • @icedwater ... did you find any approach around it? – Hmmm Jan 01 '21 at 06:41
  • @Hmmm, sadly, no. But there seems to be some sort of "script injection" workaround above. I literally haven't looked at this problem in years. – icedwater Jan 13 '21 at 09:33
  • @Hmmm based on the latest [openpyxl doc](https://openpyxl.readthedocs.io/en/stable/protection.html), protection is only meant for locking permissions, not encrypting the data. So still no answer, then. – icedwater Jan 13 '21 at 09:47