warnings
— Warning control¶
Вихідний код: Lib/warnings.py
Попереджувальні повідомлення зазвичай видаються в ситуаціях, коли корисно попередити користувача про певну умову в програмі, де ця умова (зазвичай) не вимагає виклику винятку та завершення програми. Наприклад, можна видавати попередження, коли програма використовує застарілий модуль.
Програмісти Python видають попередження, викликаючи функцію warn()
, визначену в цьому модулі. (Програмісти на C використовують PyErr_WarnEx()
; подробиці див. Обробка винятків).
Попереджувальні повідомлення зазвичай записуються в sys.stderr
, але їх розташування можна гнучко змінити, від ігнорування всіх попереджень до перетворення їх на винятки. Розташування попереджень може змінюватися залежно від категорії попередження, тексту попереджувального повідомлення та джерела, де воно надійшло. Повторення певного попередження для того самого місця джерела зазвичай пригнічується.
У управлінні попередженням є два етапи: по-перше, кожного разу, коли видається попередження, визначається, чи слід видати повідомлення чи ні; потім, якщо повідомлення має бути видано, воно форматується та друкується за допомогою налаштування користувача.
Визначення того, чи потрібно видавати попередження, контролюється фільтром попереджень, який є послідовністю відповідних правил і дій. Правила можна додати до фільтра, викликавши filterwarnings()
, і повернути його до стандартного стану, викликавши resetwarnings()
.
Друк попереджувальних повідомлень виконується шляхом виклику showwarning()
, який можна замінити; реалізація цієї функції за замовчуванням форматує повідомлення шляхом виклику formatwarning()
, який також доступний для використання користувальницькими реалізаціями.
Дивись також
logging.captureWarnings()
дозволяє обробляти всі попередження за допомогою стандартної інфраструктури журналювання.
Категорії попереджень¶
Є ряд вбудованих винятків, які представляють категорії попереджень. Ця категоризація корисна, щоб мати можливість відфільтрувати групи попереджень.
Хоча технічно це вбудовані винятки, вони задокументовані тут, оскільки концептуально вони належать до механізму попереджень.
Код користувача може визначати додаткові категорії попереджень шляхом створення підкласу однієї зі стандартних категорій попереджень. Категорія попередження завжди має бути підкласом класу Warning
.
Наразі визначено такі класи категорій попереджень:
Клас |
опис |
---|---|
Це базовий клас усіх класів категорій попереджень. Це підклас |
|
Типова категорія для |
|
Базова категорія для попереджень про застарілі функції, якщо ці попередження призначені для інших розробників Python (ігноруються за замовчуванням, якщо не викликано кодом у |
|
Базова категорія для попереджень про сумнівні синтаксичні особливості. |
|
Базова категорія для попереджень про сумнівні функції середовища виконання. |
|
Базова категорія для попереджень про застарілі функції, якщо ці попередження призначені для кінцевих користувачів програм, написаних на Python. |
|
Базова категорія для попереджень про функції, які в майбутньому будуть припинені (ігноруються за умовчанням). |
|
Основна категорія для попереджень, що викликаються під час процесу імпорту модуля (ігнорується за умовчанням). |
|
|
Базова категорія для попереджень, пов’язаних із Unicode. |
Базова категорія для попереджень, пов’язаних із |
|
Базова категорія для попереджень, пов’язаних із використанням ресурсів (ігнорується за умовчанням). |
Змінено в версії 3.7: Раніше DeprecationWarning
і FutureWarning
розрізняли залежно від того, видаляється функція повністю чи змінюється її поведінка. Тепер вони розрізняються на основі цільової аудиторії та способу їх обробки за допомогою фільтрів попереджень за замовчуванням.
Фільтр попереджень¶
Фільтр попереджень контролює, чи попередження ігноруються, відображаються чи перетворюються на помилки (створення винятку).
Концептуально, фільтр попереджень підтримує впорядкований список специфікацій фільтра; будь-яке конкретне попередження порівнюється з кожною специфікацією фільтра в списку по черзі, доки не буде знайдено збіг; фільтр визначає розташування відповідності. Кожен запис є кортежем у формі (дія, повідомлення, категорія, модуль, lineno), де:
action є одним із таких рядків:
Значення
Розпорядження
"за умовчанням"
надрукувати перше повторення відповідних попереджень для кожного місця (модуль + номер рядка), де видається попередження
"помилка"
перетворити відповідні попередження на винятки
"ігнорувати"
ніколи не друкувати відповідні попередження
"завжди"
завжди друкувати відповідні попередження
"модуль"
надрукувати перше повторення відповідних попереджень для кожного модуля, де видається попередження (незалежно від номера рядка)
"один раз"
друкувати лише перше повторення відповідних попереджень, незалежно від розташування
message is a string containing a regular expression that the start of the warning message must match. The expression is compiled to always be case-insensitive.
category — це клас (підклас
Warning
), підкласом якого має бути категорія попередження, щоб відповідати.module is a string containing a regular expression that the module name must match. The expression is compiled to be case-sensitive.
lineno — це ціле число, якому має відповідати номер рядка, у якому виникло попередження, або
0
, щоб відповідати всім номерам рядків.
Оскільки клас Warning
походить від вбудованого класу Exception
, щоб перетворити попередження на помилку, ми просто піднімаємо category(message)
.
Якщо повідомляється про попередження, яке не відповідає жодному зареєстрованому фільтру, тоді застосовується дія «за замовчуванням» (звідси й назва).
Опис фільтрів попереджень¶
Фільтр попереджень ініціалізується параметрами -W
, які передаються в командний рядок інтерпретатора Python, і змінною середовища PYTHONWARNINGS
. Інтерпретатор зберігає аргументи для всіх наданих записів без інтерпретації в sys.warnoptions
; модуль warnings
аналізує їх під час першого імпорту (недійсні параметри ігноруються після друку повідомлення до sys.stderr
).
Окремі фільтри попереджень задаються як послідовність полів, розділених двокрапками:
action:message:category:module:line
Значення кожного з цих полів описано в Фільтр попереджень. Під час переліку кількох фільтрів в одному рядку (як для PYTHONWARNINGS
), окремі фільтри відокремлюються комами, а фільтри, перелічені пізніше, мають перевагу над тими, що перераховані перед ними (оскільки вони застосовуються зліва направо, і нещодавно застосовані фільтри мають пріоритет над попередніми).
Зазвичай використовувані фільтри попереджень застосовуються до всіх попереджень, попереджень у певній категорії або попереджень, викликаних окремими модулями чи пакетами. Деякі приклади:
default # Show all warnings (even those ignored by default)
ignore # Ignore all warnings
error # Convert all warnings to errors
error::ResourceWarning # Treat ResourceWarning messages as errors
default::DeprecationWarning # Show DeprecationWarning messages
ignore,default:::mymodule # Only report warnings triggered by "mymodule"
error:::mymodule[.*] # Convert warnings to errors in "mymodule"
# and any subpackages of "mymodule"
Фільтр попереджень за умовчанням¶
За замовчуванням Python встановлює кілька фільтрів попереджень, які можна замінити параметром командного рядка -W
, змінною середовища PYTHONWARNINGS
і викликами filterwarnings()
.
У регулярних збірках випусків стандартний фільтр попереджень містить такі записи (у порядку пріоритету):
default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning
In debug builds, the list of default warning filters is empty.
Змінено в версії 3.2: DeprecationWarning
тепер ігнорується за умовчанням на додаток до PendingDeprecationWarning
.
Змінено в версії 3.7: DeprecationWarning
знову відображається за замовчуванням, якщо його запускає безпосередньо код у __main__
.
Змінено в версії 3.7: BytesWarning
більше не відображається у списку фільтрів за замовчуванням і натомість налаштовується за допомогою sys.warnoptions
, коли -b
вказано двічі.
Заміна фільтра за замовчуванням¶
Розробники програм, написаних на Python, можуть за замовчуванням приховати всі попередження рівня Python від своїх користувачів і відображати їх лише під час виконання тестів або іншої роботи над програмою. Атрибут sys.warnoptions
, який використовується для передачі конфігурацій фільтра інтерпретатору, можна використовувати як маркер, щоб вказати, чи потрібно вимкнути попередження:
import sys
if not sys.warnoptions:
import warnings
warnings.simplefilter("ignore")
Розробникам програм для виконання тестів для коду Python рекомендується натомість переконатися, що всі попередження відображаються за замовчуванням для коду, що тестується, використовуючи такий код:
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
Нарешті, розробникам інтерактивних оболонок, які запускають код користувача в просторі імен, відмінному від __main__
, рекомендується переконатися, що повідомлення DeprecationWarning
відображаються за замовчуванням, використовуючи такий код (де user_ns
це модуль, який використовується для виконання коду, введеного інтерактивно):
import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
module=user_ns.get("__name__"))
Тимчасове припинення попереджень¶
Якщо ви використовуєте код, який, як ви знаєте, викличе попередження, наприклад застарілу функцію, але не хочете бачити попередження (навіть якщо попередження було явно налаштовано за допомогою командного рядка), тоді можна придушити попередження за допомогою контекстний менеджер catch_warnings
:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
У контекстному менеджері всі попередження просто ігноруватимуться. Це дозволяє використовувати завідомо застарілий код, не переглядаючи попередження, але не приховуючи попередження для іншого коду, який може не знати про використання застарілого коду. Примітка: це можна гарантувати лише в однопотоковій програмі. Якщо два або більше потоків використовують контекстний менеджер catch_warnings
одночасно, поведінка не визначена.
Попередження щодо тестування¶
Щоб перевірити попередження, викликані кодом, використовуйте контекстний менеджер catch_warnings
. За допомогою нього ви можете тимчасово змінити фільтр попереджень, щоб полегшити ваше тестування. Наприклад, виконайте такі дії, щоб зафіксувати всі викликані попередження для перевірки:
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)
Можна також зробити всі попередження винятками, використовуючи error
замість always
. Слід пам’ятати, що якщо попередження вже виникло через правило once
/default
, то незалежно від того, які фільтри встановлено, попередження більше не відображатиметься, якщо тільки попередження не пов’язані з реєстром попереджень. до попередження було видалено.
Після виходу з диспетчера контексту фільтр попереджень відновлюється до свого стану, коли було введено контекст. Це запобігає неочікуваним змінам фільтра попереджень між тестами, що призводить до невизначених результатів тестування. Функція showwarning()
у модулі також відновлюється до початкового значення. Примітка: це можна гарантувати лише в однопотоковій програмі. Якщо два або більше потоків використовують контекстний менеджер catch_warnings
одночасно, поведінка не визначена.
Під час тестування кількох операцій, які викликають попередження того самого типу, важливо перевірити їх таким чином, щоб підтверджувати, що кожна операція викликає нове попередження (наприклад, установіть попередження, що викликаються як винятки, і перевірте, чи операції викликають винятки, перевірте, чи довжина списку попереджень продовжує збільшуватися після кожної операції, або видаляйте попередні записи зі списку попереджень перед кожною новою операцією).
Оновлення коду для нових версій залежностей¶
Категорії попереджень, які в першу чергу цікавлять розробників Python (а не кінцевих користувачів програм, написаних на Python), ігноруються за умовчанням.
Примітно, що цей список «ігнорується за замовчуванням» включає DeprecationWarning
(для кожного модуля, крім __main__
), що означає, що розробники повинні обов’язково перевірити свій код із попередженнями, які зазвичай ігноруються, щоб отримати своєчасні сповіщення. майбутніх критичних змін API (у стандартній бібліотеці чи сторонніх пакетах).
В ідеальному випадку код матиме відповідний набір тестів, а програма виконання тестів подбає про неявне ввімкнення всіх попереджень під час виконання тестів (це виконує програма виконання тестів, надана модулем unittest
).
У менш ідеальних випадках програми можна перевірити на використання застарілих інтерфейсів, передавши -Wd
інтерпретатору Python (це скорочення -W default
) або встановивши PYTHONWARNINGS=default
в навколишньому середовищі. Це вмикає обробку за замовчуванням для всіх попереджень, включаючи ті, які ігноруються за замовчуванням. Щоб змінити дії, які виконуються для виявлених попереджень, ви можете змінити аргумент, який передається до -W
(наприклад, -W error
). Перегляньте прапорець -W
, щоб дізнатися більше про те, що можливо.
Доступні функції¶
-
warnings.
warn
(message, category=None, stacklevel=1, source=None)¶ Видайте попередження, або, можливо, проігноруйте його чи створіть виняток. Аргумент category, якщо він заданий, має бути класом категорії попередження; за замовчуванням
UserWarning
. Крім того, message може бути екземпляромWarning
, у цьому випадку category буде проігноровано та використовуватиметьсяmessage.__class__
. У цьому випадку текст повідомлення будеstr(message)
. Ця функція викликає виняток, якщо фільтр попереджень змінює конкретне видане попередження на помилку. Аргумент stacklevel може використовуватися функціями-обгортками, написаними на Python, наприклад:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2)
This makes the warning refer to
deprecation()
“s caller, rather than to the source ofdeprecation()
itself (since the latter would defeat the purpose of the warning message).джерело, якщо вказано, це знищений об’єкт, який випустив
ResourceWarning
.Змінено в версії 3.6: Додано параметр джерело.
-
warnings.
warn_explicit
(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)¶ Це низькорівневий інтерфейс для функціональності
warn()
, який явно передає повідомлення, категорію, ім’я файлу та номер рядка, а також, за бажанням, назву модуля та реєстр (який має бути словником__warningregistry__
модуля). Ім’я модуля за замовчуванням – це ім’я файлу з видаленим.py
; якщо реєстр не передано, попередження ніколи не пригнічується. message має бути рядком, а category — підкласомWarning
або message може бути екземпляромWarning
, у цьому випадку category ігноруватиметься.module_globals, якщо вказано, має бути глобальним простором імен, який використовується кодом, для якого видається попередження. (Цей аргумент використовується для підтримки відображення вихідного коду для модулів, знайдених у zip-файлах або інших джерелах імпорту, які не належать до файлової системи).
джерело, якщо вказано, це знищений об’єкт, який випустив
ResourceWarning
.Змінено в версії 3.6: Додайте параметр source.
-
warnings.
showwarning
(message, category, filename, lineno, file=None, line=None)¶ Записати попередження у файл. Стандартна реалізація викликає
formatwarning(message, category, filename, lineno, line)
і записує результуючий рядок у file, який за замовчуванням має значенняsys.stderr
. Ви можете замінити цю функцію будь-якою викликаною, призначившиwarning.showwarning
. рядок — це рядок вихідного коду, який буде включено в повідомлення попередження; якщо рядок не надано,showwarning()
спробує прочитати рядок, визначений filename і lineno.
-
warnings.
formatwarning
(message, category, filename, lineno, line=None)¶ Відформатуйте попередження стандартним способом. Це повертає рядок, який може містити вбудовані символи нового рядка та закінчується символом нового рядка. рядок — це рядок вихідного коду, який буде включено в повідомлення попередження; якщо рядок не вказано,
formatwarning()
спробує прочитати рядок, визначений filename і lineno.
-
warnings.
filterwarnings
(action, message='', category=Warning, module='', lineno=0, append=False)¶ Вставте запис у список специфікацій фільтра попереджень. Запис вставляється спереду за замовчуванням; якщо append має значення true, воно вставляється в кінці. Це перевіряє типи аргументів, компілює регулярні вирази message і module і вставляє їх як кортеж у список фільтрів попереджень. Записи, розташовані ближче до початку списку, замінюють записи, розташовані далі в списку, якщо обидва відповідають певному попередженню. Пропущені аргументи за умовчанням мають значення, яке відповідає всім.
-
warnings.
simplefilter
(action, category=Warning, lineno=0, append=False)¶ Вставте простий запис у список специфікацій фільтра попереджень. Значення параметрів функції таке ж, як і для
filterwarnings()
, але регулярні вирази не потрібні, оскільки вставлений фільтр завжди відповідає будь-якому повідомленню в будь-якому модулі, якщо збігаються категорія та номер рядка.
-
warnings.
resetwarnings
()¶ Скинути фільтр попереджень. Це скасовує дію всіх попередніх викликів
filterwarnings()
, включаючи параметри командного рядка-W
і викликиsimplefilter()
.
Доступні менеджери контексту¶
-
class
warnings.
catch_warnings
(*, record=False, module=None)¶ Контекстний менеджер, який копіює та після виходу відновлює фільтр попереджень і функцію
showwarning()
. Якщо аргумент record має значенняFalse
(за замовчуванням), менеджер контексту повертаєNone
під час входу. Якщо record дорівнюєTrue
, повертається список, який поступово заповнюється об’єктами, як це бачить спеціальна функціяshowwarning()
(яка також пригнічує виведення вsys.stdout
). Кожен об’єкт у списку має атрибути з тими самими іменами, що й аргументиshowwarning()
.Аргумент module приймає модуль, який використовуватиметься замість модуля, який повертається під час імпорту
warnings
, фільтр якого буде захищено. Цей аргумент існує насамперед для тестування самого модуляwarnings
.Примітка
Менеджер
catch_warnings
працює, замінюючи, а потім пізніше відновлюючи функціюshowwarning()
модуля та внутрішній список специфікацій фільтрів. Це означає, що менеджер контексту змінює глобальний стан і тому не є потоково-безпечним.