Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libc++abi exception when running demo enable/enable/examples/demo/savage/buttons_on_canvas when running python3.11 #1023

Open
homosapien-lcy opened this issue Apr 6, 2023 · 15 comments
Assignees

Comments

@homosapien-lcy
Copy link
Contributor

homosapien-lcy commented Apr 6, 2023

Description:

When running demo enable/enable/examples/demo/savage/buttons_on_canvas, a exception will happen in libc++:

2023-04-06 11:25:18.884 Python[3819:77967] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/2z/kylzj9s92y71cxscmljmpqrh0000gt/T/org.python.python.savedState
libc++abi: terminating with uncaught exception of type kiva::$_0
zsh: abort      python3.11 enable/examples/demo/savage/buttons_on_canvas.py

Replication step:
python enable/examples/demo/savage/buttons_on_canvas.py

Environment:
MacOS, python3.11 or python3.8 (with or without EDM)

Packages Installed:

Package            Version     Editable project location
------------------ ----------- --------------------------------------
chaco              5.1.0       /Users/cyliu/Documents/3.11_test/chaco
configobj          5.0.8
enable             5.4.0.dev32
fonttools          4.39.2
joblib             1.2.0
numpy              1.24.2
pandas             1.5.3
Pillow             9.4.0
pip                22.3.1
PyAudio            0.2.13
pyface             7.4.4
pygarrayimage      1.0
pyglet             2.0.5
Pygments           2.14.0
pyparsing          3.0.9
PySide6            6.4.3
PySide6-Addons     6.4.3
PySide6-Essentials 6.4.3
python-dateutil    2.8.2
pytz               2023.2
reportlab          3.6.12
scikit-learn       1.2.2
scipy              1.10.1
setuptools         65.6.3
shiboken6          6.4.3
six                1.16.0
threadpoolctl      3.1.0
traits             6.4.1
traitsui           8.0.0.dev0
@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 6, 2023

The error seems to happen in demo.configure_traits() (enable/examples/demo/savage/buttons_on_canvas.py, Line 181). Evidence: When I add prints above and below it, only the first print (1) will print out:

demo = ButtonCanvasView()

if __name__ == "__main__":
    print("1")
    demo.configure_traits()
    print("2")

@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 6, 2023

After further locating using the same print method, the error is found inside the following part of the traits/traits/has_traits.py (line 2163-2172). This is a class from traitsui:


rc = toolkit().view_application(
                context,
                self.trait_view(view),
                kind,
                handler,
                id,
                scrollable,
                args,
            )

@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 6, 2023

We can exclude the possibility that the error comes from toolkit() construction function (traitsui/traitsui/toolkit.py line 80), since the print can successfully pass this function. The inspect tool points to the overrided view_application function in traitsui/qt4/toolkit.py using the following code (in line 2164 of traits/traits/has_traits.py)

print(inspect.getsourcefile(toolkit().view_application))

@homosapien-lcy
Copy link
Contributor Author

Further print tests leads to

traitsui/qt4/view_application.py (line 59-110)

def view_application(context, view, kind, handler, id, scrollable, args):
    """Creates a stand-alone PyQt application to display a specified traits UI
        View.

    Parameters
    ----------
    context : object or dictionary
        A single object or a dictionary of string/object pairs, whose trait
        attributes are to be edited. If not specified, the current object is
        used.
    view : view object
        A View object that defines a user interface for editing trait attribute
        values.
    kind : string
        The type of user interface window to create. See the
        **traitsui.view.kind_trait** trait for values and
        their meanings. If *kind* is unspecified or None, the **kind**
        attribute of the View object is used.
    handler : Handler object
        A handler object used for event handling in the dialog box. If
        None, the default handler for Traits UI is used.
    scrollable : Boolean
        Indicates whether the dialog box should be scrollable. When set to
        True, scroll bars appear on the dialog box if it is not large enough
        to display all of the items in the view at one time.


    """
    if (kind == "panel") or ((kind is None) and (view.kind == "panel")):
        kind = "modal"

    app = QtGui.QApplication.instance()
    if app is None or not is_event_loop_running_qt4(app):
        return ViewApplication(
            context, view, kind, handler, id, scrollable, args
        ).ui.result

    ui = view.ui(
        context,
        kind=kind,
        handler=handler,
        id=id,
        scrollable=scrollable,
        args=args,
    )

    # If the UI has not been closed yet, we need to keep a reference to
    # it until it does close.
    if not ui.destroyed:
        KEEP_ALIVE_UIS.add(ui)
        ui.on_trait_change(on_ui_destroyed, "destroyed")
    return ui.result

