Numpy: Иногда supress_warnings пропускает один из своих атрибутов

Созданный на 23 дек. 2016  ·  60Комментарии  ·  Источник: numpy/numpy

При попытке скомпилировать скимейдж я иногда получаю следующую ошибку:

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/transform/tests/test_integral.py", line 46, in test_vectorized_integrate
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/transform/integral.py", line 86, in integrate
    warn("The syntax 'integrate(ii, r0, c0, r1, c1)' is "
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/_shared/_warnings.py", line 16, in warn
    warnings.warn(message, stacklevel=stacklevel)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 2199, in _showwarning
    self._orig_show(message, category, filename, lineno,
AttributeError: 'suppress_warnings' object has no attribute '_orig_show'

Я предполагаю, что это серьезная проблема, но я не уверен.

00 - Bug numpy.testing

Все 60 Комментарий

Хммм, немного странно. Происходит ли какая-то (странная) многопоточность в тестах скимейджа? Это может серьезно нарушить тестирование предупреждений, поскольку обработка предупреждений в Python не является потокобезопасной. Мне немного сложно понять, как еще это могло произойти, но, возможно, мне стоит посмотреть на точный код, который запускает тест.

Поскольку здесь нет assert_warns или около того, я думаю. У вас должен быть только один активный контекст suppress_warnings (который будет самой внешней областью и создан средством запуска тестов numpy, если в конечном итоге его использует skimage). Теперь я смущен тем, что _orig_show не определяется, должно быть возможно только в том случае, если контекст уже был завершен. К этому моменту warnings.showwarning уже должно быть сброшено на старое значение.

Конечно, вся система предупреждений не работает, если у вас есть потоки. Например:

thread1: входит в контекст предупреждения -> заменяет обычную печать предупреждений
thread2: входит в контекст предупреждения -> заменяет обработчик предупреждений thread1
thread1: выходит из контекста предупреждения -> возвращается к нормальной печати предупреждений
thread2: существует контекст предупреждения -> сбрасывается до обработчика предупреждений thread1 -> kaboom.

Кстати. Я вижу, что у вас есть «попытаться очистить после того, как __warning_registry__ вещи в скимэге, подавление предупреждений - это диспетчер контекста, который пытается решить аналогичную проблему (и добавляет некоторые другие вещи), может быть или не быть интересным.

У меня возникла проблема, когда я попытался собрать скимейдж для Debian, и я понятия не имею об этом. Однако я открыл scikit-image / scikit-image # 2412, чтобы привлечь их внимание.

Просто для полноты: иногда я даже получаю трассировку стека без какого-либо участия скимейджа:

ERROR: test suite for <module 'skimage.transform.tests' from '/build/skimage-0.12.3/debian/tmp/usr/lib/python3/dist-packages/skimage/transform/tests/__init__.py'>
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 229, in run
    self.tearDown()
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 352, in tearDown
    self.teardownContext(ancestor)
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 368, in teardownContext
    try_run(context, names)
  File "/usr/lib/python3/dist-packages/nose/util.py", line 453, in try_run
    inspect.getargspec(func)
  File "/usr/lib/python3.5/inspect.py", line 1040, in getargspec
    stacklevel=2)
  File "/usr/lib/python3/dist-packages/numpy/testing/utils.py", line 2199, in _showwarning
    self._orig_show(message, category, filename, lineno,
AttributeError: 'suppress_warnings' object has no attribute '_orig_show'

Какие версии python, numpy и т. Д. Вы компилируете?

Numpy 1.12 ~ RC ~ beta 1, Python 2.7 и 3.5
(извините, моя ошибка: еще не проверял RC)

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

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

@olebole, как именно вы запускаете тестовый костюм?

Скопировано из нашего набора тестов :

#!/bin/sh
set -efu

pys="$(pyversions -rv 2>/dev/null)"
pkgbuild=${pkgbuild:-no}

srcdir=$PWD

for py in $pys; do
    echo "=== python$py ==="
    if [ "$pkgbuild" = "yes" ]; then
        export PYTHONPATH="$srcdir/debian/tmp/usr/lib/python$py/dist-packages"
        cd "$srcdir/build/"
    else
        cd "$ADTTMP"
    fi

    xvfb-run -a python$py /usr/bin/nosetests -s -v --exclude test_tools.py skimage 2>&1
done

xvfb-run присутствует, поскольку тест необходимо запускать в среде X11.

Хмммф, кто-нибудь знает, что именно происходит под капотом, когда нос начинает тестировать модуль? Нос сбивает меня с толку, и я не понимаю, почему он в конечном итоге тоже возится с предупреждениями ... Или это все-таки ошибка в подавлении предупреждений, но я не вижу этого, хех.

На моей странице руководства по тестам у меня есть

       --processes=NUM
              Spread  test run among this many processes. Set a number equal to the number of processors or cores in your machine for best results. Pass a negative
              number to have the number of processes automatically set to the number of cores. Passing 0 means to disable parallel testing.  Default  is  0  unless
              NOSE_PROCESSES is set. [NOSE_PROCESSES]

Похоже, что по умолчанию параллельного тестирования нет. По крайней мере, не должно быть состояния гонки.

Есть ли хоть какой-то шанс, что этот teardownContext пробегает по носу из-за мусора ?!

Нет, наверное, я дурак. Контекст предупреждения о подавлении сбрасывает warnings.showwarning перед удалением атрибута, поэтому сомневаюсь, что даже включенный gc не может создать ничего без того, чтобы что-то еще не произошло. Просто понятия не имел, что еще :).

Что ж, я вижу 33 ошибки с skimage-0.9.3, большинство из которых связаны с PIL или индексированием, но ни одной для подавления. Как вы справляетесь со всеми другими ошибками?

@charris Проблема обнаружена в версии 0.12.3, а не в версии 0.9.3. :)

