nucleic / enaml

Declarative User Interfaces for Python
http://enaml.readthedocs.io/en/latest/
Other
1.54k stars 132 forks source link

Exception in enaml code leads to cryptic stack overflow error. #265

Closed Julian-O closed 6 years ago

Julian-O commented 6 years ago

The following code is invalid, because it references an identifier that was never defined.

from enaml.widgets.api import Window, PushButton

enamldef MinimumFaultyProgramWindow(Window):
        PushButton: the_button:
            text = "Push to crash"
            clicked ::
                print(identifier_never_seen_before)

When I run it (with pyqt5) I get a crash:

Process finished with exit code -1073740791 (0xC0000409)

Googling around suggests that is a STATUS_STACK_BUFFER_OVERRUN error.

This is way too cryptic for a beginner like me to debug (especially as I get my head around Enaml scoping).

A NameError or UnboundLocalError exception should be raised referring to the identifier in question.

sccolbert commented 6 years ago

You should have gotten a NameError. What you're seeing is a new one to me. Is the code you posted the exact code that's failing?

On Tue, May 29, 2018, 21:55 Julian notifications@github.com wrote:

The following code is invalid, because it references an identifier that was never defined.

from enaml.widgets.api import Window, PushButton

enamldef MinimumFaultyProgramWindow(Window): PushButton: the_button: text = "Push to crash" clicked :: print(identifier_never_seen_before)

When I run it (with pyqt5) I get a crash:

Process finished with exit code -1073740791 (0xC0000409)

Googling around suggests that is a STATUS_STACK_BUFFER_OVERRUN https://stackoverflow.com/posts/49781951 error.

This is way too cryptic for a beginner like me to debug (especially as I get my head around Enaml scoping).

A NameError or UnboundLocalError exception should be raised referring to the identifier in question.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/nucleic/enaml/issues/265, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIYSVHZeIcN2ovsk8MydQiF3TYS-Xsaks5t3iY3gaJpZM4USmVv .

Julian-O commented 6 years ago

Yes. That is a cut-and-paste of the whole enaml file.

Here's some more info:

The main Python file:

import enaml
from enaml.qt.qt_application import QtApplication

if __name__ == '__main__':
    with enaml.imports():
        from mfp import MinimumFaultyProgramWindow

    app = QtApplication()

    view = MinimumFaultyProgramWindow()
    view.show()

    app.start()

Some version info:

Python:

Python 3.6.3 (v3.6.3:2c5fed8, Oct 3 2017, 18:11:49) [MSC v.1900 64 bit (AMD64)] on win32

And pip freeze gives:

atom==0.4.1 enaml==0.10.2 ExifRead==2.1.2 future==0.16.0 kiwisolver==1.0.1 piexif==1.0.13 Pillow==5.1.0 ply==3.11 pypiwin32==223 PyQt5==5.10.1 pywin32==223 QtPy==1.4.2 sip==4.19.8

(Pillow, ExifRead, pywin32 and pypiwin32 are due to my other project needs, not this snippet.)

MatthieuDartiailh commented 6 years ago

I cannot replicate in my current development environments (pyqt 5.6 and pyqt5.9 on Python 3.6). I will try to match exactly your environment later and see if I can replicate.

frmdstryr commented 6 years ago

Also can't replicate here. If you add the following:

import faulthandler
faulthandler.enable()

to the beginning of the main file. Does it provide any more information?

Julian-O commented 6 years ago

I rebuilt a virtualenv with PyQt5==5.9.2 to see if it a bug had been introduced recently. It still crashes on my machine.

Still on the same version, I put in the two lines requested by @frmdstryr.

Fatal Python error: Aborted

Current thread 0x0000c5e0 (most recent call first): File "[excerpted virtualenv dir]\lib\site-packages\enaml\qt\qt_application.py", line 48 in start File "[excerpted source dir]/mfpmain.py", line 16 in \

Process finished with exit code 3

As might be guessed, line 16 in mfpmain.py is the app.start().

Julian-O commented 6 years ago

Update: This doesn't seem to be specific to NameError. Any exception in my code will cause it.

Replace the print(identifier_never_seen_before) with 1/0 and the same thing happens.

Schedule a task from the app which raises an exception and the same thing happens.

frmdstryr commented 6 years ago

I was able reproduce this on windows with python 3.6.3 and 3.6.5. It does not occur on 2.7.

I stepped through with a debugger and enaml is properly raising a name error.

str: Traceback (most recent call last):
  File "C:\Users\jrm\AppData\Local\Programs\Python\Python365\lib\site-packages\enaml\qt\qt_abstract_button.py", line 77, in on_clicked
    self.declaration.clicked(checked)
  File "C:\Users\jrm\AppData\Local\Programs\Python\Python365\lib\site-packages\enaml\core\declarative_meta.py", line 68, in declarative_change_handler
    engine.write(owner, change['name'], change)
  File "C:\Users\jrm\AppData\Local\Programs\Python\Python365\lib\site-packages\enaml\core\expression_engine.py", line 217, in write
    pair.writer(owner, name, change)
  File "C:\Users\jrm\AppData\Local\Programs\Python\Python365\lib\site-packages\enaml\core\standard_handlers.py", line 82, in __call__
    call_func(func, (), {}, scope)
  File "C:\Users\jrm\workspace\tutorial\view.enaml", line 9, in f
    print(not_found)
NameError: name 'not_found' is not defined

However it looks like at some point after it generates the tb it then crashes. The last iteration before it dies it returns from codecs.py decode (where it returns the string above).

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: python.exe
  Application Version:  3.6.5150.1013
  Application Timestamp:    5abbcb08
  Fault Module Name:    ucrtbase.DLL
  Fault Module Version: 10.0.10137.0
  Fault Module Timestamp:   556ec8de
  Exception Code:   40000015
  Exception Offset: 000000000005e9ff
  OS Version:   6.1.7601.2.1.0.256.48
  Locale ID:    1033
  Additional Information 1: 281c
  Additional Information 2: 281c4ec28ee459a2ca62dbd6330b55d3
  Additional Information 3: d8bb
  Additional Information 4: d8bb51eb9e85e95f6f22514b8f723f5c

Read our privacy statement online:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409

If the online privacy statement is not available, please read our privacy statement offline:
  C:\Windows\system32\en-US\erofflps.txt

Not sure if any of that helps.

frmdstryr commented 6 years ago

Seems to be a Qt5 bug.

def on_click(e):
    raise ValueError("Blow up")

def main():
    import sys
    from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

    app = QApplication(sys.argv)

    w = QPushButton()
    w.setText("Test")
    w.clicked.connect(on_click)
    w.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

Produces the same error

MatthieuDartiailh commented 6 years ago

Thanks for investigating this @frmdstryr. It may worth reporting this to PyQt5. I will try to run some tests on my side because with pyqt 5.9 installed from anaconda I have not seen this issue.

Julian-O commented 6 years ago

Thanks, @frmdstryr, this is helpful.

I had a skim of the PyQt mailing list and couldn't find any mention of this problem.

I would raise an issue, but they appear to only offer that service to commercial customers.

I guess this is a dead-end, unless someone else has a good idea.

I am wrapping my Python in exception handlers as a work-around.

frmdstryr commented 6 years ago

A few other options:

  1. Use python 2.7 (worked on my system)
  2. Try python 3 & enaml from conda
  3. Try PySide2 instead of PyQt5
Julian-O commented 6 years ago

This seems to be related to running within the context of a PyCharm IDE. On the command line, it doesn't seem to be a problem.