[{"data":1,"prerenderedAt":1618},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings":1584,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings":1592,"children:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings":1597,"related:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings":1598},{"id":4,"title":5,"body":6,"dateModified":1551,"datePublished":1551,"description":1552,"extension":1553,"faq":1554,"keyword":1563,"kind":1564,"meta":1565,"navigation":363,"path":1574,"seo":1575,"slug":1578,"stem":1579,"topics":1580,"type":1582,"__hash__":1583},"docs\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings\u002Findex.md","Run Python from an Excel Button with xlwings RunPython",{"type":7,"value":8,"toc":1536},"minimark",[9,37,211,216,219,258,268,272,275,290,305,309,316,629,637,641,644,666,684,785,789,795,964,979,983,996,1046,1049,1053,1060,1098,1105,1109,1112,1249,1264,1268,1271,1393,1396,1400,1444,1448,1471,1475,1481,1487,1493,1499,1503,1532],[10,11,12,13,17,18,21,22,25,26,30,31,36],"p",{},"Some automation belongs inside the workbook people already use: a ",[14,15,16],"em",{},"Refresh"," button on a planning sheet that pulls the latest figures, a ",[14,19,20],{},"Validate"," button that checks what someone typed, a ",[14,23,24],{},"Build report"," button that turns the current selection into a formatted output. VBA can do the clicking; Python is better at the work behind it. xlwings joins the two: a one-line VBA macro calls ",[27,28,29],"code",{},"RunPython",", Python runs your function, and the function reads and writes the workbook that pressed the button. This guide, part of ",[32,33,35],"a",{"href":34},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002F","Automating Excel With xlwings: The Basics",", builds that setup end to end.",[38,39,47,48,47,52,47,56,47,64,47,74,47,85,47,92,47,97,47,104,47,109,47,112,47,118,47,122,47,128,47,130,47,132,47,137,47,142,47,150,47,156,47,161,47,164,47,169,47,174,47,179,47,182,47,189,47,194,47,199,47,202,47,207],"svg",{"viewBox":40,"role":41,"ariaLabelledBy":42,"xmlns":45,"style":46},"4 0 752 322","img",[43,44],"rp-seq-t","rp-seq-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[49,50,51],"title",{"id":43},"What happens when the user clicks the button",[53,54,55],"desc",{"id":44},"The user clicks a button in Excel. The button's VBA macro calls RunPython with an import and a function call. xlwings starts Python, which runs the function. The function gets the calling workbook with Book.caller, reads the inputs, and writes the results back into the workbook the user is looking at.",[57,58],"rect",{"x":59,"y":60,"width":61,"height":62,"fill":63},"4","0","752","322","#ffffff",[57,65],{"x":66,"y":67,"width":68,"height":69,"rx":70,"fill":71,"stroke":72,"style":73},"20.0","16.0","180.0","78.0","12","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[75,76,78],"g",{"transform":77},"translate(98.0,30.5) scale(1.000)",[79,80],"path",{"d":81,"fill":82,"stroke":83,"style":84},"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M4 21c0-4 3.6-7 8-7s8 3 8 7","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[86,87,91],"text",{"x":88,"y":89,"style":90},"110.0","76.5","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","User",[57,93],{"x":94,"y":67,"width":68,"height":69,"rx":70,"fill":95,"stroke":96,"style":73},"290.0","#e7ebef","var(--line,#cdd5e6)",[75,98,100],{"transform":99},"translate(368.0,30.5) scale(1.000)",[79,101],{"d":102,"fill":82,"stroke":103,"style":84},"M3 5.5l8-1.2v7.2H3z M13 4l8-1.2v8.7h-8z M3 13.5h8v7.2l-8-1.2z M13 13.5h8v8.7l-8-1.2z","var(--text,#172033)",[86,105,108],{"x":106,"y":89,"style":107},"380.0","font-size:13px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Excel + VBA",[57,110],{"x":111,"y":67,"width":68,"height":69,"rx":70,"fill":95,"stroke":96,"style":73},"560.0",[75,113,115],{"transform":114},"translate(638.0,30.5) scale(1.000)",[79,116],{"d":117,"fill":82,"stroke":103,"style":84},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01",[86,119,121],{"x":120,"y":89,"style":107},"650.0","Python",[123,124],"line",{"x1":88,"y1":125,"x2":88,"y2":126,"stroke":96,"style":127},"94.0","306.0","stroke-width:1.5px;stroke-dasharray:5 4",[123,129],{"x1":106,"y1":125,"x2":106,"y2":126,"stroke":96,"style":127},[123,131],{"x1":120,"y1":125,"x2":120,"y2":126,"stroke":96,"style":127},[123,133],{"x1":134,"y1":135,"x2":136,"y2":135,"stroke":72,"style":73},"115.0","134.0","371.0",[138,139],"polygon",{"points":140,"fill":141},"375.0,134.0 366.0,139.0 366.0,129.0","#5b5cf0",[57,143],{"x":144,"y":145,"width":146,"height":147,"rx":148,"fill":63,"stroke":96,"style":149},"170.1","105.0","149.8","21.0","10","stroke-width:1.2px",[86,151,155],{"x":152,"y":153,"style":154},"245.0","119.5","font-size:11.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","1. clicks \"Build report\"",[123,157],{"x1":158,"y1":159,"x2":160,"y2":159,"stroke":72,"style":73},"385.0","182.0","641.0",[138,162],{"points":163,"fill":141},"645.0,182.0 636.0,187.0 636.0,177.0",[57,165],{"x":166,"y":167,"width":168,"height":147,"rx":148,"fill":63,"stroke":96,"style":149},"376.5","153.0","277.0",[86,170,173],{"x":171,"y":172,"style":154},"515.0","167.5","2. RunPython \"import report; report.main()\"",[123,175],{"x1":176,"y1":177,"x2":178,"y2":177,"stroke":72,"style":73},"645.0","230.0","389.0",[138,180],{"points":181,"fill":141},"385.0,230.0 394.0,225.0 394.0,235.0",[57,183],{"x":184,"y":185,"width":186,"height":147,"rx":148,"fill":187,"stroke":188,"style":149},"409.8","201.0","210.3","#d9f4f1","var(--teal,#0f9488)",[86,190,193],{"x":171,"y":191,"style":192},"215.5","font-size:11.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","3. Book.caller() → read and write",[123,195],{"x1":196,"y1":197,"x2":198,"y2":197,"stroke":72,"style":73},"375.0","278.0","119.0",[138,200],{"points":201,"fill":141},"115.0,278.0 124.0,273.0 124.0,283.0",[57,203],{"x":204,"y":205,"width":206,"height":147,"rx":148,"fill":187,"stroke":188,"style":149},"170.2","249.0","149.7",[86,208,210],{"x":152,"y":209,"style":192},"263.5","4. results on the sheet",[212,213,215],"h2",{"id":214},"prerequisites","Prerequisites",[10,217,218],{},"Desktop Excel on Windows or macOS, Python with xlwings, and the xlwings Excel add-in (unless you use a standalone workbook, Step 6):",[220,221,226],"pre",{"className":222,"code":223,"language":224,"meta":225,"style":225},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlwings pandas\nxlwings addin install\n","bash","",[27,227,228,246],{"__ignoreMap":225},[229,230,232,236,240,243],"span",{"class":123,"line":231},1,[229,233,235],{"class":234},"sMTad","pip",[229,237,239],{"class":238},"srMev"," install",[229,241,242],{"class":238}," xlwings",[229,244,245],{"class":238}," pandas\n",[229,247,249,252,255],{"class":123,"line":248},2,[229,250,251],{"class":234},"xlwings",[229,253,254],{"class":238}," addin",[229,256,257],{"class":238}," install\n",[10,259,260,261,264,265,267],{},"The add-in adds an ",[262,263,251],"strong",{}," tab to Excel's ribbon and provides the ",[27,266,29],{}," function to VBA. Macros must be enabled for the workbook, because the button runs a VBA macro.",[212,269,271],{"id":270},"step-1-create-a-project-with-quickstart","Step 1 — Create a project with quickstart",[10,273,274],{},"xlwings can generate a matching workbook and Python file:",[220,276,278],{"className":222,"code":277,"language":224,"meta":225,"style":225},"xlwings quickstart report\n",[27,279,280],{"__ignoreMap":225},[229,281,282,284,287],{"class":123,"line":231},[229,283,251],{"class":234},[229,285,286],{"class":238}," quickstart",[229,288,289],{"class":238}," report\n",[10,291,292,293,296,297,300,301,304],{},"This creates a folder ",[27,294,295],{},"report"," containing ",[27,298,299],{},"report.xlsm"," and ",[27,302,303],{},"report.py",". The workbook's VBA module already has a macro wired to the Python file, and by default xlwings looks for the Python module next to the workbook, so the two travel together. Keeping each button-driven tool in its own quickstart folder avoids the most common problem — Python not finding the module — before it starts.",[212,306,308],{"id":307},"step-2-write-the-python-function","Step 2 — Write the Python function",[10,310,311,312,315],{},"The Python side is an ordinary function. The only special line is ",[27,313,314],{},"xw.Book.caller()",", which returns the workbook whose button started the run:",[220,317,321],{"className":318,"code":319,"language":320,"meta":225,"style":225},"language-python shiki shiki-themes github-light github-dark-high-contrast","# report.py\nimport pandas as pd\nimport xlwings as xw\n\ndef main():\n    wb = xw.Book.caller()\n    data = wb.sheets[\"Data\"].range(\"A1\").options(pd.DataFrame, header=1, index=False,\n                                                 expand=\"table\").value\n    summary = (data.groupby(\"region\", as_index=False)[\"amount\"].sum()\n                   .sort_values(\"amount\", ascending=False))\n\n    out = wb.sheets[\"Summary\"]\n    out.clear_contents()\n    out.range(\"A1\").options(index=False).value = summary\n    out.range(\"D1\").value = f\"Built {pd.Timestamp.now():%Y-%m-%d %H:%M} from {len(data)} rows\"\n","python",[27,322,323,329,345,358,365,378,390,437,451,483,503,508,524,530,555],{"__ignoreMap":225},[229,324,325],{"class":123,"line":231},[229,326,328],{"class":327},"s-wDw","# report.py\n",[229,330,331,335,339,342],{"class":123,"line":248},[229,332,334],{"class":333},"s-kum","import",[229,336,338],{"class":337},"skGVy"," pandas ",[229,340,341],{"class":333},"as",[229,343,344],{"class":337}," pd\n",[229,346,348,350,353,355],{"class":123,"line":347},3,[229,349,334],{"class":333},[229,351,352],{"class":337}," xlwings ",[229,354,341],{"class":333},[229,356,357],{"class":337}," xw\n",[229,359,361],{"class":123,"line":360},4,[229,362,364],{"emptyLinePlaceholder":363},true,"\n",[229,366,368,371,375],{"class":123,"line":367},5,[229,369,370],{"class":333},"def",[229,372,374],{"class":373},"s_Opv"," main",[229,376,377],{"class":337},"():\n",[229,379,381,384,387],{"class":123,"line":380},6,[229,382,383],{"class":337},"    wb ",[229,385,386],{"class":333},"=",[229,388,389],{"class":337}," xw.Book.caller()\n",[229,391,393,396,398,401,404,407,410,413,417,419,423,426,429,431,434],{"class":123,"line":392},7,[229,394,395],{"class":337},"    data ",[229,397,386],{"class":333},[229,399,400],{"class":337}," wb.sheets[",[229,402,403],{"class":238},"\"Data\"",[229,405,406],{"class":337},"].range(",[229,408,409],{"class":238},"\"A1\"",[229,411,412],{"class":337},").options(pd.DataFrame, ",[229,414,416],{"class":415},"sa561","header",[229,418,386],{"class":333},[229,420,422],{"class":421},"sP0c6","1",[229,424,425],{"class":337},", ",[229,427,428],{"class":415},"index",[229,430,386],{"class":333},[229,432,433],{"class":421},"False",[229,435,436],{"class":337},",\n",[229,438,440,443,445,448],{"class":123,"line":439},8,[229,441,442],{"class":415},"                                                 expand",[229,444,386],{"class":333},[229,446,447],{"class":238},"\"table\"",[229,449,450],{"class":337},").value\n",[229,452,454,457,459,462,465,467,470,472,474,477,480],{"class":123,"line":453},9,[229,455,456],{"class":337},"    summary ",[229,458,386],{"class":333},[229,460,461],{"class":337}," (data.groupby(",[229,463,464],{"class":238},"\"region\"",[229,466,425],{"class":337},[229,468,469],{"class":415},"as_index",[229,471,386],{"class":333},[229,473,433],{"class":421},[229,475,476],{"class":337},")[",[229,478,479],{"class":238},"\"amount\"",[229,481,482],{"class":337},"].sum()\n",[229,484,486,489,491,493,496,498,500],{"class":123,"line":485},10,[229,487,488],{"class":337},"                   .sort_values(",[229,490,479],{"class":238},[229,492,425],{"class":337},[229,494,495],{"class":415},"ascending",[229,497,386],{"class":333},[229,499,433],{"class":421},[229,501,502],{"class":337},"))\n",[229,504,506],{"class":123,"line":505},11,[229,507,364],{"emptyLinePlaceholder":363},[229,509,511,514,516,518,521],{"class":123,"line":510},12,[229,512,513],{"class":337},"    out ",[229,515,386],{"class":333},[229,517,400],{"class":337},[229,519,520],{"class":238},"\"Summary\"",[229,522,523],{"class":337},"]\n",[229,525,527],{"class":123,"line":526},13,[229,528,529],{"class":337},"    out.clear_contents()\n",[229,531,533,536,538,541,543,545,547,550,552],{"class":123,"line":532},14,[229,534,535],{"class":337},"    out.range(",[229,537,409],{"class":238},[229,539,540],{"class":337},").options(",[229,542,428],{"class":415},[229,544,386],{"class":333},[229,546,433],{"class":421},[229,548,549],{"class":337},").value ",[229,551,386],{"class":333},[229,553,554],{"class":337}," summary\n",[229,556,558,560,563,565,567,570,573,577,580,583,586,589,591,594,596,599,601,604,607,610,613,616,618,621,624,626],{"class":123,"line":557},15,[229,559,535],{"class":337},[229,561,562],{"class":238},"\"D1\"",[229,564,549],{"class":337},[229,566,386],{"class":333},[229,568,569],{"class":333}," f",[229,571,572],{"class":238},"\"Built ",[229,574,576],{"class":575},"sSjpA","{",[229,578,579],{"class":337},"pd.Timestamp.now()",[229,581,582],{"class":333},":",[229,584,585],{"class":337},"%",[229,587,588],{"class":333},"Y-",[229,590,585],{"class":337},[229,592,593],{"class":333},"m-",[229,595,585],{"class":337},[229,597,598],{"class":333},"d ",[229,600,585],{"class":337},[229,602,603],{"class":333},"H",[229,605,606],{"class":337},":%",[229,608,609],{"class":333},"M",[229,611,612],{"class":575},"}",[229,614,615],{"class":238}," from ",[229,617,576],{"class":575},[229,619,620],{"class":421},"len",[229,622,623],{"class":337},"(data)",[229,625,612],{"class":575},[229,627,628],{"class":238}," rows\"\n",[10,630,631,632,636],{},"The function reads the whole data block in one call and writes the summary in one call — the bulk pattern from ",[32,633,635],{"href":634},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes\u002F","Speed Up xlwings with Bulk Reads and Writes",". A button that makes the user wait is a button they stop using.",[212,638,640],{"id":639},"step-3-wire-the-button","Step 3 — Wire the button",[10,642,643],{},"In the workbook's VBA editor (Alt+F11), the macro that calls Python is one line:",[220,645,649],{"className":646,"code":647,"language":648,"meta":225,"style":225},"language-vb shiki shiki-themes github-light github-dark-high-contrast","Sub BuildReport()\n    RunPython \"import report; report.main()\"\nEnd Sub\n","vb",[27,650,651,656,661],{"__ignoreMap":225},[229,652,653],{"class":123,"line":231},[229,654,655],{},"Sub BuildReport()\n",[229,657,658],{"class":123,"line":248},[229,659,660],{},"    RunPython \"import report; report.main()\"\n",[229,662,663],{"class":123,"line":347},[229,664,665],{},"End Sub\n",[10,667,668,669,672,673,676,677,680,681,683],{},"Then add the button: on the ",[262,670,671],{},"Developer"," tab choose ",[262,674,675],{},"Insert → Button (Form Control)",", draw it on the sheet, and assign the ",[27,678,679],{},"BuildReport"," macro. The string passed to ",[27,682,29],{}," is Python code, so it can import any module the interpreter can find and call any function in it. Keep it to an import and a call — logic in that string is hard to read and impossible to test.",[38,685,47,691,47,694,47,697,47,702,47,706,47,712,47,717,47,722,47,726,47,729,47,735,47,740,47,747,47,752,47,756,47,760,47,763,47,767,47,770,47,776,47,781],{"viewBox":686,"role":41,"ariaLabelledBy":687,"xmlns":45,"style":690},"84 0 592 383",[688,689],"rp-parts-t","rp-parts-d","width:100%;max-width:592px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[49,692,693],{"id":688},"The three pieces of a button-driven Python tool",[53,695,696],{"id":689},"A button on the sheet is assigned a VBA macro. The macro contains a single RunPython call naming a module and function. The Python module does the work and reaches the workbook through Book.caller.",[57,698],{"x":699,"y":60,"width":700,"height":701,"fill":63},"84","592","383",[57,703],{"x":704,"y":67,"width":111,"height":705,"rx":70,"fill":95,"stroke":96,"style":73},"100.0","93.0",[75,707,709],{"transform":708},"translate(368.0,29.0) scale(1.000)",[79,710],{"d":711,"fill":82,"stroke":103,"style":84},"M12 9a3 3 0 1 0 .01 0z M12 2.5v3 M12 18.5v3 M2.5 12h3 M18.5 12h3 M5.3 5.3l2.1 2.1 M16.6 16.6l2.1 2.1 M5.3 18.7l2.1-2.1 M16.6 7.4l2.1-2.1",[86,713,716],{"x":106,"y":714,"style":715},"75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Button on the sheet",[86,718,721],{"x":106,"y":719,"style":720},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Developer → Insert → Button",[123,723],{"x1":106,"y1":724,"x2":106,"y2":725,"stroke":72,"style":73},"114.0","136.0",[138,727],{"points":728,"fill":141},"380.0,140.0 375.0,131.0 385.0,131.0",[86,730,734],{"x":731,"y":732,"style":733},"392.0","131.0","font-size:11px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:start","assigned macro",[57,736],{"x":704,"y":737,"width":111,"height":705,"rx":70,"fill":738,"stroke":739,"style":73},"145.0","#fdefd8","var(--gold,#b4740a)",[75,741,743],{"transform":742},"translate(368.0,158.0) scale(1.000)",[79,744],{"d":745,"fill":82,"stroke":746,"style":84},"M9 8l-4 4 4 4 M15 8l4 4-4 4","var(--gold-ink,#7a4e06)",[86,748,751],{"x":106,"y":749,"style":750},"204.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","VBA: Sub BuildReport()",[86,753,755],{"x":106,"y":754,"style":720},"224.0","RunPython \"import report; report.main()\"",[123,757],{"x1":106,"y1":758,"x2":106,"y2":759,"stroke":72,"style":73},"243.0","265.0",[138,761],{"points":762,"fill":141},"380.0,269.0 375.0,260.0 385.0,260.0",[86,764,766],{"x":731,"y":765,"style":733},"260.0","starts Python",[57,768],{"x":704,"y":769,"width":111,"height":705,"rx":70,"fill":187,"stroke":188,"style":73},"274.0",[75,771,773],{"transform":772},"translate(368.0,287.0) scale(1.000)",[79,774],{"d":117,"fill":82,"stroke":775,"style":84},"var(--teal-ink,#0b6157)",[86,777,780],{"x":106,"y":778,"style":779},"333.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","report.py: main()",[86,782,784],{"x":106,"y":783,"style":720},"353.0","xw.Book.caller(), read, compute, write",[212,786,788],{"id":787},"step-4-pass-arguments-from-the-sheet","Step 4 — Pass arguments from the sheet",[10,790,791,792,794],{},"Different buttons often run the same function with different settings — one per region, say. Either pass literal arguments in the ",[27,793,29],{}," string, or better, have the function read its inputs from named cells so users change them without touching VBA:",[220,796,798],{"className":318,"code":797,"language":320,"meta":225,"style":225},"def main_for_region():\n    wb = xw.Book.caller()\n    region = wb.sheets[\"Controls\"].range(\"SelectedRegion\").value\n    start = wb.sheets[\"Controls\"].range(\"StartDate\").value      # arrives as a datetime\n    data = wb.sheets[\"Data\"].range(\"A1\").options(pd.DataFrame, header=1, index=False,\n                                                 expand=\"table\").value\n    view = data[(data[\"region\"] == region) & (data[\"order_date\"] >= start)]\n    wb.sheets[\"Summary\"].range(\"A1\").options(index=False).value = view\n",[27,799,800,809,817,836,858,890,900,938],{"__ignoreMap":225},[229,801,802,804,807],{"class":123,"line":231},[229,803,370],{"class":333},[229,805,806],{"class":373}," main_for_region",[229,808,377],{"class":337},[229,810,811,813,815],{"class":123,"line":248},[229,812,383],{"class":337},[229,814,386],{"class":333},[229,816,389],{"class":337},[229,818,819,822,824,826,829,831,834],{"class":123,"line":347},[229,820,821],{"class":337},"    region ",[229,823,386],{"class":333},[229,825,400],{"class":337},[229,827,828],{"class":238},"\"Controls\"",[229,830,406],{"class":337},[229,832,833],{"class":238},"\"SelectedRegion\"",[229,835,450],{"class":337},[229,837,838,841,843,845,847,849,852,855],{"class":123,"line":360},[229,839,840],{"class":337},"    start ",[229,842,386],{"class":333},[229,844,400],{"class":337},[229,846,828],{"class":238},[229,848,406],{"class":337},[229,850,851],{"class":238},"\"StartDate\"",[229,853,854],{"class":337},").value      ",[229,856,857],{"class":327},"# arrives as a datetime\n",[229,859,860,862,864,866,868,870,872,874,876,878,880,882,884,886,888],{"class":123,"line":367},[229,861,395],{"class":337},[229,863,386],{"class":333},[229,865,400],{"class":337},[229,867,403],{"class":238},[229,869,406],{"class":337},[229,871,409],{"class":238},[229,873,412],{"class":337},[229,875,416],{"class":415},[229,877,386],{"class":333},[229,879,422],{"class":421},[229,881,425],{"class":337},[229,883,428],{"class":415},[229,885,386],{"class":333},[229,887,433],{"class":421},[229,889,436],{"class":337},[229,891,892,894,896,898],{"class":123,"line":380},[229,893,442],{"class":415},[229,895,386],{"class":333},[229,897,447],{"class":238},[229,899,450],{"class":337},[229,901,902,905,907,910,912,915,918,921,924,927,930,932,935],{"class":123,"line":392},[229,903,904],{"class":337},"    view ",[229,906,386],{"class":333},[229,908,909],{"class":337}," data[(data[",[229,911,464],{"class":238},[229,913,914],{"class":337},"] ",[229,916,917],{"class":333},"==",[229,919,920],{"class":337}," region) ",[229,922,923],{"class":333},"&",[229,925,926],{"class":337}," (data[",[229,928,929],{"class":238},"\"order_date\"",[229,931,914],{"class":337},[229,933,934],{"class":333},">=",[229,936,937],{"class":337}," start)]\n",[229,939,940,943,945,947,949,951,953,955,957,959,961],{"class":123,"line":439},[229,941,942],{"class":337},"    wb.sheets[",[229,944,520],{"class":238},[229,946,406],{"class":337},[229,948,409],{"class":238},[229,950,540],{"class":337},[229,952,428],{"class":415},[229,954,386],{"class":333},[229,956,433],{"class":421},[229,958,549],{"class":337},[229,960,386],{"class":333},[229,962,963],{"class":337}," view\n",[10,965,966,967,425,970,973,974,978],{},"Named cells (",[27,968,969],{},"SelectedRegion",[27,971,972],{},"StartDate",") keep working when someone inserts rows above them, and a data-validation dropdown on the region cell stops typos from reaching the code. Dropdowns are covered in ",[32,975,977],{"href":976},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fadd-dropdown-data-validation-to-excel-with-openpyxl\u002F","Add Dropdown Data Validation to Excel with openpyxl",".",[212,980,982],{"id":981},"step-5-configure-the-interpreter","Step 5 — Configure the interpreter",[10,984,985,987,988,991,992,995],{},[27,986,29],{}," needs to know which Python to start. Set it once in the xlwings ribbon (the ",[14,989,990],{},"Interpreter"," box) or, to keep the setting with the workbook, in a sheet named ",[27,993,994],{},"xlwings.conf"," with two columns of keys and values:",[997,998,999,1012],"table",{},[1000,1001,1002],"thead",{},[1003,1004,1005,1009],"tr",{},[1006,1007,1008],"th",{},"Key",[1006,1010,1011],{},"Value",[1013,1014,1015,1026,1036],"tbody",{},[1003,1016,1017,1021],{},[1018,1019,1020],"td",{},"Interpreter_Win",[1018,1022,1023],{},[27,1024,1025],{},"C:\\tools\\report-env\\Scripts\\python.exe",[1003,1027,1028,1031],{},[1018,1029,1030],{},"Interpreter_Mac",[1018,1032,1033],{},[27,1034,1035],{},"\u002FUsers\u002Fshared\u002Freport-env\u002Fbin\u002Fpython",[1003,1037,1038,1041],{},[1018,1039,1040],{},"PYTHONPATH",[1018,1042,1043],{},[27,1044,1045],{},"C:\\tools\\report",[10,1047,1048],{},"Pointing at a dedicated virtual environment keeps the tool's dependencies separate from anything else on the machine. If users have different paths, the ribbon setting per user is simpler; if the machine is shared or managed, the sheet travels with the workbook.",[212,1050,1052],{"id":1051},"step-6-test-without-clicking-and-distribute","Step 6 — Test without clicking, and distribute",[10,1054,1055,1056,1059],{},"Clicking a button is a slow way to debug. ",[27,1057,1058],{},"set_mock_caller()"," makes a workbook opened from Python look like the caller, so the function runs from your editor, breakpoints and all:",[220,1061,1063],{"className":318,"code":1062,"language":320,"meta":225,"style":225},"if __name__ == \"__main__\":\n    xw.Book(\"report.xlsm\").set_mock_caller()\n    main()\n",[27,1064,1065,1082,1093],{"__ignoreMap":225},[229,1066,1067,1070,1073,1076,1079],{"class":123,"line":231},[229,1068,1069],{"class":333},"if",[229,1071,1072],{"class":421}," __name__",[229,1074,1075],{"class":333}," ==",[229,1077,1078],{"class":238}," \"__main__\"",[229,1080,1081],{"class":337},":\n",[229,1083,1084,1087,1090],{"class":123,"line":248},[229,1085,1086],{"class":337},"    xw.Book(",[229,1088,1089],{"class":238},"\"report.xlsm\"",[229,1091,1092],{"class":337},").set_mock_caller()\n",[229,1094,1095],{"class":123,"line":347},[229,1096,1097],{"class":337},"    main()\n",[10,1099,1100,1101,1104],{},"To give the tool to people who do not have the add-in, create it with ",[27,1102,1103],{},"xlwings quickstart report --standalone",". That copies the xlwings VBA code into the workbook, so only Python and the xlwings package are needed on the user's machine. Macros must still be allowed: files that arrive by email or download are blocked by default, so distribute through a trusted network location or have users unblock the file.",[212,1106,1108],{"id":1107},"handling-errors","Handling errors",[10,1110,1111],{},"When the Python function raises, xlwings shows the traceback in a message box — useful to you, alarming to users. Catch errors at the top of the function, show a plain message in the sheet, and keep the full traceback in a log file you can ask for:",[220,1113,1115],{"className":318,"code":1114,"language":320,"meta":225,"style":225},"import logging\nimport traceback\n\nlogging.basicConfig(filename=\"report.log\", level=logging.INFO)\n\ndef safe_main():\n    wb = xw.Book.caller()\n    status = wb.sheets[\"Controls\"].range(\"Status\")\n    try:\n        main()\n        status.value = \"Done\"\n    except Exception:\n        logging.error(traceback.format_exc())\n        status.value = \"Something went wrong — the details are in report.log\"\n",[27,1116,1117,1124,1131,1135,1164,1168,1177,1185,1203,1210,1215,1225,1235,1240],{"__ignoreMap":225},[229,1118,1119,1121],{"class":123,"line":231},[229,1120,334],{"class":333},[229,1122,1123],{"class":337}," logging\n",[229,1125,1126,1128],{"class":123,"line":248},[229,1127,334],{"class":333},[229,1129,1130],{"class":337}," traceback\n",[229,1132,1133],{"class":123,"line":347},[229,1134,364],{"emptyLinePlaceholder":363},[229,1136,1137,1140,1143,1145,1148,1150,1153,1155,1158,1161],{"class":123,"line":360},[229,1138,1139],{"class":337},"logging.basicConfig(",[229,1141,1142],{"class":415},"filename",[229,1144,386],{"class":333},[229,1146,1147],{"class":238},"\"report.log\"",[229,1149,425],{"class":337},[229,1151,1152],{"class":415},"level",[229,1154,386],{"class":333},[229,1156,1157],{"class":337},"logging.",[229,1159,1160],{"class":421},"INFO",[229,1162,1163],{"class":337},")\n",[229,1165,1166],{"class":123,"line":367},[229,1167,364],{"emptyLinePlaceholder":363},[229,1169,1170,1172,1175],{"class":123,"line":380},[229,1171,370],{"class":333},[229,1173,1174],{"class":373}," safe_main",[229,1176,377],{"class":337},[229,1178,1179,1181,1183],{"class":123,"line":392},[229,1180,383],{"class":337},[229,1182,386],{"class":333},[229,1184,389],{"class":337},[229,1186,1187,1190,1192,1194,1196,1198,1201],{"class":123,"line":439},[229,1188,1189],{"class":337},"    status ",[229,1191,386],{"class":333},[229,1193,400],{"class":337},[229,1195,828],{"class":238},[229,1197,406],{"class":337},[229,1199,1200],{"class":238},"\"Status\"",[229,1202,1163],{"class":337},[229,1204,1205,1208],{"class":123,"line":453},[229,1206,1207],{"class":333},"    try",[229,1209,1081],{"class":337},[229,1211,1212],{"class":123,"line":485},[229,1213,1214],{"class":337},"        main()\n",[229,1216,1217,1220,1222],{"class":123,"line":505},[229,1218,1219],{"class":337},"        status.value ",[229,1221,386],{"class":333},[229,1223,1224],{"class":238}," \"Done\"\n",[229,1226,1227,1230,1233],{"class":123,"line":510},[229,1228,1229],{"class":333},"    except",[229,1231,1232],{"class":421}," Exception",[229,1234,1081],{"class":337},[229,1236,1237],{"class":123,"line":526},[229,1238,1239],{"class":337},"        logging.error(traceback.format_exc())\n",[229,1241,1242,1244,1246],{"class":123,"line":532},[229,1243,1219],{"class":337},[229,1245,386],{"class":333},[229,1247,1248],{"class":238}," \"Something went wrong — the details are in report.log\"\n",[10,1250,1251,1252,1255,1256,1259,1260,978],{},"Point the button at ",[27,1253,1254],{},"safe_main"," instead of ",[27,1257,1258],{},"main",". For turning individual functions into Excel formulas rather than button actions, see ",[32,1261,1263],{"href":1262},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fcall-python-from-excel-with-xlwings-udf\u002F","Call Python from Excel with an xlwings UDF",[212,1265,1267],{"id":1266},"button-formula-or-scheduled-job","Button, formula or scheduled job?",[10,1269,1270],{},"A button is one of three ways to put Python behind a workbook, and it is worth choosing deliberately. A button suits an action a person decides to take at a moment of their choosing — rebuild this summary now, validate what I just typed, export this selection. A user-defined function suits a calculation that should update like any other formula whenever its inputs change. A scheduled job suits work that must happen whether or not anyone opens the workbook, such as producing the Monday report at 06:00.",[38,1272,47,1277,47,1280,47,1283,47,1286,47,1290,47,1295,47,1299,47,1303,47,1307,47,1310,47,1313,47,1318,47,1322,47,1326,47,1331,47,1335,47,1339,47,1341,47,1344,47,1348,47,1351,47,1354,47,1360,47,1363,47,1366,47,1368,47,1371,47,1375,47,1378,47,1381,47,1387,47,1390],{"viewBox":1273,"role":41,"ariaLabelledBy":1274,"xmlns":45,"style":46},"4 0 752 272",[1275,1276],"rp-which-t","rp-which-d",[49,1278,1279],{"id":1275},"Choosing between a button, a formula and a scheduled job",[53,1281,1282],{"id":1276},"If a person triggers the action when they choose, use a button with RunPython. If the result should recalculate like a formula when inputs change, use an xlwings UDF. If the work must happen on a timetable without anyone opening Excel, run a scheduled Python job that writes the workbook.",[57,1284],{"x":59,"y":60,"width":61,"height":1285,"fill":63},"272",[57,1287],{"x":1288,"y":67,"width":1289,"height":714,"rx":70,"fill":71,"stroke":72,"style":73},"240.0","280.0",[75,1291,1292],{"transform":708},[79,1293],{"d":1294,"fill":82,"stroke":83,"style":84},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[86,1296,1298],{"x":106,"y":714,"style":1297},"font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","What starts the work?",[123,1300],{"x1":106,"y1":1301,"x2":106,"y2":1302,"stroke":72,"style":73},"91.5","111.5",[123,1304],{"x1":1305,"y1":1302,"x2":1306,"y2":1302,"stroke":72,"style":73},"134.7","625.3",[123,1308],{"x1":1305,"y1":1302,"x2":1305,"y2":1309,"stroke":72,"style":73},"157.5",[138,1311],{"points":1312,"fill":141},"134.7,161.5 129.7,152.5 139.7,152.5",[57,1314],{"x":1315,"y":1316,"width":1317,"height":147,"rx":148,"fill":63,"stroke":96,"style":149},"75.2","121.5","118.9",[86,1319,1321],{"x":1305,"y":725,"style":1320},"font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","a person decides",[57,1323],{"x":66,"y":1324,"width":1325,"height":705,"rx":70,"fill":71,"stroke":72,"style":73},"163.5","229.3",[75,1327,1329],{"transform":1328},"translate(122.7,176.5) scale(1.000)",[79,1330],{"d":81,"fill":82,"stroke":83,"style":84},[86,1332,1334],{"x":1305,"y":1333,"style":1297},"223.0","Button + RunPython",[86,1336,1338],{"x":1305,"y":1337,"style":720},"242.5","explicit action",[123,1340],{"x1":106,"y1":1302,"x2":106,"y2":1309,"stroke":72,"style":73},[138,1342],{"points":1343,"fill":141},"380.0,161.5 375.0,152.5 385.0,152.5",[57,1345],{"x":1346,"y":1316,"width":1347,"height":147,"rx":148,"fill":63,"stroke":96,"style":149},"329.0","102.0",[86,1349,1350],{"x":106,"y":725,"style":1320},"inputs change",[57,1352],{"x":1353,"y":1324,"width":1325,"height":705,"rx":70,"fill":187,"stroke":188,"style":73},"265.3",[75,1355,1357],{"transform":1356},"translate(368.0,176.5) scale(1.000)",[79,1358],{"d":1359,"fill":82,"stroke":775,"style":84},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16",[86,1361,1362],{"x":106,"y":1333,"style":779},"xlwings UDF",[86,1364,1365],{"x":106,"y":1337,"style":720},"recalculates like a formula",[123,1367],{"x1":1306,"y1":1302,"x2":1306,"y2":1309,"stroke":72,"style":73},[138,1369],{"points":1370,"fill":141},"625.3,161.5 620.3,152.5 630.3,152.5",[57,1372],{"x":1373,"y":1316,"width":1374,"height":147,"rx":148,"fill":63,"stroke":96,"style":149},"589.4","71.9",[86,1376,1377],{"x":1306,"y":725,"style":1320},"the clock",[57,1379],{"x":1380,"y":1324,"width":1325,"height":705,"rx":70,"fill":738,"stroke":739,"style":73},"510.7",[75,1382,1384],{"transform":1383},"translate(613.3,176.5) scale(1.000)",[79,1385],{"d":1386,"fill":82,"stroke":746,"style":84},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2",[86,1388,1389],{"x":1306,"y":1333,"style":750},"Scheduled job",[86,1391,1392],{"x":1306,"y":1337,"style":720},"no Excel session needed",[10,1394,1395],{},"Mixing them is common: a scheduled job refreshes the data sheet every morning, and a button lets a planner rebuild the summary after changing assumptions. Keep the shared logic in one Python module that both call, so the numbers agree however they were produced.",[212,1397,1399],{"id":1398},"common-pitfalls","Common pitfalls",[1401,1402,1403,1413,1422,1428,1434],"ul",{},[1404,1405,1406,1409,1410,1412],"li",{},[262,1407,1408],{},"Module not found."," The Python file must be on the interpreter's path — next to the workbook by default, or in ",[27,1411,1040],{},". Most \"No module named report\" errors are a moved file.",[1404,1414,1415,1418,1419,1421],{},[262,1416,1417],{},"Wrong interpreter."," The ribbon or ",[27,1420,994],{}," points at a Python without xlwings or pandas installed. Check the interpreter path first when a button that works for you fails for a colleague.",[1404,1423,1424,1427],{},[262,1425,1426],{},"Long runs with no feedback."," Excel looks frozen while Python works. Write a \"Working…\" status before the heavy step and keep the work fast.",[1404,1429,1430,1433],{},[262,1431,1432],{},"Two users, one workbook."," Each click runs Python on the clicking user's machine against the copy of the workbook they have open. If the workbook lives on a shared drive, two people pressing the button at once each change their own copy — co-authoring rules still apply to what gets saved.",[1404,1435,1436,1439,1440,1443],{},[262,1437,1438],{},"Editing the macro string."," Logic inside ",[27,1441,1442],{},"RunPython \"...\""," is invisible to tests and linters. Keep it to an import and one call.",[212,1445,1447],{"id":1446},"conclusion","Conclusion",[10,1449,1450,1451,1453,1454,1456,1457,1460,1461,1463,1464,1466,1467,1470],{},"A button-driven Python tool has three parts: a button, a one-line VBA macro calling ",[27,1452,29],{},", and a Python function that finds its workbook with ",[27,1455,314],{},". Generate the pair with ",[27,1458,1459],{},"xlwings quickstart",", read inputs from named cells, configure the interpreter per user or in ",[27,1462,994],{},", debug with ",[27,1465,1058],{},", distribute with ",[27,1468,1469],{},"--standalone",", and wrap the entry point so users see a plain message while the traceback goes to a log.",[212,1472,1474],{"id":1473},"frequently-asked-questions","Frequently asked questions",[10,1476,1477,1480],{},[262,1478,1479],{},"What does RunPython do?","\nRunPython is a VBA function provided by xlwings. It starts Python, runs the code string you give it — typically an import and a function call — and lets that code reach the workbook that called it through xw.Book.caller().",[10,1482,1483,1486],{},[262,1484,1485],{},"Do users need Python installed?","\nYes. RunPython runs Python on the user's machine, so each user needs a Python installation with xlwings and your code's dependencies, and the workbook's configuration must point at that interpreter.",[10,1488,1489,1492],{},[262,1490,1491],{},"How do I test the Python side without clicking the button?","\nOpen the workbook from Python and call set_mock_caller() on it. xw.Book.caller() then returns that workbook, so you can run and debug the function from your editor.",[10,1494,1495,1498],{},[262,1496,1497],{},"Can I distribute the workbook without the xlwings add-in?","\nYes. Create the project with xlwings quickstart --standalone, which copies the xlwings VBA module into the workbook itself, so recipients do not need the add-in — they still need Python and the xlwings package.",[212,1500,1502],{"id":1501},"related","Related",[1401,1504,1505,1511,1518,1525],{},[1404,1506,1507,1508,1510],{},"Up one level: ",[32,1509,35],{"href":34}," — xlwings fundamentals.",[1404,1512,1513,1517],{},[32,1514,1516],{"href":1515},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fxlwings-run-macro-from-python-example\u002F","xlwings: Run a VBA Macro From Python"," — the opposite direction.",[1404,1519,1520,1524],{},[32,1521,1523],{"href":1522},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-vba-for-excel-automation\u002F","Python vs VBA for Excel Automation"," — when a button tool is the right design.",[1404,1526,1527,1531],{},[32,1528,1530],{"href":1529},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Fkeep-excel-report-settings-in-a-config-file\u002F","Keep Excel Report Settings in a Config File"," — settings outside the workbook.",[1533,1534,1535],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-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 .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 .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":225,"searchDepth":248,"depth":248,"links":1537},[1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550],{"id":214,"depth":248,"text":215},{"id":270,"depth":248,"text":271},{"id":307,"depth":248,"text":308},{"id":639,"depth":248,"text":640},{"id":787,"depth":248,"text":788},{"id":981,"depth":248,"text":982},{"id":1051,"depth":248,"text":1052},{"id":1107,"depth":248,"text":1108},{"id":1266,"depth":248,"text":1267},{"id":1398,"depth":248,"text":1399},{"id":1446,"depth":248,"text":1447},{"id":1473,"depth":248,"text":1474},{"id":1501,"depth":248,"text":1502},"2026-09-23","Let Excel users run your Python code with a button — xlwings quickstart, the RunPython VBA call, Book.caller() to reach the calling workbook, passing arguments, configuring the interpreter, testing with a mock caller, and distributing the workbook.","md",[1555,1557,1559,1561],{"q":1479,"a":1556},"RunPython is a VBA function provided by xlwings. It starts Python, runs the code string you give it — typically an import and a function call — and lets that code reach the workbook that called it through xw.Book.caller().",{"q":1485,"a":1558},"Yes. RunPython runs Python on the user's machine, so each user needs a Python installation with xlwings and your code's dependencies, and the workbook's configuration must point at that interpreter.",{"q":1491,"a":1560},"Open the workbook from Python and call set_mock_caller() on it. xw.Book.caller() then returns that workbook, so you can run and debug the function from your editor.",{"q":1497,"a":1562},"Yes. Create the project with xlwings quickstart --standalone, which copies the xlwings VBA module into the workbook itself, so recipients do not need the add-in — they still need Python and the xlwings package.","run python from an excel button with xlwings runpython",null,{"breadcrumb":1566},[1567,1570,1573],{"name":1568,"item":1569},"Home","\u002F",{"name":1571,"item":1572},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":35,"item":34},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings",{"title":1576,"description":1577},"Call Python from an Excel Button with xlwings RunPython","Add a button to an Excel workbook that runs Python with xlwings RunPython — quickstart project, Book.caller, arguments from cells, interpreter configuration, set_mock_caller testing, standalone workbooks and error handling.","run-python-from-an-excel-button-with-xlwings","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frun-python-from-an-excel-button-with-xlwings\u002Findex",[251,1581],"macros-and-vba","how-to","aY06J0RRHeHAaqfCYPdOritS97VlpEag4BDwXKid57Y",[1585,1589],{"title":1586,"path":1587,"stem":1588,"children":-1},"Refresh Excel Pivot Tables and Queries with Python","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frefresh-pivot-tables-and-queries-in-excel-with-python","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Frefresh-pivot-tables-and-queries-in-excel-with-python\u002Findex",{"title":635,"path":1590,"stem":1591,"children":-1},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes","getting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fspeed-up-xlwings-with-bulk-reads-and-writes\u002Findex",[1593,1595],{"path":1594,"title":35},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics",{"path":1596,"title":1571},"\u002Fgetting-started-with-python-excel-automation",[],[1599,1602,1605,1609,1612,1615],{"path":1600,"title":1601,"kind":1582},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-win32com-and-xlwings-code-without-excel","Test win32com and xlwings Code Without Excel",{"path":1603,"title":1604,"kind":1582},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python","Automate Excel on macOS with Python",{"path":1606,"title":1607,"kind":1608},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fxlwings-vs-pywin32-for-excel-automation","xlwings vs pywin32 for Excel Automation","compare",{"path":1610,"title":1611,"kind":1582},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fcontrol-how-xlwings-converts-dataframes-and-ranges","Control How xlwings Converts DataFrames and Ranges",{"path":1613,"title":1614,"kind":1582},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fformat-cells-in-a-live-workbook-with-xlwings","Format Cells in a Live Workbook with xlwings",{"path":1616,"title":1617,"kind":1582},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Finsert-a-matplotlib-plot-into-a-live-workbook-with-xlwings","Insert a matplotlib Plot into a Live Workbook with xlwings",1790972057041]