Как гарантированно подавить предупреждение об устаревании в Python? - PullRequest
0 голосов
/ 26 января 2019

Я полагаю, что этот вопрос уже поднимался много раз, но у меня есть конкретный случай использования, когда я не могу решить проблему с помощью многих методов, описанных в Интернете.

В одном из моих проектов,Я использую библиотеку joblib, и она показывает DeprecationWarning, потому что она использует библиотеку imp где-то внутри:

from sklearn.externals.joblib import Parallel, delayed

def main():
    xs = Parallel()(delayed(lambda x: x**2)(i) for i in range(1, 6))
    print(sum(xs))

if __name__ == '__main__':
    main()

Я пытаюсь отфильтровать предупреждение с помощью опции интерпретатора -W, но это не такt help:

$ python -W ignore example.py                                                                                                                   
[...]/lib/python3.7/site-packages/sklearn/externals/joblib/externals/cloudpickle/cloudpickle.py:47:
DeprecationWarning: the imp module is deprecated in favour of importlib; 
see the module's documentation for alternative uses import imp
55

Кроме того, я пробовал явную фильтрацию с использованием модуля warnings, но это также не помогает:

import warnings
warnings.simplefilter('ignore', category=DeprecationWarning)
from sklearn.externals.joblib import Parallel, delayed

def main():
    xs = Parallel()(delayed(lambda x: x**2)(i) for i in range(1, 6))
    print(sum(xs))

if __name__ == '__main__':
    main()

У меня были похожие проблемы с модулем matplotlibи некоторые другие сторонние библиотеки.Возможно, есть и другие способы (например, env vars), но я не понимаю, почему эти решения не работают.

Может кто-нибудь объяснить, как система предупреждений на самом деле работает в Python?Возможно, что сторонние библиотеки намеренно отменяют настройки предупреждений клиента?Я бы сказал, что этот вопрос - одна из самых темных для меня.

Ответы [ 2 ]

0 голосов
/ 06 июня 2019

По запросу вот ответ отдельным постом:

Хитрость заключается в использовании предупреждений «with» при импорте sklearn (или зависимости, которая использует sklearn, в моем случае это был пакет hdbscan):

with warnings.catch_warnings():
    # filter sklearn\externals\joblib\parallel.py:268:
    # DeprecationWarning: check_pickle is deprecated
    warnings.simplefilter("ignore", category=DeprecationWarning)
    import hdbscan

Это отключит DeprecationWarning только для этого модуля (поскольку модификация warnings присоединена к блоку with).

Важно поместить этот оператор на первую позицию в вашем коде, куда импортируется модуль, иначе он не будет работать. Например. если бы я загружал hdbscan в __init__.py, и вышеуказанный блок кода появляется в некотором подклассе, который также загружает hdbscan, я все равно получил бы DeprecationWarning, потому что Python игнорирует любой последующий оператор import, если модуль / пакет уже загружен.

Поэтому важно проверить, какие модули / пакеты используют joblib\parallel.py и где они, с точки зрения линейного кода, загружаются раньше всего в кучу объектов python.

[EDIT]

Как отмечает @devforfu в комментариях, вышеупомянутое решение не работает (больше). Я снова посмотрел на это и с Python 3.7 DeprecationWarning is once again shown by default when triggered directly by code in __main__.. Кроме того, ignore предупреждения не работают, когда Dependency явно загружает устаревший модуль какого-либо другого пакета.

Это то, что происходит в моем примере hdbscan, который загружает устаревшие модули sklearn.external.six и sklearn.externals.joblib.

Вот как, наконец, решить эту надоедливую проблему:

  • убедитесь, что вы явно установили автономные пакеты, которые устарели, например, conda install -c conda-forge joblib six
  • создать поддельный импорт, который переопределит импорт зависимостей, например ::
try:
    sys.modules['sklearn.externals.six'] = __import__('six')
    sys.modules['sklearn.externals.joblib'] = __import__('joblib')
    import hdbscan
except ImportError:
    import hdbscan

Если нет ошибки импорта, будет использоваться автономная шестерка и joblib. В противном случае, например если пользователь не установил шесть или joblib, программа все равно будет работать (поскольку она загружает оба модуля из sklearn.externals), но при этом отобразится предупреждение об амортизации.

0 голосов
/ 06 июня 2019

Достаточно интересно, что даже следуя совету Алекса, у меня все еще есть вывод предупреждений, например:

import warnings
with warnings.catch_warnings():
    warnings.simplefilter('ignore', category=DeprecationWarning)
    from sklearn.externals.joblib import Parallel, delayed

def main():
    xs = Parallel()(delayed(lambda x: x**2)(i) for i in range(1, 6))
    print(sum(xs))

if __name__ == '__main__':
    main()

# $ python -W ignore example.py
# [...]
# DeprecationWarning: the imp module is deprecated in favour of importlib; 
# see the module's documentation for alternative uses
#  import imp
# 55

Так что в конце концов я решил сделать это очень хакерским способом и отключить все предупреждения, потому что яЯ устал искать правильный способ борьбы с ними.(Не только для этой библиотеки, но и для многих других, которые, похоже, очень хотят бомбардировать вас не подавляемыми предупреждениями).

import warnings
def noop(*args, **kargs): pass
warnings.warn = noop
from sklearn.externals.joblib import Parallel, delayed

def main():
    xs = Parallel()(delayed(lambda x: x**2)(i) for i in range(1, 6))
    print(sum(xs))

if __name__ == '__main__':
    main()

Если я неправильно использую совет @ Алекса, или у некоторых из вас лучшеРешение, я был бы рад принять его в качестве ответа.


Обновление:

Хорошо, кажется, что довольно сложно повлиять на предупреждения,поднял где-то внутри в пакете.Поэтому, вероятно, самой простой вещью было бы просто заменить warnings.warn на noop или, может быть, каким-то образом заранее импортировать внутренние зависимости и подавить их с помощью диспетчера контекста.

...