Numpy: Manchmal fehlt supress_warnings eines seiner Attribute

Erstellt am 23. Dez. 2016  ·  60Kommentare  ·  Quelle: numpy/numpy

Beim Versuch, Skimage zu kompilieren, wird manchmal der folgende Fehler angezeigt:

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'

Ich nehme an, dass dies ein dummes Problem ist, bin mir aber nicht sicher.

00 - Bug numpy.testing

Alle 60 Kommentare

Hmmm, ein bisschen seltsam. Gibt es ein (seltsames) Einfädeln in den Skimage-Tests? Das würde das Testen von Warnungen ziemlich stark unterbrechen, da die Behandlung von Warnungen in Python nicht threadsicher ist. Ich habe ein bisschen Schwierigkeiten zu sehen, wie dies sonst passieren könnte, sollte aber vielleicht den genauen Code betrachten, den der Test ausführt.

Da es hier kein assert_warns oder so gibt, denke ich. Sie sollten nur einen einzigen suppress_warnings -Kontext zum Leben erwecken (dies wäre der äußerste Bereich, der vom Testläufer von numpy erstellt wird, vorausgesetzt, Skimage verwendet ihn letztendlich). Ich bin jetzt verwirrt, dass _orig_show nicht definiert werden sollte, wenn der Kontext bereits beendet wurde. Zu diesem Zeitpunkt sollte warnings.showwarning bereits auf den alten Wert zurückgesetzt werden.

Natürlich bricht das ganze Warnmaterial zusammen, wenn Sie Threads haben. Zum Beispiel:

thread1: tritt in den Warnkontext ein -> ersetzt den normalen Warnungsdruck
thread2: tritt in den Warnkontext ein -> ersetzt den Warnhandler von thread1
thread1: Beendet den Warnkontext -> wird auf den normalen Warnungsdruck zurückgesetzt
thread2: existiert Warnkontext -> wird auf den Warnhandler von thread1 zurückgesetzt -> kaboom.

Übrigens. Ich sehe, Sie haben einen "Versuch, nach __warning_registry__ Sachen im Skimage aufzuräumen. Die Unterdrückungswarnungen sind ein Kontextmanager, der versucht, ein ähnliches Problem zu lösen (und einige andere Sachen hinzufügt), der vielleicht interessant ist oder nicht.

Ich habe gerade das Problem bekommen, als ich versucht habe, ein Skimage für Debian zu erstellen, und ich habe hier keine Ahnung. Ich habe jedoch scikit-image / scikit-image # 2412 geöffnet, um sie einzubeziehen.

Nur der Vollständigkeit halber: Manchmal bekomme ich sogar einen Stacktrace ohne Skimage:

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'

Mit welchen Versionen von Python, Numpy usw. kompilieren Sie?

Numpy 1.12 ~ RC ~ Beta 1, Python 2.7 und 3.5
(Entschuldigung, mein Fehler: RC noch nicht überprüft)

Hmm, ich bin verwirrt ... Ich kann nicht verstehen, warum es Threading-Probleme geben würde, kann diesen Fehler aber auch nicht wirklich ergründen, ohne dass eine Race-Bedingung oder eine falsche Verschachtelung von catch_warning -ähnlichem Material (einschließlich) vorliegt suppress_warning ).

Ich würde auch denken, dass es eine Rennbedingung ist, da es nicht immer passiert. Wenn Sie den Build zweimal unter genau derselben Umgebung ausführen, tritt das Problem an verschiedenen Stellen (oder gar nicht) auf.

@olebole Wie genau lässt du den

Aus unserer Testsuite kopiert:

#!/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

Das xvfb-run ist vorhanden, da der Test in einer X11-Umgebung ausgeführt werden muss.

Hmmmpf, weiß jemand, was genau unter der Haube passiert, wenn die Nase anfängt, ein Modul zu testen? Die Nase verwirrt mich und ich kann nicht sehen, warum es auch zu Warnungen kommen würde ... Oder es ist ein Fehler, Warnungen zu unterdrücken, aber ich kann es nicht wirklich sehen, heh.

