[{"data":1,"prerenderedAt":808},["ShallowReactive",2],{"page-\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fturning-warnings-into-errors-with-filterwarnings\u002F":3},{"id":4,"title":5,"body":6,"description":772,"extension":773,"meta":774,"navigation":113,"path":804,"seo":805,"stem":806,"__hash__":807},"content\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fturning-warnings-into-errors-with-filterwarnings\u002Findex.md","Turning Warnings into Errors with filterwarnings",{"type":7,"value":8,"toc":761},"minimark",[9,13,21,26,63,67,168,217,220,361,365,388,391,395,444,448,451,461,472,479,486,547,551,554,557,560,564,567,574,585,588,685,689,698,708,718,722,752,757],[10,11,12],"p",{},"A deprecation warning is a message from the future: the thing you are calling will stop working in a version you have not upgraded to yet. Left as warnings, those messages scroll past in a summary nobody reads until the upgrade arrives and the suite breaks in forty places at once. Turned into errors, each one fails the test that triggered it on the day it first appears, when fixing it is a one-line change.",[10,14,15,16,20],{},"The obstacle is noise. A modern dependency tree emits warnings you cannot fix, and a naive ",[17,18,19],"code",{},"-W error"," fails the suite on the first one. Teams that try it that way usually revert within a day and conclude that strict warnings are impractical, when the real problem was an all-or-nothing configuration applied to a suite that had accumulated years of tolerated messages. The approach below keeps the strictness for everything the team controls and makes each tolerated exception explicit, scoped and temporary. The workable configuration is error by default, plus a short list of narrow, documented ignores for third-party warnings — each scoped to one category and one module, each with a note on when to revisit.",[22,23,25],"h2",{"id":24},"prerequisites","Prerequisites",[27,28,29,36,55],"ul",{},[30,31,32,35],"li",{},[17,33,34],{},"pytest >= 8.0",".",[30,37,38,39,42,43,42,46,42,49,42,52,35],{},"Familiarity with Python's warning categories: ",[17,40,41],{},"DeprecationWarning",", ",[17,44,45],{},"PendingDeprecationWarning",[17,47,48],{},"ResourceWarning",[17,50,51],{},"RuntimeWarning",[17,53,54],{},"UserWarning",[30,56,57,58,35],{},"The configuration file conventions in ",[59,60,62],"a",{"href":61},"\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fpyproject-toml-vs-pytest-ini\u002F","pyproject.toml vs pytest.ini",[22,64,66],{"id":65},"solution","Solution",[68,69,74],"pre",{"className":70,"code":71,"language":72,"meta":73,"style":73},"language-toml shiki shiki-themes github-light github-dark","# pyproject.toml\n[tool.pytest.ini_options]\nfilterwarnings = [\n    # 1. Every warning is an error unless a later entry says otherwise.\n    \"error\",\n\n    # 2. Narrow ignores for third-party noise — category AND module.\n    #    botocore: datetime.utcnow() deprecation, fixed upstream in 1.35; revisit on bump.\n    \"ignore:datetime.datetime.utcnow:DeprecationWarning:botocore.*\",\n    #    a transitive dependency's pkg_resources import; no fix available yet.\n    \"ignore::DeprecationWarning:pkg_resources.*\",\n\n    # 3. Resource warnings from our own code are real bugs: keep them errors.\n    #    (No entry needed — \"error\" already covers ResourceWarning.)\n]\n","toml","",[17,75,76,84,90,96,102,108,115,121,127,133,139,145,150,156,162],{"__ignoreMap":73},[77,78,81],"span",{"class":79,"line":80},"line",1,[77,82,83],{},"# pyproject.toml\n",[77,85,87],{"class":79,"line":86},2,[77,88,89],{},"[tool.pytest.ini_options]\n",[77,91,93],{"class":79,"line":92},3,[77,94,95],{},"filterwarnings = [\n",[77,97,99],{"class":79,"line":98},4,[77,100,101],{},"    # 1. Every warning is an error unless a later entry says otherwise.\n",[77,103,105],{"class":79,"line":104},5,[77,106,107],{},"    \"error\",\n",[77,109,111],{"class":79,"line":110},6,[77,112,114],{"emptyLinePlaceholder":113},true,"\n",[77,116,118],{"class":79,"line":117},7,[77,119,120],{},"    # 2. Narrow ignores for third-party noise — category AND module.\n",[77,122,124],{"class":79,"line":123},8,[77,125,126],{},"    #    botocore: datetime.utcnow() deprecation, fixed upstream in 1.35; revisit on bump.\n",[77,128,130],{"class":79,"line":129},9,[77,131,132],{},"    \"ignore:datetime.datetime.utcnow:DeprecationWarning:botocore.*\",\n",[77,134,136],{"class":79,"line":135},10,[77,137,138],{},"    #    a transitive dependency's pkg_resources import; no fix available yet.\n",[77,140,142],{"class":79,"line":141},11,[77,143,144],{},"    \"ignore::DeprecationWarning:pkg_resources.*\",\n",[77,146,148],{"class":79,"line":147},12,[77,149,114],{"emptyLinePlaceholder":113},[77,151,153],{"class":79,"line":152},13,[77,154,155],{},"    # 3. Resource warnings from our own code are real bugs: keep them errors.\n",[77,157,159],{"class":79,"line":158},14,[77,160,161],{},"    #    (No entry needed — \"error\" already covers ResourceWarning.)\n",[77,163,165],{"class":79,"line":164},15,[77,166,167],{},"]\n",[68,169,173],{"className":170,"code":171,"language":172,"meta":73,"style":73},"language-python shiki shiki-themes github-light github-dark","import pytest\n\nfrom myapp.legacy import old_api\n\n\ndef test_old_api_warns_before_removal():\n    # Asserting on the warning makes it a tested behaviour, not a tolerated one.\n    with pytest.warns(DeprecationWarning, match=\"old_api is deprecated\"):\n        old_api()\n","python",[17,174,175,180,184,189,193,197,202,207,212],{"__ignoreMap":73},[77,176,177],{"class":79,"line":80},[77,178,179],{},"import pytest\n",[77,181,182],{"class":79,"line":86},[77,183,114],{"emptyLinePlaceholder":113},[77,185,186],{"class":79,"line":92},[77,187,188],{},"from myapp.legacy import old_api\n",[77,190,191],{"class":79,"line":98},[77,192,114],{"emptyLinePlaceholder":113},[77,194,195],{"class":79,"line":104},[77,196,114],{"emptyLinePlaceholder":113},[77,198,199],{"class":79,"line":110},[77,200,201],{},"def test_old_api_warns_before_removal():\n",[77,203,204],{"class":79,"line":117},[77,205,206],{},"    # Asserting on the warning makes it a tested behaviour, not a tolerated one.\n",[77,208,209],{"class":79,"line":123},[77,210,211],{},"    with pytest.warns(DeprecationWarning, match=\"old_api is deprecated\"):\n",[77,213,214],{"class":79,"line":129},[77,215,216],{},"        old_api()\n",[10,218,219],{},"Each ignore names a category, and most name a module. That precision is the point: the botocore entry silences one message from one package, so the same deprecation raised by your own code still fails.",[221,222,225,357],"figure",{"className":223},[224],"diagram",[226,227,234,235,234,239,234,243,234,261,234,269,234,278,234,287,234,292,234,297,234,300,234,303,234,307,234,313,234,316,234,323,234,327,234,331,234,335,234,338,234,342,234,348,234,353],"svg",{"viewBox":228,"role":229,"ariaLabelledBy":230,"xmlns":233},"0 0 820 262","img",[231,232],"fw-t","fw-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[236,237,238],"title",{"id":231},"How filter entries are applied",[240,241,242],"desc",{"id":232},"A warning is checked against the filter list from last entry to first. A DeprecationWarning attributed to botocore matches the specific ignore and is silenced. The same category raised from the application's own module matches no ignore and falls through to the leading error entry, failing the test that raised it.",[244,245,246,247,234],"defs",{},"\n    ",[248,249,256],"marker",{"id":250,"viewBox":251,"refX":252,"refY":253,"markerWidth":254,"markerHeight":254,"orient":255},"fw-a","0 0 10 10","9","5","7","auto-start-reverse",[257,258],"path",{"d":259,"fill":260},"M0 0 L10 5 L0 10 z","#3d405b",[262,263],"rect",{"x":264,"y":264,"width":265,"height":266,"rx":267,"fill":268},"0","820","262","14","#fffdf8",[270,271,277],"text",{"x":272,"y":273,"textAnchor":274,"fontSize":275,"fontWeight":276,"fill":260},"410","28","middle","16","700","Specific ignores win; everything else is an error",[262,279],{"x":280,"y":281,"width":282,"height":283,"rx":284,"fill":285,"stroke":260,"strokeWidth":286},"26","56","220","60","10","#f4f1de","1.6",[270,288,41],{"x":289,"y":290,"textAnchor":274,"fontSize":291,"fontWeight":276,"fill":260},"136","80","11.5",[270,293,296],{"x":289,"y":294,"textAnchor":274,"fontSize":295,"fill":260},"100","11","from botocore",[262,298],{"x":280,"y":299,"width":282,"height":283,"rx":284,"fill":285,"stroke":260,"strokeWidth":286},"150",[270,301,41],{"x":289,"y":302,"textAnchor":274,"fontSize":291,"fontWeight":276,"fill":260},"174",[270,304,306],{"x":289,"y":305,"textAnchor":274,"fontSize":295,"fill":260},"194","from myapp.billing",[79,308],{"x1":309,"y1":310,"x2":311,"y2":310,"stroke":260,"strokeWidth":286,"markerEnd":312},"250","86","330","url(#fw-a)",[79,314],{"x1":309,"y1":315,"x2":311,"y2":315,"stroke":260,"strokeWidth":286,"markerEnd":312},"180",[262,317],{"x":318,"y":281,"width":319,"height":283,"rx":284,"fill":320,"stroke":321,"strokeWidth":322},"336","240","#e6f0ea","#81b29a","2",[270,324,326],{"x":325,"y":290,"textAnchor":274,"fontSize":291,"fontWeight":276,"fill":260},"456","matches ignore:…:botocore.*",[270,328,330],{"x":325,"y":294,"textAnchor":274,"fontSize":295,"fill":329},"#2a5f49","silenced",[262,332],{"x":318,"y":299,"width":319,"height":283,"rx":284,"fill":333,"stroke":334,"strokeWidth":322},"#fbe9e3","#e07a5f",[270,336,337],{"x":325,"y":302,"textAnchor":274,"fontSize":291,"fontWeight":276,"fill":260},"no ignore matches",[270,339,341],{"x":325,"y":305,"textAnchor":274,"fontSize":295,"fill":340},"#8f3d22","falls through to \"error\"",[262,343],{"x":344,"y":294,"width":305,"height":345,"rx":295,"fill":268,"stroke":346,"strokeWidth":347},"600","70","rgba(61,64,91,0.35)","1.5",[270,349,352],{"x":350,"y":351,"textAnchor":274,"fontSize":295,"fill":260},"697","128","same category,",[270,354,356],{"x":350,"y":355,"textAnchor":274,"fontSize":295,"fill":260},"148","different outcome",[358,359,360],"figcaption",{},"Scoping ignores to a module is what lets a suite be strict about its own code while tolerating dependencies it cannot fix.",[22,362,364],{"id":363},"why-this-works","Why this works",[10,366,367,368,371,372,375,376,379,380,383,384,387],{},"pytest applies ",[17,369,370],{},"filterwarnings"," entries using Python's own warning-filter machinery, where each entry has the form ",[17,373,374],{},"action:message:category:module:lineno"," and later entries take precedence. Putting ",[17,377,378],{},"error"," first establishes the default; each subsequent ",[17,381,382],{},"ignore"," overrides it for the warnings it matches. The ",[17,385,386],{},"module"," field is a regular expression matched against the module the warning is attributed to, which is what allows a filter to target one dependency without silencing the category everywhere.",[10,389,390],{},"The filters are applied per test, around each test's execution, so a warning is converted to an exception inside the test that triggered it. The failure therefore points at the exact test and line, rather than appearing in a summary at the end of the run with no clear owner.",[22,392,394],{"id":393},"edge-cases-and-failure-modes","Edge cases and failure modes",[27,396,397,408,414,426,432],{},[30,398,399,403,404,407],{},[400,401,402],"strong",{},"Ignores without a module."," ",[17,405,406],{},"ignore::DeprecationWarning"," silences every deprecation, including your own. Always scope by module unless the warning genuinely comes from everywhere.",[30,409,410,413],{},[400,411,412],{},"Warnings at import time."," A warning raised while collecting a module happens outside any test and is reported as a collection error. Fix the import or add a module-scoped ignore.",[30,415,416,421,422,425],{},[400,417,418,420],{},[17,419,48],{}," depends on garbage collection."," Unclosed files and sockets are reported when the object is collected, which may be in a later test. Run with ",[17,423,424],{},"-X tracemalloc"," to see where the resource was allocated.",[30,427,428,431],{},[400,429,430],{},"Ignores that outlive their reason."," An ignore added for a bug fixed upstream two years ago hides nothing but costs nothing either — until the same message returns from your own code. Comment every ignore with the reason and a revisit condition.",[30,433,434,440,441,443],{},[400,435,436,439],{},[17,437,438],{},"-W"," on the command line."," Command-line ",[17,442,438],{}," entries are applied after the configuration and override it. Keep policy in configuration so every runner behaves the same.",[22,445,447],{"id":446},"which-categories-deserve-which-treatment","Which categories deserve which treatment",[10,449,450],{},"Not every warning category means the same thing, and a good configuration treats them differently rather than uniformly.",[10,452,453,460],{},[400,454,455,457,458],{},[17,456,41],{}," and ",[17,459,45],{}," are the reason to do any of this. They announce future breakage with a lead time, and treating them as errors converts that lead time into a to-do item on the day the warning first appears. From your own code they should always be errors; from dependencies they are errors unless scoped out with a documented reason.",[10,462,463,467,468,471],{},[400,464,465],{},[17,466,48],{}," reports an unclosed file, socket or subprocess — almost always a genuine bug in the code under test, and one that leaks file descriptors in production. Keep it an error with no ignores; the fix is a ",[17,469,470],{},"with"," statement.",[10,473,474,478],{},[400,475,476],{},[17,477,51],{}," covers several unrelated things, the most important being \"coroutine was never awaited\", which in a test nearly always means an assertion proved nothing. That alone justifies keeping the category an error, as the patching guides in this site argue.",[10,480,481,485],{},[400,482,483],{},[17,484,54],{}," is whatever a library author chose to say. Treat it case by case: some are actionable, many are informational, and the right response is to read each one once and decide.",[221,487,489,544],{"className":488},[224],[226,490,234,495,234,498,234,501,234,505,234,510,234,518,234,523,234,526,234,530,234,533,234,537,234,540],{"viewBox":491,"role":229,"ariaLabelledBy":492,"xmlns":233},"0 0 800 236",[493,494],"cat-t","cat-d",[236,496,497],{"id":493},"Treatment by warning category",[240,499,500],{"id":494},"Four categories. Deprecation warnings are errors, with scoped ignores for third-party sources. Resource warnings are always errors because they indicate leaked files or sockets. Runtime warnings stay errors because they include never-awaited coroutines. User warnings are reviewed individually and handled case by case.",[262,502],{"x":264,"y":264,"width":503,"height":504,"rx":267,"fill":268},"800","236",[270,506,509],{"x":507,"y":273,"textAnchor":274,"fontSize":508,"fontWeight":276,"fill":260},"400","15.5","Four categories, three policies",[262,511],{"x":280,"y":512,"width":513,"height":514,"rx":252,"fill":515,"stroke":516,"strokeWidth":517},"48","748","38","#f7f0da","#f2cc8f","1.8",[270,519,522],{"x":520,"y":521,"fontSize":291,"fill":260},"46","72","DeprecationWarning — error; scoped ignores for third-party only, each with a revisit note",[262,524],{"x":280,"y":525,"width":513,"height":514,"rx":252,"fill":333,"stroke":334,"strokeWidth":517},"94",[270,527,529],{"x":520,"y":528,"fontSize":291,"fill":260},"118","ResourceWarning — always an error: an unclosed file or socket is a real leak",[262,531],{"x":280,"y":532,"width":513,"height":514,"rx":252,"fill":333,"stroke":334,"strokeWidth":517},"140",[270,534,536],{"x":520,"y":535,"fontSize":291,"fill":260},"164","RuntimeWarning — error: includes \"coroutine was never awaited\"",[262,538],{"x":280,"y":539,"width":513,"height":514,"rx":252,"fill":320,"stroke":321,"strokeWidth":517},"186",[270,541,543],{"x":520,"y":542,"fontSize":291,"fill":260},"210","UserWarning — read each once; ignore the informational, fix the actionable",[358,545,546],{},"Only the bottom row needs judgement per message. The other three can be policy.",[22,548,550],{"id":549},"warnings-as-an-upgrade-early-warning-system","Warnings as an upgrade early-warning system",[10,552,553],{},"The largest payoff of error-by-default arrives at dependency upgrades. A library that deprecates an API typically warns for one or two minor releases before removing it. A suite that errors on deprecations surfaces each one the day the warning is introduced — usually in a routine minor-version bump — when the fix is small and the context is fresh.",[10,555,556],{},"The contrast with the alternative is stark. A suite that tolerates warnings accumulates them silently across a dozen minor upgrades, and the major version that finally removes the deprecated APIs breaks everything at once. What would have been twelve five-minute fixes spread over a year becomes a multi-day migration under pressure, with no record of which call sites were warned about when.",[10,558,559],{},"Running the suite against pre-release versions of key dependencies in a scheduled job extends the early warning further still: new deprecations appear in the suite weeks before the release ships, and the ignores list becomes a forward-looking inventory of upcoming work rather than a backward-looking list of tolerated noise. That job should report rather than fail, since a pre-release is allowed to be wrong; its value is the advance list of call sites that will need attention, delivered while there is still time to address them at leisure.",[22,561,563],{"id":562},"adopting-it-on-an-existing-suite","Adopting it on an existing suite",[10,565,566],{},"Switching an established suite to error-by-default all at once usually produces dozens of failures, which is discouraging and mostly noise. A staged adoption avoids that.",[10,568,569,570,573],{},"First, collect the inventory. Run the suite once with warnings reported but not raised and group them by category and origin: ",[17,571,572],{},"pytest -W default -p no:randomly -q 2>&1 | grep -E \"Warning\" | sort | uniq -c | sort -rn",". The result is usually a short list — a handful of distinct messages, each repeated many times.",[10,575,576,577,579,580,584],{},"Second, add ",[17,578,378],{}," plus an explicit ignore for every current offender, each with a comment. The suite goes green immediately, and from that moment any ",[581,582,583],"em",{},"new"," warning fails. That is the essential property: the list can only shrink.",[10,586,587],{},"Third, work through the ignores, fixing the ones in your own code and removing the corresponding entries. Third-party ones stay until the dependency is upgraded, at which point removing the entry is part of the upgrade. A reviewer checking an upgrade pull request can then confirm that the matching ignore was deleted, which keeps the list from quietly outliving its reasons.",[221,589,591,682],{"className":590},[224],[226,592,234,596,234,599,234,602,234,609,234,611,234,614,234,618,234,624,234,629,234,633,234,636,234,642,234,645,234,649,234,653,234,656,234,660,234,664,234,668,234,672,234,676,234,679],{"viewBox":491,"role":229,"ariaLabelledBy":593,"xmlns":233},[594,595],"adp-t","adp-d",[236,597,598],{"id":594},"Staged adoption of error-by-default",[240,600,601],{"id":595},"Three stages. Inventory the current warnings grouped by message and origin. Add error plus an explicit ignore for each current offender so the suite is green and any new warning fails. Then remove ignores one by one as the underlying code is fixed or dependencies are upgraded.",[244,603,246,604,234],{},[248,605,607],{"id":606,"viewBox":251,"refX":252,"refY":253,"markerWidth":254,"markerHeight":254,"orient":255},"adp-a",[257,608],{"d":259,"fill":260},[262,610],{"x":264,"y":264,"width":503,"height":504,"rx":267,"fill":268},[270,612,613],{"x":507,"y":273,"textAnchor":274,"fontSize":508,"fontWeight":276,"fill":260},"Green immediately, stricter every week",[262,615],{"x":616,"y":281,"width":504,"height":532,"rx":617,"fill":285,"stroke":260,"strokeWidth":286},"24","12",[270,619,623],{"x":620,"y":621,"textAnchor":274,"fontSize":622,"fontWeight":276,"fill":260},"142","82","12.5","1 · inventory",[270,625,628],{"x":626,"y":627,"fontSize":295,"fill":260},"40","110","run with -W default",[270,630,632],{"x":626,"y":631,"fontSize":295,"fill":260},"132","group by message and origin",[270,634,635],{"x":626,"y":535,"fontSize":295,"fill":260},"usually a short list",[79,637],{"x1":638,"y1":639,"x2":640,"y2":639,"stroke":260,"strokeWidth":286,"markerEnd":641},"264","126","290","url(#adp-a)",[262,643],{"x":644,"y":281,"width":504,"height":532,"rx":617,"fill":515,"stroke":516,"strokeWidth":322},"296",[270,646,648],{"x":647,"y":621,"textAnchor":274,"fontSize":622,"fontWeight":276,"fill":260},"414","2 · freeze",[270,650,652],{"x":651,"y":627,"fontSize":295,"fill":260},"312","\"error\" + one ignore each",[270,654,655],{"x":651,"y":631,"fontSize":295,"fill":260},"every ignore commented",[270,657,659],{"x":651,"y":535,"fontSize":295,"fill":658},"#8a5a00","new warnings now fail",[79,661],{"x1":662,"y1":639,"x2":663,"y2":639,"stroke":260,"strokeWidth":286,"markerEnd":641},"536","562",[262,665],{"x":666,"y":281,"width":667,"height":532,"rx":617,"fill":320,"stroke":321,"strokeWidth":322},"568","208",[270,669,671],{"x":670,"y":621,"textAnchor":274,"fontSize":622,"fontWeight":276,"fill":260},"672","3 · shrink",[270,673,675],{"x":674,"y":627,"fontSize":295,"fill":260},"584","fix your own warnings",[270,677,678],{"x":674,"y":631,"fontSize":295,"fill":260},"drop ignores on upgrade",[270,680,681],{"x":674,"y":535,"fontSize":295,"fill":329},"the list only gets shorter",[358,683,684],{},"Stage two is the one that matters most: it stops the problem growing on the same day, and the cleanup can then proceed at whatever pace suits the team.",[22,686,688],{"id":687},"frequently-asked-questions","Frequently Asked Questions",[10,690,691,694,695,697],{},[400,692,693],{},"In what order are filterwarnings entries applied?","\nLater entries take precedence over earlier ones, matching Python's own warning filters. Put the broad rule — usually ",[17,696,378],{}," — first, and the specific ignores after it, so each ignore overrides the blanket error for the warnings it names.",[10,699,700,703,704,707],{},[400,701,702],{},"How do I ignore a warning from one third-party package only?","\nMatch on the module with the fourth field of the filter: ",[17,705,706],{},"ignore::DeprecationWarning:somepackage.*",". That silences the category only when the warning is attributed to that package, leaving the same category an error everywhere else.",[10,709,710,713,714,717],{},[400,711,712],{},"How do I assert that my own code emits a warning?","\nUse ",[17,715,716],{},"pytest.warns(DeprecationWarning, match=\"...\")"," as a context manager around the call. It fails if the warning is not emitted, and inside it the warning does not count as an error even with error-by-default configured.",[22,719,721],{"id":720},"related","Related",[27,723,724,731,738,745],{},[30,725,726,730],{},[59,727,729],{"href":728},"\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002F","pytest Configuration Best Practices"," — where this setting sits among the others worth enforcing.",[30,732,733,737],{},[59,734,736],{"href":735},"\u002Fadvanced-mocking-test-doubles-in-python\u002Fpatching-async-code-and-coroutines\u002F","Patching Async Code & Coroutines"," — why \"coroutine was never awaited\" should be an error.",[30,739,740,744],{},[59,741,743],{"href":742},"\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fcapturing-logs-with-caplog-and-log-cli\u002F","Capturing Logs with caplog and log_cli"," — the companion capture mechanism for log records.",[30,746,747,751],{},[59,748,750],{"href":749},"\u002Ftesting-async-and-concurrent-python\u002Fpytest-asyncio-in-depth\u002F","pytest-asyncio in Depth"," — surfacing plugin deprecations before an upgrade breaks the suite.",[10,753,754,755],{},"← Back to ",[59,756,729],{"href":728},[758,759,760],"style",{},"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);}",{"title":73,"searchDepth":86,"depth":86,"links":762},[763,764,765,766,767,768,769,770,771],{"id":24,"depth":86,"text":25},{"id":65,"depth":86,"text":66},{"id":363,"depth":86,"text":364},{"id":393,"depth":86,"text":394},{"id":446,"depth":86,"text":447},{"id":549,"depth":86,"text":550},{"id":562,"depth":86,"text":563},{"id":687,"depth":86,"text":688},{"id":720,"depth":86,"text":721},"Make pytest fail on warnings without drowning in third-party noise: filterwarnings ordering, error-by-default with targeted ignores, per-test overrides, and pytest.warns.","md",{"slug":775,"type":776,"breadcrumb":370,"datePublished":777,"dateModified":777,"faq":778,"howto":785},"turning-warnings-into-errors-with-filterwarnings","article","2026-09-18",[779,781,783],{"q":693,"a":780},"Later entries take precedence over earlier ones, matching Python's own warning filters. Put the broad rule — usually 'error' — first, and the specific ignores after it, so each ignore overrides the blanket error for the warnings it names.",{"q":702,"a":782},"Match on the module with the fourth field of the filter: 'ignore::DeprecationWarning:somepackage.*'. That silences the category only when the warning is attributed to that package, leaving the same category an error everywhere else.",{"q":712,"a":784},"Use pytest.warns(DeprecationWarning, match='...') as a context manager around the call. It fails if the warning is not emitted, and inside it the warning does not count as an error even with error-by-default configured.",{"name":786,"description":787,"steps":788},"How to make warnings fail the suite without noise","Error on every warning by default, add narrow ignores for third-party noise, and assert on your own warnings explicitly.",[789,792,795,798,801],{"name":790,"text":791},"Start from error","Add 'error' as the first filterwarnings entry so every unfiltered warning fails the test that raised it.",{"name":793,"text":794},"Run the suite and list the offenders","Collect every warning that now errors and classify it as yours or third-party.",{"name":796,"text":797},"Fix your own warnings","Resolve deprecations and resource warnings in your code rather than ignoring them.",{"name":799,"text":800},"Add narrow ignores for third-party noise","Ignore by category and module, with a comment naming the upstream issue and when to revisit.",{"name":802,"text":803},"Assert on intended warnings","Use pytest.warns around calls that should warn, so those warnings are tested rather than tolerated.","\u002Fadvanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fturning-warnings-into-errors-with-filterwarnings",{"title":5,"description":772},"advanced-pytest-architecture-configuration\u002Fpytest-configuration-best-practices\u002Fturning-warnings-into-errors-with-filterwarnings\u002Findex","SSdylkMovWF1EszNfvXg8psC2nLx4Es6lEcnZz91JT4",1789718768180]