@jwiggins
Copy link
Member

jwiggins commented Apr 6, 2023

Is there no stack trace? Most of the code you're referencing here is nowhere near kiva.

@mdickinson
Copy link
Member

@homosapien-lcy It may be worth trying to run this under faulthandler to see if that gives useful output: https://docs.python.org/3/library/faulthandler.html.

@corranwebster
Copy link
Contributor

As John noted the code you have linked here is just generic GUI wrapper code that starts and runs a TraitsUI application and so is not helpful in diagnosing the issue - or likely at fault (by the way, github allows you to highlight and copy permanent links to other code stored in github, which is a nicer way of linking in issues). As Mark suggests, run with faulthandler to get a better idea of the issue.

@homosapien-lcy
Copy link
Contributor Author

Thanks for the comments! Looking into faulthandler now

@mdickinson
Copy link
Member

Looking into faulthandler now

For the quick version: just use python -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py instead of python enable/examples/demo/savage/buttons_on_canvas.py

@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 6, 2023

Thanks! I got much more information from the error message. It seems the problem comes from kiva/agg/agg.py", line 1183 in clip_to_rect:

Traceback (most recent call last):
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 22, in <module>
    from enable.api import BaseTool, Component, ComponentEditor, Container
ModuleNotFoundError: No module named 'enable'
(py311) (base) cyliu@aus552cyliu enable % python3.11 -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py
2023-04-06 17:31:16.778 Python[11186:238536] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/2z/kylzj9s92y71cxscmljmpqrh0000gt/T/org.python.python.savedState
libc++abi: terminating with uncaught exception of type kiva::$_0
Fatal Python error: Aborted

Current thread 0x0000000119235600 (most recent call first):
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/kiva/agg/agg.py", line 1183 in clip_to_rect
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 218 in set_on_gc
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 534 in gradientPath
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/savage/svg/document.py", line 1119 in render
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 79 in _draw_svg_document
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 59 in draw
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 99 in draw
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/abstract_window.py", line 536 in _paint
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/qt4/base_window.py", line 90 in paintEvent
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/qt4/base_window.py", line 255 in paintEvent
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/pyface/util/guisupport.py", line 155 in start_event_loop_qt4
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/traitsui/qt4/view_application.py", line 138 in __init__
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/traitsui/qt4/view_application.py", line 92 in view_application
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/traitsui/qt4/toolkit.py", line 237 in view_application
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/traits/has_traits.py", line 2164 in configure_traits
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 181 in <module>

Extension modules: traits.ctraits, numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator, kiva._cython_speedups, kiva._marker_renderer, xxsubtype, shiboken6.Shiboken, PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets, PySide6.QtPrintSupport, PySide6.QtNetwork, PySide6.QtWebChannel, PySide6.QtWebEngineCore, PySide6.QtWebEngineWidgets, PySide6.QtSvg, kiva.agg._agg, kiva.agg._plat_support, PySide6.QtOpenGL, PySide6.QtOpenGLWidgets (total: 31)
zsh: abort      python3.11 -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py

@jwiggins
Copy link
Member

jwiggins commented Apr 6, 2023

Ahh... that's the level of detail we needed. Here's the relevant C++ code:

