[{"data":1,"prerenderedAt":1695},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python":1686},{"id":4,"title":5,"body":6,"dateModified":1663,"datePublished":1663,"description":1664,"extension":1665,"faq":1666,"meta":1677,"navigation":236,"path":1678,"seo":1679,"slug":1682,"stem":1683,"type":1684,"__hash__":1685},"docs\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python\u002Findex.md","Recalculate Excel Formulas Without Excel in Python",{"type":7,"value":8,"toc":1649},"minimark",[9,38,135,140,171,178,204,208,322,332,336,343,438,441,470,476,480,483,704,707,763,777,860,864,867,1018,1021,1025,1028,1234,1237,1241,1249,1407,1414,1470,1475,1479,1540,1544,1554,1558,1564,1568,1579,1585,1595,1601,1607,1611,1645],[10,11,12,16,17,20,21,24,25,16,28,31,32,37],"p",{},[13,14,15],"code",{},"ws[\"B10\"].value"," returns ",[13,18,19],{},"'=SUM(B2:B9)'"," when you wanted ",[13,22,23],{},"4823.50",", and loading with ",[13,26,27],{},"data_only=True",[13,29,30],{},"None",". Neither is a bug: openpyxl reads what is in the file, and the file only contains a cached result if Excel has saved it. A workbook your script just wrote has no cache at all. This guide covers the three ways to get real numbers without Excel — a pure-Python calculation engine, a headless LibreOffice pass, and the restructuring that makes the question go away. It extends ",[33,34,36],"a",{"href":35},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002F","Working with Excel Formulas in Python",".",[39,40,48,49,48,53,48,57,48,64,48,71,48,80,48,85,48,90,48,94,48,99,48,103,48,109,48,114,48,119,48,122,48,126,48,130],"svg",{"viewBox":41,"role":42,"ariaLabelledBy":43,"xmlns":46,"style":47},"0 0 760 236","img",[44,45],"rc-t","rc-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:760px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[50,51,52],"title",{"id":44},"Why a formula cell can hold two different things",[54,55,56],"desc",{"id":45},"A cell stores the formula string and, only after Excel saves the file, a cached result; openpyxl returns whichever one you ask for, and the cache is absent in a file Excel never opened.",[58,59],"rect",{"x":60,"y":60,"width":61,"height":62,"fill":63},"0","760","236","#ffffff",[65,66,70],"text",{"x":67,"y":68,"style":69},"380","26","font-size:13px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","One cell, two stored values",[58,72],{"x":73,"y":74,"width":75,"height":76,"rx":77,"fill":78,"stroke":79},"30","46","330","76","12","#ebebfd","var(--line,#cdd5e6)",[65,81,84],{"x":82,"y":76,"style":83},"195","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","the formula string",[65,86,89],{"x":82,"y":87,"style":88},"102","font-size:11.5px;fill:var(--text,#172033);text-anchor:middle","always present: \"=SUM(B2:B9)\"",[58,91],{"x":92,"y":74,"width":75,"height":76,"rx":77,"fill":93,"stroke":79},"400","#fdefd8",[65,95,98],{"x":96,"y":76,"style":97},"565","font-size:12.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","the cached result",[65,100,102],{"x":96,"y":87,"style":101},"font-size:11.5px;fill:var(--gold-ink,#7a4e06);text-anchor:middle","only after Excel saves the file",[58,104],{"x":73,"y":105,"width":75,"height":106,"rx":107,"fill":108,"stroke":79},"134","62","10","#d9f4f1",[65,110,113],{"x":82,"y":111,"style":112},"160","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","load_workbook(path)",[65,115,118],{"x":82,"y":116,"style":117},"182","font-size:11.5px;fill:var(--teal-ink,#0b6157);text-anchor:middle","gives you the formula",[58,120],{"x":92,"y":105,"width":75,"height":106,"rx":107,"fill":121,"stroke":79},"#fee8f2",[65,123,125],{"x":96,"y":111,"style":124},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","load_workbook(path, data_only=True)",[65,127,129],{"x":96,"y":116,"style":128},"font-size:11.5px;fill:var(--accent-ink,#be185d);text-anchor:middle","gives None when no cache exists",[65,131,134],{"x":67,"y":132,"style":133},"222","font-size:11.5px;fill:var(--muted,#5b6780);text-anchor:middle","Nothing in openpyxl computes — it reads what the file already holds",[136,137,139],"h2",{"id":138},"prerequisites","Prerequisites",[141,142,147],"pre",{"className":143,"code":144,"language":145,"meta":146,"style":146},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install openpyxl pandas formulas\n","bash","",[13,148,149],{"__ignoreMap":146},[150,151,154,158,162,165,168],"span",{"class":152,"line":153},"line",1,[150,155,157],{"class":156},"sMTad","pip",[150,159,161],{"class":160},"srMev"," install",[150,163,164],{"class":160}," openpyxl",[150,166,167],{"class":160}," pandas",[150,169,170],{"class":160}," formulas\n",[10,172,173,174,177],{},"The LibreOffice route needs the application itself, available as ",[13,175,176],{},"soffice"," on the path:",[141,179,181],{"className":143,"code":180,"language":145,"meta":146,"style":146},"sudo apt-get install -y libreoffice-calc     # Debian\u002FUbuntu\n",[13,182,183],{"__ignoreMap":146},[150,184,185,188,191,193,197,200],{"class":152,"line":153},[150,186,187],{"class":156},"sudo",[150,189,190],{"class":160}," apt-get",[150,192,161],{"class":160},[150,194,196],{"class":195},"sP0c6"," -y",[150,198,199],{"class":160}," libreoffice-calc",[150,201,203],{"class":202},"s-wDw","     # Debian\u002FUbuntu\n",[136,205,207],{"id":206},"confirm-the-diagnosis-first","Confirm the diagnosis first",[141,209,213],{"className":210,"code":211,"language":212,"meta":146,"style":146},"language-python shiki shiki-themes github-light github-dark-high-contrast","from openpyxl import load_workbook\n\nformulas = load_workbook(\"report.xlsx\")[\"Summary\"][\"B10\"].value\nvalues = load_workbook(\"report.xlsx\", data_only=True)[\"Summary\"][\"B10\"].value\nprint(repr(formulas), repr(values))\n","python",[13,214,215,231,238,268,302],{"__ignoreMap":146},[150,216,217,221,225,228],{"class":152,"line":153},[150,218,220],{"class":219},"s-kum","from",[150,222,224],{"class":223},"skGVy"," openpyxl ",[150,226,227],{"class":219},"import",[150,229,230],{"class":223}," load_workbook\n",[150,232,234],{"class":152,"line":233},2,[150,235,237],{"emptyLinePlaceholder":236},true,"\n",[150,239,241,244,247,250,253,256,259,262,265],{"class":152,"line":240},3,[150,242,243],{"class":223},"formulas ",[150,245,246],{"class":219},"=",[150,248,249],{"class":223}," load_workbook(",[150,251,252],{"class":160},"\"report.xlsx\"",[150,254,255],{"class":223},")[",[150,257,258],{"class":160},"\"Summary\"",[150,260,261],{"class":223},"][",[150,263,264],{"class":160},"\"B10\"",[150,266,267],{"class":223},"].value\n",[150,269,271,274,276,278,280,283,287,289,292,294,296,298,300],{"class":152,"line":270},4,[150,272,273],{"class":223},"values ",[150,275,246],{"class":219},[150,277,249],{"class":223},[150,279,252],{"class":160},[150,281,282],{"class":223},", ",[150,284,286],{"class":285},"sa561","data_only",[150,288,246],{"class":219},[150,290,291],{"class":195},"True",[150,293,255],{"class":223},[150,295,258],{"class":160},[150,297,261],{"class":223},[150,299,264],{"class":160},[150,301,267],{"class":223},[150,303,305,308,311,314,317,319],{"class":152,"line":304},5,[150,306,307],{"class":195},"print",[150,309,310],{"class":223},"(",[150,312,313],{"class":195},"repr",[150,315,316],{"class":223},"(formulas), ",[150,318,313],{"class":195},[150,320,321],{"class":223},"(values))\n",[10,323,324,325,327,328,37],{},"If the first prints a formula and the second prints ",[13,326,30],{},", the file has no cached results — it was written by a library and never opened in Excel. If the second prints a number, you already have what you need; the cache is there and no recalculation is required. The distinction is explored further in ",[33,329,331],{"href":330},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","Read formula results with openpyxl data_only",[136,333,335],{"id":334},"option-1-calculate-in-pure-python","Option 1: calculate in pure Python",[10,337,338,339,342],{},"The ",[13,340,341],{},"formulas"," package parses a workbook, builds a dependency graph and evaluates it — no Excel, no LibreOffice, no external process:",[141,344,346],{"className":210,"code":345,"language":212,"meta":146,"style":146},"\"\"\"Recalculate a workbook and read a result, in pure Python.\"\"\"\nimport formulas\n\nmodel = formulas.ExcelModel().loads(\"report.xlsx\").finish()\nsolution = model.calculate()\n\nfor key, value in solution.items():\n    if key.upper().endswith(\"'[REPORT.XLSX]SUMMARY'!B10\"):\n        print(key, \"=\", value)\n",[13,347,348,353,359,363,378,388,393,408,423],{"__ignoreMap":146},[150,349,350],{"class":152,"line":153},[150,351,352],{"class":160},"\"\"\"Recalculate a workbook and read a result, in pure Python.\"\"\"\n",[150,354,355,357],{"class":152,"line":233},[150,356,227],{"class":219},[150,358,170],{"class":223},[150,360,361],{"class":152,"line":240},[150,362,237],{"emptyLinePlaceholder":236},[150,364,365,368,370,373,375],{"class":152,"line":270},[150,366,367],{"class":223},"model ",[150,369,246],{"class":219},[150,371,372],{"class":223}," formulas.ExcelModel().loads(",[150,374,252],{"class":160},[150,376,377],{"class":223},").finish()\n",[150,379,380,383,385],{"class":152,"line":304},[150,381,382],{"class":223},"solution ",[150,384,246],{"class":219},[150,386,387],{"class":223}," model.calculate()\n",[150,389,391],{"class":152,"line":390},6,[150,392,237],{"emptyLinePlaceholder":236},[150,394,396,399,402,405],{"class":152,"line":395},7,[150,397,398],{"class":219},"for",[150,400,401],{"class":223}," key, value ",[150,403,404],{"class":219},"in",[150,406,407],{"class":223}," solution.items():\n",[150,409,411,414,417,420],{"class":152,"line":410},8,[150,412,413],{"class":219},"    if",[150,415,416],{"class":223}," key.upper().endswith(",[150,418,419],{"class":160},"\"'[REPORT.XLSX]SUMMARY'!B10\"",[150,421,422],{"class":223},"):\n",[150,424,426,429,432,435],{"class":152,"line":425},9,[150,427,428],{"class":195},"        print",[150,430,431],{"class":223},"(key, ",[150,433,434],{"class":160},"\"=\"",[150,436,437],{"class":223},", value)\n",[10,439,440],{},"It can also write the recalculated workbook back out, cached values included:",[141,442,444],{"className":210,"code":443,"language":212,"meta":146,"style":146},"model.calculate()\nmodel.write(dirpath=\".\u002Fcalculated\")     # writes report.xlsx with results\n",[13,445,446,451],{"__ignoreMap":146},[150,447,448],{"class":152,"line":153},[150,449,450],{"class":223},"model.calculate()\n",[150,452,453,456,459,461,464,467],{"class":152,"line":233},[150,454,455],{"class":223},"model.write(",[150,457,458],{"class":285},"dirpath",[150,460,246],{"class":219},[150,462,463],{"class":160},"\".\u002Fcalculated\"",[150,465,466],{"class":223},")     ",[150,468,469],{"class":202},"# writes report.xlsx with results\n",[10,471,472,473,475],{},"The keys are fully qualified — book, sheet and cell — which is verbose but unambiguous in a workbook with cross-sheet references. Coverage is the caveat: ",[13,474,341],{}," implements a large subset of Excel's function library, and a workbook that uses an unsupported function raises rather than silently guessing. Test it against your real file before building a pipeline on it.",[136,477,479],{"id":478},"option-2-let-libreoffice-recalculate","Option 2: let LibreOffice recalculate",[10,481,482],{},"LibreOffice recalculates on load and can write the result back, which gives much broader function coverage at the cost of a heavier dependency:",[141,484,486],{"className":210,"code":485,"language":212,"meta":146,"style":146},"\"\"\"Recalculate by round-tripping through headless LibreOffice.\"\"\"\nimport subprocess\nfrom pathlib import Path\n\ndef recalculate(path: Path, out_dir: Path) -> Path:\n    out_dir.mkdir(parents=True, exist_ok=True)\n    subprocess.run(\n        [\"soffice\", \"--headless\", \"--norestore\",\n         \"--convert-to\", \"xlsx\", \"--outdir\", str(out_dir), str(path)],\n        check=True, timeout=180,\n        stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,\n    )\n    return out_dir \u002F path.name\n\nresult = recalculate(Path(\"report.xlsx\"), Path(\"calculated\"))\n",[13,487,488,493,500,512,516,528,552,557,578,606,628,656,662,677,682],{"__ignoreMap":146},[150,489,490],{"class":152,"line":153},[150,491,492],{"class":160},"\"\"\"Recalculate by round-tripping through headless LibreOffice.\"\"\"\n",[150,494,495,497],{"class":152,"line":233},[150,496,227],{"class":219},[150,498,499],{"class":223}," subprocess\n",[150,501,502,504,507,509],{"class":152,"line":240},[150,503,220],{"class":219},[150,505,506],{"class":223}," pathlib ",[150,508,227],{"class":219},[150,510,511],{"class":223}," Path\n",[150,513,514],{"class":152,"line":270},[150,515,237],{"emptyLinePlaceholder":236},[150,517,518,521,525],{"class":152,"line":304},[150,519,520],{"class":219},"def",[150,522,524],{"class":523},"s_Opv"," recalculate",[150,526,527],{"class":223},"(path: Path, out_dir: Path) -> Path:\n",[150,529,530,533,536,538,540,542,545,547,549],{"class":152,"line":390},[150,531,532],{"class":223},"    out_dir.mkdir(",[150,534,535],{"class":285},"parents",[150,537,246],{"class":219},[150,539,291],{"class":195},[150,541,282],{"class":223},[150,543,544],{"class":285},"exist_ok",[150,546,246],{"class":219},[150,548,291],{"class":195},[150,550,551],{"class":223},")\n",[150,553,554],{"class":152,"line":395},[150,555,556],{"class":223},"    subprocess.run(\n",[150,558,559,562,565,567,570,572,575],{"class":152,"line":410},[150,560,561],{"class":223},"        [",[150,563,564],{"class":160},"\"soffice\"",[150,566,282],{"class":223},[150,568,569],{"class":160},"\"--headless\"",[150,571,282],{"class":223},[150,573,574],{"class":160},"\"--norestore\"",[150,576,577],{"class":223},",\n",[150,579,580,583,585,588,590,593,595,598,601,603],{"class":152,"line":425},[150,581,582],{"class":160},"         \"--convert-to\"",[150,584,282],{"class":223},[150,586,587],{"class":160},"\"xlsx\"",[150,589,282],{"class":223},[150,591,592],{"class":160},"\"--outdir\"",[150,594,282],{"class":223},[150,596,597],{"class":195},"str",[150,599,600],{"class":223},"(out_dir), ",[150,602,597],{"class":195},[150,604,605],{"class":223},"(path)],\n",[150,607,609,612,614,616,618,621,623,626],{"class":152,"line":608},10,[150,610,611],{"class":285},"        check",[150,613,246],{"class":219},[150,615,291],{"class":195},[150,617,282],{"class":223},[150,619,620],{"class":285},"timeout",[150,622,246],{"class":219},[150,624,625],{"class":195},"180",[150,627,577],{"class":223},[150,629,631,634,636,639,642,644,647,649,651,654],{"class":152,"line":630},11,[150,632,633],{"class":285},"        stdout",[150,635,246],{"class":219},[150,637,638],{"class":223},"subprocess.",[150,640,641],{"class":195},"DEVNULL",[150,643,282],{"class":223},[150,645,646],{"class":285},"stderr",[150,648,246],{"class":219},[150,650,638],{"class":223},[150,652,653],{"class":195},"PIPE",[150,655,577],{"class":223},[150,657,659],{"class":152,"line":658},12,[150,660,661],{"class":223},"    )\n",[150,663,665,668,671,674],{"class":152,"line":664},13,[150,666,667],{"class":219},"    return",[150,669,670],{"class":223}," out_dir ",[150,672,673],{"class":219},"\u002F",[150,675,676],{"class":223}," path.name\n",[150,678,680],{"class":152,"line":679},14,[150,681,237],{"emptyLinePlaceholder":236},[150,683,685,688,690,693,695,698,701],{"class":152,"line":684},15,[150,686,687],{"class":223},"result ",[150,689,246],{"class":219},[150,691,692],{"class":223}," recalculate(Path(",[150,694,252],{"class":160},[150,696,697],{"class":223},"), Path(",[150,699,700],{"class":160},"\"calculated\"",[150,702,703],{"class":223},"))\n",[10,705,706],{},"Then read the cached values normally:",[141,708,710],{"className":210,"code":709,"language":212,"meta":146,"style":146},"from openpyxl import load_workbook\n\nwb = load_workbook(result, data_only=True)\nprint(wb[\"Summary\"][\"B10\"].value)      # a number, at last\n",[13,711,712,722,726,744],{"__ignoreMap":146},[150,713,714,716,718,720],{"class":152,"line":153},[150,715,220],{"class":219},[150,717,224],{"class":223},[150,719,227],{"class":219},[150,721,230],{"class":223},[150,723,724],{"class":152,"line":233},[150,725,237],{"emptyLinePlaceholder":236},[150,727,728,731,733,736,738,740,742],{"class":152,"line":240},[150,729,730],{"class":223},"wb ",[150,732,246],{"class":219},[150,734,735],{"class":223}," load_workbook(result, ",[150,737,286],{"class":285},[150,739,246],{"class":219},[150,741,291],{"class":195},[150,743,551],{"class":223},[150,745,746,748,751,753,755,757,760],{"class":152,"line":270},[150,747,307],{"class":195},[150,749,750],{"class":223},"(wb[",[150,752,258],{"class":160},[150,754,261],{"class":223},[150,756,264],{"class":160},[150,758,759],{"class":223},"].value)      ",[150,761,762],{"class":202},"# a number, at last\n",[10,764,765,766,769,770,772,773,37],{},"Two operational notes. LibreOffice keeps a user profile directory and will refuse to run two instances against the same one, so pass ",[13,767,768],{},"-env:UserInstallation=file:\u002F\u002F\u002Ftmp\u002Flo-$$"," when running conversions in parallel. And always set a ",[13,771,620],{},": a malformed file can hang the process indefinitely, which is exactly the failure a nightly job cannot recover from. The same tool converts to PDF, as covered in ",[33,774,776],{"href":775},"\u002Fautomating-reporting-workflows\u002Fexporting-excel-reports-to-pdf\u002Fconvert-excel-file-to-pdf-with-python\u002F","Convert an Excel file to PDF with Python",[39,778,48,783,48,786,48,789,48,792,48,795,48,800,48,804,48,808,48,812,48,816,48,820,48,823,48,827,48,830,48,833,48,836,48,839,48,843,48,848,48,851,48,854,48,857],{"viewBox":779,"role":42,"ariaLabelledBy":780,"xmlns":46,"style":47},"0 0 760 238",[781,782],"rc2-t","rc2-d",[50,784,785],{"id":781},"Three ways to end up with numbers",[54,787,788],{"id":782},"A pure-Python engine covers a subset of functions quickly, LibreOffice covers almost everything but costs a process, and computing in pandas avoids recalculation entirely.",[58,790],{"x":60,"y":60,"width":61,"height":791,"fill":63},"238",[65,793,794],{"x":67,"y":68,"style":69},"Coverage, cost and complexity",[58,796],{"x":797,"y":74,"width":798,"height":799,"rx":77,"fill":78,"stroke":79},"28","226","156",[65,801,803],{"x":802,"y":76,"style":83},"141","formulas package",[65,805,807],{"x":802,"y":806,"style":88},"106","pure Python, pip only",[65,809,811],{"x":802,"y":810,"style":133},"130","a subset of functions",[65,813,815],{"x":802,"y":814,"style":133},"154","slow on big models",[65,817,819],{"x":802,"y":116,"style":818},"font-size:11.5px;fill:var(--brand-strong,#4338ca);text-anchor:middle","for: simple workbooks",[58,821],{"x":822,"y":74,"width":798,"height":799,"rx":77,"fill":93,"stroke":79},"268",[65,824,826],{"x":825,"y":76,"style":97},"381","LibreOffice headless",[65,828,829],{"x":825,"y":806,"style":88},"near-complete coverage",[65,831,832],{"x":825,"y":810,"style":133},"a process per file",[65,834,835],{"x":825,"y":814,"style":133},"profile and timeout care",[65,837,838],{"x":825,"y":116,"style":101},"for: inherited models",[58,840],{"x":841,"y":74,"width":842,"height":799,"rx":77,"fill":108,"stroke":79},"508","224",[65,844,847],{"x":845,"y":76,"style":846},"620","font-size:12.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","compute in pandas",[65,849,850],{"x":845,"y":806,"style":88},"nothing to recalculate",[65,852,853],{"x":845,"y":810,"style":117},"milliseconds, testable",[65,855,856],{"x":845,"y":814,"style":133},"logic moves out of the sheet",[65,858,859],{"x":845,"y":116,"style":117},"for: anything you own",[136,861,863],{"id":862},"option-3-do-not-put-the-calculation-in-the-sheet","Option 3: do not put the calculation in the sheet",[10,865,866],{},"The fastest recalculation is the one that never happens. If your code generates the workbook, compute the numbers in Python and write values — optionally alongside the formula, so a reader can still see how a figure was derived:",[141,868,870],{"className":210,"code":869,"language":212,"meta":146,"style":146},"import pandas as pd\nfrom openpyxl import load_workbook\n\ndf = pd.read_excel(\"raw.xlsx\", engine=\"calamine\")\ntotal = float(df[\"revenue\"].sum())\n\nwb = load_workbook(\"report.xlsx\")\nws = wb[\"Summary\"]\nws[\"B10\"] = total                       # the number, computed and testable\nws[\"C10\"] = \"=SUM(B2:B9)\"               # the formula, for transparency\nwb.save(\"report.xlsx\")\n",[13,871,872,885,895,899,924,943,947,959,974,992,1009],{"__ignoreMap":146},[150,873,874,876,879,882],{"class":152,"line":153},[150,875,227],{"class":219},[150,877,878],{"class":223}," pandas ",[150,880,881],{"class":219},"as",[150,883,884],{"class":223}," pd\n",[150,886,887,889,891,893],{"class":152,"line":233},[150,888,220],{"class":219},[150,890,224],{"class":223},[150,892,227],{"class":219},[150,894,230],{"class":223},[150,896,897],{"class":152,"line":240},[150,898,237],{"emptyLinePlaceholder":236},[150,900,901,904,906,909,912,914,917,919,922],{"class":152,"line":270},[150,902,903],{"class":223},"df ",[150,905,246],{"class":219},[150,907,908],{"class":223}," pd.read_excel(",[150,910,911],{"class":160},"\"raw.xlsx\"",[150,913,282],{"class":223},[150,915,916],{"class":285},"engine",[150,918,246],{"class":219},[150,920,921],{"class":160},"\"calamine\"",[150,923,551],{"class":223},[150,925,926,929,931,934,937,940],{"class":152,"line":304},[150,927,928],{"class":223},"total ",[150,930,246],{"class":219},[150,932,933],{"class":195}," float",[150,935,936],{"class":223},"(df[",[150,938,939],{"class":160},"\"revenue\"",[150,941,942],{"class":223},"].sum())\n",[150,944,945],{"class":152,"line":390},[150,946,237],{"emptyLinePlaceholder":236},[150,948,949,951,953,955,957],{"class":152,"line":395},[150,950,730],{"class":223},[150,952,246],{"class":219},[150,954,249],{"class":223},[150,956,252],{"class":160},[150,958,551],{"class":223},[150,960,961,964,966,969,971],{"class":152,"line":410},[150,962,963],{"class":223},"ws ",[150,965,246],{"class":219},[150,967,968],{"class":223}," wb[",[150,970,258],{"class":160},[150,972,973],{"class":223},"]\n",[150,975,976,979,981,984,986,989],{"class":152,"line":425},[150,977,978],{"class":223},"ws[",[150,980,264],{"class":160},[150,982,983],{"class":223},"] ",[150,985,246],{"class":219},[150,987,988],{"class":223}," total                       ",[150,990,991],{"class":202},"# the number, computed and testable\n",[150,993,994,996,999,1001,1003,1006],{"class":152,"line":608},[150,995,978],{"class":223},[150,997,998],{"class":160},"\"C10\"",[150,1000,983],{"class":223},[150,1002,246],{"class":219},[150,1004,1005],{"class":160}," \"=SUM(B2:B9)\"",[150,1007,1008],{"class":202},"               # the formula, for transparency\n",[150,1010,1011,1014,1016],{"class":152,"line":630},[150,1012,1013],{"class":223},"wb.save(",[150,1015,252],{"class":160},[150,1017,551],{"class":223},[10,1019,1020],{},"This is the right default for generated reports. The calculation lives in code that can be unit-tested and reviewed, the delivered file opens with correct numbers everywhere, and nothing depends on the recipient's software recalculating anything.",[136,1022,1024],{"id":1023},"verify-the-recalculation","Verify the recalculation",[10,1026,1027],{},"Whichever route you take, check a known figure rather than assuming:",[141,1029,1031],{"className":210,"code":1030,"language":212,"meta":146,"style":146},"from openpyxl import load_workbook\n\nwb = load_workbook(\"calculated\u002Freport.xlsx\", data_only=True)\nws = wb[\"Summary\"]\n\nexpected = round(sum(ws.cell(row=r, column=2).value or 0 for r in range(2, 10)), 2)\nactual = round(ws[\"B10\"].value or 0, 2)\nassert abs(expected - actual) \u003C 0.01, f\"total mismatch: {actual} vs {expected}\"\n",[13,1032,1033,1043,1047,1068,1080,1084,1153,1180],{"__ignoreMap":146},[150,1034,1035,1037,1039,1041],{"class":152,"line":153},[150,1036,220],{"class":219},[150,1038,224],{"class":223},[150,1040,227],{"class":219},[150,1042,230],{"class":223},[150,1044,1045],{"class":152,"line":233},[150,1046,237],{"emptyLinePlaceholder":236},[150,1048,1049,1051,1053,1055,1058,1060,1062,1064,1066],{"class":152,"line":240},[150,1050,730],{"class":223},[150,1052,246],{"class":219},[150,1054,249],{"class":223},[150,1056,1057],{"class":160},"\"calculated\u002Freport.xlsx\"",[150,1059,282],{"class":223},[150,1061,286],{"class":285},[150,1063,246],{"class":219},[150,1065,291],{"class":195},[150,1067,551],{"class":223},[150,1069,1070,1072,1074,1076,1078],{"class":152,"line":270},[150,1071,963],{"class":223},[150,1073,246],{"class":219},[150,1075,968],{"class":223},[150,1077,258],{"class":160},[150,1079,973],{"class":223},[150,1081,1082],{"class":152,"line":304},[150,1083,237],{"emptyLinePlaceholder":236},[150,1085,1086,1089,1091,1094,1096,1099,1102,1105,1107,1110,1113,1115,1118,1121,1124,1127,1130,1133,1135,1138,1140,1142,1144,1146,1149,1151],{"class":152,"line":390},[150,1087,1088],{"class":223},"expected ",[150,1090,246],{"class":219},[150,1092,1093],{"class":195}," round",[150,1095,310],{"class":223},[150,1097,1098],{"class":195},"sum",[150,1100,1101],{"class":223},"(ws.cell(",[150,1103,1104],{"class":285},"row",[150,1106,246],{"class":219},[150,1108,1109],{"class":223},"r, ",[150,1111,1112],{"class":285},"column",[150,1114,246],{"class":219},[150,1116,1117],{"class":195},"2",[150,1119,1120],{"class":223},").value ",[150,1122,1123],{"class":219},"or",[150,1125,1126],{"class":195}," 0",[150,1128,1129],{"class":219}," for",[150,1131,1132],{"class":223}," r ",[150,1134,404],{"class":219},[150,1136,1137],{"class":195}," range",[150,1139,310],{"class":223},[150,1141,1117],{"class":195},[150,1143,282],{"class":223},[150,1145,107],{"class":195},[150,1147,1148],{"class":223},")), ",[150,1150,1117],{"class":195},[150,1152,551],{"class":223},[150,1154,1155,1158,1160,1162,1165,1167,1170,1172,1174,1176,1178],{"class":152,"line":395},[150,1156,1157],{"class":223},"actual ",[150,1159,246],{"class":219},[150,1161,1093],{"class":195},[150,1163,1164],{"class":223},"(ws[",[150,1166,264],{"class":160},[150,1168,1169],{"class":223},"].value ",[150,1171,1123],{"class":219},[150,1173,1126],{"class":195},[150,1175,282],{"class":223},[150,1177,1117],{"class":195},[150,1179,551],{"class":223},[150,1181,1182,1185,1188,1191,1194,1197,1200,1203,1205,1208,1211,1215,1218,1221,1224,1226,1229,1231],{"class":152,"line":410},[150,1183,1184],{"class":219},"assert",[150,1186,1187],{"class":195}," abs",[150,1189,1190],{"class":223},"(expected ",[150,1192,1193],{"class":219},"-",[150,1195,1196],{"class":223}," actual) ",[150,1198,1199],{"class":219},"\u003C",[150,1201,1202],{"class":195}," 0.01",[150,1204,282],{"class":223},[150,1206,1207],{"class":219},"f",[150,1209,1210],{"class":160},"\"total mismatch: ",[150,1212,1214],{"class":1213},"sSjpA","{",[150,1216,1217],{"class":223},"actual",[150,1219,1220],{"class":1213},"}",[150,1222,1223],{"class":160}," vs ",[150,1225,1214],{"class":1213},[150,1227,1228],{"class":223},"expected",[150,1230,1220],{"class":1213},[150,1232,1233],{"class":160},"\"\n",[10,1235,1236],{},"An assertion like this belongs in the job, not just in a test: a recalculation that silently produced zeros — because a function was unsupported, or the process timed out — otherwise ships a plausible-looking report full of blanks.",[136,1238,1240],{"id":1239},"cache-results-so-the-recipient-sees-numbers-immediately","Cache results so the recipient sees numbers immediately",[10,1242,1243,1244,1248],{},"There is a middle path worth knowing: write the formula ",[1245,1246,1247],"em",{},"and"," its cached result, so the file shows correct values the instant it opens and still recalculates if the reader edits an input. openpyxl does not expose the cache directly, but xlsxwriter does:",[141,1250,1252],{"className":210,"code":1251,"language":212,"meta":146,"style":146},"import xlsxwriter\n\nwith xlsxwriter.Workbook(\"report.xlsx\") as book:\n    ws = book.add_worksheet(\"Summary\")\n    values = [1200.0, 980.5, 1450.0, 610.25]\n    for row, value in enumerate(values, start=1):\n        ws.write_number(row, 1, value)\n\n    # formula string plus the result Excel would compute\n    ws.write_formula(len(values) + 1, 1, \"=SUM(B2:B5)\", None, sum(values))\n",[13,1253,1254,1261,1265,1283,1297,1327,1353,1362,1366,1371],{"__ignoreMap":146},[150,1255,1256,1258],{"class":152,"line":153},[150,1257,227],{"class":219},[150,1259,1260],{"class":223}," xlsxwriter\n",[150,1262,1263],{"class":152,"line":233},[150,1264,237],{"emptyLinePlaceholder":236},[150,1266,1267,1270,1273,1275,1278,1280],{"class":152,"line":240},[150,1268,1269],{"class":219},"with",[150,1271,1272],{"class":223}," xlsxwriter.Workbook(",[150,1274,252],{"class":160},[150,1276,1277],{"class":223},") ",[150,1279,881],{"class":219},[150,1281,1282],{"class":223}," book:\n",[150,1284,1285,1288,1290,1293,1295],{"class":152,"line":270},[150,1286,1287],{"class":223},"    ws ",[150,1289,246],{"class":219},[150,1291,1292],{"class":223}," book.add_worksheet(",[150,1294,258],{"class":160},[150,1296,551],{"class":223},[150,1298,1299,1302,1304,1307,1310,1312,1315,1317,1320,1322,1325],{"class":152,"line":304},[150,1300,1301],{"class":223},"    values ",[150,1303,246],{"class":219},[150,1305,1306],{"class":223}," [",[150,1308,1309],{"class":195},"1200.0",[150,1311,282],{"class":223},[150,1313,1314],{"class":195},"980.5",[150,1316,282],{"class":223},[150,1318,1319],{"class":195},"1450.0",[150,1321,282],{"class":223},[150,1323,1324],{"class":195},"610.25",[150,1326,973],{"class":223},[150,1328,1329,1332,1335,1337,1340,1343,1346,1348,1351],{"class":152,"line":390},[150,1330,1331],{"class":219},"    for",[150,1333,1334],{"class":223}," row, value ",[150,1336,404],{"class":219},[150,1338,1339],{"class":195}," enumerate",[150,1341,1342],{"class":223},"(values, ",[150,1344,1345],{"class":285},"start",[150,1347,246],{"class":219},[150,1349,1350],{"class":195},"1",[150,1352,422],{"class":223},[150,1354,1355,1358,1360],{"class":152,"line":395},[150,1356,1357],{"class":223},"        ws.write_number(row, ",[150,1359,1350],{"class":195},[150,1361,437],{"class":223},[150,1363,1364],{"class":152,"line":410},[150,1365,237],{"emptyLinePlaceholder":236},[150,1367,1368],{"class":152,"line":425},[150,1369,1370],{"class":202},"    # formula string plus the result Excel would compute\n",[150,1372,1373,1376,1379,1382,1385,1388,1390,1392,1394,1397,1399,1401,1403,1405],{"class":152,"line":608},[150,1374,1375],{"class":223},"    ws.write_formula(",[150,1377,1378],{"class":195},"len",[150,1380,1381],{"class":223},"(values) ",[150,1383,1384],{"class":219},"+",[150,1386,1387],{"class":195}," 1",[150,1389,282],{"class":223},[150,1391,1350],{"class":195},[150,1393,282],{"class":223},[150,1395,1396],{"class":160},"\"=SUM(B2:B5)\"",[150,1398,282],{"class":223},[150,1400,30],{"class":195},[150,1402,282],{"class":223},[150,1404,1098],{"class":195},[150,1406,321],{"class":223},[10,1408,1409,1410,1413],{},"The fifth argument to ",[13,1411,1412],{},"write_formula"," is the cached value. Excel shows it immediately and replaces it the moment anything recalculates, so the two can never disagree for long. Getting it wrong is worse than omitting it, though — a wrong cached value is displayed as fact until someone edits the sheet, so compute it with the same code that produced the data.",[39,1415,48,1420,48,1423,48,1426,48,1429,48,1434,48,1438,48,1442,48,1447,48,1450,48,1454,48,1457,48,1462,48,1464,48,1467],{"viewBox":1416,"role":42,"ariaLabelledBy":1417,"xmlns":46,"style":47},"0 0 760 202",[1418,1419],"rc3-t","rc3-d",[50,1421,1422],{"id":1418},"What the reader sees, with and without a cached result",[54,1424,1425],{"id":1419},"A formula with no cached value shows as blank or zero until the reader recalculates, while a formula written with its computed result displays correctly on open.",[58,1427],{"x":60,"y":60,"width":61,"height":1428,"fill":63},"202",[65,1430,1433],{"x":1431,"y":797,"style":1432},"196","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","formula only",[65,1435,1437],{"x":1436,"y":797,"style":846},"566","formula + cached value",[58,1439],{"x":73,"y":74,"width":1440,"height":74,"rx":1441,"fill":121,"stroke":79},"332","9",[65,1443,1446],{"x":1431,"y":1444,"style":1445},"74","font-size:12px;fill:var(--accent-ink,#be185d);text-anchor:middle","openpyxl reads None",[58,1448],{"x":73,"y":1449,"width":1440,"height":74,"rx":1441,"fill":121,"stroke":79},"100",[65,1451,1453],{"x":1431,"y":1452,"style":1445},"128","PDF export prints a blank cell",[58,1455],{"x":1456,"y":74,"width":1440,"height":74,"rx":1441,"fill":108,"stroke":79},"398",[65,1458,1461],{"x":1459,"y":1444,"style":1460},"564","font-size:12px;fill:var(--teal-ink,#0b6157);text-anchor:middle","openpyxl reads the number",[58,1463],{"x":1456,"y":1449,"width":1440,"height":74,"rx":1441,"fill":108,"stroke":79},[65,1465,1466],{"x":1459,"y":1452,"style":1460},"PDF export prints the value",[65,1468,1469],{"x":67,"y":625,"style":133},"The PDF case is where a missing cache is noticed by the recipient, not by you",[10,1471,1472,1473,37],{},"The PDF row is the one that catches teams out. A report exported to PDF without cached results prints blank cells wherever a formula sits, because no application ever recalculated the file — see ",[33,1474,776],{"href":775},[136,1476,1478],{"id":1477},"common-pitfalls-and-gotchas","Common pitfalls and gotchas",[1480,1481,1482,1493,1506,1515,1524],"ul",{},[1483,1484,1485,1492],"li",{},[1486,1487,1488,1489,1491],"strong",{},"Expecting ",[13,1490,27],{}," to compute."," It reads a cache; it never calculates.",[1483,1494,1495,1498,1499,1501,1502,1505],{},[1486,1496,1497],{},"Losing formulas on save."," Opening with ",[13,1500,27],{}," and saving writes the cached values ",[1245,1503,1504],{},"instead of"," the formulas, permanently.",[1483,1507,1508,1511,1512,1514],{},[1486,1509,1510],{},"Unsupported functions."," ",[13,1513,341],{}," raises on what it does not implement — catch it and fall back rather than shipping a partial recalculation.",[1483,1516,1517,1520,1521,37],{},[1486,1518,1519],{},"Parallel LibreOffice runs."," They collide on the shared user profile; give each an isolated ",[13,1522,1523],{},"-env:UserInstallation",[1483,1525,1526,1511,1529,282,1532,1535,1536,1539],{},[1486,1527,1528],{},"Volatile functions.",[13,1530,1531],{},"NOW()",[13,1533,1534],{},"TODAY()"," and ",[13,1537,1538],{},"RAND()"," change on every recalculation, so an output diff will never be stable.",[136,1541,1543],{"id":1542},"performance-and-scale-notes","Performance and scale notes",[10,1545,1546,1548,1549,1553],{},[13,1547,341],{}," builds a dependency graph of the whole workbook, so its cost grows with the number of formula cells rather than the number of data rows — a sheet with ten thousand formula cells is genuinely slow, while one with ten formulas over a hundred thousand rows is fast. LibreOffice costs a process start of a second or two plus its own recalculation, which makes it a batch tool: convert many files in one run rather than starting the application per request. Computing in pandas is orders of magnitude faster than either and is the only option that scales linearly with data rather than with formulas. For workbooks large enough that this matters, the write-side techniques in ",[33,1550,1552],{"href":1551},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fwrite-large-dataframes-to-excel-with-write-only-mode\u002F","Write large DataFrames to Excel with write-only mode"," pair well with computing values up front.",[136,1555,1557],{"id":1556},"conclusion","Conclusion",[10,1559,1560,1561,1563],{},"openpyxl does not calculate, and a file written by Python has no cached results to read. Pick the route that matches the workbook: ",[13,1562,341],{}," when it is simple and you want to stay in Python, headless LibreOffice when you have inherited a model that uses the full function library, and computed values when you own the report — which is faster, testable, and removes the dependency altogether. Whichever you choose, assert a known total before delivery so a silent recalculation failure cannot reach a reader.",[136,1565,1567],{"id":1566},"frequently-asked-questions","Frequently asked questions",[10,1569,1570,1573,1574,1576,1577,37],{},[1486,1571,1572],{},"Why does openpyxl return None for my formula cell?","\nWith ",[13,1575,27],{}," openpyxl returns the cached result Excel stored when it last saved the file. A workbook written by a Python library has never been opened by Excel, so there is no cache and the value is ",[13,1578,30],{},[10,1580,1581,1584],{},[1486,1582,1583],{},"Does the formulas library support every Excel function?","\nNo. It covers a large, useful subset — arithmetic, logic, lookup, text and common maths and date functions — but not everything, and not modern dynamic arrays. Test it against your actual workbook before depending on it.",[10,1586,1587,1590,1591,1594],{},[1486,1588,1589],{},"Is LibreOffice a reasonable dependency on a server?","\nYes, and it is a common one. Headless LibreOffice recalculates on load and can convert to ",[13,1592,1593],{},".xlsx"," or PDF, which makes it the most compatible option short of Excel itself.",[10,1596,1597,1600],{},[1486,1598,1599],{},"What is the fastest approach?","\nNot recalculating at all. Compute the numbers in pandas and write values, optionally alongside formulas for transparency. That runs in milliseconds and needs no extra process.",[10,1602,1603,1606],{},[1486,1604,1605],{},"Can I keep the formulas and still have values?","\nYes — write the formula string and set the cached value, or recalculate once with LibreOffice before delivery so the file carries both.",[136,1608,1610],{"id":1609},"related","Related",[1480,1612,1613,1621,1626,1633,1640],{},[1483,1614,1615,1511,1618,1620],{},[1486,1616,1617],{},"Up:",[33,1619,36],{"href":35}," — writing, copying and reading formulas.",[1483,1622,1623,1625],{},[33,1624,331],{"href":330}," — the cache this page works around.",[1483,1627,1628,1632],{},[33,1629,1631],{"href":1630},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fconvert-excel-formulas-to-values-with-python\u002F","Convert Excel formulas to values with Python"," — freezing results once they are correct.",[1483,1634,1635,1639],{},[33,1636,1638],{"href":1637},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frefresh-pivot-tables-and-queries-in-excel-with-python\u002F","Refresh Excel pivot tables and queries with Python"," — the same problem when Excel is available to drive.",[1483,1641,1642,1644],{},[33,1643,776],{"href":775}," — the other job headless LibreOffice does well.",[1646,1647,1648],"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 .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 .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 .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":146,"searchDepth":233,"depth":233,"links":1650},[1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662],{"id":138,"depth":233,"text":139},{"id":206,"depth":233,"text":207},{"id":334,"depth":233,"text":335},{"id":478,"depth":233,"text":479},{"id":862,"depth":233,"text":863},{"id":1023,"depth":233,"text":1024},{"id":1239,"depth":233,"text":1240},{"id":1477,"depth":233,"text":1478},{"id":1542,"depth":233,"text":1543},{"id":1556,"depth":233,"text":1557},{"id":1566,"depth":233,"text":1567},{"id":1609,"depth":233,"text":1610},"2026-08-27","Get formula results when openpyxl returns None: recalculate with the formulas library or LibreOffice headless, or restructure so the values are computed in Python.","md",[1667,1669,1671,1673,1675],{"q":1572,"a":1668},"With data_only=True openpyxl returns the cached result Excel stored when it last saved the file. A workbook written by a Python library has never been opened by Excel, so there is no cache and the value is None.",{"q":1583,"a":1670},"No. It covers a large, useful subset — arithmetic, logic, lookup, text and common maths and date functions — but not everything, and not modern dynamic arrays. Test it against your actual workbook before depending on it.",{"q":1589,"a":1672},"Yes, and it is a common one. Headless LibreOffice recalculates on load and can convert to xlsx or PDF, which makes it the most compatible option short of Excel itself.",{"q":1599,"a":1674},"Not recalculating at all. Compute the numbers in pandas and write values, optionally alongside formulas for transparency. That runs in milliseconds and needs no extra process.",{"q":1605,"a":1676},"Yes — write the formula string and set the cached value, or recalculate once with LibreOffice before delivery so the file carries both.",{},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python",{"title":1680,"description":1681},"Recalculate Excel Formulas in Python","Compute formula results with no Excel installed — the formulas package, LibreOffice headless conversion, and why writing computed values beats shipping live formulas.","recalculate-excel-formulas-without-excel-in-python","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Frecalculate-excel-formulas-without-excel-in-python\u002Findex","how-to","4FXzzrCbBumCrEJdDgCOdHJiCKFNL-teLSApgmd-XZA",[1687,1691],{"title":1688,"path":1689,"stem":1690,"children":-1},"Read Formula Results with openpyxl data_only","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002Findex",{"title":1692,"path":1693,"stem":1694,"children":-1},"Write a Formula to an Excel Cell with openpyxl","\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl","getting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fwrite-formula-to-excel-cell-with-openpyxl\u002Findex",1788710159522]