Хорошо, наконец-то получил это от апстрима, теперь 39 ошибок и тонна устаревших. Большинство предупреждений связано с тем, что тесты думают, что они работают в QT, а не в Wayland, что может быть проблемой конфигурации здесь. Мне также нужно запустить тесты как

python -c'import skimage; skimage.test()'

поскольку nosetests вообще не работает.

Износ нормальный. Мы по-прежнему проверяем наш старый API, даже если ожидается его прекращение. Насчет ошибок, это ненормально. Не могли бы вы сообщить о них в нашем (scikit-image) трекере ошибок?

@sciunto В документации могут использоваться инструкции для локального тестирования.

Хорошо, я вижу это там же. Тест

def test_vectorized_integrate():
    r0 = np.array([12, 0, 0, 10, 0, 10, 30])
    c0 = np.array([10, 0, 10, 0, 0, 10, 31])
    r1 = np.array([23, 19, 19, 19, 0, 10, 49])
    c1 = np.array([19, 19, 19, 19, 0, 10, 49])

    expected = np.array([x[12:24, 10:20].sum(),
                         x[:20, :20].sum(),
                         x[:20, 10:20].sum(),
                         x[10:20, :20].sum(),
                         x[0,0],
                         x[10, 10],
                         x[30:, 31:].sum()])
    start_pts = [(r0[i], c0[i]) for i in range(len(r0))]
    end_pts = [(r1[i], c1[i]) for i in range(len(r0))]
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
    assert_equal(expected, integrate(s, start_pts, end_pts))

Комментарий # test deprecated подсказывает мне, что, возможно, тест требует некоторого исправления, но все же suppress_warnings должен завершиться более изящно.

Немного больше информации, делаю

$ python skimage/transform/tests/test_integral.py

Что использует NumPy run_module_suite , похоже, не работает, но выдает предупреждение

======================================================================
ERROR: skimage.transform.tests.test_integral.test_vectorized_integrate
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/charris/Workspace/scikit-image/skimage/transform/tests/test_integral.py", line 46, in test_vectorized_integrate
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
  File "/home/charris/Workspace/scikit-image/skimage/transform/integral.py", line 86, in integrate
    warn("The syntax 'integrate(ii, r0, c0, r1, c1)' is "
  File "/home/charris/Workspace/scikit-image/skimage/_shared/_warnings.py", line 16, in warn
    warnings.warn(message, stacklevel=stacklevel)
UserWarning: The syntax 'integrate(ii, r0, c0, r1, c1)' is deprecated, and will be phased out in release 0.14. The new syntax is 'integrate(ii, (r0, c0), (r1, c1))'.

Обратите внимание, что scikit-image имеет собственный менеджер контекста для предупреждений в skimage/_shared/_warnings.py . Это может конфликтовать с suppress_warnings .

Из любопытства мне интересно, имеет ли значение явное указание DeprecationWarning вместо использования значения по умолчанию UserWarning .

Поэтому я не вижу ошибок с

$ nosetests-2.7 skimage/transform/tests/test_integral.py |& grep orig_show

В то время как

$ nosetests-2.7 skimage/transform/tests/ |& grep orig_show

Показывает это примерно в 25% случаев. Это говорит о том, что источник ошибки находится в другом месте, и неудачный тест просто выявляет его.

В частности, skimage/transform/tests/test_geometric.py содержит диспетчер контекста предупреждений expected_warnings что вызывает у меня подозрения.

Хорошо, теперь я подозреваю декоратор test_parallel , https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/testing.py . По умолчанию это два потока.

Если я удалю три файла, импортирующих test_parallel , проблема исчезнет.

РЕДАКТИРОВАТЬ: И теперь я вообще не могу воспроизвести проблему. Хм ... Может еще и зависит от того, что еще на машине запущено.

Хммм, test_parallel может быть им, я полагаю, хотя, просматривая код, ни одна из функций явно не использует контекст предупреждения, хотя это не невозможно, я думаю.

что-то в test_hough_transform.py кажется инициатором. После удаления этого файла ошибки нет.

РЕДАКТИРОВАТЬ: Возможно, потому, что он предшествует модулю test_integral.py ?

Проблема, похоже, заключается в этом тесте в test_hough_transform.py

@test_parallel()
def test_hough_circle():
    # Prepare picture
    img = np.zeros((120, 100), dtype=int)
    radius = 20
    x_0, y_0 = (99, 50)
    y, x = circle_perimeter(y_0, x_0, radius)
    img[x, y] = 1

    out1 = tf.hough_circle(img, radius)
    out2 = tf.hough_circle(img, [radius])
    assert_equal(out1, out2)
    out = tf.hough_circle(img, np.array([radius], dtype=np.intp))
    assert_equal(out, out1)
    x, y = np.where(out[0] == out[0].max())
    assert_equal(x[0], x_0)
    assert_equal(y[0], y_0)

в частности, любая из двух строк

    assert_equal(out1, out2)

# or

    assert_equal(out, out1)

Включит ошибку.

Точно так же удаление декоратора @parallel исправляет ошибку. В результате получается, что потоки в сочетании с вызовом assert_equal с векторами приводят к проблеме.

Имеет смысл, функция assert equal использует его для фильтрации предупреждений ".*NAT ==" , мы могли бы попытаться удалить его из этой функции, поскольку не совсем очевидно, что assert_equal подавляет предупреждения (и, следовательно, не полностью поддержка резьбы).

Замечательно выследить Чака!

Попытка удалить это было бы хорошо.

Интересно, есть ли другие функции numpy, которые не являются потокобезопасными?

Не уверен, я думаю, что в тестовом костюме мы используем только предупреждения. А np.errstate , вероятно, потокобезопасен?

Большое спасибо за это хорошее расследование @seberg

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

Думаю, достаточно просто исправить assert_equal , в любом случае это потребует исправления для сравнения NaT. Обратите внимание, что NaT может быть преобразован в int64 и имеет значение min_int64.

О, правда, мы можем просто явно поддерживать NaT, что в настоящее время немного раздражает (поскольку нет функции, которая бы специально проверяла NaT), но не сложно. Есть еще одна из этих вещей, связанных с другими сравнениями массивов, но я предполагаю, что она мало используется (и не уверен, для чего).

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

Нам все еще нужна функция isnat или, возможно, поддержка datetime/timedelta в isnan .

Да, согласен насчет функции isnat . Также существует два типа ошибок: timedelta64 и datetime64 . Обратите внимание, что значение NaT также нигде не отображается, мы, вероятно, также могли бы использовать np.nat . Фактическое определение находится в ndarraytypes.h .

@charris , Чак, что ты np.isnat или, скорее, разрешить datetime и timedelta в isnan ?

Хм, поместить все это в isnan - интересная мысль, но я подозреваю, что это может вызвать проблемы сейчас, а может, позже? @njsmith @juliantaylor Мысли?

@shoyer тоже может иметь свое мнение.

Я только что реализовал isnat , но я не уверен во всех моментах выпуска. Если нам нужно попытаться исправить это в минимальной версии, лучшим вариантом будет, вероятно, подключить версию python isnat в тестовый костюм, хотя исправление этого может оказаться немного сложным в любом случае ( по крайней мере, другие получат больше предупреждений, чем раньше, хотя может быть несколько: 1. используйте наш тестовый костюм и 2. на самом деле внимательно тестируйте предупреждения).

Я не считаю неисправность ужасно серьезной, но было бы неплохо ее исправить. (Частная?) Версия isnat для Python подойдет мне для версии 1.12.

В строке документации suppress_warnings также следует указать, что она не является потокобезопасной.

Оно делает :)