if (this->state.use_rect_clipping())
{
kiva::rect_type device_rect(transform_clip_rectangle(rect));
// optimize for case when there is only one existing rectangle
if (this->state.device_space_clip_rects.size() == 1)
{
kiva::rect_type old(this->state.device_space_clip_rects.back());
this->state.device_space_clip_rects.pop_back();
kiva::rect_type newrect(kiva::disjoint_intersect(old, device_rect));
if ((newrect.w < 0) || (newrect.h < 0))
{
// new clip rectangle doesn't intersect anything, so we push on
// an empty rect as the new clipping region.
this->renderer.reset_clipping(false);
this->state.device_space_clip_rects.push_back(kiva::rect_type(0, 0, -1, -1));
}
else
{
this->renderer.reset_clipping(true);
this->renderer.add_clip_box(int(newrect.x), int(newrect.y),
int(newrect.x2()), int(newrect.y2()));
this->state.device_space_clip_rects.push_back(newrect);
}
}
else
{
// we need to compute the intersection of the new rectangle with
// the current set of clip rectangles. we assume that the existing
// clip_rects are a disjoint set.
this->state.device_space_clip_rects = kiva::disjoint_intersect(
this->state.device_space_clip_rects, device_rect);
if (this->state.device_space_clip_rects.size() == 0)
{
this->renderer.reset_clipping(false);
this->state.device_space_clip_rects.push_back(kiva::rect_type(0, 0, -1, -1));
}
else
{
this->renderer.reset_clipping(true);
for (unsigned int i=0; i<this->state.device_space_clip_rects.size(); i++)
{
kiva::rect_type *tmp = &this->state.device_space_clip_rects[i];
this->renderer.add_clip_box(int(tmp->x), int(tmp->y),
int(tmp->x2()), int(tmp->y2()));
}
}
}
}
else
{
// We don't support non-rect clipping.
throw clipping_path_unsupported;
}

Yes, there is an else clause where an exception is thrown, but I don't think that's the exception here. In order for this->state.use_rect_clipping() to be false, this->state.clipping_path must be non-empty, but that appears to be an unimplemented feature in kiva's AGG backend. this->state.clipping_path is always empty:

