warnings — Varningskontroll

Källkod: Lib/warnings.py


Varningsmeddelanden utfärdas vanligtvis i situationer där det är lämpligt att varna användaren för ett visst tillstånd i ett program, där detta tillstånd (normalt) inte motiverar att ett undantag görs och programmet avslutas. Man kan t.ex. vilja utfärda en varning när ett program använder en föråldrad modul.

Python-programmerare utfärdar varningar genom att anropa funktionen warn() som definieras i denna modul. (C-programmerare använder PyErr_WarnEx(); se Hantering av undantag för detaljer).

Varningsmeddelanden skrivs normalt till sys.stderr, men deras disposition kan ändras på ett flexibelt sätt, från att ignorera alla varningar till att omvandla dem till undantag. Dispositionen för varningar kan variera beroende på varningskategorin, texten i varningsmeddelandet och källplatsen där den utfärdades. Upprepningar av en viss varning för samma källplats undertrycks vanligtvis.

Det finns två steg i varningskontrollen: först, varje gång en varning utfärdas, avgörs om ett meddelande ska utfärdas eller inte; därefter, om ett meddelande ska utfärdas, formateras och skrivs det ut med hjälp av en hook som kan ställas in av användaren.

Avgörandet om ett varningsmeddelande ska utfärdas styrs av varningsfiltret, som är en sekvens av matchande regler och åtgärder. Regler kan läggas till i filtret genom att anropa filterwarnings() och återställas till dess standardtillstånd genom att anropa resetwarnings().

Utskriften av varningsmeddelanden sker genom anrop av showwarning(), som kan åsidosättas; standardimplementeringen av denna funktion formaterar meddelandet genom anrop av formatwarning(), som också kan användas av anpassade implementeringar.

Se även

logging.captureWarnings() gör att du kan hantera alla varningar med standardinfrastrukturen för loggning.

Varningskategorier

Det finns ett antal inbyggda undantag som representerar varningskategorier. Denna kategorisering är användbar för att kunna filtrera bort grupper av varningar.

Även om dessa tekniskt sett är inbyggda undantag, dokumenteras de här, eftersom de konceptuellt sett hör till varningsmekanismen.

Användarkod kan definiera ytterligare varningskategorier genom att subklassa en av standardvarningskategorierna. En varningskategori måste alltid vara en subklass av klassen Warning.

Följande klasser av varningskategorier är för närvarande definierade:

Klass

Beskrivning

Warning

Detta är basklassen för alla klasser i varningskategorin. Den är en underklass till Exception.

UserWarning

Standardkategorin för warn().

DeprecationWarning

Baskategori för varningar om föråldrade funktioner när dessa varningar är avsedda för andra Python-utvecklare (ignoreras som standard, såvida de inte utlöses av kod i __main__).

SyntaxWarning

Baskategori för varningar om tvivelaktiga syntaktiska egenskaper.

RuntimeWarning

Baskategori för varningar om tvivelaktiga runtime-funktioner.

FutureWarning

Baskategori för varningar om föråldrade funktioner när dessa varningar är avsedda för slutanvändare av program som är skrivna i Python.

PendingDeprecationWarning

Baskategori för varningar om funktioner som kommer att bli föråldrade i framtiden (ignoreras som standard).

ImportWarning

Baskategori för varningar som utlöses under import av en modul (ignoreras som standard).

UnicodeWarning

Baskategori för varningar relaterade till Unicode.

BytesWarning

Baskategori för varningar relaterade till bytes och bytearray.

ResourceWarning

Baskategori för varningar relaterade till resursanvändning (ignoreras som standard).

Ändrad i version 3.7: Tidigare skilde sig DeprecationWarning och FutureWarning åt baserat på om en funktion togs bort helt eller ändrade sitt beteende. De skiljer sig nu åt baserat på deras avsedda målgrupp och hur de hanteras av standardfiltren för varningar.

Filtret för varningar

Filtret för varningar styr om varningar ska ignoreras, visas eller omvandlas till fel (skapa ett undantag).

