[{"data":1,"prerenderedAt":2327},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines":2291,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines":2300,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines":2305,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines":2306},{"id":4,"title":5,"body":6,"dateModified":2256,"datePublished":2256,"description":2257,"extension":2258,"faq":2259,"keyword":2269,"kind":2270,"meta":2271,"navigation":113,"path":2280,"seo":2281,"slug":2284,"stem":2285,"topics":2286,"type":2289,"__hash__":2290},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines\u002Findex.md","Fix pandas FutureWarnings in Excel Pipelines",{"type":7,"value":8,"toc":2243},"minimark",[9,29,34,66,73,77,714,851,889,1102,1106,1109,1452,1518,1688,1692,1715,1797,1801,1824,1831,1843,2017,2060,2064,2128,2132,2172,2176,2182,2188,2202,2208,2212,2239],[10,11,12,13,17,18,22,23,28],"p",{},"A reporting script that has run quietly for years starts printing ",[14,15,16],"code",{},"FutureWarning"," messages after a pandas upgrade. They are easy to ignore — the report still comes out right — and that is exactly the danger: a FutureWarning is pandas announcing that the code will ",[19,20,21],"em",{},"stop working"," in a later release. With pandas 3, many of the warnings that pandas 2.2 printed have become errors, and one change produces no warning at all and simply changes behaviour. This page reproduces the warnings that turn up most in Excel pipelines — resampling by month, hourly frequencies, filling gaps, formatting every cell, positional indexing, chained assignment and in-place updates of a column — runs them under pandas 2.2 and pandas 3 side by side, and gives the replacement for each that works in both. It belongs to ",[24,25,27],"a",{"href":26},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",".",[30,31,33],"h2",{"id":32},"prerequisites","Prerequisites",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl     # and uv, to run the probe under two pandas versions\n","bash","",[14,42,43],{"__ignoreMap":40},[44,45,48,52,56,59,62],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"sMTad","pip",[44,53,55],{"class":54},"srMev"," install",[44,57,58],{"class":54}," pandas",[44,60,61],{"class":54}," openpyxl",[44,63,65],{"class":64},"s-wDw","     # and uv, to run the probe under two pandas versions\n",[10,67,68,69,28],{},"The comparison runs a small probe script in two throwaway environments created by uv, one with pandas 2.2.3 and one with pandas 3.0.6, so the behaviour of both versions is shown from real runs on the same machine. Testing a whole project against several versions is covered in ",[24,70,72],{"href":71},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-excel-code-against-several-library-versions-with-nox\u002F","Test Excel Code Against Several Library Versions with nox",[30,74,76],{"id":75},"step-1-the-old-patterns-under-both-versions","Step 1 — The old patterns, under both versions",[35,78,82],{"className":79,"code":80,"language":81,"meta":40,"style":40},"language-python shiki shiki-themes github-light github-dark-high-contrast","import warnings\nimport pandas as pd\n\ndf = pd.DataFrame({\"region\": [\"N\", \"S\", \"N\"], \"amount\": [1.0, None, 3.0],\n                   \"date\": pd.to_datetime([\"2026-01-05\", \"2026-02-03\", \"2026-03-09\"])})\nprobes = {\n    \"resample('M')\": lambda: df.set_index(\"date\").resample(\"M\")[\"amount\"].sum(),\n    \"freq='H'\": lambda: pd.date_range(\"2026-01-01\", periods=3, freq=\"H\"),\n    \"fillna(method=)\": lambda: df.fillna(method=\"ffill\"),\n    \"applymap\": lambda: df.applymap(str),\n    \"s[0] on labels\": lambda: pd.Series([1, 2], index=[\"a\", \"b\"])[0],\n    \"chained assignment\": lambda: df[\"amount\"].__setitem__(df[\"region\"] == \"N\", 0),\n    \"inplace on a column\": lambda: df[\"amount\"].fillna(0, inplace=True),\n    \"select_dtypes('object')\": lambda: df.select_dtypes(\"object\"),\n    \"dtype == object\": lambda: df[\"region\"].dtype == object,\n}\nprint(\"pandas\", pd.__version__)\nfor name, probe in probes.items():\n    with warnings.catch_warnings(record=True) as caught:\n        warnings.simplefilter(\"always\")\n        try:\n            result = probe()\n            msg = caught[0].category.__name__ if caught else (\"returns \" + str(result) if isinstance(result, bool) else \"ok\")\n        except Exception as e:\n            msg = type(e).__name__\n    print(f\"  {name:\u003C24} {msg}\")\n","python",[14,83,84,94,108,115,171,196,207,239,279,302,320,367,408,439,457,482,488,509,524,548,559,568,579,643,658,674],{"__ignoreMap":40},[44,85,86,90],{"class":46,"line":47},[44,87,89],{"class":88},"s-kum","import",[44,91,93],{"class":92},"skGVy"," warnings\n",[44,95,97,99,102,105],{"class":46,"line":96},2,[44,98,89],{"class":88},[44,100,101],{"class":92}," pandas ",[44,103,104],{"class":88},"as",[44,106,107],{"class":92}," pd\n",[44,109,111],{"class":46,"line":110},3,[44,112,114],{"emptyLinePlaceholder":113},true,"\n",[44,116,118,121,124,127,130,133,136,139,142,144,146,149,152,154,158,160,163,165,168],{"class":46,"line":117},4,[44,119,120],{"class":92},"df ",[44,122,123],{"class":88},"=",[44,125,126],{"class":92}," pd.DataFrame({",[44,128,129],{"class":54},"\"region\"",[44,131,132],{"class":92},": [",[44,134,135],{"class":54},"\"N\"",[44,137,138],{"class":92},", ",[44,140,141],{"class":54},"\"S\"",[44,143,138],{"class":92},[44,145,135],{"class":54},[44,147,148],{"class":92},"], ",[44,150,151],{"class":54},"\"amount\"",[44,153,132],{"class":92},[44,155,157],{"class":156},"sP0c6","1.0",[44,159,138],{"class":92},[44,161,162],{"class":156},"None",[44,164,138],{"class":92},[44,166,167],{"class":156},"3.0",[44,169,170],{"class":92},"],\n",[44,172,174,177,180,183,185,188,190,193],{"class":46,"line":173},5,[44,175,176],{"class":54},"                   \"date\"",[44,178,179],{"class":92},": pd.to_datetime([",[44,181,182],{"class":54},"\"2026-01-05\"",[44,184,138],{"class":92},[44,186,187],{"class":54},"\"2026-02-03\"",[44,189,138],{"class":92},[44,191,192],{"class":54},"\"2026-03-09\"",[44,194,195],{"class":92},"])})\n",[44,197,199,202,204],{"class":46,"line":198},6,[44,200,201],{"class":92},"probes ",[44,203,123],{"class":88},[44,205,206],{"class":92}," {\n",[44,208,210,213,216,219,222,225,228,231,234,236],{"class":46,"line":209},7,[44,211,212],{"class":54},"    \"resample('M')\"",[44,214,215],{"class":92},": ",[44,217,218],{"class":88},"lambda",[44,220,221],{"class":92},": df.set_index(",[44,223,224],{"class":54},"\"date\"",[44,226,227],{"class":92},").resample(",[44,229,230],{"class":54},"\"M\"",[44,232,233],{"class":92},")[",[44,235,151],{"class":54},[44,237,238],{"class":92},"].sum(),\n",[44,240,242,245,247,249,252,255,257,261,263,266,268,271,273,276],{"class":46,"line":241},8,[44,243,244],{"class":54},"    \"freq='H'\"",[44,246,215],{"class":92},[44,248,218],{"class":88},[44,250,251],{"class":92},": pd.date_range(",[44,253,254],{"class":54},"\"2026-01-01\"",[44,256,138],{"class":92},[44,258,260],{"class":259},"sa561","periods",[44,262,123],{"class":88},[44,264,265],{"class":156},"3",[44,267,138],{"class":92},[44,269,270],{"class":259},"freq",[44,272,123],{"class":88},[44,274,275],{"class":54},"\"H\"",[44,277,278],{"class":92},"),\n",[44,280,282,285,287,289,292,295,297,300],{"class":46,"line":281},9,[44,283,284],{"class":54},"    \"fillna(method=)\"",[44,286,215],{"class":92},[44,288,218],{"class":88},[44,290,291],{"class":92},": df.fillna(",[44,293,294],{"class":259},"method",[44,296,123],{"class":88},[44,298,299],{"class":54},"\"ffill\"",[44,301,278],{"class":92},[44,303,305,308,310,312,315,318],{"class":46,"line":304},10,[44,306,307],{"class":54},"    \"applymap\"",[44,309,215],{"class":92},[44,311,218],{"class":88},[44,313,314],{"class":92},": df.applymap(",[44,316,317],{"class":156},"str",[44,319,278],{"class":92},[44,321,323,326,328,330,333,336,338,341,343,346,348,351,354,356,359,362,365],{"class":46,"line":322},11,[44,324,325],{"class":54},"    \"s[0] on labels\"",[44,327,215],{"class":92},[44,329,218],{"class":88},[44,331,332],{"class":92},": pd.Series([",[44,334,335],{"class":156},"1",[44,337,138],{"class":92},[44,339,340],{"class":156},"2",[44,342,148],{"class":92},[44,344,345],{"class":259},"index",[44,347,123],{"class":88},[44,349,350],{"class":92},"[",[44,352,353],{"class":54},"\"a\"",[44,355,138],{"class":92},[44,357,358],{"class":54},"\"b\"",[44,360,361],{"class":92},"])[",[44,363,364],{"class":156},"0",[44,366,170],{"class":92},[44,368,370,373,375,377,380,382,385,388,391,393,396,399,402,404,406],{"class":46,"line":369},12,[44,371,372],{"class":54},"    \"chained assignment\"",[44,374,215],{"class":92},[44,376,218],{"class":88},[44,378,379],{"class":92},": df[",[44,381,151],{"class":54},[44,383,384],{"class":92},"].",[44,386,387],{"class":156},"__setitem__",[44,389,390],{"class":92},"(df[",[44,392,129],{"class":54},[44,394,395],{"class":92},"] ",[44,397,398],{"class":88},"==",[44,400,401],{"class":54}," \"N\"",[44,403,138],{"class":92},[44,405,364],{"class":156},[44,407,278],{"class":92},[44,409,411,414,416,418,420,422,425,427,429,432,434,437],{"class":46,"line":410},13,[44,412,413],{"class":54},"    \"inplace on a column\"",[44,415,215],{"class":92},[44,417,218],{"class":88},[44,419,379],{"class":92},[44,421,151],{"class":54},[44,423,424],{"class":92},"].fillna(",[44,426,364],{"class":156},[44,428,138],{"class":92},[44,430,431],{"class":259},"inplace",[44,433,123],{"class":88},[44,435,436],{"class":156},"True",[44,438,278],{"class":92},[44,440,442,445,447,449,452,455],{"class":46,"line":441},14,[44,443,444],{"class":54},"    \"select_dtypes('object')\"",[44,446,215],{"class":92},[44,448,218],{"class":88},[44,450,451],{"class":92},": df.select_dtypes(",[44,453,454],{"class":54},"\"object\"",[44,456,278],{"class":92},[44,458,460,463,465,467,469,471,474,476,479],{"class":46,"line":459},15,[44,461,462],{"class":54},"    \"dtype == object\"",[44,464,215],{"class":92},[44,466,218],{"class":88},[44,468,379],{"class":92},[44,470,129],{"class":54},[44,472,473],{"class":92},"].dtype ",[44,475,398],{"class":88},[44,477,478],{"class":156}," object",[44,480,481],{"class":92},",\n",[44,483,485],{"class":46,"line":484},16,[44,486,487],{"class":92},"}\n",[44,489,491,494,497,500,503,506],{"class":46,"line":490},17,[44,492,493],{"class":156},"print",[44,495,496],{"class":92},"(",[44,498,499],{"class":54},"\"pandas\"",[44,501,502],{"class":92},", pd.",[44,504,505],{"class":156},"__version__",[44,507,508],{"class":92},")\n",[44,510,512,515,518,521],{"class":46,"line":511},18,[44,513,514],{"class":88},"for",[44,516,517],{"class":92}," name, probe ",[44,519,520],{"class":88},"in",[44,522,523],{"class":92}," probes.items():\n",[44,525,527,530,533,536,538,540,543,545],{"class":46,"line":526},19,[44,528,529],{"class":88},"    with",[44,531,532],{"class":92}," warnings.catch_warnings(",[44,534,535],{"class":259},"record",[44,537,123],{"class":88},[44,539,436],{"class":156},[44,541,542],{"class":92},") ",[44,544,104],{"class":88},[44,546,547],{"class":92}," caught:\n",[44,549,551,554,557],{"class":46,"line":550},20,[44,552,553],{"class":92},"        warnings.simplefilter(",[44,555,556],{"class":54},"\"always\"",[44,558,508],{"class":92},[44,560,562,565],{"class":46,"line":561},21,[44,563,564],{"class":88},"        try",[44,566,567],{"class":92},":\n",[44,569,571,574,576],{"class":46,"line":570},22,[44,572,573],{"class":92},"            result ",[44,575,123],{"class":88},[44,577,578],{"class":92}," probe()\n",[44,580,582,585,587,590,592,595,598,601,604,607,610,613,616,619,622,625,628,631,634,636,638,641],{"class":46,"line":581},23,[44,583,584],{"class":92},"            msg ",[44,586,123],{"class":88},[44,588,589],{"class":92}," caught[",[44,591,364],{"class":156},[44,593,594],{"class":92},"].category.",[44,596,597],{"class":156},"__name__",[44,599,600],{"class":88}," if",[44,602,603],{"class":92}," caught ",[44,605,606],{"class":88},"else",[44,608,609],{"class":92}," (",[44,611,612],{"class":54},"\"returns \"",[44,614,615],{"class":88}," +",[44,617,618],{"class":156}," str",[44,620,621],{"class":92},"(result) ",[44,623,624],{"class":88},"if",[44,626,627],{"class":156}," isinstance",[44,629,630],{"class":92},"(result, ",[44,632,633],{"class":156},"bool",[44,635,542],{"class":92},[44,637,606],{"class":88},[44,639,640],{"class":54}," \"ok\"",[44,642,508],{"class":92},[44,644,646,649,652,655],{"class":46,"line":645},24,[44,647,648],{"class":88},"        except",[44,650,651],{"class":156}," Exception",[44,653,654],{"class":88}," as",[44,656,657],{"class":92}," e:\n",[44,659,661,663,665,668,671],{"class":46,"line":660},25,[44,662,584],{"class":92},[44,664,123],{"class":88},[44,666,667],{"class":156}," type",[44,669,670],{"class":92},"(e).",[44,672,673],{"class":156},"__name__\n",[44,675,677,680,682,685,688,692,695,698,701,704,707,709,712],{"class":46,"line":676},26,[44,678,679],{"class":156},"    print",[44,681,496],{"class":92},[44,683,684],{"class":88},"f",[44,686,687],{"class":54},"\"  ",[44,689,691],{"class":690},"sSjpA","{",[44,693,694],{"class":92},"name",[44,696,697],{"class":88},":\u003C24",[44,699,700],{"class":690},"}",[44,702,703],{"class":690}," {",[44,705,706],{"class":92},"msg",[44,708,700],{"class":690},[44,710,711],{"class":54},"\"",[44,713,508],{"class":92},[35,715,717],{"className":79,"code":716,"language":81,"meta":40,"style":40},"import subprocess\n\nfor version in [\"2.2.3\", \"3.0.6\"]:\n    out = subprocess.run([\"uv\", \"run\", \"--quiet\", \"--no-project\", \"--python\", \"3.13\", \"--with\", f\"pandas=={version}\",\n                          \"python\", \"probe.py\"], capture_output=True, text=True)\n    print(out.stdout.strip())\n",[14,718,719,726,730,753,814,844],{"__ignoreMap":40},[44,720,721,723],{"class":46,"line":47},[44,722,89],{"class":88},[44,724,725],{"class":92}," subprocess\n",[44,727,728],{"class":46,"line":96},[44,729,114],{"emptyLinePlaceholder":113},[44,731,732,734,737,739,742,745,747,750],{"class":46,"line":110},[44,733,514],{"class":88},[44,735,736],{"class":92}," version ",[44,738,520],{"class":88},[44,740,741],{"class":92}," [",[44,743,744],{"class":54},"\"2.2.3\"",[44,746,138],{"class":92},[44,748,749],{"class":54},"\"3.0.6\"",[44,751,752],{"class":92},"]:\n",[44,754,755,758,760,763,766,768,771,773,776,778,781,783,786,788,791,793,796,798,800,803,805,808,810,812],{"class":46,"line":117},[44,756,757],{"class":92},"    out ",[44,759,123],{"class":88},[44,761,762],{"class":92}," subprocess.run([",[44,764,765],{"class":54},"\"uv\"",[44,767,138],{"class":92},[44,769,770],{"class":54},"\"run\"",[44,772,138],{"class":92},[44,774,775],{"class":54},"\"--quiet\"",[44,777,138],{"class":92},[44,779,780],{"class":54},"\"--no-project\"",[44,782,138],{"class":92},[44,784,785],{"class":54},"\"--python\"",[44,787,138],{"class":92},[44,789,790],{"class":54},"\"3.13\"",[44,792,138],{"class":92},[44,794,795],{"class":54},"\"--with\"",[44,797,138],{"class":92},[44,799,684],{"class":88},[44,801,802],{"class":54},"\"pandas==",[44,804,691],{"class":690},[44,806,807],{"class":92},"version",[44,809,700],{"class":690},[44,811,711],{"class":54},[44,813,481],{"class":92},[44,815,816,819,821,824,826,829,831,833,835,838,840,842],{"class":46,"line":173},[44,817,818],{"class":54},"                          \"python\"",[44,820,138],{"class":92},[44,822,823],{"class":54},"\"probe.py\"",[44,825,148],{"class":92},[44,827,828],{"class":259},"capture_output",[44,830,123],{"class":88},[44,832,436],{"class":156},[44,834,138],{"class":92},[44,836,837],{"class":259},"text",[44,839,123],{"class":88},[44,841,436],{"class":156},[44,843,508],{"class":92},[44,845,846,848],{"class":46,"line":198},[44,847,679],{"class":156},[44,849,850],{"class":92},"(out.stdout.strip())\n",[10,852,853,854,856,857,138,860,138,863,138,866,869,870,873,874,877,878,881,882,884,885,888],{},"Under pandas 2.2.3, every one of the first seven patterns works but prints a ",[14,855,16],{},". Under pandas 3.0.6 the first five are errors — ",[14,858,859],{},"ValueError",[14,861,862],{},"TypeError",[14,864,865],{},"AttributeError",[14,867,868],{},"KeyError"," — and the two assignment patterns raise a ",[14,871,872],{},"ChainedAssignmentError"," warning because, with copy-on-write now always on, they no longer change the DataFrame at all. The last two lines are the quiet ones: ",[14,875,876],{},"select_dtypes(\"object\")"," gains a new deprecation warning, and ",[14,879,880],{},"dtype == object"," on a text column changes from ",[14,883,436],{}," to ",[14,886,887],{},"False"," with no warning whatsoever.",[890,891,899,900,899,904,899,908,899,915,899,923,899,930,899,936,899,939,899,943,899,946,899,950,899,955,899,961,899,963,899,967,899,969,899,971,899,973,899,976,899,979,899,983,899,985,899,988,899,990,899,992,899,994,899,997,899,1000,899,1004,899,1006,899,1009,899,1011,899,1013,899,1015,899,1018,899,1021,899,1025,899,1027,899,1030,899,1032,899,1034,899,1036,899,1039,899,1042,899,1046,899,1048,899,1051,899,1053,899,1055,899,1057,899,1060,899,1063,899,1067,899,1069,899,1072,899,1074,899,1077,899,1079,899,1082,899,1085,899,1088,899,1090,899,1093,899,1095,899,1097,899,1099],"svg",{"viewBox":892,"role":893,"ariaLabelledBy":894,"xmlns":897,"style":898},"4 0 752 310","img",[895,896],"fw-table-t","fw-table-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  ",[901,902,903],"title",{"id":895},"The same code under pandas 2.2 and pandas 3",[905,906,907],"desc",{"id":896},"Month-end and hourly aliases, fillna with method, applymap and positional indexing with square brackets warn in 2.2 and fail in 3. Chained assignment and inplace on a column warn in 2.2 and do nothing in 3. select_dtypes object starts warning in 3, and dtype == object changes from True to False silently.",[909,910],"rect",{"x":911,"y":364,"width":912,"height":913,"fill":914},"4","752","310","#ffffff",[909,916],{"x":917,"y":918,"width":919,"height":920,"rx":364,"fill":914,"stroke":921,"style":922},"20.0","16.0","207.5","40.0","var(--line,#cdd5e6)","stroke-width:1px",[909,924],{"x":925,"y":918,"width":926,"height":920,"rx":364,"fill":927,"stroke":928,"style":929},"227.5","170.8","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.2px",[837,931,935],{"x":932,"y":933,"style":934},"312.9","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","pandas 2.2",[909,937],{"x":938,"y":918,"width":926,"height":920,"rx":364,"fill":927,"stroke":928,"style":929},"398.3",[837,940,942],{"x":941,"y":933,"style":934},"483.7","pandas 3",[909,944],{"x":945,"y":918,"width":926,"height":920,"rx":364,"fill":927,"stroke":928,"style":929},"569.2",[837,947,949],{"x":948,"y":933,"style":934},"654.6","use instead",[909,951],{"x":917,"y":952,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"56.0","34.0","#e7ebef",[837,956,960],{"x":957,"y":958,"style":959},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","resample('M')",[909,962],{"x":925,"y":952,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,964,16],{"x":932,"y":965,"style":966},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[909,968],{"x":938,"y":952,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,970,859],{"x":941,"y":965,"style":966},[909,972],{"x":945,"y":952,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,974,975],{"x":948,"y":965,"style":966},"'ME'",[909,977],{"x":917,"y":978,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"90.0",[837,980,982],{"x":957,"y":981,"style":959},"112.0","freq='H'",[909,984],{"x":925,"y":978,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,986,16],{"x":932,"y":987,"style":966},"111.0",[909,989],{"x":938,"y":978,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,991,859],{"x":941,"y":987,"style":966},[909,993],{"x":945,"y":978,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,995,996],{"x":948,"y":987,"style":966},"'h'",[909,998],{"x":917,"y":999,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"124.0",[837,1001,1003],{"x":957,"y":1002,"style":959},"146.0","fillna(method='ffill')",[909,1005],{"x":925,"y":999,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1007,16],{"x":932,"y":1008,"style":966},"145.0",[909,1010],{"x":938,"y":999,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1012,862],{"x":941,"y":1008,"style":966},[909,1014],{"x":945,"y":999,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1016,1017],{"x":948,"y":1008,"style":966},".ffill()",[909,1019],{"x":917,"y":1020,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"158.0",[837,1022,1024],{"x":957,"y":1023,"style":959},"180.0","applymap",[909,1026],{"x":925,"y":1020,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1028,16],{"x":932,"y":1029,"style":966},"179.0",[909,1031],{"x":938,"y":1020,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1033,865],{"x":941,"y":1029,"style":966},[909,1035],{"x":945,"y":1020,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1037,1038],{"x":948,"y":1029,"style":966},".map()",[909,1040],{"x":917,"y":1041,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"192.0",[837,1043,1045],{"x":957,"y":1044,"style":959},"214.0","s[0] on labels",[909,1047],{"x":925,"y":1041,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1049,16],{"x":932,"y":1050,"style":966},"213.0",[909,1052],{"x":938,"y":1041,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1054,868],{"x":941,"y":1050,"style":966},[909,1056],{"x":945,"y":1041,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1058,1059],{"x":948,"y":1050,"style":966},".iloc[0]",[909,1061],{"x":917,"y":1062,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"226.0",[837,1064,1066],{"x":957,"y":1065,"style":959},"248.0","chained \u002F inplace on column",[909,1068],{"x":925,"y":1062,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1070,16],{"x":932,"y":1071,"style":966},"247.0",[909,1073],{"x":938,"y":1062,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1075,1076],{"x":941,"y":1071,"style":966},"no effect",[909,1078],{"x":945,"y":1062,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1080,1081],{"x":948,"y":1071,"style":966},"df.loc[...] =",[909,1083],{"x":917,"y":1084,"width":919,"height":953,"rx":364,"fill":954,"stroke":921,"style":922},"260.0",[837,1086,880],{"x":957,"y":1087,"style":959},"282.0",[909,1089],{"x":925,"y":1084,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1091,436],{"x":932,"y":1092,"style":966},"281.0",[909,1094],{"x":938,"y":1084,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1096,887],{"x":941,"y":1092,"style":966},[909,1098],{"x":945,"y":1084,"width":926,"height":953,"rx":364,"fill":914,"stroke":921,"style":922},[837,1100,1101],{"x":948,"y":1092,"style":966},"is_string_dtype",[30,1103,1105],{"id":1104},"step-2-the-replacements","Step 2 — The replacements",[10,1107,1108],{},"Each pattern has a replacement that works under both versions:",[35,1110,1112],{"className":79,"code":1111,"language":81,"meta":40,"style":40},"import pandas as pd\nfrom pandas.api.types import is_string_dtype\n\ndf = pd.DataFrame({\"region\": [\"N\", \"S\", \"N\"], \"amount\": [1.0, None, 3.0],\n                   \"date\": pd.to_datetime([\"2026-01-05\", \"2026-02-03\", \"2026-03-09\"])})\n\nmonthly = df.set_index(\"date\").resample(\"ME\")[\"amount\"].sum()        # 'M' -> 'ME' (month end)\nhours = pd.date_range(\"2026-01-01\", periods=3, freq=\"h\")              # 'H' -> 'h'\nfilled = df.ffill()                                                   # fillna(method=\"ffill\") -> ffill()\nas_text = df.map(str)                                                 # applymap -> map\nfirst = pd.Series([1, 2], index=[\"a\", \"b\"]).iloc[0]                   # s[0] -> s.iloc[0]\ndf.loc[df[\"region\"] == \"N\", \"amount\"] = 0                             # df[\"amount\"][mask] = 0 -> df.loc[mask, col]\ndf[\"amount\"] = df[\"amount\"].fillna(0)                                 # inplace on a column -> assign the result\ntext_cols = [c for c in df.columns if is_string_dtype(df[c])]         # dtype == object -> is_string_dtype\nprint(monthly.index.strftime(\"%Y-%m-%d\").tolist(), \"|\", df[\"amount\"].tolist(), \"|\", text_cols)\n",[14,1113,1114,1124,1137,1141,1181,1199,1203,1230,1265,1278,1296,1337,1364,1390,1418],{"__ignoreMap":40},[44,1115,1116,1118,1120,1122],{"class":46,"line":47},[44,1117,89],{"class":88},[44,1119,101],{"class":92},[44,1121,104],{"class":88},[44,1123,107],{"class":92},[44,1125,1126,1129,1132,1134],{"class":46,"line":96},[44,1127,1128],{"class":88},"from",[44,1130,1131],{"class":92}," pandas.api.types ",[44,1133,89],{"class":88},[44,1135,1136],{"class":92}," is_string_dtype\n",[44,1138,1139],{"class":46,"line":110},[44,1140,114],{"emptyLinePlaceholder":113},[44,1142,1143,1145,1147,1149,1151,1153,1155,1157,1159,1161,1163,1165,1167,1169,1171,1173,1175,1177,1179],{"class":46,"line":117},[44,1144,120],{"class":92},[44,1146,123],{"class":88},[44,1148,126],{"class":92},[44,1150,129],{"class":54},[44,1152,132],{"class":92},[44,1154,135],{"class":54},[44,1156,138],{"class":92},[44,1158,141],{"class":54},[44,1160,138],{"class":92},[44,1162,135],{"class":54},[44,1164,148],{"class":92},[44,1166,151],{"class":54},[44,1168,132],{"class":92},[44,1170,157],{"class":156},[44,1172,138],{"class":92},[44,1174,162],{"class":156},[44,1176,138],{"class":92},[44,1178,167],{"class":156},[44,1180,170],{"class":92},[44,1182,1183,1185,1187,1189,1191,1193,1195,1197],{"class":46,"line":173},[44,1184,176],{"class":54},[44,1186,179],{"class":92},[44,1188,182],{"class":54},[44,1190,138],{"class":92},[44,1192,187],{"class":54},[44,1194,138],{"class":92},[44,1196,192],{"class":54},[44,1198,195],{"class":92},[44,1200,1201],{"class":46,"line":198},[44,1202,114],{"emptyLinePlaceholder":113},[44,1204,1205,1208,1210,1213,1215,1217,1220,1222,1224,1227],{"class":46,"line":209},[44,1206,1207],{"class":92},"monthly ",[44,1209,123],{"class":88},[44,1211,1212],{"class":92}," df.set_index(",[44,1214,224],{"class":54},[44,1216,227],{"class":92},[44,1218,1219],{"class":54},"\"ME\"",[44,1221,233],{"class":92},[44,1223,151],{"class":54},[44,1225,1226],{"class":92},"].sum()        ",[44,1228,1229],{"class":64},"# 'M' -> 'ME' (month end)\n",[44,1231,1232,1235,1237,1240,1242,1244,1246,1248,1250,1252,1254,1256,1259,1262],{"class":46,"line":241},[44,1233,1234],{"class":92},"hours ",[44,1236,123],{"class":88},[44,1238,1239],{"class":92}," pd.date_range(",[44,1241,254],{"class":54},[44,1243,138],{"class":92},[44,1245,260],{"class":259},[44,1247,123],{"class":88},[44,1249,265],{"class":156},[44,1251,138],{"class":92},[44,1253,270],{"class":259},[44,1255,123],{"class":88},[44,1257,1258],{"class":54},"\"h\"",[44,1260,1261],{"class":92},")              ",[44,1263,1264],{"class":64},"# 'H' -> 'h'\n",[44,1266,1267,1270,1272,1275],{"class":46,"line":281},[44,1268,1269],{"class":92},"filled ",[44,1271,123],{"class":88},[44,1273,1274],{"class":92}," df.ffill()                                                   ",[44,1276,1277],{"class":64},"# fillna(method=\"ffill\") -> ffill()\n",[44,1279,1280,1283,1285,1288,1290,1293],{"class":46,"line":304},[44,1281,1282],{"class":92},"as_text ",[44,1284,123],{"class":88},[44,1286,1287],{"class":92}," df.map(",[44,1289,317],{"class":156},[44,1291,1292],{"class":92},")                                                 ",[44,1294,1295],{"class":64},"# applymap -> map\n",[44,1297,1298,1301,1303,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1329,1331,1334],{"class":46,"line":322},[44,1299,1300],{"class":92},"first ",[44,1302,123],{"class":88},[44,1304,1305],{"class":92}," pd.Series([",[44,1307,335],{"class":156},[44,1309,138],{"class":92},[44,1311,340],{"class":156},[44,1313,148],{"class":92},[44,1315,345],{"class":259},[44,1317,123],{"class":88},[44,1319,350],{"class":92},[44,1321,353],{"class":54},[44,1323,138],{"class":92},[44,1325,358],{"class":54},[44,1327,1328],{"class":92},"]).iloc[",[44,1330,364],{"class":156},[44,1332,1333],{"class":92},"]                   ",[44,1335,1336],{"class":64},"# s[0] -> s.iloc[0]\n",[44,1338,1339,1342,1344,1346,1348,1350,1352,1354,1356,1358,1361],{"class":46,"line":369},[44,1340,1341],{"class":92},"df.loc[df[",[44,1343,129],{"class":54},[44,1345,395],{"class":92},[44,1347,398],{"class":88},[44,1349,401],{"class":54},[44,1351,138],{"class":92},[44,1353,151],{"class":54},[44,1355,395],{"class":92},[44,1357,123],{"class":88},[44,1359,1360],{"class":156}," 0",[44,1362,1363],{"class":64},"                             # df[\"amount\"][mask] = 0 -> df.loc[mask, col]\n",[44,1365,1366,1369,1371,1373,1375,1378,1380,1382,1384,1387],{"class":46,"line":410},[44,1367,1368],{"class":92},"df[",[44,1370,151],{"class":54},[44,1372,395],{"class":92},[44,1374,123],{"class":88},[44,1376,1377],{"class":92}," df[",[44,1379,151],{"class":54},[44,1381,424],{"class":92},[44,1383,364],{"class":156},[44,1385,1386],{"class":92},")                                 ",[44,1388,1389],{"class":64},"# inplace on a column -> assign the result\n",[44,1391,1392,1395,1397,1400,1402,1405,1407,1410,1412,1415],{"class":46,"line":441},[44,1393,1394],{"class":92},"text_cols ",[44,1396,123],{"class":88},[44,1398,1399],{"class":92}," [c ",[44,1401,514],{"class":88},[44,1403,1404],{"class":92}," c ",[44,1406,520],{"class":88},[44,1408,1409],{"class":92}," df.columns ",[44,1411,624],{"class":88},[44,1413,1414],{"class":92}," is_string_dtype(df[c])]         ",[44,1416,1417],{"class":64},"# dtype == object -> is_string_dtype\n",[44,1419,1420,1422,1425,1428,1431,1433,1436,1439,1442,1444,1447,1449],{"class":46,"line":459},[44,1421,493],{"class":156},[44,1423,1424],{"class":92},"(monthly.index.strftime(",[44,1426,1427],{"class":54},"\"%Y-%m-",[44,1429,1430],{"class":690},"%d",[44,1432,711],{"class":54},[44,1434,1435],{"class":92},").tolist(), ",[44,1437,1438],{"class":54},"\"|\"",[44,1440,1441],{"class":92},", df[",[44,1443,151],{"class":54},[44,1445,1446],{"class":92},"].tolist(), ",[44,1448,1438],{"class":54},[44,1450,1451],{"class":92},", text_cols)\n",[10,1453,1454,1455,1458,1459,1462,1463,1466,1467,138,1470,138,1473,1476,1477,1480,1481,1484,1485,1488,1489,1492,1493,1495,1496,1499,1500,1503,1504,138,1507,138,1510,138,1512,1480,1514,1517],{},"The frequency aliases were renamed to say what they mean: ",[14,1456,1457],{},"ME"," is month ",[19,1460,1461],{},"end"," (as opposed to ",[14,1464,1465],{},"MS",", month start), and the time units became lower case — ",[14,1468,1469],{},"h",[14,1471,1472],{},"min",[14,1474,1475],{},"s",". ",[14,1478,1479],{},"ffill()"," and ",[14,1482,1483],{},"bfill()"," replace the ",[14,1486,1487],{},"method="," argument. ",[14,1490,1491],{},"DataFrame.map"," is the element-wise function that used to be called ",[14,1494,1024],{},". Square brackets on a Series now always mean labels, so position needs ",[14,1497,1498],{},"iloc",". And the two assignment forms are replaced by a single ",[14,1501,1502],{},"loc"," assignment on the DataFrame, or by assigning the result of a method back to the column — the only forms that change the data under copy-on-write. All of these replacements already exist in pandas 2.2, so the code can be fixed before upgrading and will run unchanged on both versions — there is no need to support two code paths. These are mechanical edits; a search for ",[14,1505,1506],{},"resample(\"M\"",[14,1508,1509],{},"freq=\"H\"",[14,1511,1487],{},[14,1513,1024],{},[14,1515,1516],{},"inplace=True"," finds most of them in an Excel pipeline.",[890,1519,899,1524,899,1527,899,1530,899,1533,899,1541,899,1552,899,1558,899,1562,899,1566,899,1570,899,1575,899,1580,899,1583,899,1590,899,1595,899,1598,899,1601,899,1603,899,1607,899,1610,899,1613,899,1620,899,1626,899,1630,899,1633,899,1637,899,1640,899,1643,899,1649,899,1653,899,1657,899,1659,899,1663,899,1666,899,1671,899,1678,899,1683,899,1685],{"viewBox":1520,"role":893,"ariaLabelledBy":1521,"xmlns":897,"style":898},"4 0 752 160",[1522,1523],"fw-route-t","fw-route-d",[901,1525,1526],{"id":1522},"Clearing the warnings in a project",[905,1528,1529],{"id":1523},"Run the pipeline with warnings shown, or the test suite with warnings as errors. Search for the known patterns, apply the mechanical replacements, check text-column logic that compared dtype with object, and rerun under the newest pandas until no warnings remain.",[909,1531],{"x":911,"y":364,"width":912,"height":1532,"fill":914},"160",[909,1534],{"x":917,"y":918,"width":1535,"height":1536,"rx":1537,"fill":1538,"stroke":1539,"style":1540},"115.2","128.0","12","#fdefd8","var(--gold,#b4740a)","stroke-width:2px",[1542,1543,1545],"g",{"transform":1544},"translate(65.6,29.0) scale(1.000)",[1546,1547],"path",{"d":1548,"fill":1549,"stroke":1550,"style":1551},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","none","var(--gold-ink,#7a4e06)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[837,1553,1557],{"x":1554,"y":1555,"style":1556},"77.6","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Surface",[837,1559,1561],{"x":1554,"y":1560,"style":1556},"93.0","warnings",[837,1563,1565],{"x":1554,"y":1564,"style":966},"112.5","-W error in",[837,1567,1569],{"x":1554,"y":1568,"style":966},"130.0","tests",[46,1571],{"x1":1572,"y1":1573,"x2":1574,"y2":1573,"stroke":928,"style":1540},"140.2","80.0","162.2",[1576,1577],"polygon",{"points":1578,"fill":1579},"166.2,80.0 157.2,85.0 157.2,75.0","#5b5cf0",[909,1581],{"x":1582,"y":918,"width":1535,"height":1536,"rx":1537,"fill":954,"stroke":921,"style":1540},"171.2",[1542,1584,1586],{"transform":1585},"translate(216.8,29.0) scale(1.000)",[1546,1587],{"d":1588,"fill":1549,"stroke":1589,"style":1551},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--text,#172033)",[837,1591,1594],{"x":1592,"y":1555,"style":1593},"228.8","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Search",[837,1596,1597],{"x":1592,"y":1560,"style":1593},"patterns",[837,1599,1600],{"x":1592,"y":1564,"style":966},"M, H, method=,",[837,1602,1024],{"x":1592,"y":1568,"style":966},[46,1604],{"x1":1605,"y1":1573,"x2":1606,"y2":1573,"stroke":928,"style":1540},"291.4","313.4",[1576,1608],{"points":1609,"fill":1579},"317.4,80.0 308.4,85.0 308.4,75.0",[909,1611],{"x":1612,"y":918,"width":1535,"height":1536,"rx":1537,"fill":927,"stroke":928,"style":1540},"322.4",[1542,1614,1616],{"transform":1615},"translate(368.0,37.8) scale(1.000)",[1546,1617],{"d":1618,"fill":1549,"stroke":1619,"style":1551},"M9 8l-4 4 4 4 M15 8l4 4-4 4","var(--brand-strong,#4338ca)",[837,1621,1625],{"x":1622,"y":1623,"style":1624},"380.0","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Replace",[837,1627,1629],{"x":1622,"y":1628,"style":966},"103.8","ME, h, ffill, map,",[837,1631,1502],{"x":1622,"y":1632,"style":966},"121.2",[46,1634],{"x1":1635,"y1":1573,"x2":1636,"y2":1573,"stroke":928,"style":1540},"442.6","464.6",[1576,1638],{"points":1639,"fill":1579},"468.6,80.0 459.6,85.0 459.6,75.0",[909,1641],{"x":1642,"y":918,"width":1535,"height":1536,"rx":1537,"fill":1538,"stroke":1539,"style":1540},"473.6",[1542,1644,1646],{"transform":1645},"translate(519.2,37.8) scale(1.000)",[1546,1647],{"d":1648,"fill":1549,"stroke":1550,"style":1551},"M3 5h18l-7 8v6l-4 2v-8z",[837,1650,1652],{"x":1651,"y":1623,"style":1556},"531.2","Check text",[837,1654,1656],{"x":1651,"y":1655,"style":1556},"101.8","columns",[837,1658,880],{"x":1651,"y":1632,"style":966},[46,1660],{"x1":1661,"y1":1573,"x2":1662,"y2":1573,"stroke":928,"style":1540},"593.8","615.8",[1576,1664],{"points":1665,"fill":1579},"619.8,80.0 610.8,85.0 610.8,75.0",[909,1667],{"x":1668,"y":918,"width":1535,"height":1536,"rx":1537,"fill":1669,"stroke":1670,"style":1540},"624.8","#d9f4f1","var(--teal,#0f9488)",[1542,1672,1674],{"transform":1673},"translate(670.4,37.8) scale(1.000)",[1546,1675],{"d":1676,"fill":1549,"stroke":1677,"style":1551},"M5 12.5l4.5 4.5L19 7","var(--teal-ink,#0b6157)",[837,1679,1682],{"x":1680,"y":1623,"style":1681},"682.4","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Rerun on",[837,1684,942],{"x":1680,"y":1655,"style":1681},[837,1686,1687],{"x":1680,"y":1632,"style":966},"no warnings left",[30,1689,1691],{"id":1690},"why-the-assignment-patterns-stop-working","Why the assignment patterns stop working",[10,1693,1694,1695,1698,1699,1702,1703,1706,1707,1710,1711,1714],{},"The two assignment patterns deserve a closer look, because in pandas 3 they fail by doing nothing. ",[14,1696,1697],{},"df[\"amount\"][mask] = 0"," first takes the column ",[14,1700,1701],{},"df[\"amount\"]"," — under copy-on-write, a new Series that only shares memory with the DataFrame until it is modified — and then sets values on ",[19,1704,1705],{},"that"," Series, which triggers a copy; the DataFrame is untouched. ",[14,1708,1709],{},"df[\"amount\"].fillna(0, inplace=True)"," does the same thing with a method. In pandas 2 these sometimes worked and sometimes did not, depending on internal details, which is why pandas warned; in pandas 3 they never work, and the warning is the only sign. Excel scripts are full of these patterns, often in the cleaning step just before ",[14,1712,1713],{},"to_excel",", so the symptom is a report that still contains the blanks or bad values the code was supposed to fix.",[890,1716,899,1721,899,1724,899,1727,899,1730,899,1735,899,1742,899,1747,899,1752,899,1756,899,1760,899,1764,899,1768,899,1771,899,1776,899,1781,899,1785,899,1788,899,1791,899,1794],{"viewBox":1717,"role":893,"ariaLabelledBy":1718,"xmlns":897,"style":898},"4 0 752 233",[1719,1720],"fw-cow-t","fw-cow-d",[901,1722,1723],{"id":1719},"Chained assignment or a single loc assignment",[905,1725,1726],{"id":1720},"Chained assignment first takes a column and then sets values on it, which in pandas 3 modifies a copy and leaves the DataFrame unchanged. A single loc assignment, or assigning a method's result back to the column, changes the DataFrame in every version.",[909,1728],{"x":911,"y":364,"width":912,"height":1729,"fill":914},"233",[909,1731],{"x":917,"y":918,"width":1732,"height":1733,"rx":1734,"fill":1538,"stroke":1539,"style":1540},"351.0","201.0","14",[1542,1736,1738],{"transform":1737},"translate(182.5,29.0) scale(1.083)",[1546,1739],{"d":1740,"fill":1549,"stroke":1550,"style":1741},"M6 6l12 12 M18 6L6 18","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[837,1743,1746],{"x":1744,"y":958,"style":1745},"195.5","font-size:14px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","df['amount'][mask] = 0",[46,1748],{"x1":1749,"y1":1750,"x2":1751,"y2":1750,"stroke":1539,"style":922},"36.0","91.0","355.0",[837,1753,1755],{"x":1744,"y":987,"style":1754},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","takes the column first",[837,1757,1759],{"x":1744,"y":1758,"style":1754},"137.0","sets values on a copy",[837,1761,1763],{"x":1744,"y":1762,"style":1754},"163.0","DataFrame unchanged in pandas 3",[837,1765,1767],{"x":1744,"y":1766,"style":1754},"189.0","ChainedAssignmentError warning",[909,1769],{"x":1770,"y":918,"width":1732,"height":1733,"rx":1734,"fill":1669,"stroke":1670,"style":1540},"389.0",[1542,1772,1774],{"transform":1773},"translate(551.5,29.0) scale(1.083)",[1546,1775],{"d":1676,"fill":1549,"stroke":1677,"style":1741},[837,1777,1780],{"x":1778,"y":958,"style":1779},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","df.loc[mask, 'amount'] = 0",[46,1782],{"x1":1783,"y1":1750,"x2":1784,"y2":1750,"stroke":1670,"style":922},"405.0","724.0",[837,1786,1787],{"x":1778,"y":987,"style":1754},"one operation on the DataFrame",[837,1789,1790],{"x":1778,"y":1758,"style":1754},"changes the data",[837,1792,1793],{"x":1778,"y":1762,"style":1754},"same in pandas 2 and 3",[837,1795,1796],{"x":1778,"y":1766,"style":1754},"no warning",[30,1798,1800],{"id":1799},"making-warnings-visible-in-scheduled-jobs","Making warnings visible in scheduled jobs",[10,1802,1803,1804,1807,1808,1811,1812,1815,1816,1819,1820,28],{},"Warnings go to standard error, which a scheduled job often discards, so nobody sees them until the upgrade that turns them into errors. Two settings fix that. In the job itself, ",[14,1805,1806],{},"logging.captureWarnings(True)"," routes every warning into the logging system, so FutureWarnings land in the same log file as the rest of the run and can be searched for. In the test suite, run pytest with ",[14,1809,1810],{},"-W error::FutureWarning"," — or set ",[14,1813,1814],{},"filterwarnings = [\"error\"]"," in the project configuration — so a deprecation fails a test the day it appears rather than the day the code breaks. Setting the environment variable ",[14,1817,1818],{},"PYTHONWARNINGS=error::FutureWarning"," does the same for a one-off run of a script. Logging in general is covered in ",[24,1821,1823],{"href":1822},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Flog-python-excel-script-output-to-a-file\u002F","Log Python Excel Script Output to a File",[30,1825,1827,1828],{"id":1826},"step-3-the-silent-one-text-columns-are-no-longer-object","Step 3 — The silent one: text columns are no longer ",[14,1829,1830],{},"object",[10,1832,1833,1834,1836,1837,1839,1840,1842],{},"In pandas 3, text read from Excel is stored in the new ",[14,1835,317],{}," dtype rather than ",[14,1838,1830],{},". Code that finds text columns by comparing with ",[14,1841,1830],{}," stops finding them, without any warning:",[35,1844,1846],{"className":79,"code":1845,"language":81,"meta":40,"style":40},"from openpyxl import Workbook\n\nwb = Workbook()\nwb.active.append([\"Customer\", \"City\", \"Amount\"])\nwb.active.append([\"  Acme Ltd \", \" Leeds\", 120.5])\nwb.save(\"customers.xlsx\")\ncustomers = pd.read_excel(\"customers.xlsx\")\n\ntrimmed_old = [c for c in customers.columns if customers[c].dtype == object]\ntrimmed_new = [c for c in customers.columns if is_string_dtype(customers[c])]\nprint(pd.__version__, \"| dtype == object finds:\", trimmed_old, \"| is_string_dtype finds:\", trimmed_new)\n",[14,1847,1848,1860,1864,1874,1895,1914,1924,1938,1942,1972,1994],{"__ignoreMap":40},[44,1849,1850,1852,1855,1857],{"class":46,"line":47},[44,1851,1128],{"class":88},[44,1853,1854],{"class":92}," openpyxl ",[44,1856,89],{"class":88},[44,1858,1859],{"class":92}," Workbook\n",[44,1861,1862],{"class":46,"line":96},[44,1863,114],{"emptyLinePlaceholder":113},[44,1865,1866,1869,1871],{"class":46,"line":110},[44,1867,1868],{"class":92},"wb ",[44,1870,123],{"class":88},[44,1872,1873],{"class":92}," Workbook()\n",[44,1875,1876,1879,1882,1884,1887,1889,1892],{"class":46,"line":117},[44,1877,1878],{"class":92},"wb.active.append([",[44,1880,1881],{"class":54},"\"Customer\"",[44,1883,138],{"class":92},[44,1885,1886],{"class":54},"\"City\"",[44,1888,138],{"class":92},[44,1890,1891],{"class":54},"\"Amount\"",[44,1893,1894],{"class":92},"])\n",[44,1896,1897,1899,1902,1904,1907,1909,1912],{"class":46,"line":173},[44,1898,1878],{"class":92},[44,1900,1901],{"class":54},"\"  Acme Ltd \"",[44,1903,138],{"class":92},[44,1905,1906],{"class":54},"\" Leeds\"",[44,1908,138],{"class":92},[44,1910,1911],{"class":156},"120.5",[44,1913,1894],{"class":92},[44,1915,1916,1919,1922],{"class":46,"line":198},[44,1917,1918],{"class":92},"wb.save(",[44,1920,1921],{"class":54},"\"customers.xlsx\"",[44,1923,508],{"class":92},[44,1925,1926,1929,1931,1934,1936],{"class":46,"line":209},[44,1927,1928],{"class":92},"customers ",[44,1930,123],{"class":88},[44,1932,1933],{"class":92}," pd.read_excel(",[44,1935,1921],{"class":54},[44,1937,508],{"class":92},[44,1939,1940],{"class":46,"line":241},[44,1941,114],{"emptyLinePlaceholder":113},[44,1943,1944,1947,1949,1951,1953,1955,1957,1960,1962,1965,1967,1969],{"class":46,"line":281},[44,1945,1946],{"class":92},"trimmed_old ",[44,1948,123],{"class":88},[44,1950,1399],{"class":92},[44,1952,514],{"class":88},[44,1954,1404],{"class":92},[44,1956,520],{"class":88},[44,1958,1959],{"class":92}," customers.columns ",[44,1961,624],{"class":88},[44,1963,1964],{"class":92}," customers[c].dtype ",[44,1966,398],{"class":88},[44,1968,478],{"class":156},[44,1970,1971],{"class":92},"]\n",[44,1973,1974,1977,1979,1981,1983,1985,1987,1989,1991],{"class":46,"line":304},[44,1975,1976],{"class":92},"trimmed_new ",[44,1978,123],{"class":88},[44,1980,1399],{"class":92},[44,1982,514],{"class":88},[44,1984,1404],{"class":92},[44,1986,520],{"class":88},[44,1988,1959],{"class":92},[44,1990,624],{"class":88},[44,1992,1993],{"class":92}," is_string_dtype(customers[c])]\n",[44,1995,1996,1998,2001,2003,2005,2008,2011,2014],{"class":46,"line":322},[44,1997,493],{"class":156},[44,1999,2000],{"class":92},"(pd.",[44,2002,505],{"class":156},[44,2004,138],{"class":92},[44,2006,2007],{"class":54},"\"| dtype == object finds:\"",[44,2009,2010],{"class":92},", trimmed_old, ",[44,2012,2013],{"class":54},"\"| is_string_dtype finds:\"",[44,2015,2016],{"class":92},", trimmed_new)\n",[10,2018,2019,2020,1476,2022,2024,2025,2028,2029,2032,2033,2035,2036,2039,2040,2043,2044,1480,2046,2049,2050,2053,2054,2056,2057,28],{},"Under pandas 3 the old test finds no text columns, so a cleaning step that trims spaces from \"every text column\" quietly trims nothing and the report keeps ",[14,2021,1901],{},[14,2023,1101],{}," finds both columns under either version. The same applies to ",[14,2026,2027],{},"select_dtypes",": use ",[14,2030,2031],{},"include=[\"object\", \"string\"]"," rather than ",[14,2034,454],{}," alone. Of all the changes on this page, this is the one most worth searching for, precisely because it does not announce itself. Related checks deserve the same review: ",[14,2037,2038],{},"isinstance(value, str)"," still works on individual values, but code that inspects ",[14,2041,2042],{},"df.dtypes"," to decide how to format columns when writing to Excel — text left-aligned, numbers with a number format — should also use ",[14,2045,1101],{},[14,2047,2048],{},"is_numeric_dtype"," rather than comparing dtype names. Missing text values change too: in the new string dtype a missing value is ",[14,2051,2052],{},"NaN",", so tests that compared with ",[14,2055,162],{}," need ",[14,2058,2059],{},"pd.isna()",[30,2061,2063],{"id":2062},"common-pitfalls","Common pitfalls",[2065,2066,2067,2075,2085,2104,2117],"ul",{},[2068,2069,2070,2074],"li",{},[2071,2072,2073],"strong",{},"Ignoring FutureWarnings."," They are the list of what will break on the next upgrade.",[2068,2076,2077,2080,2081,2084],{},[2071,2078,2079],{},"Silencing warnings globally."," ",[14,2082,2083],{},"warnings.filterwarnings(\"ignore\")"," hides the useful ones too.",[2068,2086,2087,2097,2098,2101,2102,28],{},[2071,2088,2089,2090,2093,2094,28],{},"Replacing ",[14,2091,2092],{},"'M'"," with ",[14,2095,2096],{},"'MS'"," That moves results to month ",[19,2099,2100],{},"start","; month end is ",[14,2103,975],{},[2068,2105,2106,2112,2113,2116],{},[2071,2107,2108,2109,28],{},"Fixing chained assignment with ",[14,2110,2111],{},".copy()"," Assign through ",[14,2114,2115],{},"df.loc"," instead.",[2068,2118,2119,2125,2126,28],{},[2071,2120,2121,2122,2124],{},"Checking ",[14,2123,880],{}," for text."," Use ",[14,2127,1101],{},[30,2129,2131],{"id":2130},"conclusion","Conclusion",[10,2133,2134,2135,2093,2138,138,2140,2093,2142,138,2144,2093,2147,2149,2150,138,2152,2093,2154,138,2157,2093,2160,2163,2164,2166,2167,2169,2170,2116],{},"The FutureWarnings pandas 2.2 prints in Excel pipelines are the errors of pandas 3: replace ",[14,2136,2137],{},"resample(\"M\")",[14,2139,1219],{},[14,2141,1509],{},[14,2143,1258],{},[14,2145,2146],{},"fillna(method=...)",[14,2148,1479],{}," or ",[14,2151,1483],{},[14,2153,1024],{},[14,2155,2156],{},"map",[14,2158,2159],{},"s[0]",[14,2161,2162],{},"s.iloc[0]",", and chained or in-place column updates with ",[14,2165,1081],{}," or an assignment of the result. Then look for text-column logic based on ",[14,2168,880],{},", which pandas 3 changes silently, and use ",[14,2171,1101],{},[30,2173,2175],{"id":2174},"frequently-asked-questions","Frequently asked questions",[10,2177,2178,2181],{},[2071,2179,2180],{},"Why does resample(\"M\") fail in pandas 3?","\nThe month-end alias was renamed to \"ME\"; \"M\" warned in pandas 2.2 and raises ValueError in pandas 3.",[10,2183,2184,2187],{},[2071,2185,2186],{},"What replaces fillna(method=\"ffill\")?","\nCall df.ffill() or df.bfill() directly; the method argument was removed in pandas 3.",[10,2189,2190,2197,2198,2201],{},[2071,2191,2192,2193,2196],{},"Why does my assignment df[\"col\"]",[44,2194,2195],{},"mask"," = value no longer change the DataFrame?","\nWith copy-on-write in pandas 3, chained assignment works on a copy; use df.loc",[44,2199,2200],{},"mask, \"col\""," = value.",[10,2203,2204,2207],{},[2071,2205,2206],{},"Why are my text columns not detected as object dtype in pandas 3?","\npandas 3 stores text in the new str dtype; test with pandas.api.types.is_string_dtype instead of comparing with object.",[30,2209,2211],{"id":2210},"related","Related",[2065,2213,2214,2220,2227,2232],{},[2068,2215,2216,2217,2219],{},"Up one level: ",[24,2218,27],{"href":26}," — fixes for common errors.",[2068,2221,2222,2226],{},[24,2223,2225],{"href":2224},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-excelwriter-has-no-attribute-save\u002F","Fix \"ExcelWriter Object Has No Attribute save\""," — an earlier removal.",[2068,2228,2229,2231],{},[24,2230,72],{"href":71}," — catching these automatically.",[2068,2233,2234,2238],{},[24,2235,2237],{"href":2236},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstrip-whitespace-and-normalise-text-columns-with-pandas\u002F","Strip Whitespace and Normalise Text Columns with pandas"," — the cleaning step affected by the dtype change.",[2240,2241,2242],"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 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-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":40,"searchDepth":96,"depth":96,"links":2244},[2245,2246,2247,2248,2249,2250,2252,2253,2254,2255],{"id":32,"depth":96,"text":33},{"id":75,"depth":96,"text":76},{"id":1104,"depth":96,"text":1105},{"id":1690,"depth":96,"text":1691},{"id":1799,"depth":96,"text":1800},{"id":1826,"depth":96,"text":2251},"Step 3 — The silent one: text columns are no longer object",{"id":2062,"depth":96,"text":2063},{"id":2130,"depth":96,"text":2131},{"id":2174,"depth":96,"text":2175},{"id":2210,"depth":96,"text":2211},"2026-10-02","Clear the FutureWarnings an Excel reporting script prints under pandas 2.x before they turn into errors in pandas 3: month-end and hourly frequency aliases, fillna(method=), applymap, positional Series indexing, chained assignment and inplace on a column — plus the silent pandas 3 change to text columns that breaks dtype == object checks — with each warning reproduced under both versions and fixed.","md",[2260,2262,2264,2267],{"q":2180,"a":2261},"The month-end alias was renamed to \"ME\"; \"M\" warned in pandas 2.2 and raises ValueError in pandas 3.",{"q":2186,"a":2263},"Call df.ffill() or df.bfill() directly; the method argument was removed in pandas 3.",{"q":2265,"a":2266},"Why does my assignment df[\"col\"][mask] = value no longer change the DataFrame?","With copy-on-write in pandas 3, chained assignment works on a copy; use df.loc[mask, \"col\"] = value.",{"q":2206,"a":2268},"pandas 3 stores text in the new str dtype; test with pandas.api.types.is_string_dtype instead of comparing with object.","fix pandas futurewarnings in excel pipelines",null,{"breadcrumb":2272},[2273,2276,2279],{"name":2274,"item":2275},"Home","\u002F",{"name":2277,"item":2278},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":27,"item":26},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines",{"title":2282,"description":2283},"Fix pandas FutureWarnings in Excel Pipelines Before pandas 3","The FutureWarnings Excel scripts hit in pandas 2.2 and the errors they become in pandas 3: resample M to ME, H to h, ffill, map, iloc, chained assignment, inplace, and the str dtype that breaks dtype == object.","fix-pandas-futurewarnings-in-excel-pipelines","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines\u002Findex",[2287,2288],"troubleshooting","pandas","how-to","_WPdwA_fAK0PKLhI5kDffrvqovc4LNRDxrMa23XBbKM",[2292,2296],{"title":2293,"path":2294,"stem":2295,"children":-1},"Fix \"OverflowError: date value out of range\" When Reading Excel","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel\u002Findex",{"title":2297,"path":2298,"stem":2299,"children":-1},"Fix read_excel Returning an Empty DataFrame","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-read-excel-returning-an-empty-dataframe","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-read-excel-returning-an-empty-dataframe\u002Findex",[2301,2303],{"path":2302,"title":2277},"\u002Fgetting-started-with-python-excel-automation",{"path":2304,"title":27},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[2307,2311,2314,2317,2320,2323],{"path":2308,"title":2309,"kind":2310},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fhandle-permission-denied-when-writing-excel-in-python","Handle Permission Denied When Writing Excel in Python","fix",{"path":2312,"title":2313,"kind":2289},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook","What openpyxl Loses When You Save an Existing Workbook",{"path":2315,"title":2316,"kind":2310},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffix-excel-serial-numbers-showing-instead-of-dates","Fix Excel Serial Numbers Showing Instead of Dates",{"path":2318,"title":2319,"kind":2289},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-daylight-saving-time-in-excel-timestamps","Handle Daylight Saving Time in Excel Timestamps",{"path":2321,"title":2322,"kind":2289},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":2324,"title":2325,"kind":2326},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972067384]