In meiner Nosetests-Manpage habe ich

       --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]

Es scheint, dass es standardmäßig keine parallelen Tests gibt. Zumindest sollte die Rennbedingung nicht vorhanden sein.

Gibt es eine entfernte Chance, dass die Nase dieses teardownContext basierend auf Müllsammelmaterial ausführt?!

Nein, ich bin wahrscheinlich albern. Der Kontext für die Unterdrückung von Warnungen setzt warnings.showwarning bevor das Attribut gelöscht wird. Zweifeln Sie also daran, dass selbst der einschaltende GC nichts wirklich erstellen kann, ohne dass etwas anderes passiert. Habe gerade keine Ahnung was noch :).

Nun, ich sehe 33 Fehler mit skimage-0.9.3, die meisten von PIL oder Indizierung, aber keine zur Unterdrückung. Wie gehen Sie mit all den anderen Fehlern um?

@charris Das Problem wird für 0.12.3 gemeldet, nicht für 0.9.3. :) :)

OK, habe das endlich vom Upstream runtergezogen, jetzt 39 Fehler und eine Menge Abwertungen. Die meisten Warnungen scheinen auf die Tatsache zurückzuführen zu sein, dass Tests glauben, dass sie in QT anstelle von Wayland ausgeführt werden. Dies könnte hier ein Konfigurationsproblem sein. Ich muss die Tests auch als ausführen

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

da nosetests überhaupt nicht funktioniert.

Abschreibungen sind normal. Wir überprüfen weiterhin unsere alte API, auch wenn eine Abwertung erwartet wird. Über Fehler ist es nicht normal. Würde es Ihnen etwas ausmachen, sie auf unserem (Scikit-Image) Bug-Tracker zu melden?

@sciunto Die Dokumente könnten Anweisungen zum lokalen Testen verwenden.

OK, ich sehe es an der gleichen Stelle. Der Test ist

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))

Der Kommentar # test deprecated legt mir nahe, dass der Test möglicherweise korrigiert werden muss, aber suppress_warnings sollte dennoch

Etwas mehr Informationen machen

$ python skimage/transform/tests/test_integral.py

Was NumPy run_module_suite scheint nicht zu scheitern, gibt aber die Warnung aus

======================================================================
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))'.

Beachten Sie, dass scikit-image einen eigenen Kontextmanager für Warnungen in skimage/_shared/_warnings.py . Das könnte im Widerspruch zu suppress_warnings .

Aus Neugier frage ich mich, ob es einen Unterschied macht, DeprecationWarning explizit anzugeben, anstatt den Standard UserWarning .

Ich sehe also keine Fehler mit

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

Wohingegen

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

Zeigt es ungefähr 25% der Zeit. Dies deutet darauf hin, dass die Fehlerquelle an anderer Stelle liegt und der fehlgeschlagene Test sie nur aufdeckt.

Insbesondere enthält skimage/transform/tests/test_geometric.py den Kontextmanager für Warnungen expected_warnings und das macht mich misstrauisch.

OK, jetzt vermute ich den test_parallel Dekorateur, https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/testing.py . Das sind standardmäßig zwei Threads.

Wenn ich die drei Dateien entferne, die test_parallel importieren, gibt es kein Problem mehr.

EDIT: Und jetzt kann ich das Problem überhaupt nicht reproduzieren. Hmm ... Vielleicht hängt es auch davon ab, was sonst noch auf der Maschine läuft.

Hmmm, das test_parallel könnte es sein, denke ich, obwohl ich den Code durchschaue, verwendet keine der Funktionen offensichtlich einen Warnkontext, obwohl es nicht unmöglich ist, denke ich.

etwas in test_hough_transform.py scheint der Initiator zu sein. Wenn diese Datei entfernt wird, liegt kein Fehler vor.