void graphics_context<agg_pixfmt>::clip()
{
// this->state.clipping_path = this->path;

I suspect, but do not know, that bad values are being passed as the clipping rect and that big block of code is throwing an exception somewhere.

@corranwebster
Copy link
Contributor

One thing to try is to see what happens when using a backend other than old Agg. Something like:

ETS_TOOLKIT=qt.qpainter python -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py

or

ETS_TOOLKIT=qt.celiagg python -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py

@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 7, 2023

ETS_TOOLKIT=qt.qpainter python -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py

After test, I found qt.qpainter can run with no error.

But the qt.celiagg will yield the following error:

Traceback (most recent call last):
  File "/Users/cyliu/Documents/3.11_test/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 23, in <module>
    from enable.savage.svg.backends.kiva.renderer import Renderer as KivaRenderer
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 36, in <module>
    class CompiledPath(KivaCompiledPath):
  File "/Users/cyliu/.venvs/py311/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 38, in CompiledPath
    AddPath = KivaCompiledPath.add_path
              ^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: type object 'Unimplemented' has no attribute 'add_path

@homosapien-lcy
Copy link
Contributor Author

homosapien-lcy commented Apr 10, 2023

After more tests:

        if sys.platform == "darwin":
            print('in darwin')
            if self.spreadMethod != "pad":
                warnings.warn(
                    "spreadMethod %r is not supported. Using 'pad'"
                    % self.spreadMethod
                )

            if bbox is not None:
                print("in clip")
                print("bbox", bbox)
                gc.clip_to_rect(*bbox)

The bbox inputted that caused unimplemented error seems normal:

in darwin
in clip
bbox [0.0, 0.0, 72.0, 16.0]
in darwin
in clip
bbox [0.0, 0.0, 104.00238, 120.0]
in darwin
in clip
bbox [0.0, 0.0, 77.351562, 25.5921935]
in darwin
in clip
bbox [0.0, 0.0, 84.556527, 32.353364]
libc++abi: terminating with uncaught exception of type kiva::$_0
Fatal Python error: Aborted

Indeed, even if I pin the bbox value to all 0s (enable/savage/svg/backends/kiva/renderer.py, line 195-235)

    def set_on_gc(self, gc, bbox=None):

        # Apply transforms
        if self.transforms is not None:
            for func, f_args in self.transforms:
                if isinstance(f_args, tuple):
                    func(gc, *f_args)
                else:
                    func(gc, f_args)

        x1 = self.x1
        x2 = self.x2
        y1 = self.y1
        y2 = self.y2

        if sys.platform == "darwin":
            if self.spreadMethod != "pad":
                warnings.warn(
                    "spreadMethod %r is not supported. Using 'pad'"
                    % self.spreadMethod
                )

            if bbox is not None:
                bbox = [0, 0, 0, 0]
                gc.clip_to_rect(*bbox)
            else:
                print("Alert, None!!!")

        else:
            if self.units == "objectBoundingBox" and bbox is not None:
                x1 = (bbox[2] + bbox[0]) * x1
                y1 = (bbox[3] + bbox[1]) * y1
                x2 = (bbox[2] + bbox[0]) * x2
                y2 = (bbox[3] + bbox[1]) * y2

                self.bbox_transform(gc, bbox)

        stops = np.transpose(self.stops)
        gc.linear_gradient(
            x1, y1, x2, y2, stops, self.spreadMethod, self.units
        )

I print the *args out before it is past into the C++ code

    def clip_to_rect(self, *args):
        print("in clip_to_rect", *args)
        return _agg.GraphicsContextArray_clip_to_rect(self, *args)

The program will still failed in the end, even though it didn't raised error with the same input in the first few calls:

2023-04-10 14:45:13.649 Python[7063:125720] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/2z/kylzj9s92y71cxscmljmpqrh0000gt/T/org.python.python.savedState
in clip_to_rect 0.0 0.0 108.0 120.0
in clip_to_rect 0.0 0.0 106.25 118.28572
in clip_to_rect 0 0 0 0
in clip_to_rect 0.0 0.0 108.0 120.0
in clip_to_rect 0.0 0.0 106.25 118.28572
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
in clip_to_rect 0 0 0 0
libc++abi: terminating with uncaught exception of type kiva::$_0
Fatal Python error: Aborted

Current thread 0x0000000109f83600 (most recent call first):
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/kiva/agg/agg.py", line 1184 in clip_to_rect
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 219 in set_on_gc
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/savage/svg/backends/kiva/renderer.py", line 537 in gradientPath
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/savage/svg/document.py", line 1119 in render
  File "/Users/cyliu/Documents/3.11_test_2/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 79 in _draw_svg_document
  File "/Users/cyliu/Documents/3.11_test_2/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 59 in draw
  File "/Users/cyliu/Documents/3.11_test_2/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 99 in draw
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/abstract_window.py", line 536 in _paint
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/qt4/base_window.py", line 90 in paintEvent
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/enable/qt4/base_window.py", line 255 in paintEvent
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/pyface/util/guisupport.py", line 156 in start_event_loop_qt4
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/traitsui/qt4/view_application.py", line 138 in __init__
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/traitsui/qt4/view_application.py", line 92 in view_application
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/traitsui/qt4/toolkit.py", line 237 in view_application
  File "/Users/cyliu/.venvs/py311_test_2/lib/python3.11/site-packages/traits/has_traits.py", line 2164 in configure_traits
  File "/Users/cyliu/Documents/3.11_test_2/enable/enable/examples/demo/savage/buttons_on_canvas.py", line 181 in <module>

Extension modules: traits.ctraits, numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator, kiva._cython_speedups, kiva._marker_renderer, xxsubtype, shiboken6.Shiboken, PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets, PySide6.QtPrintSupport, PySide6.QtNetwork, PySide6.QtWebChannel, PySide6.QtWebEngineCore, PySide6.QtWebEngineWidgets, kiva.agg._agg, kiva.agg._plat_support, PySide6.QtOpenGL, PySide6.QtOpenGLWidgets, kiwisolver._cext, PySide6.QtSvg, PySide6.QtSvgWidgets (total: 33)
zsh: abort      python3.11 -X faulthandler enable/examples/demo/savage/buttons_on_canvas.py

@dpinte
Copy link
Member

dpinte commented Apr 10, 2023

I tested it with edm on Python 3.8 and Linux (enable 5.3) and it works as expected. The issue seems to be OS-X specific.

@homosapien-lcy homosapien-lcy changed the title libc++abi exception libc++abi exception when running demo enable/enable/examples/demo/savage/buttons_on_canvas Apr 21, 2023
@homosapien-lcy homosapien-lcy changed the title libc++abi exception when running demo enable/enable/examples/demo/savage/buttons_on_canvas libc++abi exception when running demo enable/enable/examples/demo/savage/buttons_on_canvas when running python3.11 Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants