[{"data":1,"prerenderedAt":1852},["ShallowReactive",2],{"doc:\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl":3,"surround:\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl":1818,"ancestors:\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl":1827,"children:\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl":1832,"related:\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl":1833},{"id":4,"title":5,"body":6,"dateModified":1784,"datePublished":1784,"description":1785,"extension":1786,"faq":1787,"keyword":1796,"kind":1797,"meta":1798,"navigation":266,"path":1807,"seo":1808,"slug":1811,"stem":1812,"topics":1813,"type":1816,"__hash__":1817},"docs\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl\u002Findex.md","Remove Sheet Protection from a Workbook You Own with openpyxl",{"type":7,"value":8,"toc":1771},"minimark",[9,19,189,194,219,222,496,500,503,700,707,711,718,799,809,939,943,946,1052,1055,1059,1062,1324,1331,1335,1338,1491,1498,1502,1515,1647,1651,1684,1688,1706,1710,1716,1722,1728,1734,1738,1767],[10,11,12,13,18],"p",{},"Protected templates are common in reporting: the budget template with locked formulas, the monthly pack whose structure is locked so nobody renames the data sheet. Sooner or later the team that owns those files needs to change them — a new column, a corrected formula, a sheet added to fifty regional copies — and unprotecting each file by hand in Excel is slow and error-prone. openpyxl can turn protection off, make the change and put the protection back exactly as it was. This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002F","Protecting and Sharing Excel Workbooks",", shows how, for workbooks you own or are responsible for maintaining.",[20,21,29,30,29,34,29,38,29,46,29,56,29,67,29,74,29,79,29,85,29,90,29,95,29,102,29,108,29,112,29,116,29,120,29,123,29,128,29,135,29,140,29,143,29,147,29,150,29,153,29,159,29,163,29,166,29,170,29,173,29,176,29,182,29,186],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"4 0 752 142","img",[25,26],"rp-flow-t","rp-flow-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"Maintaining a protected workbook without losing its protection",[35,36,37],"desc",{"id":26},"Load the workbook, copy each sheet's protection and the workbook protection, switch protection off, make the change, assign the saved protection objects back and save. The stored password hashes are written back unchanged, so the original passwords still work.",[39,40],"rect",{"x":41,"y":42,"width":43,"height":44,"fill":45},"4","0","752","142","#ffffff",[39,47],{"x":48,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"20.0","16.0","115.2","110.5","12","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[57,58,60],"g",{"transform":59},"translate(65.6,37.8) scale(1.000)",[61,62],"path",{"d":63,"fill":64,"stroke":65,"style":66},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[68,69,73],"text",{"x":70,"y":71,"style":72},"77.6","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Load",[68,75,78],{"x":70,"y":76,"style":77},"103.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","load_workbook",[80,81],"line",{"x1":82,"y1":83,"x2":84,"y2":83,"stroke":54,"style":55},"140.2","71.2","162.2",[86,87],"polygon",{"points":88,"fill":89},"166.2,71.2 157.2,76.2 157.2,66.2","#5b5cf0",[39,91],{"x":92,"y":49,"width":50,"height":51,"rx":52,"fill":93,"stroke":94,"style":55},"171.2","#d9f4f1","var(--teal,#0f9488)",[57,96,98],{"transform":97},"translate(216.8,29.0) scale(1.000)",[61,99],{"d":100,"fill":64,"stroke":101,"style":66},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--teal-ink,#0b6157)",[68,103,107],{"x":104,"y":105,"style":106},"228.8","75.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Save",[68,109,111],{"x":104,"y":110,"style":106},"93.0","settings",[68,113,115],{"x":104,"y":114,"style":77},"112.5","copy(ws.protection)",[80,117],{"x1":118,"y1":83,"x2":119,"y2":83,"stroke":54,"style":55},"291.4","313.4",[86,121],{"points":122,"fill":89},"317.4,71.2 308.4,76.2 308.4,66.2",[39,124],{"x":125,"y":49,"width":50,"height":51,"rx":52,"fill":126,"stroke":127,"style":55},"322.4","#fdefd8","var(--gold,#b4740a)",[57,129,131],{"transform":130},"translate(368.0,37.8) scale(1.000)",[61,132],{"d":133,"fill":64,"stroke":134,"style":66},"M8 11a4 4 0 1 0 .01 0z M11 13l9-9 M17 7l2 2 M15 9l2 2","var(--gold-ink,#7a4e06)",[68,136,139],{"x":137,"y":71,"style":138},"380.0","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Unprotect",[68,141,142],{"x":137,"y":76,"style":77},"SheetProtection()",[80,144],{"x1":145,"y1":83,"x2":146,"y2":83,"stroke":54,"style":55},"442.6","464.6",[86,148],{"points":149,"fill":89},"468.6,71.2 459.6,76.2 459.6,66.2",[39,151],{"x":152,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"473.6",[57,154,156],{"transform":155},"translate(519.2,37.8) scale(1.000)",[61,157],{"d":158,"fill":64,"stroke":65,"style":66},"M9 8l-4 4 4 4 M15 8l4 4-4 4",[68,160,162],{"x":161,"y":71,"style":72},"531.2","Change",[68,164,165],{"x":161,"y":76,"style":77},"cells, sheets",[80,167],{"x1":168,"y1":83,"x2":169,"y2":83,"stroke":54,"style":55},"593.8","615.8",[86,171],{"points":172,"fill":89},"619.8,71.2 610.8,76.2 610.8,66.2",[39,174],{"x":175,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"624.8",[57,177,179],{"transform":178},"translate(670.4,37.8) scale(1.000)",[61,180],{"d":181,"fill":64,"stroke":65,"style":66},"M6 11h12v9H6z M8.5 11V8a3.5 3.5 0 0 1 7 0v3",[68,183,185],{"x":184,"y":71,"style":72},"682.4","Restore",[68,187,188],{"x":184,"y":76,"style":77},"same hash back",[190,191,193],"h2",{"id":192},"prerequisites","Prerequisites",[195,196,201],"pre",{"className":197,"code":198,"language":199,"meta":200,"style":200},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[202,203,204],"code",{"__ignoreMap":200},[205,206,208,212,216],"span",{"class":80,"line":207},1,[205,209,211],{"class":210},"sMTad","pip",[205,213,215],{"class":214},"srMev"," install",[205,217,218],{"class":214}," openpyxl\n",[10,220,221],{},"A protected template to work on — a budget sheet with protection, a locked structure and a formula that needs fixing:",[195,223,227],{"className":224,"code":225,"language":226,"meta":200,"style":200},"language-python shiki shiki-themes github-light github-dark-high-contrast","import re\nimport zipfile\nfrom copy import copy\n\nfrom openpyxl import Workbook, load_workbook\nfrom openpyxl.workbook.protection import WorkbookProtection\nfrom openpyxl.worksheet.protection import SheetProtection\n\nwb = Workbook()\nws = wb.active\nws.title = \"Budget\"\nws.append([\"Item\", \"Amount\"])\nws.append([\"Rent\", 1200])\nws.append([\"Staff\", 5400])\nws[\"B4\"] = \"=SUM(B2:B2)\"                         # the bug: should include B3\nws.protection.sheet = True\nws.protection.password = \"team-password\"\nws.protection.formatColumns = False              # readers may still resize columns\nwb.security = WorkbookProtection(workbookPassword=\"team-password\", lockStructure=True)\nwb.save(\"budget_template.xlsx\")\n","python",[202,228,229,239,247,261,268,281,294,307,312,324,335,346,364,380,395,416,427,438,452,485],{"__ignoreMap":200},[205,230,231,235],{"class":80,"line":207},[205,232,234],{"class":233},"s-kum","import",[205,236,238],{"class":237},"skGVy"," re\n",[205,240,242,244],{"class":80,"line":241},2,[205,243,234],{"class":233},[205,245,246],{"class":237}," zipfile\n",[205,248,250,253,256,258],{"class":80,"line":249},3,[205,251,252],{"class":233},"from",[205,254,255],{"class":237}," copy ",[205,257,234],{"class":233},[205,259,260],{"class":237}," copy\n",[205,262,264],{"class":80,"line":263},4,[205,265,267],{"emptyLinePlaceholder":266},true,"\n",[205,269,271,273,276,278],{"class":80,"line":270},5,[205,272,252],{"class":233},[205,274,275],{"class":237}," openpyxl ",[205,277,234],{"class":233},[205,279,280],{"class":237}," Workbook, load_workbook\n",[205,282,284,286,289,291],{"class":80,"line":283},6,[205,285,252],{"class":233},[205,287,288],{"class":237}," openpyxl.workbook.protection ",[205,290,234],{"class":233},[205,292,293],{"class":237}," WorkbookProtection\n",[205,295,297,299,302,304],{"class":80,"line":296},7,[205,298,252],{"class":233},[205,300,301],{"class":237}," openpyxl.worksheet.protection ",[205,303,234],{"class":233},[205,305,306],{"class":237}," SheetProtection\n",[205,308,310],{"class":80,"line":309},8,[205,311,267],{"emptyLinePlaceholder":266},[205,313,315,318,321],{"class":80,"line":314},9,[205,316,317],{"class":237},"wb ",[205,319,320],{"class":233},"=",[205,322,323],{"class":237}," Workbook()\n",[205,325,327,330,332],{"class":80,"line":326},10,[205,328,329],{"class":237},"ws ",[205,331,320],{"class":233},[205,333,334],{"class":237}," wb.active\n",[205,336,338,341,343],{"class":80,"line":337},11,[205,339,340],{"class":237},"ws.title ",[205,342,320],{"class":233},[205,344,345],{"class":214}," \"Budget\"\n",[205,347,349,352,355,358,361],{"class":80,"line":348},12,[205,350,351],{"class":237},"ws.append([",[205,353,354],{"class":214},"\"Item\"",[205,356,357],{"class":237},", ",[205,359,360],{"class":214},"\"Amount\"",[205,362,363],{"class":237},"])\n",[205,365,367,369,372,374,378],{"class":80,"line":366},13,[205,368,351],{"class":237},[205,370,371],{"class":214},"\"Rent\"",[205,373,357],{"class":237},[205,375,377],{"class":376},"sP0c6","1200",[205,379,363],{"class":237},[205,381,383,385,388,390,393],{"class":80,"line":382},14,[205,384,351],{"class":237},[205,386,387],{"class":214},"\"Staff\"",[205,389,357],{"class":237},[205,391,392],{"class":376},"5400",[205,394,363],{"class":237},[205,396,398,401,404,407,409,412],{"class":80,"line":397},15,[205,399,400],{"class":237},"ws[",[205,402,403],{"class":214},"\"B4\"",[205,405,406],{"class":237},"] ",[205,408,320],{"class":233},[205,410,411],{"class":214}," \"=SUM(B2:B2)\"",[205,413,415],{"class":414},"s-wDw","                         # the bug: should include B3\n",[205,417,419,422,424],{"class":80,"line":418},16,[205,420,421],{"class":237},"ws.protection.sheet ",[205,423,320],{"class":233},[205,425,426],{"class":376}," True\n",[205,428,430,433,435],{"class":80,"line":429},17,[205,431,432],{"class":237},"ws.protection.password ",[205,434,320],{"class":233},[205,436,437],{"class":214}," \"team-password\"\n",[205,439,441,444,446,449],{"class":80,"line":440},18,[205,442,443],{"class":237},"ws.protection.formatColumns ",[205,445,320],{"class":233},[205,447,448],{"class":376}," False",[205,450,451],{"class":414},"              # readers may still resize columns\n",[205,453,455,458,460,463,467,469,472,474,477,479,482],{"class":80,"line":454},19,[205,456,457],{"class":237},"wb.security ",[205,459,320],{"class":233},[205,461,462],{"class":237}," WorkbookProtection(",[205,464,466],{"class":465},"sa561","workbookPassword",[205,468,320],{"class":233},[205,470,471],{"class":214},"\"team-password\"",[205,473,357],{"class":237},[205,475,476],{"class":465},"lockStructure",[205,478,320],{"class":233},[205,480,481],{"class":376},"True",[205,483,484],{"class":237},")\n",[205,486,488,491,494],{"class":80,"line":487},20,[205,489,490],{"class":237},"wb.save(",[205,492,493],{"class":214},"\"budget_template.xlsx\"",[205,495,484],{"class":237},[190,497,499],{"id":498},"step-1-see-what-protection-a-workbook-has","Step 1 — See what protection a workbook has",[10,501,502],{},"Before changing anything, list the protection on each sheet and on the workbook. openpyxl reads both the legacy password hashes it writes itself and the salted SHA-512 hashes current Excel versions write:",[195,504,506],{"className":224,"code":505,"language":226,"meta":200,"style":200},"def describe_protection(path):\n    wb = load_workbook(path)\n    lines = [f\"structure locked: {bool(wb.security and wb.security.lockStructure)}\"]\n    for sheet in wb.worksheets:\n        p = sheet.protection\n        kind = p.algorithmName or (\"legacy hash\" if p.password else \"no password\")\n        lines.append(f\"{sheet.title}: protected={bool(p.sheet)} ({kind})\")\n    return lines\n\nprint(describe_protection(\"budget_template.xlsx\"))\n# ['structure locked: True', 'Budget: protected=True (legacy hash)']\n",[202,507,508,520,530,571,585,595,628,670,678,682,695],{"__ignoreMap":200},[205,509,510,513,517],{"class":80,"line":207},[205,511,512],{"class":233},"def",[205,514,516],{"class":515},"s_Opv"," describe_protection",[205,518,519],{"class":237},"(path):\n",[205,521,522,525,527],{"class":80,"line":241},[205,523,524],{"class":237},"    wb ",[205,526,320],{"class":233},[205,528,529],{"class":237}," load_workbook(path)\n",[205,531,532,535,537,540,543,546,550,553,556,559,562,565,568],{"class":80,"line":249},[205,533,534],{"class":237},"    lines ",[205,536,320],{"class":233},[205,538,539],{"class":237}," [",[205,541,542],{"class":233},"f",[205,544,545],{"class":214},"\"structure locked: ",[205,547,549],{"class":548},"sSjpA","{",[205,551,552],{"class":376},"bool",[205,554,555],{"class":237},"(wb.security ",[205,557,558],{"class":233},"and",[205,560,561],{"class":237}," wb.security.lockStructure)",[205,563,564],{"class":548},"}",[205,566,567],{"class":214},"\"",[205,569,570],{"class":237},"]\n",[205,572,573,576,579,582],{"class":80,"line":263},[205,574,575],{"class":233},"    for",[205,577,578],{"class":237}," sheet ",[205,580,581],{"class":233},"in",[205,583,584],{"class":237}," wb.worksheets:\n",[205,586,587,590,592],{"class":80,"line":270},[205,588,589],{"class":237},"        p ",[205,591,320],{"class":233},[205,593,594],{"class":237}," sheet.protection\n",[205,596,597,600,602,605,608,611,614,617,620,623,626],{"class":80,"line":283},[205,598,599],{"class":237},"        kind ",[205,601,320],{"class":233},[205,603,604],{"class":237}," p.algorithmName ",[205,606,607],{"class":233},"or",[205,609,610],{"class":237}," (",[205,612,613],{"class":214},"\"legacy hash\"",[205,615,616],{"class":233}," if",[205,618,619],{"class":237}," p.password ",[205,621,622],{"class":233},"else",[205,624,625],{"class":214}," \"no password\"",[205,627,484],{"class":237},[205,629,630,633,635,637,639,642,644,647,649,651,654,656,658,660,663,665,668],{"class":80,"line":296},[205,631,632],{"class":237},"        lines.append(",[205,634,542],{"class":233},[205,636,567],{"class":214},[205,638,549],{"class":548},[205,640,641],{"class":237},"sheet.title",[205,643,564],{"class":548},[205,645,646],{"class":214},": protected=",[205,648,549],{"class":548},[205,650,552],{"class":376},[205,652,653],{"class":237},"(p.sheet)",[205,655,564],{"class":548},[205,657,610],{"class":214},[205,659,549],{"class":548},[205,661,662],{"class":237},"kind",[205,664,564],{"class":548},[205,666,667],{"class":214},")\"",[205,669,484],{"class":237},[205,671,672,675],{"class":80,"line":309},[205,673,674],{"class":233},"    return",[205,676,677],{"class":237}," lines\n",[205,679,680],{"class":80,"line":314},[205,681,267],{"emptyLinePlaceholder":266},[205,683,684,687,690,692],{"class":80,"line":326},[205,685,686],{"class":376},"print",[205,688,689],{"class":237},"(describe_protection(",[205,691,493],{"class":214},[205,693,694],{"class":237},"))\n",[205,696,697],{"class":80,"line":337},[205,698,699],{"class":414},"# ['structure locked: True', 'Budget: protected=True (legacy hash)']\n",[10,701,702,703,706],{},"Knowing which kind of protection is in place tells you what you are about to change and what you must put back. A sheet marked ",[202,704,705],{},"protected=False"," with a password is unusual but possible — someone unprotected it in Excel without removing the password setting.",[190,708,710],{"id":709},"step-2-keep-a-copy-then-unprotect","Step 2 — Keep a copy, then unprotect",[10,712,713,714,717],{},"Copy the protection objects before touching them. Then replace each sheet's protection with a fresh, empty ",[202,715,716],{},"SheetProtection"," and clear the workbook's structure lock:",[195,719,721],{"className":224,"code":720,"language":226,"meta":200,"style":200},"wb = load_workbook(\"budget_template.xlsx\")\nsaved_sheets = {sheet.title: copy(sheet.protection) for sheet in wb.worksheets}\nsaved_workbook = copy(wb.security)\n\nfor sheet in wb.worksheets:\n    sheet.protection = SheetProtection()\nwb.security = None\n",[202,722,723,736,756,766,770,780,790],{"__ignoreMap":200},[205,724,725,727,729,732,734],{"class":80,"line":207},[205,726,317],{"class":237},[205,728,320],{"class":233},[205,730,731],{"class":237}," load_workbook(",[205,733,493],{"class":214},[205,735,484],{"class":237},[205,737,738,741,743,746,749,751,753],{"class":80,"line":241},[205,739,740],{"class":237},"saved_sheets ",[205,742,320],{"class":233},[205,744,745],{"class":237}," {sheet.title: copy(sheet.protection) ",[205,747,748],{"class":233},"for",[205,750,578],{"class":237},[205,752,581],{"class":233},[205,754,755],{"class":237}," wb.worksheets}\n",[205,757,758,761,763],{"class":80,"line":249},[205,759,760],{"class":237},"saved_workbook ",[205,762,320],{"class":233},[205,764,765],{"class":237}," copy(wb.security)\n",[205,767,768],{"class":80,"line":263},[205,769,267],{"emptyLinePlaceholder":266},[205,771,772,774,776,778],{"class":80,"line":270},[205,773,748],{"class":233},[205,775,578],{"class":237},[205,777,581],{"class":233},[205,779,584],{"class":237},[205,781,782,785,787],{"class":80,"line":283},[205,783,784],{"class":237},"    sheet.protection ",[205,786,320],{"class":233},[205,788,789],{"class":237}," SheetProtection()\n",[205,791,792,794,796],{"class":80,"line":296},[205,793,457],{"class":237},[205,795,320],{"class":233},[205,797,798],{"class":376}," None\n",[10,800,801,802,804,805,808],{},"A fresh ",[202,803,142],{}," is off and has no password, so nothing is written to the sheet at all. Setting only ",[202,806,807],{},"sheet.protection.sheet = False"," also works, but leaves the password hash and permission flags in place — harmless, but confusing for the next person who inspects the file. Cells keep their locked and hidden flags either way; those take effect only while a sheet is protected. The hidden flag is the one to remember: on a protected sheet it hides a cell's formula from the formula bar, so while protection is off — and in any unprotected copy you save along the way — those formulas are visible to anyone who opens the file.",[20,810,29,815,29,818,29,821,29,824,29,829,29,835,29,841,29,847,29,853,29,860,29,864,29,870,29,874,29,879,29,883,29,888,29,891,29,896,29,901,29,905,29,909,29,914,29,917,29,922,29,925,29,932,29,934],{"viewBox":811,"role":23,"ariaLabelledBy":812,"xmlns":27,"style":28},"4 0 752 233",[813,814],"rp-methods-t","rp-methods-d",[31,816,817],{"id":813},"Two ways to switch sheet protection off",[35,819,820],{"id":814},"Setting protection.sheet to False switches protection off but keeps the password hash and the permission flags in the file. Replacing the protection with a new SheetProtection object removes the whole setting, leaving a clean sheet. Both keep cell values and the locked flags of cells.",[39,822],{"x":41,"y":42,"width":43,"height":823,"fill":45},"233",[39,825],{"x":48,"y":49,"width":826,"height":827,"rx":828,"fill":126,"stroke":127,"style":55},"351.0","201.0","14",[57,830,832],{"transform":831},"translate(182.5,29.0) scale(1.083)",[61,833],{"d":133,"fill":64,"stroke":134,"style":834},"stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[68,836,840],{"x":837,"y":838,"style":839},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","protection.sheet = False",[80,842],{"x1":843,"y1":844,"x2":845,"y2":844,"stroke":127,"style":846},"36.0","91.0","355.0","stroke-width:1px",[68,848,852],{"x":849,"y":850,"style":851},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","one attribute",[57,854,856],{"transform":855},"translate(38.5,99.5) scale(0.625)",[61,857],{"d":858,"fill":64,"stroke":94,"style":859},"M5 12.5l4.5 4.5L19 7","stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[68,861,863],{"x":849,"y":862,"style":851},"137.0","password hash stays in the file",[57,865,867],{"transform":866},"translate(38.5,125.5) scale(0.625)",[61,868],{"d":869,"fill":64,"stroke":127,"style":859},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[68,871,873],{"x":849,"y":872,"style":851},"163.0","permission flags stay",[57,875,877],{"transform":876},"translate(38.5,151.5) scale(0.625)",[61,878],{"d":869,"fill":64,"stroke":127,"style":859},[68,880,882],{"x":849,"y":881,"style":851},"189.0","cells untouched",[57,884,886],{"transform":885},"translate(38.5,177.5) scale(0.625)",[61,887],{"d":858,"fill":64,"stroke":94,"style":859},[39,889],{"x":890,"y":49,"width":826,"height":827,"rx":828,"fill":93,"stroke":94,"style":55},"389.0",[57,892,894],{"transform":893},"translate(551.5,29.0) scale(1.083)",[61,895],{"d":858,"fill":64,"stroke":101,"style":834},[68,897,900],{"x":898,"y":838,"style":899},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","protection = SheetProtection()",[80,902],{"x1":903,"y1":844,"x2":904,"y2":844,"stroke":94,"style":846},"405.0","724.0",[68,906,908],{"x":907,"y":850,"style":851},"429.0","nothing written to the sheet",[57,910,912],{"transform":911},"translate(407.5,99.5) scale(0.625)",[61,913],{"d":858,"fill":64,"stroke":94,"style":859},[68,915,916],{"x":907,"y":862,"style":851},"clean for the next inspection",[57,918,920],{"transform":919},"translate(407.5,125.5) scale(0.625)",[61,921],{"d":858,"fill":64,"stroke":94,"style":859},[68,923,924],{"x":907,"y":872,"style":851},"copy it first to restore later",[57,926,928],{"transform":927},"translate(407.5,151.5) scale(0.625)",[61,929],{"d":930,"fill":64,"stroke":931,"style":859},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[68,933,882],{"x":907,"y":881,"style":851},[57,935,937],{"transform":936},"translate(407.5,177.5) scale(0.625)",[61,938],{"d":858,"fill":64,"stroke":94,"style":859},[190,940,942],{"id":941},"step-3-make-the-change-and-restore-the-protection","Step 3 — Make the change and restore the protection",[10,944,945],{},"With protection off, edit as usual. Then assign the saved objects back. The stored hashes go back into the file unchanged, so the team's existing password keeps working in Excel — without the script ever needing to know it:",[195,947,949],{"className":224,"code":948,"language":226,"meta":200,"style":200},"wb[\"Budget\"][\"B4\"] = \"=SUM(B2:B3)\"                # the fix\nwb[\"Budget\"].column_dimensions[\"B\"].width = 14\n\nfor title, protection in saved_sheets.items():\n    wb[title].protection = protection\nwb.security = saved_workbook\nwb.save(\"budget_template_fixed.xlsx\")\nprint(describe_protection(\"budget_template_fixed.xlsx\"))\n# ['structure locked: True', 'Budget: protected=True (legacy hash)']\n",[202,950,951,974,994,998,1010,1020,1029,1038,1048],{"__ignoreMap":200},[205,952,953,956,959,962,964,966,968,971],{"class":80,"line":207},[205,954,955],{"class":237},"wb[",[205,957,958],{"class":214},"\"Budget\"",[205,960,961],{"class":237},"][",[205,963,403],{"class":214},[205,965,406],{"class":237},[205,967,320],{"class":233},[205,969,970],{"class":214}," \"=SUM(B2:B3)\"",[205,972,973],{"class":414},"                # the fix\n",[205,975,976,978,980,983,986,989,991],{"class":80,"line":241},[205,977,955],{"class":237},[205,979,958],{"class":214},[205,981,982],{"class":237},"].column_dimensions[",[205,984,985],{"class":214},"\"B\"",[205,987,988],{"class":237},"].width ",[205,990,320],{"class":233},[205,992,993],{"class":376}," 14\n",[205,995,996],{"class":80,"line":249},[205,997,267],{"emptyLinePlaceholder":266},[205,999,1000,1002,1005,1007],{"class":80,"line":263},[205,1001,748],{"class":233},[205,1003,1004],{"class":237}," title, protection ",[205,1006,581],{"class":233},[205,1008,1009],{"class":237}," saved_sheets.items():\n",[205,1011,1012,1015,1017],{"class":80,"line":270},[205,1013,1014],{"class":237},"    wb[title].protection ",[205,1016,320],{"class":233},[205,1018,1019],{"class":237}," protection\n",[205,1021,1022,1024,1026],{"class":80,"line":283},[205,1023,457],{"class":237},[205,1025,320],{"class":233},[205,1027,1028],{"class":237}," saved_workbook\n",[205,1030,1031,1033,1036],{"class":80,"line":296},[205,1032,490],{"class":237},[205,1034,1035],{"class":214},"\"budget_template_fixed.xlsx\"",[205,1037,484],{"class":237},[205,1039,1040,1042,1044,1046],{"class":80,"line":309},[205,1041,686],{"class":376},[205,1043,689],{"class":237},[205,1045,1035],{"class":214},[205,1047,694],{"class":237},[205,1049,1050],{"class":80,"line":314},[205,1051,699],{"class":414},[10,1053,1054],{},"The same works for workbooks protected in a recent Excel version: the SHA-512 hash, salt and spin count are copied and written back as they were. Strictly, openpyxl does not enforce protection at all, so the edits would also succeed with protection left on; switching it off and back explicitly makes the script's intent clear, and the pattern also covers tools that do respect protection.",[190,1056,1058],{"id":1057},"step-4-maintain-many-copies-at-once","Step 4 — Maintain many copies at once",[10,1060,1061],{},"Protected templates tend to be copied — one per region, per client, per year. A loop applies the same fix to every file and records what it did:",[195,1063,1065],{"className":224,"code":1064,"language":226,"meta":200,"style":200},"for region in [\"North\", \"South\"]:\n    load_workbook(\"budget_template.xlsx\").save(f\"budget_{region}.xlsx\")\n\ndef fix_budget(path):\n    wb = load_workbook(path)\n    sheets = {s.title: copy(s.protection) for s in wb.worksheets}\n    structure = copy(wb.security)\n    for s in wb.worksheets:\n        s.protection = SheetProtection()\n    wb.security = None\n    changed = wb[\"Budget\"][\"B4\"].value != \"=SUM(B2:B3)\"\n    wb[\"Budget\"][\"B4\"] = \"=SUM(B2:B3)\"\n    for title, protection in sheets.items():\n        wb[title].protection = protection\n    wb.security = structure\n    wb.save(path)\n    return changed\n\nprint({region: fix_budget(f\"budget_{region}.xlsx\") for region in [\"North\", \"South\"]})\n# {'North': True, 'South': True}\n",[202,1066,1067,1089,1116,1120,1129,1137,1156,1165,1175,1184,1193,1218,1235,1246,1255,1264,1269,1276,1280,1319],{"__ignoreMap":200},[205,1068,1069,1071,1074,1076,1078,1081,1083,1086],{"class":80,"line":207},[205,1070,748],{"class":233},[205,1072,1073],{"class":237}," region ",[205,1075,581],{"class":233},[205,1077,539],{"class":237},[205,1079,1080],{"class":214},"\"North\"",[205,1082,357],{"class":237},[205,1084,1085],{"class":214},"\"South\"",[205,1087,1088],{"class":237},"]:\n",[205,1090,1091,1094,1096,1099,1101,1104,1106,1109,1111,1114],{"class":80,"line":241},[205,1092,1093],{"class":237},"    load_workbook(",[205,1095,493],{"class":214},[205,1097,1098],{"class":237},").save(",[205,1100,542],{"class":233},[205,1102,1103],{"class":214},"\"budget_",[205,1105,549],{"class":548},[205,1107,1108],{"class":237},"region",[205,1110,564],{"class":548},[205,1112,1113],{"class":214},".xlsx\"",[205,1115,484],{"class":237},[205,1117,1118],{"class":80,"line":249},[205,1119,267],{"emptyLinePlaceholder":266},[205,1121,1122,1124,1127],{"class":80,"line":263},[205,1123,512],{"class":233},[205,1125,1126],{"class":515}," fix_budget",[205,1128,519],{"class":237},[205,1130,1131,1133,1135],{"class":80,"line":270},[205,1132,524],{"class":237},[205,1134,320],{"class":233},[205,1136,529],{"class":237},[205,1138,1139,1142,1144,1147,1149,1152,1154],{"class":80,"line":283},[205,1140,1141],{"class":237},"    sheets ",[205,1143,320],{"class":233},[205,1145,1146],{"class":237}," {s.title: copy(s.protection) ",[205,1148,748],{"class":233},[205,1150,1151],{"class":237}," s ",[205,1153,581],{"class":233},[205,1155,755],{"class":237},[205,1157,1158,1161,1163],{"class":80,"line":296},[205,1159,1160],{"class":237},"    structure ",[205,1162,320],{"class":233},[205,1164,765],{"class":237},[205,1166,1167,1169,1171,1173],{"class":80,"line":309},[205,1168,575],{"class":233},[205,1170,1151],{"class":237},[205,1172,581],{"class":233},[205,1174,584],{"class":237},[205,1176,1177,1180,1182],{"class":80,"line":314},[205,1178,1179],{"class":237},"        s.protection ",[205,1181,320],{"class":233},[205,1183,789],{"class":237},[205,1185,1186,1189,1191],{"class":80,"line":326},[205,1187,1188],{"class":237},"    wb.security ",[205,1190,320],{"class":233},[205,1192,798],{"class":376},[205,1194,1195,1198,1200,1203,1205,1207,1209,1212,1215],{"class":80,"line":337},[205,1196,1197],{"class":237},"    changed ",[205,1199,320],{"class":233},[205,1201,1202],{"class":237}," wb[",[205,1204,958],{"class":214},[205,1206,961],{"class":237},[205,1208,403],{"class":214},[205,1210,1211],{"class":237},"].value ",[205,1213,1214],{"class":233},"!=",[205,1216,1217],{"class":214}," \"=SUM(B2:B3)\"\n",[205,1219,1220,1223,1225,1227,1229,1231,1233],{"class":80,"line":348},[205,1221,1222],{"class":237},"    wb[",[205,1224,958],{"class":214},[205,1226,961],{"class":237},[205,1228,403],{"class":214},[205,1230,406],{"class":237},[205,1232,320],{"class":233},[205,1234,1217],{"class":214},[205,1236,1237,1239,1241,1243],{"class":80,"line":366},[205,1238,575],{"class":233},[205,1240,1004],{"class":237},[205,1242,581],{"class":233},[205,1244,1245],{"class":237}," sheets.items():\n",[205,1247,1248,1251,1253],{"class":80,"line":382},[205,1249,1250],{"class":237},"        wb[title].protection ",[205,1252,320],{"class":233},[205,1254,1019],{"class":237},[205,1256,1257,1259,1261],{"class":80,"line":397},[205,1258,1188],{"class":237},[205,1260,320],{"class":233},[205,1262,1263],{"class":237}," structure\n",[205,1265,1266],{"class":80,"line":418},[205,1267,1268],{"class":237},"    wb.save(path)\n",[205,1270,1271,1273],{"class":80,"line":429},[205,1272,674],{"class":233},[205,1274,1275],{"class":237}," changed\n",[205,1277,1278],{"class":80,"line":440},[205,1279,267],{"emptyLinePlaceholder":266},[205,1281,1282,1284,1287,1289,1291,1293,1295,1297,1299,1302,1304,1306,1308,1310,1312,1314,1316],{"class":80,"line":454},[205,1283,686],{"class":376},[205,1285,1286],{"class":237},"({region: fix_budget(",[205,1288,542],{"class":233},[205,1290,1103],{"class":214},[205,1292,549],{"class":548},[205,1294,1108],{"class":237},[205,1296,564],{"class":548},[205,1298,1113],{"class":214},[205,1300,1301],{"class":237},") ",[205,1303,748],{"class":233},[205,1305,1073],{"class":237},[205,1307,581],{"class":233},[205,1309,539],{"class":237},[205,1311,1080],{"class":214},[205,1313,357],{"class":237},[205,1315,1085],{"class":214},[205,1317,1318],{"class":237},"]})\n",[205,1320,1321],{"class":80,"line":487},[205,1322,1323],{"class":414},"# {'North': True, 'South': True}\n",[10,1325,1326,1327,1330],{},"Reporting whether each file actually needed the change, rather than just rewriting it, makes the run safe to repeat — a second run reports ",[202,1328,1329],{},"False"," everywhere — and gives you a record of which copies were touched. Keep the originals until someone has opened a fixed copy in Excel and confirmed that the protection prompts as before, and write the fixed files to a separate folder first when the change is large.",[190,1332,1334],{"id":1333},"step-5-prove-the-protection-came-back-unchanged","Step 5 — Prove the protection came back unchanged",[10,1336,1337],{},"\"The protection is restored\" is a claim worth checking automatically, because a maintenance script that quietly drops a permission flag — say, the right to resize columns — annoys readers for months. Compare every protection attribute of the original file with the fixed one:",[195,1339,1341],{"className":224,"code":1340,"language":226,"meta":200,"style":200},"def protection_state(path):\n    wb = load_workbook(path)\n    state = {\"workbook\": dict(wb.security) if wb.security else {}}\n    for sheet in wb.worksheets:\n        state[sheet.title] = dict(sheet.protection)\n    return state\n\nbefore = protection_state(\"budget_template.xlsx\")\nafter = protection_state(\"budget_template_fixed.xlsx\")\nprint(before == after)                                  # True\nprint(after[\"Budget\"].get(\"formatColumns\"))             # 0 — resizing still allowed\n",[202,1342,1343,1352,1360,1393,1403,1416,1423,1427,1441,1454,1470],{"__ignoreMap":200},[205,1344,1345,1347,1350],{"class":80,"line":207},[205,1346,512],{"class":233},[205,1348,1349],{"class":515}," protection_state",[205,1351,519],{"class":237},[205,1353,1354,1356,1358],{"class":80,"line":241},[205,1355,524],{"class":237},[205,1357,320],{"class":233},[205,1359,529],{"class":237},[205,1361,1362,1365,1367,1370,1373,1376,1379,1382,1385,1388,1390],{"class":80,"line":249},[205,1363,1364],{"class":237},"    state ",[205,1366,320],{"class":233},[205,1368,1369],{"class":237}," {",[205,1371,1372],{"class":214},"\"workbook\"",[205,1374,1375],{"class":237},": ",[205,1377,1378],{"class":376},"dict",[205,1380,1381],{"class":237},"(wb.security) ",[205,1383,1384],{"class":233},"if",[205,1386,1387],{"class":237}," wb.security ",[205,1389,622],{"class":233},[205,1391,1392],{"class":237}," {}}\n",[205,1394,1395,1397,1399,1401],{"class":80,"line":263},[205,1396,575],{"class":233},[205,1398,578],{"class":237},[205,1400,581],{"class":233},[205,1402,584],{"class":237},[205,1404,1405,1408,1410,1413],{"class":80,"line":270},[205,1406,1407],{"class":237},"        state[sheet.title] ",[205,1409,320],{"class":233},[205,1411,1412],{"class":376}," dict",[205,1414,1415],{"class":237},"(sheet.protection)\n",[205,1417,1418,1420],{"class":80,"line":283},[205,1419,674],{"class":233},[205,1421,1422],{"class":237}," state\n",[205,1424,1425],{"class":80,"line":296},[205,1426,267],{"emptyLinePlaceholder":266},[205,1428,1429,1432,1434,1437,1439],{"class":80,"line":309},[205,1430,1431],{"class":237},"before ",[205,1433,320],{"class":233},[205,1435,1436],{"class":237}," protection_state(",[205,1438,493],{"class":214},[205,1440,484],{"class":237},[205,1442,1443,1446,1448,1450,1452],{"class":80,"line":314},[205,1444,1445],{"class":237},"after ",[205,1447,320],{"class":233},[205,1449,1436],{"class":237},[205,1451,1035],{"class":214},[205,1453,484],{"class":237},[205,1455,1456,1458,1461,1464,1467],{"class":80,"line":326},[205,1457,686],{"class":376},[205,1459,1460],{"class":237},"(before ",[205,1462,1463],{"class":233},"==",[205,1465,1466],{"class":237}," after)                                  ",[205,1468,1469],{"class":414},"# True\n",[205,1471,1472,1474,1477,1479,1482,1485,1488],{"class":80,"line":337},[205,1473,686],{"class":376},[205,1475,1476],{"class":237},"(after[",[205,1478,958],{"class":214},[205,1480,1481],{"class":237},"].get(",[205,1483,1484],{"class":214},"\"formatColumns\"",[205,1486,1487],{"class":237},"))             ",[205,1489,1490],{"class":414},"# 0 — resizing still allowed\n",[10,1492,1493,1494,1497],{},"openpyxl's protection objects can be turned into dictionaries of their XML attributes, which makes the comparison a single equality test: the password hash, every permission flag and the workbook lock must all match. Run it for every file the maintenance loop touched, and fail the run on any difference. The ",[202,1495,1496],{},"formatColumns"," flag shows the kind of detail that survives this way — it was set when the template was created, and it is still there after the fix.",[190,1499,1501],{"id":1500},"encrypted-files-are-a-different-thing","Encrypted files are a different thing",[10,1503,1504,1505,1509,1510,1514],{},"Everything above concerns sheet and structure protection, which are settings inside a readable file. A workbook saved with a ",[1506,1507,1508],"em",{},"password to open"," is encrypted; openpyxl cannot load it and there is nothing to switch off. Decrypting it requires the real password — see ",[14,1511,1513],{"href":1512},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fopen-a-password-protected-excel-file-with-python\u002F","Open a Password-Protected Excel File with Python",". And whichever kind of protection is involved, only change files you own or are responsible for; protection set by someone else is a request not to edit, and removing it without permission is not a technical question.",[20,1516,29,1521,29,1524,29,1527,29,1530,29,1534,29,1539,29,1542,29,1546,29,1550,29,1553,29,1556,29,1565,29,1570,29,1575,29,1578,29,1581,29,1584,29,1587,29,1591,29,1594,29,1597,29,1600,29,1603,29,1606,29,1609,29,1613,29,1615,29,1618,29,1621,29,1624,29,1626,29,1629,29,1633,29,1636,29,1640,29,1644],{"viewBox":1517,"role":23,"ariaLabelledBy":1518,"xmlns":27,"style":28},"4 0 752 238",[1519,1520],"rp-kind-t","rp-kind-d",[31,1522,1523],{"id":1519},"What to do depends on the kind of protection",[35,1525,1526],{"id":1520},"Sheet protection in your own workbook is switched off by resetting SheetProtection and restored from a copy. Workbook structure protection is cleared with wb.security set to None and restored the same way. A password to open needs the real password to decrypt. Protection on someone else's file is a request to ask its owner.",[39,1528],{"x":41,"y":42,"width":43,"height":1529,"fill":45},"238",[39,1531],{"x":1532,"y":49,"width":1533,"height":105,"rx":52,"fill":53,"stroke":54,"style":55},"196.4","367.1",[57,1535,1537],{"transform":1536},"translate(368.0,29.0) scale(1.000)",[61,1538],{"d":181,"fill":64,"stroke":65,"style":66},[68,1540,1541],{"x":137,"y":105,"style":72},"What kind of protection, and whose file is it?",[80,1543],{"x1":137,"y1":1544,"x2":137,"y2":1545,"stroke":54,"style":55},"91.5","111.5",[80,1547],{"x1":1548,"y1":1545,"x2":1549,"y2":1545,"stroke":54,"style":55},"104.0","656.0",[80,1551],{"x1":1548,"y1":1545,"x2":1548,"y2":1552,"stroke":54,"style":55},"157.5",[86,1554],{"points":1555,"fill":89},"104.0,161.5 99.0,152.5 109.0,152.5",[39,1557],{"x":1558,"y":1559,"width":1560,"height":1561,"rx":1562,"fill":45,"stroke":1563,"style":1564},"50.7","121.5","106.5","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[68,1566,1569],{"x":1548,"y":1567,"style":1568},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","sheet, your file",[39,1571],{"x":48,"y":1572,"width":1573,"height":1574,"rx":52,"fill":93,"stroke":94,"style":55},"163.5","168.0","59.0",[68,1576,1577],{"x":1548,"y":881,"style":106},"reset and restore",[68,1579,115],{"x":1548,"y":1580,"style":77},"208.5",[80,1582],{"x1":1583,"y1":1545,"x2":1583,"y2":1552,"stroke":54,"style":55},"288.0",[86,1585],{"points":1586,"fill":89},"288.0,161.5 283.0,152.5 293.0,152.5",[39,1588],{"x":1589,"y":1559,"width":1590,"height":1561,"rx":1562,"fill":45,"stroke":1563,"style":1564},"223.9","128.2",[68,1592,1593],{"x":1583,"y":1567,"style":1568},"structure, your file",[39,1595],{"x":1596,"y":1572,"width":1573,"height":1574,"rx":52,"fill":53,"stroke":54,"style":55},"204.0",[68,1598,1599],{"x":1583,"y":881,"style":72},"wb.security = None",[68,1601,1602],{"x":1583,"y":1580,"style":77},"restore afterwards",[80,1604],{"x1":1605,"y1":1545,"x2":1605,"y2":1552,"stroke":54,"style":55},"472.0",[86,1607],{"points":1608,"fill":89},"472.0,161.5 467.0,152.5 477.0,152.5",[39,1610],{"x":1611,"y":1559,"width":1612,"height":1561,"rx":1562,"fill":45,"stroke":1563,"style":1564},"410.2","123.6",[68,1614,1508],{"x":1605,"y":1567,"style":1568},[39,1616],{"x":1617,"y":1572,"width":1573,"height":1574,"rx":52,"fill":126,"stroke":127,"style":55},"388.0",[68,1619,1620],{"x":1605,"y":881,"style":138},"decrypt",[68,1622,1623],{"x":1605,"y":1580,"style":77},"needs the real password",[80,1625],{"x1":1549,"y1":1545,"x2":1549,"y2":1552,"stroke":54,"style":55},[86,1627],{"points":1628,"fill":89},"656.0,161.5 651.0,152.5 661.0,152.5",[39,1630],{"x":1631,"y":1559,"width":1632,"height":1561,"rx":1562,"fill":45,"stroke":1563,"style":1564},"590.0","132.1",[68,1634,1635],{"x":1549,"y":1567,"style":1568},"someone else's file",[39,1637],{"x":1638,"y":1572,"width":1573,"height":1574,"rx":52,"fill":1639,"stroke":931,"style":55},"572.0","#fee8f2",[68,1641,1643],{"x":1549,"y":881,"style":1642},"font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","ask the owner",[68,1645,1646],{"x":1549,"y":1580,"style":77},"not a technical question",[190,1648,1650],{"id":1649},"common-pitfalls","Common pitfalls",[1652,1653,1654,1662,1668,1678],"ul",{},[1655,1656,1657,1661],"li",{},[1658,1659,1660],"strong",{},"Forgetting to restore."," A maintenance script that unprotects and saves ships unprotected templates. Restore in the same function, as above, so the two steps cannot be separated by a later edit to the script.",[1655,1663,1664,1667],{},[1658,1665,1666],{},"Restoring the wrong sheet's settings."," Key saved settings by sheet title and restore by title; sheet order can change.",[1655,1669,1670,1673,1674,1677],{},[1658,1671,1672],{},"Saving the unprotected state by accident."," If the script fails between unprotecting and restoring, a ",[202,1675,1676],{},"wb.save"," in an exception handler writes the unprotected file. Save only after restoring, and let failures leave the original untouched.",[1655,1679,1680,1683],{},[1658,1681,1682],{},"Assuming protection hides data."," Unprotected or not, every value and formula is readable by any tool. Protection is about editing in Excel, not confidentiality.",[190,1685,1687],{"id":1686},"conclusion","Conclusion",[10,1689,1690,1691,1694,1695,1698,1699,1701,1702,1705],{},"To maintain protected workbooks you own, list their protection first, copy each sheet's ",[202,1692,1693],{},"protection"," and the workbook's ",[202,1696,1697],{},"security",", replace them with an empty ",[202,1700,142],{}," and ",[202,1703,1704],{},"None",", make the change, and assign the saved objects back. The stored password hashes — legacy or SHA-512 — are restored unchanged, so the existing passwords keep working. Encrypted files need their real password, and protection set by others is not yours to remove.",[190,1707,1709],{"id":1708},"frequently-asked-questions","Frequently asked questions",[10,1711,1712,1715],{},[1658,1713,1714],{},"How do I remove sheet protection with openpyxl?","\nReplace the sheet's protection with a fresh SheetProtection() object, or set ws.protection.sheet = False, and save. For workbook structure protection, set wb.security = None. Only do this on workbooks you own or are authorised to maintain.",[10,1717,1718,1721],{},[1658,1719,1720],{},"Can I re-protect the sheet with the original password afterwards?","\nYes, without knowing the password. Copy the protection object before removing it and assign the copy back after your changes. The stored password hash — legacy or SHA-512 — is written back unchanged, so the original password still works in Excel.",[10,1723,1724,1727],{},[1658,1725,1726],{},"Does removing protection change the cells?","\nNo. Cells keep their locked and hidden flags; those only take effect while the sheet is protected. Values, formulas and formatting are untouched.",[10,1729,1730,1733],{},[1658,1731,1732],{},"Can openpyxl remove a password to open?","\nNo. A password to open encrypts the whole file; openpyxl cannot read it at all. You need the real password to decrypt it, for example with msoffcrypto-tool, before any Python library can work with the contents.",[190,1735,1737],{"id":1736},"related","Related",[1652,1739,1740,1746,1753,1760],{},[1655,1741,1742,1743,1745],{},"Up one level: ",[14,1744,17],{"href":16}," — protection, comments and sharing.",[1655,1747,1748,1752],{},[14,1749,1751],{"href":1750},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Flock-cells-and-protect-a-sheet-with-openpyxl\u002F","Lock Cells and Protect a Sheet with openpyxl"," — setting protection up in the first place.",[1655,1754,1755,1759],{},[14,1756,1758],{"href":1757},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fprotect-workbook-structure-with-openpyxl\u002F","Protect Workbook Structure with openpyxl"," — the workbook-level lock.",[1655,1761,1762,1766],{},[14,1763,1765],{"href":1764},"\u002Fautomating-reporting-workflows\u002Fgenerating-excel-reports-from-templates\u002Ffill-excel-template-with-python-openpyxl\u002F","Fill an Excel Template with Python and openpyxl"," — templates that are often protected.",[1768,1769,1770],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":200,"searchDepth":241,"depth":241,"links":1772},[1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783],{"id":192,"depth":241,"text":193},{"id":498,"depth":241,"text":499},{"id":709,"depth":241,"text":710},{"id":941,"depth":241,"text":942},{"id":1057,"depth":241,"text":1058},{"id":1333,"depth":241,"text":1334},{"id":1500,"depth":241,"text":1501},{"id":1649,"depth":241,"text":1650},{"id":1686,"depth":241,"text":1687},{"id":1708,"depth":241,"text":1709},{"id":1736,"depth":241,"text":1737},"2026-09-23","Update your own protected report templates from Python — turn off sheet and workbook structure protection, make changes, and put the original protection back exactly as it was, including Excel's SHA-512 password hashes. Covers what openpyxl keeps, what \"unprotecting\" does and does not change, and batch maintenance of many files.","md",[1788,1790,1792,1794],{"q":1714,"a":1789},"Replace the sheet's protection with a fresh SheetProtection() object, or set ws.protection.sheet = False, and save. For workbook structure protection, set wb.security = None. Only do this on workbooks you own or are authorised to maintain.",{"q":1720,"a":1791},"Yes, without knowing the password. Copy the protection object before removing it and assign the copy back after your changes. The stored password hash — legacy or SHA-512 — is written back unchanged, so the original password still works in Excel.",{"q":1726,"a":1793},"No. Cells keep their locked and hidden flags; those only take effect while the sheet is protected. Values, formulas and formatting are untouched.",{"q":1732,"a":1795},"No. A password to open encrypts the whole file; openpyxl cannot read it at all. You need the real password to decrypt it, for example with msoffcrypto-tool, before any Python library can work with the contents.","remove sheet protection from a workbook you own with openpyxl",null,{"breadcrumb":1799},[1800,1803,1806],{"name":1801,"item":1802},"Home","\u002F",{"name":1804,"item":1805},"Formatting and Charting Excel Reports with Python","\u002Fformatting-and-charting-excel-reports-with-python\u002F",{"name":17,"item":16},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl",{"title":1809,"description":1810},"Remove Sheet Protection with openpyxl (Your Own Workbooks)","Unprotect sheets and workbook structure in workbooks you own with openpyxl — SheetProtection reset, wb.security, preserving and restoring the original protection with copy(), SHA-512 hashes, locked and hidden cell flags, and encrypted files that need the real password.","remove-sheet-protection-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-sheet-protection-with-openpyxl\u002Findex",[1814,1815],"protection-and-sharing","openpyxl","how-to","y_B2WEvTnNFPKwIVoCJyXXMCYx0ZjgytBLMo7fuggY8",[1819,1823],{"title":1820,"path":1821,"stem":1822,"children":-1},"Remove Hidden Data Before Sharing an Excel File","\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-hidden-data-before-sharing-an-excel-file","formatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fremove-hidden-data-before-sharing-an-excel-file\u002Findex",{"title":1824,"path":1825,"stem":1826,"children":-1},"Styling Excel Cells with openpyxl","\u002Fformatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl","formatting-and-charting-excel-reports-with-python\u002Fstyling-excel-cells-with-openpyxl\u002Findex",[1828,1830],{"path":1829,"title":1804},"\u002Fformatting-and-charting-excel-reports-with-python",{"path":1831,"title":17},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks",[],[1834,1837,1840,1843,1846,1849],{"path":1835,"title":1836,"kind":1816},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fanonymise-personal-data-in-an-excel-file-with-python","Anonymise Personal Data in an Excel File with Python",{"path":1838,"title":1839,"kind":1816},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fpassword-protect-a-pdf-exported-from-excel","Password-Protect a PDF Exported from Excel",{"path":1841,"title":1842,"kind":1816},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fsign-a-pdf-report-digitally-with-python","Sign a PDF Report Digitally with Python",{"path":1844,"title":1845,"kind":1816},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fbuilding-excel-reports-with-xlsxwriter\u002Fdefine-names-and-protect-sheets-with-xlsxwriter","Define Names and Protect Sheets with XlsxWriter",{"path":1847,"title":1848,"kind":1816},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fadd-comments-and-notes-to-excel-cells-with-python","Add Comments and Notes to Excel Cells with Python",{"path":1850,"title":1851,"kind":1816},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fprotecting-and-sharing-excel-workbooks\u002Fhide-sheets-rows-and-columns-with-openpyxl","Hide Sheets, Rows and Columns with openpyxl",1790972117058]