EDIT: Vielleicht, weil vor dem test_integral.py Modul steht?

Das Problem scheint dieser Test in 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)

insbesondere eine der beiden Zeilen

    assert_equal(out1, out2)

# or

    assert_equal(out, out1)

Aktiviert den Fehler.

Ebenso behebt das Entfernen des Dekorators @parallel den Fehler. Das Ergebnis ist also, dass Threads in Kombination mit dem mit Vektoren aufgerufenen assert_equal zu dem Problem führen.

Es macht Sinn, dass die Funktion "Gleichheit bestätigen" sie verwendet, um ".*NAT ==" Warnungen zu filtern. Wir könnten möglicherweise versuchen, sie aus dieser Funktion zu entfernen, da es nicht wirklich offensichtlich ist, dass assert_equal Warnungsunterdrückung durchführt (und daher nicht vollständig Support Threading).

Schön, Chuck aufzuspüren!

Der Versuch, es zu entfernen, wäre eine gute Sache.

Ich frage mich, ob es andere Numpy-Funktionen gibt, die nicht threadsicher sind.

Ich bin mir nicht sicher, ich denke, wir verwenden nur Warnmaterial im Testanzug. Und das np.errstate ist wahrscheinlich threadsicher?

Vielen Dank für diese nette Untersuchung @charris und @seberg

Hmmm, ich finde es etwas nervig. Das Entfernen der Unterdrückungen von ihrem Standort aus kann das Verhalten für Downstreams ändern. Dies ist wahrscheinlich in Ordnung (möglicherweise sogar sauberer), aber nicht sicher, ob es für eine Bugfix-Version von Nutzen ist. Könnte auch einen Mutex für die Vergleichstyp-Tests sperren, was im Prinzip nicht immer in Ordnung ist, aber ich kann mir nicht wirklich vorstellen, wie es brechen könnte.

Ich denke, es würde ausreichen, nur assert_equal zu reparieren, es muss in Zukunft auf jeden Fall für den NaT-Vergleich repariert werden. Beachten Sie, dass das NaT in int64 konvertiert werden kann und den Wert min_int64 hat.

Oh, stimmt, wir können NaT tatsächlich nur explizit unterstützen, was derzeit etwas ärgerlich ist (da es keine Funktion gibt, die speziell auf NaT überprüft werden kann), aber nicht schwer. Es gibt noch eine andere dieser Dinge um andere Array-Vergleiche, aber ich denke, es wird nicht viel verwendet (und nicht sicher, wofür).

Das Hinzufügen von NaT-Logik zu den Asserts scheint für Master ziemlich gut zu funktionieren, obwohl ich nicht sicher bin, ob es für Backporting funktioniert. Ich denke, während die suppress_warnings mögen, war die Rennbedingung selbst bereits in der letzten Veröffentlichung vorhanden.

Wir brauchen noch eine isnat -Funktion oder unterstützen vielleicht datetime/timedelta in isnan .

Ja, stimmen Sie der Funktion isnat . Es gibt auch zwei Arten, bei denen Unfälle auftreten: timedelta64 und datetime64 . Beachten Sie, dass der NaT-Wert auch nirgendwo verfügbar ist. Wir könnten wahrscheinlich auch einen np.nat . Die eigentliche Definition ist in ndarraytypes.h .

@charris , Chuck, wie sehen Sie das, erstellen Sie lieber np.isnat oder lassen Sie Datum und Uhrzeit in isnan ?

Hmm, alles in isnan ist ein interessanter Gedanke, aber ich vermute, dass es zu diesem Zeitpunkt Probleme verursachen könnte, vielleicht später? @njsmith @juliantaylor Gedanken?

@shoyer kann auch eine Meinung haben.

Ich habe gerade isnat implementiert, bin mir aber nicht sicher, was das Timing in Bezug auf die Veröffentlichung angeht. Wenn wir versuchen müssen, dies in einer minimalen Version zu beheben, ist es wahrscheinlich die bessere Option, eine Python isnat -Version in den Testanzug einzustecken, obwohl sich das Beheben in jedem Fall als etwas schwierig herausstellen kann ( Zumindest werden andere mehr Warnungen erhalten als zuvor, obwohl vielleicht nur wenige 1. unser Testanzugmaterial verwenden und 2. tatsächlich Warnungen sorgfältig testen).

Ich halte den Fehler nicht für schrecklich schwerwiegend, aber es wäre schön, ihn beheben zu lassen. Eine (private?) Python-Version von isnat wäre für mich für 1.12 in Ordnung.

Der suppress_warnings docstring sollte auch erwähnen, dass er nicht threadsicher ist.

Es tut :)

Vielen Dank, Jungs, für das Springen in den Ferien und für das gründliche Debuggen

Kann ich etwas tun, um eine Lösung dafür zu implementieren / zu testen? Debian ist bestrebt, eine Lösung dafür zu finden :)

@sandrotosi , leider ist es vielleicht ein bisschen knifflig, die einfachste Lösung könnte darin bestehen, das parallele Testmaterial einfach nicht im Skimage zu verwenden, aber das macht den Zweck etwas zunichte. Wir können ziemlich einfach so etwas wie in meinem isnat-Zeug machen (mit einer privaten Python-Version von isnat). Ich bin mir jedoch nicht ganz sicher, ob es anderswo keine Testregressionen geben kann: /.

Das Hinzufügen eines Mutex für diese beiden Fälle kann tatsächlich ein plausibler Hack sein, der das Problem beseitigen sollte und wahrscheinlich nicht schlecht wird (da Sie innerhalb von assert_equal nicht assert_equal oder ähnliches aufrufen würden). Ich würde das eigentlich nicht in Numpy Master verwenden, aber als minimaler Bugfix für 1.12 kann es eine echte Option sein. Und es würde die Skimage-Tests selbst nicht stören.

@olebole wäre das Deaktivieren von parallelen Tests in Skimage eine akzeptable vorübergehende Lösung?

@seberg Ja, ich denke, das Ziel könnte sein, eine minimale Korrektur für 1.12 zu haben und sie schließlich in Master vollständiger / umfassender anzugehen - das würde zumindest dazu führen, dass die nächste Debian-Veröffentlichung ohne dieses Problem numpy wird

@sandrotosi Ich habe den Lock-Ansatz in gh-8427 ausprobiert. Ich bin nicht, ob der Gedanke verrückt ist oder nicht, aber ob jemand es versuchen will ...

Gibt es eine Möglichkeit, suppress_warnings einfach so zu ändern, dass es ein undefiniertes Verhalten aufweist, aber nicht abstürzt, wenn es in einer Multithread-Weise verwendet wird?

(Ich habe einige Ideen, aber ich denke immer noch darüber nach, wie genau es funktionieren könnte.)

Sicher, wir können das Attribut einfach nicht löschen, aber es kann später zu Fehlern in den Tests führen ... Obwohl ich denke, dass die meisten Testanzüge beim Testen von Warnungen nicht so pingelig wie numpy sind, also ...

Ich habe 1.12.0rc2 (das https://github.com/numpy/numpy/pull/8427 enthält) auf debian hochgeladen und dreimal skimage neu erstellt (eine etwas alte Version des debian-Pakets, ohne dass die Testsuite vollständig deaktiviert ist). und all die Male, die es erfolgreich gebaut hat.

Vielen Dank Jungs für die Arbeit in den Ferien!

Gibt es Pläne für die endgültige Version 1.12.0? :) :)

Ich plane die endgültige Veröffentlichung am 15. Januar.

Ich kann bestätigen, dass es mit rc2 funktioniert. Vielen Dank für ihre Bemühungen!

Ich lasse dies offen, bis es im Master behoben ist.

Hmm, nicht im Master fixiert. @seberg Ist es richtig, dass # 8421 dies schließt?

Behoben durch # 8421.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen