[{"data":1,"prerenderedAt":2027},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl":2019},{"id":4,"title":5,"body":6,"dateModified":1988,"datePublished":1988,"description":1989,"extension":1990,"faq":1991,"meta":2000,"navigation":190,"path":2011,"seo":2012,"slug":2015,"stem":2016,"type":2017,"__hash__":2018},"docs\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl\u002Findex.md","Rename, Reorder and Delete Excel Sheets with openpyxl",{"type":7,"value":8,"toc":1974},"minimark",[9,13,22,127,132,158,162,379,383,390,803,806,810,829,1085,1096,1099,1103,1113,1259,1267,1275,1279,1290,1390,1393,1433,1443,1523,1527,1530,1621,1720,1731,1735,1859,1863,1866,1873,1877,1883,1887,1898,1908,1917,1923,1927,1930,1939,1942,1970],[10,11,12],"p",{},"Sheet housekeeping looks like the least risky code in a reporting script and quietly is not. A rename can break every formula that referenced the old name, a deletion can invalidate a chart's series, and both fail in ways that only appear when someone opens the file in Excel — long after the job reported success.",[10,14,15,16,21],{},"None of that is hard to avoid, but it does need knowing. This guide covers the naming rules Excel enforces, reordering, the difference between deleting and hiding, and choosing which tab a reader lands on. It is part of ",[17,18,20],"a",{"href":19},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002F","Working with Multiple Excel Sheets in Python",".",[23,24,32,33,32,37,32,41,32,48,32,55,32,65,32,71,32,76,32,81,32,85,32,88,32,91,32,95,32,98,32,104,32,110,32,114,32,119,32,124],"svg",{"viewBox":25,"role":26,"ariaLabelledBy":27,"xmlns":30,"style":31},"0 0 740 240","img",[28,29],"sh-rules-t","sh-rules-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:740px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[34,35,36],"title",{"id":28},"What makes a sheet title legal",[38,39,40],"desc",{"id":29},"A sheet title must be between one and thirty-one characters, must not contain backslash, forward slash, question mark, asterisk, square brackets or colon, must not be the reserved name History, and must be unique within the workbook. Excel refuses to open a file that breaks any of these rules.",[42,43],"rect",{"x":44,"y":44,"width":45,"height":46,"fill":47},"0","740","240","#ffffff",[49,50,54],"text",{"x":51,"y":52,"style":53},"370","30","font-size:12.5px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","Excel enforces these on open — openpyxl will happily write a file that fails them",[42,56],{"x":57,"y":58,"width":59,"height":60,"rx":61,"fill":62,"stroke":63,"style":64},"16","50","228","76","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[49,66,70],{"x":67,"y":68,"style":69},"130","78","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","1 to 31 characters",[49,72,75],{"x":67,"y":73,"style":74},"102","font-size:11px;fill:var(--text,#172033);text-anchor:middle","\"Q1 2026 regional detail\" fits",[42,77],{"x":78,"y":58,"width":59,"height":60,"rx":61,"fill":79,"stroke":80,"style":64},"256","#fce9e9","var(--accent-ink,#be185d)",[49,82,84],{"x":51,"y":68,"style":83},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","no \\ \u002F ? * [ ] :",[49,86,87],{"x":51,"y":73,"style":74},"\"2026\u002F07\" is rejected",[42,89],{"x":90,"y":58,"width":59,"height":60,"rx":61,"fill":79,"stroke":80,"style":64},"496",[49,92,94],{"x":93,"y":68,"style":83},"610","not \"History\"",[49,96,97],{"x":93,"y":73,"style":74},"reserved by Excel",[42,99],{"x":57,"y":100,"width":101,"height":60,"rx":61,"fill":102,"stroke":103,"style":64},"138","344","#fdefd8","var(--gold,#b4740a)",[49,105,109],{"x":106,"y":107,"style":108},"188","166","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","unique within the workbook",[49,111,113],{"x":106,"y":112,"style":74},"190","case-insensitively: \"Jan\" and \"jan\" collide",[42,115],{"x":116,"y":100,"width":101,"height":60,"rx":61,"fill":117,"stroke":118,"style":64},"380","#ebebfd","var(--brand,#5b5cf0)",[49,120,123],{"x":121,"y":107,"style":122},"552","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","a name with a space needs quotes in formulas",[49,125,126],{"x":121,"y":112,"style":74},"='Q1 detail'!B2 — the apostrophes are required",[128,129,131],"h2",{"id":130},"prerequisites","Prerequisites",[133,134,139],"pre",{"className":135,"code":136,"language":137,"meta":138,"style":138},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl\n","bash","",[140,141,142],"code",{"__ignoreMap":138},[143,144,147,151,155],"span",{"class":145,"line":146},"line",1,[143,148,150],{"class":149},"sMTad","pip",[143,152,154],{"class":153},"srMev"," install",[143,156,157],{"class":153}," openpyxl\n",[128,159,161],{"id":160},"step-1-a-workbook-to-tidy","Step 1: A workbook to tidy",[133,163,167],{"className":164,"code":165,"language":166,"meta":138,"style":138},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import Workbook\n\nwb = Workbook()\nwb.active.title = \"Sheet1\"\nfor name in [\"Mar\", \"Jan\", \"Feb\", \"_scratch\", \"old_notes\"]:\n    wb.create_sheet(name)\n\nwb[\"Jan\"][\"A1\"] = 120\nwb[\"Feb\"][\"A1\"] = 131\nwb[\"Mar\"][\"A1\"] = 140\nwb[\"Sheet1\"][\"A1\"] = \"=Jan!A1+Feb!A1+Mar!A1\"\nwb.save(\"messy.xlsx\")\n\nprint(wb.sheetnames)\n# ['Sheet1', 'Mar', 'Jan', 'Feb', '_scratch', 'old_notes']\n","python",[140,168,169,185,192,204,215,257,263,268,291,309,327,346,358,363,372],{"__ignoreMap":138},[143,170,171,175,179,182],{"class":145,"line":146},[143,172,174],{"class":173},"s-kum","from",[143,176,178],{"class":177},"skGVy"," openpyxl ",[143,180,181],{"class":173},"import",[143,183,184],{"class":177}," Workbook\n",[143,186,188],{"class":145,"line":187},2,[143,189,191],{"emptyLinePlaceholder":190},true,"\n",[143,193,195,198,201],{"class":145,"line":194},3,[143,196,197],{"class":177},"wb ",[143,199,200],{"class":173},"=",[143,202,203],{"class":177}," Workbook()\n",[143,205,207,210,212],{"class":145,"line":206},4,[143,208,209],{"class":177},"wb.active.title ",[143,211,200],{"class":173},[143,213,214],{"class":153}," \"Sheet1\"\n",[143,216,218,221,224,227,230,233,236,239,241,244,246,249,251,254],{"class":145,"line":217},5,[143,219,220],{"class":173},"for",[143,222,223],{"class":177}," name ",[143,225,226],{"class":173},"in",[143,228,229],{"class":177}," [",[143,231,232],{"class":153},"\"Mar\"",[143,234,235],{"class":177},", ",[143,237,238],{"class":153},"\"Jan\"",[143,240,235],{"class":177},[143,242,243],{"class":153},"\"Feb\"",[143,245,235],{"class":177},[143,247,248],{"class":153},"\"_scratch\"",[143,250,235],{"class":177},[143,252,253],{"class":153},"\"old_notes\"",[143,255,256],{"class":177},"]:\n",[143,258,260],{"class":145,"line":259},6,[143,261,262],{"class":177},"    wb.create_sheet(name)\n",[143,264,266],{"class":145,"line":265},7,[143,267,191],{"emptyLinePlaceholder":190},[143,269,271,274,276,279,282,285,287],{"class":145,"line":270},8,[143,272,273],{"class":177},"wb[",[143,275,238],{"class":153},[143,277,278],{"class":177},"][",[143,280,281],{"class":153},"\"A1\"",[143,283,284],{"class":177},"] ",[143,286,200],{"class":173},[143,288,290],{"class":289},"sP0c6"," 120\n",[143,292,294,296,298,300,302,304,306],{"class":145,"line":293},9,[143,295,273],{"class":177},[143,297,243],{"class":153},[143,299,278],{"class":177},[143,301,281],{"class":153},[143,303,284],{"class":177},[143,305,200],{"class":173},[143,307,308],{"class":289}," 131\n",[143,310,312,314,316,318,320,322,324],{"class":145,"line":311},10,[143,313,273],{"class":177},[143,315,232],{"class":153},[143,317,278],{"class":177},[143,319,281],{"class":153},[143,321,284],{"class":177},[143,323,200],{"class":173},[143,325,326],{"class":289}," 140\n",[143,328,330,332,335,337,339,341,343],{"class":145,"line":329},11,[143,331,273],{"class":177},[143,333,334],{"class":153},"\"Sheet1\"",[143,336,278],{"class":177},[143,338,281],{"class":153},[143,340,284],{"class":177},[143,342,200],{"class":173},[143,344,345],{"class":153}," \"=Jan!A1+Feb!A1+Mar!A1\"\n",[143,347,349,352,355],{"class":145,"line":348},12,[143,350,351],{"class":177},"wb.save(",[143,353,354],{"class":153},"\"messy.xlsx\"",[143,356,357],{"class":177},")\n",[143,359,361],{"class":145,"line":360},13,[143,362,191],{"emptyLinePlaceholder":190},[143,364,366,369],{"class":145,"line":365},14,[143,367,368],{"class":289},"print",[143,370,371],{"class":177},"(wb.sheetnames)\n",[143,373,375],{"class":145,"line":374},15,[143,376,378],{"class":377},"s-wDw","# ['Sheet1', 'Mar', 'Jan', 'Feb', '_scratch', 'old_notes']\n",[128,380,382],{"id":381},"step-2-rename-safely","Step 2: Rename safely",[10,384,385,386,389],{},"Assign to ",[140,387,388],{},".title",", but sanitise first — openpyxl will write an illegal name and Excel will then refuse to open the file:",[133,391,393],{"className":164,"code":392,"language":166,"meta":138,"style":138},"import re\n\nILLEGAL = re.compile(r\"[\\\\\u002F?*\\[\\]:]\")\n\n\ndef safe_title(name, existing=(), limit=31):\n    \"\"\"Return a legal, unique sheet title.\"\"\"\n    clean = ILLEGAL.sub(\"-\", str(name)).strip() or \"Sheet\"\n    if clean.lower() == \"history\":\n        clean = \"History data\"\n    clean = clean[:limit]\n\n    if clean.lower() not in {e.lower() for e in existing}:\n        return clean\n    stem = clean[: limit - 4]\n    for n in range(2, 100):\n        candidate = f\"{stem} ({n})\"\n        if candidate.lower() not in {e.lower() for e in existing}:\n            return candidate\n    raise ValueError(f\"cannot make a unique title from {name!r}\")\n\n\nfrom openpyxl import load_workbook\n\nwb = load_workbook(\"messy.xlsx\")\nwb[\"Sheet1\"].title = safe_title(\"Summary\", wb.sheetnames)\nwb.save(\"messy.xlsx\")\n",[140,394,395,402,406,447,451,455,480,485,515,532,542,551,555,580,588,607,634,669,692,701,732,737,742,754,759,773,794],{"__ignoreMap":138},[143,396,397,399],{"class":145,"line":146},[143,398,181],{"class":173},[143,400,401],{"class":177}," re\n",[143,403,404],{"class":145,"line":187},[143,405,191],{"emptyLinePlaceholder":190},[143,407,408,411,414,417,420,423,426,430,434,437,440,443,445],{"class":145,"line":194},[143,409,410],{"class":289},"ILLEGAL",[143,412,413],{"class":173}," =",[143,415,416],{"class":177}," re.compile(",[143,418,419],{"class":173},"r",[143,421,422],{"class":153},"\"",[143,424,425],{"class":289},"[",[143,427,429],{"class":428},"s_b0D","\\\\",[143,431,433],{"class":432},"sSjpA","\u002F?*",[143,435,436],{"class":428},"\\[\\]",[143,438,439],{"class":432},":",[143,441,442],{"class":289},"]",[143,444,422],{"class":153},[143,446,357],{"class":177},[143,448,449],{"class":145,"line":206},[143,450,191],{"emptyLinePlaceholder":190},[143,452,453],{"class":145,"line":217},[143,454,191],{"emptyLinePlaceholder":190},[143,456,457,460,464,467,469,472,474,477],{"class":145,"line":259},[143,458,459],{"class":173},"def",[143,461,463],{"class":462},"s_Opv"," safe_title",[143,465,466],{"class":177},"(name, existing",[143,468,200],{"class":173},[143,470,471],{"class":177},"(), limit",[143,473,200],{"class":173},[143,475,476],{"class":289},"31",[143,478,479],{"class":177},"):\n",[143,481,482],{"class":145,"line":265},[143,483,484],{"class":153},"    \"\"\"Return a legal, unique sheet title.\"\"\"\n",[143,486,487,490,492,495,498,501,503,506,509,512],{"class":145,"line":270},[143,488,489],{"class":177},"    clean ",[143,491,200],{"class":173},[143,493,494],{"class":289}," ILLEGAL",[143,496,497],{"class":177},".sub(",[143,499,500],{"class":153},"\"-\"",[143,502,235],{"class":177},[143,504,505],{"class":289},"str",[143,507,508],{"class":177},"(name)).strip() ",[143,510,511],{"class":173},"or",[143,513,514],{"class":153}," \"Sheet\"\n",[143,516,517,520,523,526,529],{"class":145,"line":293},[143,518,519],{"class":173},"    if",[143,521,522],{"class":177}," clean.lower() ",[143,524,525],{"class":173},"==",[143,527,528],{"class":153}," \"history\"",[143,530,531],{"class":177},":\n",[143,533,534,537,539],{"class":145,"line":311},[143,535,536],{"class":177},"        clean ",[143,538,200],{"class":173},[143,540,541],{"class":153}," \"History data\"\n",[143,543,544,546,548],{"class":145,"line":329},[143,545,489],{"class":177},[143,547,200],{"class":173},[143,549,550],{"class":177}," clean[:limit]\n",[143,552,553],{"class":145,"line":348},[143,554,191],{"emptyLinePlaceholder":190},[143,556,557,559,561,564,567,570,572,575,577],{"class":145,"line":360},[143,558,519],{"class":173},[143,560,522],{"class":177},[143,562,563],{"class":173},"not",[143,565,566],{"class":173}," in",[143,568,569],{"class":177}," {e.lower() ",[143,571,220],{"class":173},[143,573,574],{"class":177}," e ",[143,576,226],{"class":173},[143,578,579],{"class":177}," existing}:\n",[143,581,582,585],{"class":145,"line":365},[143,583,584],{"class":173},"        return",[143,586,587],{"class":177}," clean\n",[143,589,590,593,595,598,601,604],{"class":145,"line":374},[143,591,592],{"class":177},"    stem ",[143,594,200],{"class":173},[143,596,597],{"class":177}," clean[: limit ",[143,599,600],{"class":173},"-",[143,602,603],{"class":289}," 4",[143,605,606],{"class":177},"]\n",[143,608,610,613,616,618,621,624,627,629,632],{"class":145,"line":609},16,[143,611,612],{"class":173},"    for",[143,614,615],{"class":177}," n ",[143,617,226],{"class":173},[143,619,620],{"class":289}," range",[143,622,623],{"class":177},"(",[143,625,626],{"class":289},"2",[143,628,235],{"class":177},[143,630,631],{"class":289},"100",[143,633,479],{"class":177},[143,635,637,640,642,645,647,650,653,656,659,661,664,666],{"class":145,"line":636},17,[143,638,639],{"class":177},"        candidate ",[143,641,200],{"class":173},[143,643,644],{"class":173}," f",[143,646,422],{"class":153},[143,648,649],{"class":432},"{",[143,651,652],{"class":177},"stem",[143,654,655],{"class":432},"}",[143,657,658],{"class":153}," (",[143,660,649],{"class":432},[143,662,663],{"class":177},"n",[143,665,655],{"class":432},[143,667,668],{"class":153},")\"\n",[143,670,672,675,678,680,682,684,686,688,690],{"class":145,"line":671},18,[143,673,674],{"class":173},"        if",[143,676,677],{"class":177}," candidate.lower() ",[143,679,563],{"class":173},[143,681,566],{"class":173},[143,683,569],{"class":177},[143,685,220],{"class":173},[143,687,574],{"class":177},[143,689,226],{"class":173},[143,691,579],{"class":177},[143,693,695,698],{"class":145,"line":694},19,[143,696,697],{"class":173},"            return",[143,699,700],{"class":177}," candidate\n",[143,702,704,707,710,712,715,718,720,723,726,728,730],{"class":145,"line":703},20,[143,705,706],{"class":173},"    raise",[143,708,709],{"class":289}," ValueError",[143,711,623],{"class":177},[143,713,714],{"class":173},"f",[143,716,717],{"class":153},"\"cannot make a unique title from ",[143,719,649],{"class":432},[143,721,722],{"class":177},"name",[143,724,725],{"class":173},"!r",[143,727,655],{"class":432},[143,729,422],{"class":153},[143,731,357],{"class":177},[143,733,735],{"class":145,"line":734},21,[143,736,191],{"emptyLinePlaceholder":190},[143,738,740],{"class":145,"line":739},22,[143,741,191],{"emptyLinePlaceholder":190},[143,743,745,747,749,751],{"class":145,"line":744},23,[143,746,174],{"class":173},[143,748,178],{"class":177},[143,750,181],{"class":173},[143,752,753],{"class":177}," load_workbook\n",[143,755,757],{"class":145,"line":756},24,[143,758,191],{"emptyLinePlaceholder":190},[143,760,762,764,766,769,771],{"class":145,"line":761},25,[143,763,197],{"class":177},[143,765,200],{"class":173},[143,767,768],{"class":177}," load_workbook(",[143,770,354],{"class":153},[143,772,357],{"class":177},[143,774,776,778,780,783,785,788,791],{"class":145,"line":775},26,[143,777,273],{"class":177},[143,779,334],{"class":153},[143,781,782],{"class":177},"].title ",[143,784,200],{"class":173},[143,786,787],{"class":177}," safe_title(",[143,789,790],{"class":153},"\"Summary\"",[143,792,793],{"class":177},", wb.sheetnames)\n",[143,795,797,799,801],{"class":145,"line":796},27,[143,798,351],{"class":177},[143,800,354],{"class":153},[143,802,357],{"class":177},[10,804,805],{},"Truncating to 31 characters is the rule that bites in generated reports, because a name built from a customer or a period easily exceeds it — and a title that is silently cut can collide with another that was cut to the same prefix, which is why the uniqueness check runs after the truncation rather than before.",[128,807,809],{"id":808},"step-3-fix-the-formulas-the-rename-broke","Step 3: Fix the formulas the rename broke",[10,811,812,813,817,818,821,822,825,826,439],{},"Excel rewrites references when ",[814,815,816],"em",{},"it"," renames a tab. openpyxl does not, so a formula that said ",[140,819,820],{},"=Jan!A1+Feb!A1"," still says exactly that even if ",[140,823,824],{},"Jan"," is now ",[140,827,828],{},"January",[133,830,832],{"className":164,"code":831,"language":166,"meta":138,"style":138},"def rename_sheet(wb, old, new):\n    \"\"\"Rename a sheet and repoint formula references that named it.\"\"\"\n    new = safe_title(new, [n for n in wb.sheetnames if n != old])\n    wb[old].title = new\n\n    quoted_old, quoted_new = f\"'{old}'!\", f\"'{new}'!\"\n    plain_old, plain_new = f\"{old}!\", f\"{new}!\"\n\n    for ws in wb.worksheets:\n        for row in ws.iter_rows():\n            for cell in row:\n                if isinstance(cell.value, str) and cell.value.startswith(\"=\"):\n                    updated = (cell.value\n                               .replace(quoted_old, quoted_new)\n                               .replace(plain_old, plain_new))\n                    if updated != cell.value:\n                        cell.value = updated\n    return new\n",[140,833,834,844,849,879,889,893,931,966,970,982,995,1008,1035,1045,1050,1055,1068,1078],{"__ignoreMap":138},[143,835,836,838,841],{"class":145,"line":146},[143,837,459],{"class":173},[143,839,840],{"class":462}," rename_sheet",[143,842,843],{"class":177},"(wb, old, new):\n",[143,845,846],{"class":145,"line":187},[143,847,848],{"class":153},"    \"\"\"Rename a sheet and repoint formula references that named it.\"\"\"\n",[143,850,851,854,856,859,861,863,865,868,871,873,876],{"class":145,"line":194},[143,852,853],{"class":177},"    new ",[143,855,200],{"class":173},[143,857,858],{"class":177}," safe_title(new, [n ",[143,860,220],{"class":173},[143,862,615],{"class":177},[143,864,226],{"class":173},[143,866,867],{"class":177}," wb.sheetnames ",[143,869,870],{"class":173},"if",[143,872,615],{"class":177},[143,874,875],{"class":173},"!=",[143,877,878],{"class":177}," old])\n",[143,880,881,884,886],{"class":145,"line":206},[143,882,883],{"class":177},"    wb[old].title ",[143,885,200],{"class":173},[143,887,888],{"class":177}," new\n",[143,890,891],{"class":145,"line":217},[143,892,191],{"emptyLinePlaceholder":190},[143,894,895,898,900,902,905,907,910,912,915,917,919,921,923,926,928],{"class":145,"line":259},[143,896,897],{"class":177},"    quoted_old, quoted_new ",[143,899,200],{"class":173},[143,901,644],{"class":173},[143,903,904],{"class":153},"\"'",[143,906,649],{"class":432},[143,908,909],{"class":177},"old",[143,911,655],{"class":432},[143,913,914],{"class":153},"'!\"",[143,916,235],{"class":177},[143,918,714],{"class":173},[143,920,904],{"class":153},[143,922,649],{"class":432},[143,924,925],{"class":177},"new",[143,927,655],{"class":432},[143,929,930],{"class":153},"'!\"\n",[143,932,933,936,938,940,942,944,946,948,951,953,955,957,959,961,963],{"class":145,"line":265},[143,934,935],{"class":177},"    plain_old, plain_new ",[143,937,200],{"class":173},[143,939,644],{"class":173},[143,941,422],{"class":153},[143,943,649],{"class":432},[143,945,909],{"class":177},[143,947,655],{"class":432},[143,949,950],{"class":153},"!\"",[143,952,235],{"class":177},[143,954,714],{"class":173},[143,956,422],{"class":153},[143,958,649],{"class":432},[143,960,925],{"class":177},[143,962,655],{"class":432},[143,964,965],{"class":153},"!\"\n",[143,967,968],{"class":145,"line":270},[143,969,191],{"emptyLinePlaceholder":190},[143,971,972,974,977,979],{"class":145,"line":293},[143,973,612],{"class":173},[143,975,976],{"class":177}," ws ",[143,978,226],{"class":173},[143,980,981],{"class":177}," wb.worksheets:\n",[143,983,984,987,990,992],{"class":145,"line":311},[143,985,986],{"class":173},"        for",[143,988,989],{"class":177}," row ",[143,991,226],{"class":173},[143,993,994],{"class":177}," ws.iter_rows():\n",[143,996,997,1000,1003,1005],{"class":145,"line":329},[143,998,999],{"class":173},"            for",[143,1001,1002],{"class":177}," cell ",[143,1004,226],{"class":173},[143,1006,1007],{"class":177}," row:\n",[143,1009,1010,1013,1016,1019,1021,1024,1027,1030,1033],{"class":145,"line":348},[143,1011,1012],{"class":173},"                if",[143,1014,1015],{"class":289}," isinstance",[143,1017,1018],{"class":177},"(cell.value, ",[143,1020,505],{"class":289},[143,1022,1023],{"class":177},") ",[143,1025,1026],{"class":173},"and",[143,1028,1029],{"class":177}," cell.value.startswith(",[143,1031,1032],{"class":153},"\"=\"",[143,1034,479],{"class":177},[143,1036,1037,1040,1042],{"class":145,"line":360},[143,1038,1039],{"class":177},"                    updated ",[143,1041,200],{"class":173},[143,1043,1044],{"class":177}," (cell.value\n",[143,1046,1047],{"class":145,"line":365},[143,1048,1049],{"class":177},"                               .replace(quoted_old, quoted_new)\n",[143,1051,1052],{"class":145,"line":374},[143,1053,1054],{"class":177},"                               .replace(plain_old, plain_new))\n",[143,1056,1057,1060,1063,1065],{"class":145,"line":609},[143,1058,1059],{"class":173},"                    if",[143,1061,1062],{"class":177}," updated ",[143,1064,875],{"class":173},[143,1066,1067],{"class":177}," cell.value:\n",[143,1069,1070,1073,1075],{"class":145,"line":636},[143,1071,1072],{"class":177},"                        cell.value ",[143,1074,200],{"class":173},[143,1076,1077],{"class":177}," updated\n",[143,1079,1080,1083],{"class":145,"line":671},[143,1081,1082],{"class":173},"    return",[143,1084,888],{"class":177},[10,1086,1087,1088,1091,1092,1095],{},"This is a text substitution, so treat it as a best effort rather than a parser: a sheet named ",[140,1089,1090],{},"Q1"," will also match inside a name like ",[140,1093,1094],{},"Q1 detail!",", and a formula referencing another workbook will not be handled. For anything beyond simple names, the safer approach is to avoid renaming at all — decide the sheet names when the workbook is created, which is entirely within your control in a generated report.",[10,1097,1098],{},"Charts and defined names hold their own references and are not touched by the loop above, so a chart whose series pointed at the old name will need rebuilding.",[128,1100,1102],{"id":1101},"step-4-reorder-the-tabs","Step 4: Reorder the tabs",[10,1104,1105,1108,1109,1112],{},[140,1106,1107],{},"move_sheet"," shifts a sheet by an offset, and ",[140,1110,1111],{},"wb._sheets"," holds the order. Working with the public method and a target list is the readable way to impose an order:",[133,1114,1116],{"className":164,"code":1115,"language":166,"meta":138,"style":138},"def order_sheets(wb, preferred):\n    \"\"\"Put the named sheets first, in the order given; leave the rest behind them.\"\"\"\n    for position, name in enumerate(preferred):\n        if name not in wb.sheetnames:\n            continue\n        current = wb.sheetnames.index(name)\n        wb.move_sheet(name, offset=position - current)\n    return wb.sheetnames\n\n\nwb = load_workbook(\"messy.xlsx\")\nprint(order_sheets(wb, [\"Summary\", \"Jan\", \"Feb\", \"Mar\"]))\n# ['Summary', 'Jan', 'Feb', 'Mar', '_scratch', 'old_notes']\nwb.save(\"messy.xlsx\")\n",[140,1117,1118,1128,1133,1148,1161,1166,1176,1195,1202,1206,1210,1222,1246,1251],{"__ignoreMap":138},[143,1119,1120,1122,1125],{"class":145,"line":146},[143,1121,459],{"class":173},[143,1123,1124],{"class":462}," order_sheets",[143,1126,1127],{"class":177},"(wb, preferred):\n",[143,1129,1130],{"class":145,"line":187},[143,1131,1132],{"class":153},"    \"\"\"Put the named sheets first, in the order given; leave the rest behind them.\"\"\"\n",[143,1134,1135,1137,1140,1142,1145],{"class":145,"line":194},[143,1136,612],{"class":173},[143,1138,1139],{"class":177}," position, name ",[143,1141,226],{"class":173},[143,1143,1144],{"class":289}," enumerate",[143,1146,1147],{"class":177},"(preferred):\n",[143,1149,1150,1152,1154,1156,1158],{"class":145,"line":206},[143,1151,674],{"class":173},[143,1153,223],{"class":177},[143,1155,563],{"class":173},[143,1157,566],{"class":173},[143,1159,1160],{"class":177}," wb.sheetnames:\n",[143,1162,1163],{"class":145,"line":217},[143,1164,1165],{"class":173},"            continue\n",[143,1167,1168,1171,1173],{"class":145,"line":259},[143,1169,1170],{"class":177},"        current ",[143,1172,200],{"class":173},[143,1174,1175],{"class":177}," wb.sheetnames.index(name)\n",[143,1177,1178,1181,1185,1187,1190,1192],{"class":145,"line":265},[143,1179,1180],{"class":177},"        wb.move_sheet(name, ",[143,1182,1184],{"class":1183},"sa561","offset",[143,1186,200],{"class":173},[143,1188,1189],{"class":177},"position ",[143,1191,600],{"class":173},[143,1193,1194],{"class":177}," current)\n",[143,1196,1197,1199],{"class":145,"line":270},[143,1198,1082],{"class":173},[143,1200,1201],{"class":177}," wb.sheetnames\n",[143,1203,1204],{"class":145,"line":293},[143,1205,191],{"emptyLinePlaceholder":190},[143,1207,1208],{"class":145,"line":311},[143,1209,191],{"emptyLinePlaceholder":190},[143,1211,1212,1214,1216,1218,1220],{"class":145,"line":329},[143,1213,197],{"class":177},[143,1215,200],{"class":173},[143,1217,768],{"class":177},[143,1219,354],{"class":153},[143,1221,357],{"class":177},[143,1223,1224,1226,1229,1231,1233,1235,1237,1239,1241,1243],{"class":145,"line":348},[143,1225,368],{"class":289},[143,1227,1228],{"class":177},"(order_sheets(wb, [",[143,1230,790],{"class":153},[143,1232,235],{"class":177},[143,1234,238],{"class":153},[143,1236,235],{"class":177},[143,1238,243],{"class":153},[143,1240,235],{"class":177},[143,1242,232],{"class":153},[143,1244,1245],{"class":177},"]))\n",[143,1247,1248],{"class":145,"line":360},[143,1249,1250],{"class":377},"# ['Summary', 'Jan', 'Feb', 'Mar', '_scratch', 'old_notes']\n",[143,1252,1253,1255,1257],{"class":145,"line":365},[143,1254,351],{"class":177},[143,1256,354],{"class":153},[143,1258,357],{"class":177},[10,1260,1261,1263,1264,1266],{},[140,1262,1107],{}," takes an ",[814,1265,1184],{},", not a destination index, which is the most common source of confusion — moving a sheet to position 0 means passing a negative offset equal to its current index. Computing the offset from the current position, as above, sidesteps having to think about it.",[10,1268,1269,1270,1274],{},"Tab order is not just cosmetic in a multi-sheet report: readers open the first tab, and the summary belongs there. That is the ordering ",[17,1271,1273],{"href":1272},"\u002Fautomating-reporting-workflows\u002Fbuilding-multi-sheet-excel-dashboards\u002Fadd-summary-sheet-to-excel-report-python\u002F","Add a Summary Sheet to an Excel Report in Python"," assumes.",[128,1276,1278],{"id":1277},"step-5-delete-or-hide","Step 5: Delete, or hide",[10,1280,1281,1282,1285,1286,1289],{},"Deleting is ",[140,1283,1284],{},"del wb[name]"," or ",[140,1287,1288],{},"wb.remove(ws)",". Both are unconditional, and both will break anything that referenced the sheet:",[133,1291,1293],{"className":164,"code":1292,"language":166,"meta":138,"style":138},"wb = load_workbook(\"messy.xlsx\")\n\nfor name in [\"_scratch\", \"old_notes\"]:\n    if name in wb.sheetnames:\n        del wb[name]\n\nif len(wb.sheetnames) == 0:\n    raise RuntimeError(\"a workbook must keep at least one sheet\")\nwb.save(\"messy.xlsx\")\n",[140,1294,1295,1307,1311,1329,1339,1347,1351,1368,1382],{"__ignoreMap":138},[143,1296,1297,1299,1301,1303,1305],{"class":145,"line":146},[143,1298,197],{"class":177},[143,1300,200],{"class":173},[143,1302,768],{"class":177},[143,1304,354],{"class":153},[143,1306,357],{"class":177},[143,1308,1309],{"class":145,"line":187},[143,1310,191],{"emptyLinePlaceholder":190},[143,1312,1313,1315,1317,1319,1321,1323,1325,1327],{"class":145,"line":194},[143,1314,220],{"class":173},[143,1316,223],{"class":177},[143,1318,226],{"class":173},[143,1320,229],{"class":177},[143,1322,248],{"class":153},[143,1324,235],{"class":177},[143,1326,253],{"class":153},[143,1328,256],{"class":177},[143,1330,1331,1333,1335,1337],{"class":145,"line":206},[143,1332,519],{"class":173},[143,1334,223],{"class":177},[143,1336,226],{"class":173},[143,1338,1160],{"class":177},[143,1340,1341,1344],{"class":145,"line":217},[143,1342,1343],{"class":173},"        del",[143,1345,1346],{"class":177}," wb[name]\n",[143,1348,1349],{"class":145,"line":259},[143,1350,191],{"emptyLinePlaceholder":190},[143,1352,1353,1355,1358,1361,1363,1366],{"class":145,"line":265},[143,1354,870],{"class":173},[143,1356,1357],{"class":289}," len",[143,1359,1360],{"class":177},"(wb.sheetnames) ",[143,1362,525],{"class":173},[143,1364,1365],{"class":289}," 0",[143,1367,531],{"class":177},[143,1369,1370,1372,1375,1377,1380],{"class":145,"line":270},[143,1371,706],{"class":173},[143,1373,1374],{"class":289}," RuntimeError",[143,1376,623],{"class":177},[143,1378,1379],{"class":153},"\"a workbook must keep at least one sheet\"",[143,1381,357],{"class":177},[143,1383,1384,1386,1388],{"class":145,"line":293},[143,1385,351],{"class":177},[143,1387,354],{"class":153},[143,1389,357],{"class":177},[10,1391,1392],{},"A workbook with no sheets is not a valid file, so guard the last one. When something might still point at the sheet — a formula, a chart series, a named range, a pivot cache — hide it instead:",[133,1394,1396],{"className":164,"code":1395,"language":166,"meta":138,"style":138},"wb[\"Working\"].sheet_state = \"hidden\"        # visible in the unhide dialog\nwb[\"Internal\"].sheet_state = \"veryHidden\"   # only reachable from the VBA editor\n",[140,1397,1398,1416],{"__ignoreMap":138},[143,1399,1400,1402,1405,1408,1410,1413],{"class":145,"line":146},[143,1401,273],{"class":177},[143,1403,1404],{"class":153},"\"Working\"",[143,1406,1407],{"class":177},"].sheet_state ",[143,1409,200],{"class":173},[143,1411,1412],{"class":153}," \"hidden\"",[143,1414,1415],{"class":377},"        # visible in the unhide dialog\n",[143,1417,1418,1420,1423,1425,1427,1430],{"class":145,"line":187},[143,1419,273],{"class":177},[143,1421,1422],{"class":153},"\"Internal\"",[143,1424,1407],{"class":177},[143,1426,200],{"class":173},[143,1428,1429],{"class":153}," \"veryHidden\"",[143,1431,1432],{"class":377},"   # only reachable from the VBA editor\n",[10,1434,1435,1438,1439,1442],{},[140,1436,1437],{},"hidden"," is the right choice for a working sheet a curious reader may legitimately want to see. ",[140,1440,1441],{},"veryHidden"," is for a sheet that supports the workbook's machinery — a lookup table behind a dropdown, say — where an accidental edit would break something. Neither is a security measure: both are trivially reversible by anyone who knows where to look.",[23,1444,32,1449,32,1452,32,1455,32,1458,32,1464,32,1470,32,1474,32,1477,32,1481,32,1483,32,1487,32,1491,32,1496,32,1501,32,1504,32,1507,32,1509,32,1512,32,1514,32,1517,32,1520],{"viewBox":1445,"role":26,"ariaLabelledBy":1446,"xmlns":30,"style":31},"0 0 740 246",[1447,1448],"sh-del-t","sh-del-d",[34,1450,1451],{"id":1447},"Deleting a sheet versus hiding it",[38,1453,1454],{"id":1448},"Deleting removes the sheet and every reference to it fails: formulas resolve to REF errors, chart series lose their data and named ranges break. Hiding keeps all of those working while removing the tab from view, with veryHidden also removing it from the unhide dialog.",[42,1456],{"x":44,"y":44,"width":45,"height":1457,"fill":47},"246",[49,1459,1463],{"x":1460,"y":1461,"style":1462},"184","32","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","del wb[\"Lookup\"]",[42,1465],{"x":1466,"y":58,"width":1467,"height":1468,"rx":1469,"fill":79,"stroke":80,"style":64},"24","320","34","6",[49,1471,1473],{"x":1460,"y":1472,"style":74},"72","formulas → #REF!",[42,1475],{"x":1466,"y":1476,"width":1467,"height":1468,"rx":1469,"fill":79,"stroke":80,"style":64},"90",[49,1478,1480],{"x":1460,"y":1479,"style":74},"112","chart series → empty",[42,1482],{"x":1466,"y":67,"width":1467,"height":1468,"rx":1469,"fill":79,"stroke":80,"style":64},[49,1484,1486],{"x":1460,"y":1485,"style":74},"152","named ranges and dropdowns → broken",[49,1488,1490],{"x":1460,"y":106,"style":1489},"font-size:11.5px;fill:var(--text,#172033);text-anchor:middle","and none of it shows until someone opens the file",[49,1492,1495],{"x":1460,"y":1493,"style":1494},"212","font-size:11px;fill:var(--muted,#5b6780);text-anchor:middle","the job reports success either way",[49,1497,1500],{"x":1498,"y":1461,"style":1499},"556","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","sheet_state = \"hidden\"",[42,1502],{"x":1503,"y":58,"width":1467,"height":1468,"rx":1469,"fill":62,"stroke":63,"style":64},"396",[49,1505,1506],{"x":1498,"y":1472,"style":74},"formulas keep resolving",[42,1508],{"x":1503,"y":1476,"width":1467,"height":1468,"rx":1469,"fill":62,"stroke":63,"style":64},[49,1510,1511],{"x":1498,"y":1479,"style":74},"charts keep their data",[42,1513],{"x":1503,"y":67,"width":1467,"height":1468,"rx":1469,"fill":62,"stroke":63,"style":64},[49,1515,1516],{"x":1498,"y":1485,"style":74},"the tab is simply out of the way",[49,1518,1519],{"x":1498,"y":106,"style":1489},"\"veryHidden\" also removes it from the unhide dialog",[49,1521,1522],{"x":1498,"y":1493,"style":1494},"neither is a security control",[128,1524,1526],{"id":1525},"step-6-choose-the-tab-that-opens","Step 6: Choose the tab that opens",[10,1528,1529],{},"The sheet a reader lands on is a workbook-level index:",[133,1531,1533],{"className":164,"code":1532,"language":166,"meta":138,"style":138},"wb = load_workbook(\"messy.xlsx\")\nwb.active = wb.sheetnames.index(\"Summary\")     # an index, not a sheet object\nwb[\"Summary\"].sheet_view.tabSelected = True\nfor ws in wb.worksheets:\n    if ws.title != \"Summary\":\n        ws.sheet_view.tabSelected = False\nwb.save(\"messy.xlsx\")\n",[140,1534,1535,1547,1565,1579,1589,1603,1613],{"__ignoreMap":138},[143,1536,1537,1539,1541,1543,1545],{"class":145,"line":146},[143,1538,197],{"class":177},[143,1540,200],{"class":173},[143,1542,768],{"class":177},[143,1544,354],{"class":153},[143,1546,357],{"class":177},[143,1548,1549,1552,1554,1557,1559,1562],{"class":145,"line":187},[143,1550,1551],{"class":177},"wb.active ",[143,1553,200],{"class":173},[143,1555,1556],{"class":177}," wb.sheetnames.index(",[143,1558,790],{"class":153},[143,1560,1561],{"class":177},")     ",[143,1563,1564],{"class":377},"# an index, not a sheet object\n",[143,1566,1567,1569,1571,1574,1576],{"class":145,"line":194},[143,1568,273],{"class":177},[143,1570,790],{"class":153},[143,1572,1573],{"class":177},"].sheet_view.tabSelected ",[143,1575,200],{"class":173},[143,1577,1578],{"class":289}," True\n",[143,1580,1581,1583,1585,1587],{"class":145,"line":206},[143,1582,220],{"class":173},[143,1584,976],{"class":177},[143,1586,226],{"class":173},[143,1588,981],{"class":177},[143,1590,1591,1593,1596,1598,1601],{"class":145,"line":217},[143,1592,519],{"class":173},[143,1594,1595],{"class":177}," ws.title ",[143,1597,875],{"class":173},[143,1599,1600],{"class":153}," \"Summary\"",[143,1602,531],{"class":177},[143,1604,1605,1608,1610],{"class":145,"line":259},[143,1606,1607],{"class":177},"        ws.sheet_view.tabSelected ",[143,1609,200],{"class":173},[143,1611,1612],{"class":289}," False\n",[143,1614,1615,1617,1619],{"class":145,"line":265},[143,1616,351],{"class":177},[143,1618,354],{"class":153},[143,1620,357],{"class":177},[23,1622,32,1627,32,1630,32,1633,32,1638,32,1641,32,1647,32,1652,32,1657,32,1660,32,1663,32,1667,32,1670,32,1674,32,1677,32,1681,32,1685,32,1688,32,1690,32,1693,32,1695,32,1698,32,1701,32,1704,32,1707,32,1710,32,1714,32,1717],{"viewBox":1623,"role":26,"ariaLabelledBy":1624,"xmlns":30,"style":31},"8 2 728 175",[1625,1626],"sh-tab-t","sh-tab-d",[34,1628,1629],{"id":1625},"One selected tab against several left selected",[38,1631,1632],{"id":1626},"With one tab selected the workbook opens on the summary and typing affects that sheet only. If several sheets are saved with tabSelected still true, Excel opens with a group selection, and anything the reader types is written into every selected sheet at once.",[42,1634],{"x":1635,"y":626,"width":1636,"height":1637,"fill":47},"8","728","175",[49,1639,1640],{"x":1460,"y":52,"style":1499},"one tab selected",[42,1642],{"x":1466,"y":58,"width":1643,"height":1644,"rx":1645,"fill":1646},"96","28","4","#5b5cf0",[49,1648,1651],{"x":1472,"y":1649,"style":1650},"69","font-size:11px;font-weight:700;fill:#ffffff;text-anchor:middle","Summary",[42,1653],{"x":1654,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1655,"stroke":1656},"124","#f0f2f5","var(--line,#cdd5e6)",[49,1658,824],{"x":1659,"y":1649,"style":1494},"160",[42,1661],{"x":1662,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1655,"stroke":1656},"200",[49,1664,1666],{"x":1665,"y":1649,"style":1494},"236","Feb",[42,1668],{"x":1669,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1655,"stroke":1656},"276",[49,1671,1673],{"x":1672,"y":1649,"style":1494},"312","Mar",[49,1675,1676],{"x":1460,"y":1479,"style":1489},"opens on Summary",[49,1678,1680],{"x":1460,"y":1679,"style":1494},"140","typing goes into that sheet,",[49,1682,1684],{"x":1460,"y":1683,"style":1494},"158","which is what a reader expects",[49,1686,1687],{"x":1498,"y":52,"style":1462},"four tabs left selected",[42,1689],{"x":1503,"y":58,"width":1643,"height":1644,"rx":1645,"fill":1646},[49,1691,1651],{"x":1692,"y":1649,"style":1650},"444",[42,1694],{"x":90,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1646},[49,1696,824],{"x":1697,"y":1649,"style":1650},"532",[42,1699],{"x":1700,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1646},"572",[49,1702,1666],{"x":1703,"y":1649,"style":1650},"608",[42,1705],{"x":1706,"y":58,"width":1472,"height":1644,"rx":1645,"fill":1646},"648",[49,1708,1673],{"x":1709,"y":1649,"style":1650},"684",[49,1711,1713],{"x":1498,"y":1479,"style":1712},"font-size:11.5px;fill:var(--accent-ink,#be185d);text-anchor:middle","opens with a group selection",[49,1715,1716],{"x":1498,"y":1679,"style":1494},"one edit is written into all four sheets,",[49,1718,1719],{"x":1498,"y":1683,"style":1494},"and the reader may not notice for a week",[10,1721,1722,1723,1726,1727,1730],{},"Assigning a worksheet object to ",[140,1724,1725],{},"wb.active"," is the mistake people make; it wants the index. Clearing ",[140,1728,1729],{},"tabSelected"," on the others matters too — a workbook saved with several sheets marked selected opens with a multi-sheet selection, and anything the reader then types goes into all of them at once.",[128,1732,1734],{"id":1733},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[1736,1737,1738,1754],"table",{},[1739,1740,1741],"thead",{},[1742,1743,1744,1748,1751],"tr",{},[1745,1746,1747],"th",{},"Symptom",[1745,1749,1750],{},"Cause",[1745,1752,1753],{},"Fix",[1755,1756,1757,1769,1780,1791,1807,1818,1829,1843],"tbody",{},[1742,1758,1759,1763,1766],{},[1760,1761,1762],"td",{},"Excel says the file is corrupt",[1760,1764,1765],{},"Illegal character or a name over 31 characters",[1760,1767,1768],{},"Sanitise and truncate before assigning",[1742,1770,1771,1774,1777],{},[1760,1772,1773],{},"Two sheets collide after truncation",[1760,1775,1776],{},"Both cut to the same 31-character prefix",[1760,1778,1779],{},"Check uniqueness after truncating",[1742,1781,1782,1785,1788],{},[1760,1783,1784],{},"Formulas break after renaming",[1760,1786,1787],{},"openpyxl does not repoint references",[1760,1789,1790],{},"Rewrite the references, or name sheets up front",[1742,1792,1793,1798,1801],{},[1760,1794,1795,1797],{},[140,1796,1107],{}," puts it in the wrong place",[1760,1799,1800],{},"The argument is an offset, not an index",[1760,1802,1803,1804],{},"Compute ",[140,1805,1806],{},"target - current",[1742,1808,1809,1812,1815],{},[1760,1810,1811],{},"Deleting the last sheet",[1760,1813,1814],{},"A workbook must keep one",[1760,1816,1817],{},"Guard before deleting",[1742,1819,1820,1823,1826],{},[1760,1821,1822],{},"Chart is empty after cleanup",[1760,1824,1825],{},"Its series pointed at a deleted sheet",[1760,1827,1828],{},"Hide instead of delete, or rebuild the chart",[1742,1830,1831,1834,1837],{},[1760,1832,1833],{},"Typing edits several sheets at once",[1760,1835,1836],{},"Multiple tabs left selected",[1760,1838,1839,1840,1842],{},"Clear ",[140,1841,1729],{}," on the others",[1742,1844,1845,1848,1853],{},[1760,1846,1847],{},"Hidden sheet still visible to users",[1760,1849,1850,1852],{},[140,1851,1437],{}," is reversible by design",[1760,1854,1855,1856,1858],{},"Use ",[140,1857,1441],{},", and do not treat it as protection",[128,1860,1862],{"id":1861},"performance-and-scale-notes","Performance and scale notes",[10,1864,1865],{},"These operations are metadata changes, so they cost nothing regardless of how much data the sheets hold — with one exception. The formula-repointing loop in step 3 visits every cell in the workbook, which on a large file is the slowest thing on this page; restrict it to the sheets that could plausibly reference the renamed one if that matters.",[10,1867,1868,1869,1872],{},"Note also that ",[140,1870,1871],{},"load_workbook(read_only=True)"," cannot be used for any of this: read-only mode gives you cell values, not a mutable workbook. Housekeeping needs a normal load, which means the whole workbook is parsed into memory first.",[128,1874,1876],{"id":1875},"conclusion","Conclusion",[10,1878,1879,1880,1882],{},"Sanitise every generated sheet name to 31 legal characters and check uniqueness after truncating, because Excel enforces both and openpyxl does not. Reorder with computed offsets so the summary is the first tab, set ",[140,1881,1725],{}," by index and clear the selection on the rest. Prefer hiding to deleting whenever a formula, chart or named range might still point at the sheet — a deletion is invisible to your script and obvious to whoever opens the file.",[128,1884,1886],{"id":1885},"frequently-asked-questions","Frequently asked questions",[10,1888,1889,1893,1894,1897],{},[1890,1891,1892],"strong",{},"What are the rules for a sheet name?","\nOne to 31 characters, and none of ",[140,1895,1896],{},"\\ \u002F ? * [ ] :",". It cannot be blank, cannot be \"History\", and must be unique within the workbook — Excel refuses to open a file that breaks any of these.",[10,1899,1900,1903,1904,1907],{},[1890,1901,1902],{},"Does renaming a sheet break formulas that reference it?","\nYes, if they are in the file as text. Excel rewrites references when you rename a tab in the application; openpyxl does not, so a formula reading ",[140,1905,1906],{},"'Q1'!B2"," keeps pointing at a sheet that no longer exists.",[10,1909,1910,1913,1914,1916],{},[1890,1911,1912],{},"How do I control which tab is selected when the file opens?","\nSet ",[140,1915,1725],{}," to the index of the sheet you want. It is an index, not a sheet object, which is the usual source of confusion.",[10,1918,1919,1922],{},[1890,1920,1921],{},"Should I delete a sheet or hide it?","\nHide it when anything might still reference it — a formula, a chart series, a named range. Deletion breaks all three, and a hidden sheet keeps the workbook working while staying out of the way.",[128,1924,1926],{"id":1925},"related","Related",[10,1928,1929],{},"Up to the parent guide:",[1931,1932,1933],"ul",{},[1934,1935,1936,1938],"li",{},[17,1937,20],{"href":19}," — the rest of the multi-sheet toolkit.",[10,1940,1941],{},"Related guides:",[1931,1943,1944,1951,1958,1965],{},[1934,1945,1946,1950],{},[17,1947,1949],{"href":1948},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fcopy-a-sheet-between-excel-workbooks-with-python\u002F","Copy a Sheet Between Excel Workbooks with Python"," — the operation that usually precedes this cleanup.",[1934,1952,1953,1957],{},[17,1954,1956],{"href":1955},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fread-all-sheets-from-an-excel-file-into-dataframes\u002F","Read All Sheets from an Excel File into DataFrames"," — filtering out the sheets this guide hides.",[1934,1959,1960,1964],{},[17,1961,1963],{"href":1962},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fcreate-named-range-in-excel-with-openpyxl\u002F","Create a Named Range in Excel with openpyxl"," — one of the references a deletion breaks.",[1934,1966,1967,1969],{},[17,1968,1273],{"href":1272}," — why the first tab matters.",[1971,1972,1973],"style",{},"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 .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}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 .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_b0D, html code.shiki .s_b0D{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#72F088;--shiki-dark-font-weight:bold}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}",{"title":138,"searchDepth":187,"depth":187,"links":1975},[1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987],{"id":130,"depth":187,"text":131},{"id":160,"depth":187,"text":161},{"id":381,"depth":187,"text":382},{"id":808,"depth":187,"text":809},{"id":1101,"depth":187,"text":1102},{"id":1277,"depth":187,"text":1278},{"id":1525,"depth":187,"text":1526},{"id":1733,"depth":187,"text":1734},{"id":1861,"depth":187,"text":1862},{"id":1875,"depth":187,"text":1876},{"id":1885,"depth":187,"text":1886},{"id":1925,"depth":187,"text":1926},"2026-08-10","Sheet housekeeping that does not break the workbook: the 31-character title rules, move_sheet and the index list, safe deletion, hiding instead of removing, and which tab opens first.","md",[1992,1994,1996,1998],{"q":1892,"a":1993},"One to 31 characters, and none of \\\\ \u002F ? * [ ] :. It cannot be blank, cannot be \"History\", and must be unique within the workbook — Excel refuses to open a file that breaks any of these.",{"q":1902,"a":1995},"Yes, if they are in the file as text. Excel rewrites references when you rename a tab in the application; openpyxl does not, so a formula reading 'Q1'!B2 keeps pointing at a sheet that no longer exists.",{"q":1912,"a":1997},"Set wb.active to the index of the sheet you want. It is an index, not a sheet object, which is the usual source of confusion.",{"q":1921,"a":1999},"Hide it when anything might still reference it — a formula, a chart series, a named range. Deletion breaks all three, and a hidden sheet keeps the workbook working while staying out of the way.",{"breadcrumb":2001},[2002,2005,2008,2009],{"name":2003,"item":2004},"Home","\u002F",{"name":2006,"item":2007},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":20,"item":19},{"name":5,"item":2010},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl\u002F","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl",{"title":2013,"description":2014},"Rename, Reorder & Delete Excel Sheets (openpyxl)","Manage worksheets with openpyxl — legal sheet titles, renaming safely, reordering with move_sheet, deleting versus hiding, setting the active tab and the formula references that break.","rename-reorder-and-delete-excel-sheets-with-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Frename-reorder-and-delete-excel-sheets-with-openpyxl\u002Findex","how-to","1EHukEDdSz8fYX56JXYrszjob0QCavoNM56iLZSz0mo",[2020,2023],{"title":1956,"path":2021,"stem":2022,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fread-all-sheets-from-an-excel-file-into-dataframes","getting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fread-all-sheets-from-an-excel-file-into-dataframes\u002Findex",{"title":2024,"path":2025,"stem":2026,"children":-1},"Split One Excel Sheet into Multiple Files by Column Value","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fsplit-one-excel-sheet-into-multiple-files-by-value","getting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fsplit-one-excel-sheet-into-multiple-files-by-value\u002Findex",1786800028728]