Begreppsmässigt upprätthåller varningsfiltret en ordnad lista med filterspecifikationer; en specifik varning matchas mot varje filterspecifikation i listan i tur och ordning tills en matchning hittas; filtret avgör hur matchningen ska hanteras. Varje post är en tupel av formen (action, message, category, module, lineno), där:

  • action är en av följande strängar:

    Värde

    Disposition

    "standard"

    skriva ut den första förekomsten av matchande varningar för varje plats (modul + radnummer) där varningen utfärdas

    "fel"

    omvandla matchande varningar till undantag

    "ignorera"

    skriv aldrig ut matchande varningar

    "alltid"

    alltid skriva ut matchande varningar

    "alla"

    alias till ”alltid”

    "modul"

    skriva ut den första förekomsten av matchande varningar för varje modul där varningen utfärdas (oavsett radnummer)

    ”en gång”

    skriv bara ut den första förekomsten av matchande varningar, oavsett plats

  • message är en sträng som innehåller ett reguljärt uttryck som början av varningsmeddelandet måste matcha, utan hänsyn till skiftlägesskillnader. I -W och PYTHONWARNINGS är message en bokstavlig sträng som början av varningsmeddelandet måste innehålla (utan hänsyn till skiftlägesskillnader), varvid eventuella blanksteg i början eller slutet av message ignoreras.

  • category är en klass (en subklass av Warning) som varningskategorin måste vara en subklass av för att matcha.

  • module är en sträng som innehåller ett reguljärt uttryck som början av det fullständigt kvalificerade modulnamnet måste matcha (skiftlägeskänsligt). I -W och PYTHONWARNINGS är module en bokstavlig sträng som det fullständigt kvalificerade modulnamnet måste vara lika med (skiftlägeskänsligt), utan hänsyn till eventuella blanksteg i början eller slutet av module.

  • lineno är ett heltal som det radnummer där varningen inträffade måste matcha, eller 0 för att matcha alla radnummer.

Eftersom klassen Warning är härledd från den inbyggda klassen Exception kan vi helt enkelt höja category(message) för att omvandla en varning till ett fel.

Om en varning rapporteras och inte matchar något registrerat filter tillämpas ”standard”-åtgärden (därav namnet).

Kriterier för undertryckande av upprepad varning

De filter som undertrycker upprepade varningar tillämpar följande kriterier för att avgöra om en varning anses vara upprepad:

  • "standard": En varning betraktas som en upprepning endast om (message, category, module, lineno) är identiska.

  • "modul": En varning betraktas som en upprepning om (message, category, module) är desamma, utan hänsyn till radnummer.

  • "en gång": En varning betraktas som en upprepning om (meddelande, kategori) är desamma, utan hänsyn till modul- och radnummer.

Beskrivning av varningsfilter

Varningsfiltret initieras av -W alternativ som skickas till Python-tolkens kommandorad och miljövariabeln PYTHONWARNINGS. Tolken sparar argumenten för alla medföljande poster utan tolkning i sys.warnoptions; modulen warnings analyserar dessa när den importeras första gången (ogiltiga alternativ ignoreras efter att ett meddelande skrivits ut till sys.stderr).

Enskilda varningsfilter anges som en sekvens av fält åtskilda med kolon:

åtgärd:meddelande:kategori:modul:linje

Betydelsen av vart och ett av dessa fält beskrivs i Filtret för varningar. När flera filter listas på en rad (som för PYTHONWARNINGS) separeras de enskilda filtren med kommatecken och de filter som listas senare har företräde framför de som listas före dem (eftersom de tillämpas från vänster till höger och de senast tillämpade filtren har företräde framför de tidigare).

Vanligt förekommande varningsfilter gäller antingen alla varningar, varningar i en viss kategori eller varningar som orsakas av vissa moduler eller paket. Några exempel:

default # Visa alla varningar (även de som ignoreras som standard)
ignore # Ignorera alla varningar
error # Konvertera alla varningar till fel
error::ResourceWarning # Behandla ResourceWarning-meddelanden som fel
default::DeprecationWarning # Visa DeprecationWarning-meddelanden
ignore,default:::mymodule # Rapportera bara varningar som utlöses av "mymodule"
error:::mymodule # Konvertera varningar till fel i "mymodule"

Standard varningsfilter

Som standard installerar Python flera varningsfilter som kan åsidosättas med kommandoradsalternativet -W, miljövariabeln PYTHONWARNINGS och anrop till filterwarnings().

I vanliga versionsversioner har standardvarningsfiltret följande poster (i prioritetsordning):

default::DeprecationWarning:__main__
ignorera::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning

I en debug build är listan över standardvarningsfilter tom.

Ändrad i version 3.2: DeprecationWarning ignoreras nu som standard i tillägg till PendingDeprecationWarning.

Ändrad i version 3.7: DeprecationWarning visas återigen som standard när den utlöses direkt av kod i __main__.

Ändrad i version 3.7: BytesWarning visas inte längre i standardfilterlistan och konfigureras istället via sys.warnoptions när -b anges två gånger.

Åsidosätta standardfiltret

Utvecklare av applikationer skrivna i Python kanske vill dölja alla varningar på Python-nivå från sina användare som standard, och bara visa dem när de kör tester eller på annat sätt arbetar med applikationen. Attributet sys.warnoptions som används för att skicka filterkonfigurationer till tolken kan användas som en markör för att ange om varningar ska inaktiveras eller inte:

import sys

if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

Utvecklare av testlöpare för Python-kod rekommenderas att istället se till att alla varningar visas som standard för den kod som testas, med hjälp av kod som:

import sys

if not sys.warnoptions:
    import os, warnings
    warnings.simplefilter("default") # Change the filter in this process
    os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses

Slutligen rekommenderas utvecklare av interaktiva skal som kör användarkod i ett annat namnrymd än __main__ att se till att DeprecationWarning-meddelanden görs synliga som standard, med hjälp av kod som följande (där user_ns är den modul som används för att köra kod som matas in interaktivt):

import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
                                   module=user_ns.get("__name__"))

Tillfälligt undertryckande av varningar

Om du använder kod som du vet kommer att ge upphov till en varning, t.ex. en föråldrad funktion, men inte vill se varningen (även när varningar uttryckligen har konfigurerats via kommandoraden), är det möjligt att undertrycka varningen med hjälp av kontexthanteraren catch_warnings:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

När du befinner dig i kontexthanteraren ignoreras alla varningar helt enkelt. Detta gör att du kan använda känd föråldrad kod utan att behöva se varningen samtidigt som varningen inte undertrycks för annan kod som kanske inte är medveten om att den använder föråldrad kod.

Anteckning

Se Samtidig säkerhet för kontexthanterare för detaljer om samtidighetssäkerheten för kontexthanteraren catch_warnings när den används i program som använder flera trådar eller asynkrona funktioner.

Varningar för testning

Om du vill testa varningar som orsakas av kod använder du kontexthanteraren catch_warnings. Med den kan du tillfälligt ändra varningsfiltret för att underlätta din testning. Gör till exempel följande för att fånga upp alla varningar för att kontrollera:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

Man kan också få alla varningar att bli undantag genom att använda error istället för always. En sak man bör vara medveten om är att om en varning redan har tagits upp på grund av en once/default-regel, så kommer varningen inte att visas igen oavsett vilka filter som ställs in, såvida inte varningsregistret som är relaterat till varningen har rensats.

När kontexthanteraren avslutas återställs varningsfiltret till det tillstånd som rådde när kontexten skapades. Detta förhindrar att testerna ändrar varningsfiltret på oväntade sätt mellan testerna, vilket leder till obestämda testresultat.

Anteckning

Se Samtidig säkerhet för kontexthanterare för detaljer om samtidighetssäkerheten för kontexthanteraren catch_warnings när den används i program som använder flera trådar eller asynkrona funktioner.

När du testar flera operationer som ger upphov till samma typ av varning är det viktigt att du testar dem på ett sätt som bekräftar att varje operation ger upphov till en ny varning (t.ex. genom att ställa in att varningar ska ges upphov till undantag och kontrollera att operationerna ger upphov till undantag, kontrollera att varningslistans längd fortsätter att öka efter varje operation, eller radera de tidigare posterna från varningslistan före varje ny operation).

Uppdatering av kod för nya versioner av beroenden

Varningskategorier som främst är av intresse för Python-utvecklare (snarare än slutanvändare av program som skrivits i Python) ignoreras som standard.

Noterbart är att denna ”ignoreras som standard”-lista innehåller DeprecationWarning (för alla moduler utom __main__), vilket innebär att utvecklare bör se till att testa sin kod med typiskt ignorerade varningar synliggjorda för att i god tid få meddelanden om framtida API-ändringar (oavsett om det är i standardbiblioteket eller tredjepartspaket).

I det ideala fallet har koden en lämplig testsvit och testköraren tar hand om att implicit aktivera alla varningar när tester körs (testköraren som tillhandahålls av modulen unittest gör detta).

I mindre idealiska fall kan applikationer kontrolleras för användning av föråldrade gränssnitt genom att skicka -Wd till Python-tolken (detta är en förkortning för -W default) eller ställa in PYTHONWARNINGS=default i miljön. Detta aktiverar standardhantering för alla varningar, inklusive de som ignoreras som standard. För att ändra vilken åtgärd som vidtas för varningar kan du ändra vilket argument som skickas till -W (t.ex. -W error). Se flaggan -W för mer information om vad som är möjligt.

Tillgängliga funktioner

warnings.warn(message, category=None, stacklevel=1, source=None, *, skip_file_prefixes=())

Utfärda en varning, eller kanske ignorera den eller höja en undantag. Argumentet category, om det anges, måste vara en varning kategori klass; standardvärdet är UserWarning. Alternativt kan message vara en Warning-instans, i vilket fall category ignoreras och message.__class__ används. I detta fall blir meddelandetexten str(message). Denna funktion genererar ett undantag om den specifika varningen ändras till ett fel av warnings filter. Argumentet stacklevel kan användas av wrapper-funktioner skrivna i Python, så här:

def deprecated_api(meddelande):
    warnings.warn(message, DeprecationWarning, stacklevel=2)

Detta gör att varningen hänvisar till deprecated_api’s anropare, snarare än till källan till deprecated_api själv (eftersom det senare skulle motverka syftet med varningsmeddelandet).

Nyckelordsargumentet skip_file_prefixes kan användas för att ange vilka stackramar som ska ignoreras när man räknar stacknivåer. Detta kan vara användbart när du vill att varningen alltid ska visas på anropsplatser utanför ett paket när en konstant stacklevel inte passar alla anropsvägar eller på annat sätt är svår att underhålla. Om det anges måste det vara en tupel av strängar. När prefix anges åsidosätts stacklevel implicit till att vara max(2, stacklevel). För att få en varning att tillskrivas den som anropar från utanför det aktuella paketet kan du skriva:

# example/lower.py
_warn_skips = (os.path.dirname(__file__),)

def one_way(r_luxury_yacht=None, t_wobbler_mangrove=None):
    if r_luxury_yacht:
        warnings.warn("Please migrate to t_wobbler_mangrove=.",
                      skip_file_prefixes=_warn_skips)

# example/higher.py
from . import lower

def another_way(**kw):
    lower.one_way(**kw)

Detta gör att varningen hänvisar till både anropsställena example.lower.one_way() och package.higher.another_way() endast vid anrop av kod som ligger utanför example-paketet.

source, om det anges, är det förstörda objekt som gav upphov till en ResourceWarning.

Ändrad i version 3.6: Parametern source har lagts till.

Ändrad i version 3.12: Lagt till skip_file_prefixes.

warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)

Detta är ett lågnivågränssnitt till funktionaliteten i warn(), som explicit skickar in meddelandet, kategorin, filnamnet och radnumret, samt eventuellt modulnamnet och registret (som bör vara modulens __warningregistry__-ordbok). Modulnamnet är som standard filnamnet med .py borttaget; om inget register skickas med undertrycks aldrig varningen. message måste vara en sträng och category en underklass till Warning eller så kan message vara en instans av Warning, i vilket fall category ignoreras.

module_globals, om det anges, bör vara det globala namnrymden som används av koden för vilken varningen utfärdas. (Detta argument används för att visa källan för moduler som finns i zip-filer eller andra importkällor som inte är filsystem).

source, om det anges, är det förstörda objekt som gav upphov till en ResourceWarning.

Ändrad i version 3.6: Lägg till parametern source.

warnings.showwarning(message, category, filename, lineno, file=None, line=None)

Skriva en varning till en fil. Standardimplementeringen anropar formatwarning(message, category, filename, lineno, line) och skriver den resulterande strängen till file, som är standard för sys.stderr. Du kan ersätta denna funktion med en valfri anropsbar funktion genom att tilldela den till warnings.showwarning. line är en rad källkod som ska ingå i varningsmeddelandet; om line inte anges kommer showwarning() att försöka läsa den rad som anges av filename och lineno.

warnings.formatwarning(message, category, filename, lineno, line=None)

Formatera en varning på vanligt sätt. Detta returnerar en sträng som kan innehålla inbäddade nya rader och som slutar med en ny rad. line är en rad med källkod som ska ingå i varningsmeddelandet; om line inte anges kommer formatwarning() att försöka läsa den rad som anges av filename och lineno.

warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False)

Infoga en post i listan över warnings filter specifications. Som standard infogas posten längst fram; om append är true infogas den i slutet. Detta kontrollerar argumentens typer, sammanställer de reguljära uttrycken message och module och infogar dem som en tupel i listan över varningsfilter. Poster längre fram i listan åsidosätter poster längre fram i listan, om båda matchar en viss varning. Utelämnade argument får som standard ett värde som matchar allt.

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

Infoga en enkel post i listan över warnings filter specifications. Betydelsen av funktionsparametrarna är densamma som för filterwarnings(), men reguljära uttryck behövs inte eftersom det infogade filtret alltid matchar alla meddelanden i alla moduler så länge som kategorin och radnumret matchar.

warnings.resetwarnings()

Återställer filtret för varningar. Detta tar bort effekten av alla tidigare anrop till filterwarnings(), inklusive effekten av kommandoradsalternativen -W och anrop till simplefilter().

@warnings.deprecated(msg, *, category=DeprecationWarning, stacklevel=1)

Dekorator för att ange att en klass, funktion eller överbelastning är avskriven.

När denna dekorator används på ett objekt kan varningar om att objektet är föråldrat utfärdas vid körning när objektet används. static type checkers kommer också att generera en diagnos vid användning av det föråldrade objektet.

Användning:

from warnings import deprecated
from typing import overload

@deprecated("Use B instead")
class A:
    pass

@deprecated("Use g instead")
def f():
    pass

@overload
@deprecated("int support is deprecated")
def g(x: int) -> int: ...
@overload
def g(x: str) -> int: ...

Den varning som specificeras av category kommer att utfärdas vid körning vid användning av föråldrade objekt. För funktioner sker detta vid anrop, för klasser vid instansiering och skapande av underklasser. Om category är None avges ingen varning vid körning. stacklevel avgör var varningen utfärdas. Om den är 1 (standard) skickas varningen till den som direkt anropar det föråldrade objektet; om den är högre skickas den längre upp i stacken. Den statiska typkontrollens beteende påverkas inte av argumenten category och stacklevel.

Deprecation-meddelandet som skickas till dekoratorn sparas i attributet __deprecated__ på det dekorerade objektet. Om det tillämpas på en överbelastning måste dekoratorn vara efter dekoratorn @overload för att attributet ska finnas på överbelastningen som returneras av typing.get_overloads().

Tillagd i version 3.13: Se PEP 702.

Tillgängliga kontexthanterare

class warnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False)

En kontexthanterare som kopierar och, vid avslut, återställer varningsfiltret och funktionen showwarning(). Om argumentet record är False (standard) returnerar kontexthanteraren None vid inmatning. Om record är True returneras en lista som successivt fylls på med objekt som ses av en anpassad showwarning()-funktion (som också undertrycker utdata till sys.stdout). Varje objekt i listan har attribut med samma namn som argumenten till showwarning().

Argumentet module tar en modul som kommer att användas istället för den modul som returneras när du importerar warnings vars filter kommer att skyddas. Detta argument finns främst för att testa själva modulen warnings.

Om argumentet action inte är None, skickas de återstående argumenten till simplefilter() som om det hade anropats direkt när det kom in i kontexten.

Se Filtret för varningar för betydelsen av parametrarna category och lineno.

Anteckning

Se Samtidig säkerhet för kontexthanterare för detaljer om samtidighetssäkerheten för kontexthanteraren catch_warnings när den används i program som använder flera trådar eller asynkrona funktioner.

Ändrad i version 3.11: Lagt till parametrarna action, category, lineno och append.

Samtidig säkerhet för kontexthanterare

Beteendet hos kontexthanteraren catch_warnings beror på flaggan sys.flags.context_aware_warnings. Om flaggan är true beter sig kontexthanteraren på ett concurrent-safe sätt och annars inte. Concurrent-safe innebär att den är både trådsäker och säker att använda inom asyncio coroutines och uppgifter. Att vara trådsäker innebär att beteendet är förutsägbart i ett flertrådat program. Flaggan är som standard true för fritt trådade program och false i annat fall.

Om flaggan context_aware_warnings är false kommer catch_warnings att ändra de globala attributen för modulen warnings. Detta är inte säkert om det används i ett samtidigt program (med flera trådar eller asyncio coroutines). Om t.ex. två eller flera trådar använder klassen catch_warnings samtidigt är beteendet odefinierat.

Om flaggan är true kommer catch_warnings inte att ändra globala attribut och kommer istället att använda en ContextVar för att lagra det nyligen etablerade filtreringstillståndet för varningar. En kontextvariabel ger trådlokal lagring och det gör användningen av catch_warnings trådsäker.

Parametern record i kontexthanteraren beter sig också på olika sätt beroende på flaggans värde. När record är true och flaggan är false, fungerar kontexthanteraren genom att ersätta och senare återställa modulens showwarning()-funktion. Det är inte simultansäkert.

När record är true och flaggan är true, ersätts inte funktionen showwarning(). Istället indikeras inspelningsstatusen av en intern egenskap i kontextvariabeln. I detta fall kommer funktionen showwarning() inte att återställas när kontexthanteraren avslutas.

Flaggan context_aware_warnings kan ställas in med kommandoradsalternativet -X context_aware_warnings eller med miljövariabeln PYTHON_CONTEXT_AWARE_WARNINGS.

Anteckning

Det är troligt att de flesta program som vill ha ett trådsäkert beteende i varningsmodulen också vill sätta flaggan thread_inherit_context till true. Denna flagga gör att trådar som skapas av threading.Thread börjar med en kopia av kontextvariablerna från den tråd som startar den. När den är true kommer kontexten som etablerats av catch_warnings i en tråd även att gälla för nya trådar som startas av den. Om false, kommer nya trådar att starta med en tom warnings-kontextvariabel, vilket innebär att all filtrering som upprättades av en catch_warnings-kontexthanterare inte längre kommer att vara aktiv.

Ändrad i version 3.14: Lade till sys.flags.context_aware_warnings-flaggan och användningen av en kontextvariabel för catch_warnings om flaggan är true. Tidigare versioner av Python agerade som om flaggan alltid var satt till false.