Большое спасибо, ребята, за то, что подняли проблему во время отпуска и за тщательную отладку

Могу ли я что-нибудь сделать, чтобы реализовать / протестировать решение для этого? debian очень хочет исправить это :)

@sandrotosi , к сожалению, это может быть немного сложно, самое простое исправление может заключаться в том, чтобы просто не использовать материал параллельного тестирования в skimage, но это несколько противоречит цели. Мы можем довольно просто сделать что-то вроде моего материала isnat (используя частную версию isnat для Python). Однако я не совсем уверен, что он не может создавать тестовые регрессии где-либо еще: /.

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

@olebole отключит параллельное тестирование в skimage - это приемлемое временное решение?

@seberg да, я думаю, что целью может быть минимальное исправление для 1.12 и, в конечном итоге, решить его более полным / всесторонним способом в мастере - это, по крайней мере, позволило бы следующему выпуску debian иметь numpy без этой проблемы

@sandrotosi Я пробовал использовать блокировку в gh-8427. Я не уверен, безумна эта мысль или нет, но если кто-то захочет попробовать ...

Есть ли способ просто изменить suppress_warnings чтобы он имел неопределенное поведение, но не приводил к сбою при использовании в многопоточном режиме?

(У меня есть несколько идей, но я все еще думаю, как именно это могло бы работать.)

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

Я загрузил 1.12.0rc2 (который содержит https://github.com/numpy/numpy/pull/8427) в debian и 3 раза перестроил скимейдж (немного старая версия пакета debian, без полностью отключенного набора тестов) и все время он строился успешно.

Большое спасибо, ребята, за работу над этим во время праздников!

Какие планы на финальную версию 1.12.0? :)

Я планирую выпустить финальный релиз 15 января.

Могу подтвердить, что он работает с rc2. Большое спасибо за ваши усилия!

Я оставляю это открытым, пока он не будет исправлен в мастере.

Хм, не исправлено в мастере. @seberg Это правда, что # 8421 закроет это?

Исправлено # 8421.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

Kreol64 picture Kreol64  ·  3Комментарии

kevinzhai80 picture kevinzhai80  ·  4Комментарии

astrofrog picture astrofrog  ·  4Комментарии

Levstyle picture Levstyle  ·  3Комментарии

dmvianna picture dmvianna  ·  4Комментарии