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

AttributeError: type object 'Unimplemented' has no attribute 'add_path' #1002

Open
capn-freako opened this issue Oct 5, 2022 · 13 comments
Open

Comments

@capn-freako
Copy link

Since updating as follows:

  • Chaco ==> 5.0.0
  • Enable ==> 5.3.1
  • Pyface ==> 7.4.2

my Traits/UI GUI application yields the following error upon launch, from the enable/savage/svg/backends/kiva/renderer.py file:

AttributeError: type object 'Unimplemented' has no attribute 'add_path'

Is this a known issue?

Any ideas about what's going on here?

Thanks!
-db

Here's the full back-trace:

Traceback (most recent call last):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\__main__.py", line 2, in <module>
    from pybert.pybert      import PyBERT
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\pybert.py", line 29, in <module>
    from chaco.api import ArrayPlotData, GridPlotContainer
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\api.py", line 343, in <module>
    from chaco.overlays.api import (
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\Lib\site-packages\shiboken2\files.dir\shibokensupport\feature.py", line 139, in _import
    return original_import(name, *args, **kwargs)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\overlays\api.py", line 63, in <module>
    from chaco.overlays.layers.api import (
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\Lib\site-packages\shiboken2\files.dir\shibokensupport\feature.py", line 139, in _import
    return original_import(name, *args, **kwargs)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\overlays\layers\api.py", line 11, in <module>
    from .status_layer import ErrorLayer, StatusLayer, WarningLayer
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\Lib\site-packages\shiboken2\files.dir\shibokensupport\feature.py", line 139, in _import
    return original_import(name, *args, **kwargs)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\overlays\layers\status_layer.py", line 18, in <module>
    from enable.savage.svg.backends.kiva.renderer import Renderer as KivaRenderer
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\Lib\site-packages\shiboken2\files.dir\shibokensupport\feature.py", line 139, in _import
    return original_import(name, *args, **kwargs)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\savage\svg\backends\kiva\renderer.py", line 36, in <module>
    class CompiledPath(KivaCompiledPath):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\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'
@corranwebster
Copy link
Contributor

Are you on WxPython or one of the Qt backends? Do you know which Kiva backend you are using (the default is "image" but sometimes you may get another one).

I have not seen this particular issue before.

My suspicion is that:

  • Chaco is using SVG to render the status layer
  • The enable.savage renderer is being used to render the SVG
  • something is going wrong with loading the KivaCompiledPath class, which I think comes from the Agg/image backend

So my suspicions are that there is something wrong with the build, something unusual with the backend or environment being used, or a regression has crept in where KivaCompiledPath is not being imported correctly.

@capn-freako
Copy link
Author

The original case was with:

from traits.etsconfig.api import ETSConfig
ETSConfig.toolkit = 'qt.celiagg'

Changing to:

ETSConfig.toolkit = 'qt.qpainter'

results in a successful launch, but none of my plots are visible and the program crashes after a few minutes.
Here's that backtrace:

Traceback (most recent call last):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\qt4\base_window.py", line 255, in paintEvent
    self.handler.paintEvent(event)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\qt4\base_window.py", line 90, in paintEvent
    self._enable_window._paint(event)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\abstract_window.py", line 536, in _paint
    self.component.draw(gc, view_bounds=(0, 0, size[0], size[1]))
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\component.py", line 410, in draw
    self._draw(gc, view_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\component.py", line 791, in _draw
    self._dispatch_draw(layer, gc, view_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\container.py", line 270, in _dispatch_draw
    component._dispatch_draw(layer, gc, new_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\container.py", line 255, in _dispatch_draw
    my_handler(gc, view_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\container.py", line 293, in _draw_container_underlay
    self._draw_underlay(gc, view_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\component.py", line 902, in _draw_underlay
    underlay.overlay(self, gc, view_bounds, mode)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\grid.py", line 412, in overlay
    gc.clip_to_rect(
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\kiva\qpainter.py", line 482, in clip_to_rect
    self.gc.setClipRect(
AttributeError: PySide2.QtGui.QPainter.setClipRect(): unsupported keyword 'operation'
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?
Segmentation fault

Changing to:

ETSConfig.toolkit = 'qt.image'

yields normal program behavior, but that includes plot titles and axis labels with unreadable small font sizes on my high DPI display Windows machine, which is what started me on this quest to begin with. :(

Changing to:

ETSConfig.toolkit = 'wx'

results in a crash at launch w/ this backtrace:

Traceback (most recent call last):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\__main__.py", line 2, in <module>
    from pybert.pybert      import PyBERT
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\pybert.py", line 31, in <module>
    from chaco.api import ArrayPlotData, GridPlotContainer
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\api.py", line 314, in <module>
    from .plots.horizon_plot import BandedMapper
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\plots\horizon_plot.py", line 14, in <module>
    from enable.api import transparent_color_trait
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\api.py", line 184, in <module>
    from .base import (
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\base.py", line 41, in <module>
    from .colors import color_table, transparent_color
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\colors.py", line 13, in <module>
    from pyface.toolkit import toolkit
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\toolkit.py", line 23, in <module>
    toolkit = toolkit_object = find_toolkit("pyface.toolkits")
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\base_toolkit.py", line 263, in find_toolkit
    return import_toolkit(ETSConfig.toolkit, entry_point)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\base_toolkit.py", line 229, in import_toolkit
    raise RuntimeError(msg)
RuntimeError: No pyface.toolkits plugin could be loaded for wx

(Did I get the syntax correct?)

@capn-freako
Copy link
Author

By the way, should this work?:

ETSConfig.toolkit = 'qt5.celiagg'

It doesn't and I'm wondering if that's a clue.
Here's the backtrace it yields:

Traceback (most recent call last):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\__main__.py", line 2, in <module>
    from pybert.pybert      import PyBERT
  File "C:\Users\capnf\Documents\GitHub\PyBERT\pybert\pybert.py", line 32, in <module>
    from chaco.api import ArrayPlotData, GridPlotContainer
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\api.py", line 314, in <module>
    from .plots.horizon_plot import BandedMapper
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\chaco\plots\horizon_plot.py", line 14, in <module>
    from enable.api import transparent_color_trait
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\api.py", line 184, in <module>
    from .base import (
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\base.py", line 41, in <module>
    from .colors import color_table, transparent_color
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\colors.py", line 13, in <module>
    from pyface.toolkit import toolkit
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\toolkit.py", line 23, in <module>
    toolkit = toolkit_object = find_toolkit("pyface.toolkits")
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\base_toolkit.py", line 263, in find_toolkit
    return import_toolkit(ETSConfig.toolkit, entry_point)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\pyface\base_toolkit.py", line 207, in import_toolkit
    raise RuntimeError(msg)
RuntimeError: No pyface.toolkits plugin found for toolkit qt5

@capn-freako
Copy link
Author

Does this all look correct?

$ conda list qt
# packages in environment at C:\Users\capnf\anaconda3\envs\pybert-dev:
#
# Name                    Version                   Build  Channel
pyqt                      5.15.7           py38hd77b12b_0
pyqt5-sip                 12.11.0          py38hd77b12b_0
qt-main                   5.15.6               hf0cf448_0    conda-forge
qt-webengine              5.15.9               hb9a9bb5_4
qtconsole                 5.3.2            py38haa95532_0
qtpy                      2.2.0            py38haa95532_0
qtwebkit                  5.212                h0db62b3_6    conda-forge

$ conda list pyface
# packages in environment at C:\Users\capnf\anaconda3\envs\pybert-dev:
#
# Name                    Version                   Build  Channel
pyface                    7.4.2              pyhd8ed1ab_0    conda-forge

@corranwebster
Copy link
Contributor

corranwebster commented Oct 6, 2022

Thanks for the feedback. I think that the celiagg backend is the issue for the original problem - somehow it looks like its compiled path method isn't being provided correctly to Enable or Savage, so that feels like there is a bug somewhere. either in the celiagg backend or in the dynamic import logic. It's possible that this is related to #959 but the fact that you are getting an Unimplemented object implies a toolkit import issue is more likely.

It might be worth a try with qt4.celiagg - we are moving away from the old qt4 to just bare qt but there might be a few places where the old qt4 may linger and still be required (we aren't going to support qt5 or qt6 since we use the same codebase for all qt versions, so qt5.celiagg won't work).

Your environment looks OK - you seem to be on the most recent versions of ETS. We just released a bugfix release of TraitsUI but I don't think it should affect this issue. Chaco is in dire need of a release, hopefully we will get to that this quarter.

In terms of the original problem, if you are having issues with high-dpi displays, in recent versions of enable you can use Item(..., editor=ComponentEditor(..., high_resolution=False)) to render at 72-ish DPI if you have control over the editor. That may be something else you can try as a work-around.

It might also be worth digging in a bit at the font size problem for the image backend - at this point there is a known issue with polygon rendering at high resolution on the image backend (the lines are half the width they should be) but I thought we had resolved the font rendering issues. Can you run the benchmark in your environment (python -m enable.gcbench -o <output_dir> or something similar should work) and upload the high-res output of show_text_font_styles and show_text from the image backend either here or in a new issue if they look dramatically different from the lo-res versions.

For the other errors:

  • the wx failure is exactly what you would expect if WxPython isn't installed, so that 's fine and expected
  • the qpainter backend failure looks like a genuine bug - probably an API change between Qt version (I also notice that it is using PySide2 rather than PyQt5, not that that should matter deeply) so I've opened QPainter backend clipping error on PySide2 #1003 to track that.

@capn-freako
Copy link
Author

Can you run the benchmark in your environment (python -m enable.gcbench -o <output_dir> or something similar should work) and upload the high-res output of show_text_font_styles and show_text from the image backend either here or in a new issue if they look dramatically different from the lo-res versions.

I don't see an "image" backend in the output.
Is it the "kiva.agg" backend?

$ python -m enable.gcbench -o enable.gcbench
Benchmarking backend: kiva.agg
        Benchmark draw_image
        Benchmark draw_image_2x
        Benchmark draw_marker_at_points
        Benchmark draw_marker_at_points_2x
        Benchmark draw_path
        Benchmark draw_path_2x
        Benchmark draw_path_at_points
        Benchmark draw_path_at_points_2x
        Benchmark draw_path_linear_gradient
        Benchmark draw_path_linear_gradient_2x
        Benchmark draw_rect
        Benchmark draw_rect_2x
        Benchmark show_text
        Benchmark show_text_2x
        Benchmark show_text_radial_gradient
        Benchmark show_text_radial_gradient_2x
Benchmarking backend: blend2d ... Not available
Benchmarking backend: cairo ... Not available
Benchmarking backend: celiagg ... Not available
Benchmarking backend: opengl ... Not available
Benchmarking backend: qpainter
        Benchmark draw_image
        Benchmark draw_image_2x
        Benchmark draw_marker_at_points ... Failed
        Benchmark draw_marker_at_points_2x ... Failed
        Benchmark draw_path
        Benchmark draw_path_2x
        Benchmark draw_path_at_points
        Benchmark draw_path_at_points_2x
        Benchmark draw_path_linear_gradient
        Benchmark draw_path_linear_gradient_2x
        Benchmark draw_rect
        Benchmark draw_rect_2x
        Benchmark show_text
        Benchmark show_text_2x
        Benchmark show_text_radial_gradient ... Failed
        Benchmark show_text_radial_gradient_2x ... Failed
Benchmarking backend: quartz ... Not available
Benchmarking backend: pdf ... Not available
Benchmarking backend: ps
        Benchmark draw_image
        Benchmark draw_marker_at_points ... Failed
        Benchmark draw_path
        Benchmark draw_path_at_points ... Failed
        Benchmark draw_path_linear_gradient
        Benchmark draw_rect
        Benchmark show_text ... Failed
        Benchmark show_text_radial_gradient ... Failed
Benchmarking backend: svg
        Benchmark draw_image
        Benchmark draw_marker_at_points ... Failed
        Benchmark draw_path
        Benchmark draw_path_at_points ... Failed
        Benchmark draw_path_linear_gradient
        Benchmark draw_rect
        Benchmark show_text
        Benchmark show_text_radial_gradient

@capn-freako
Copy link
Author

Here are all outputs containing the word "text" in their filenames.
kiva agg show_text
kiva agg show_text_2x
kiva agg show_text_radial_gradient
kiva agg show_text_radial_gradient_2x
qpainter show_text
qpainter show_text_2x
svg show_text
svg show_text_radial_gradient

@capn-freako
Copy link
Author

  • the qpainter backend failure looks like a genuine bug

I just noticed this, in the first few lines of that particular backtrace:

Traceback (most recent call last):
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\qt4\base_window.py", line 255, in paintEvent
    self.handler.paintEvent(event)
  File "C:\Users\capnf\anaconda3\envs\pybert-dev\lib\site-packages\enable\qt4\base_window.py", line 90, in paintEvent
    self._enable_window._paint(event)

It looks like my (locally built) Enable package has "hard coded" the selection of Qt4, as opposed to Qt5.
Am I reading that correctly?
If so, it's strange, for two reasons:

  1. I've been in a concerted effort to push this whole thing towards Qt5, in hopes that that might solve my small font problem.
  2. I don't think I have Qt4 installed:
$ conda list qt
# packages in environment at C:\Users\capnf\anaconda3\envs\pybert-dev:
#
# Name                    Version                   Build  Channel
pyqt                      5.15.7           py38hd77b12b_0
pyqt5-sip                 12.11.0          py38hd77b12b_0
qt-main                   5.15.6               hf0cf448_0    conda-forge
qt-webengine              5.15.9               hb9a9bb5_4
qtconsole                 5.3.2            py38haa95532_0
qtpy                      2.2.0            py38haa95532_0
qtwebkit                  5.212                h0db62b3_6    conda-forge

It all seems to be version 5.

Here's my build YAML for Enable; see any problems?

{% set name = "enable" %}
{% set version = "5.3.1" %}

package:
  name: "{{ name|lower }}"
  version: "{{ version }}"

source:
  git_url: https://github.com/enthought/{{name}}.git
  git_rev: {{version}}

build:
  number: 1
  script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "

requirements:
  build:
    - setuptools
    - git
    - cmake
    - swig =3
    # - {{compiler('c')}}
    # - {{ compiler('cxx') }}
    # - {{ cdt('xorg-x11-devel') }}  # [linux]
    # - vs2017_win-64
    - vs2019_win-64
  host:
    - fonttools
    - numpy
    - pillow
    - pip
    - pyface >=7.4.2
    - pyparsing
    - python
    - six
    - traitsui
    - Cython
  run:
    - fonttools
    - numpy
    - pillow
    - pyface >=7.4.2
    - pyparsing
    - python
    - six
    - traitsui

test:
  imports:
    - enable
    - enable.drawing
    - enable.gadgets
    - enable.layout
    - enable.null
    - enable.primitives
    # - enable.pyglet_backend
    - enable.qt4
    - enable.savage
    - enable.savage.compliance
    - enable.savage.svg
    - enable.savage.svg.backends
    - enable.savage.svg.backends.kiva
    - enable.savage.svg.backends.null
    - enable.savage.svg.backends.wx
    - enable.savage.svg.css
    - enable.savage.svg.tests
    - enable.savage.svg.tests.css
    - enable.savage.trait_defs
    - enable.savage.trait_defs.ui
    - enable.savage.trait_defs.ui.qt4
    - enable.savage.trait_defs.ui.wx
    - enable.tests
    - enable.tests.primitives
    - enable.tests.qt4
    - enable.tests.tools
    # - enable.tests.tools.apptools
    - enable.tests.wx
    - enable.tools
    - enable.tools.apptools
    - enable.tools.pyface
    - enable.tools.toolbars
    - enable.trait_defs
    - enable.trait_defs.ui
    - enable.trait_defs.ui.qt4
    - enable.trait_defs.ui.wx
    # - enable.vtk_backend
    - enable.wx
    - kiva
    - kiva.agg
    - kiva.agg.tests
    - kiva.fonttools
    - kiva.fonttools.tests
    - kiva.quartz
    - kiva.tests
    - kiva.tests.agg
    - kiva.trait_defs
    - kiva.trait_defs.ui
    - kiva.trait_defs.ui.wx

about:
  home: "https://github.com/enthought/enable/"
  license: "BSD"
  license_family: "BSD"
  license_file: ""
  summary: "low-level drawing and interaction"
  doc_url: ""
  dev_url: ""

extra:
  recipe-maintainers:
    - capn-freako

@capn-freako
Copy link
Author

In terms of the original problem, if you are having issues with high-dpi displays, in recent versions of enable you can use Item(..., editor=ComponentEditor(..., high_resolution=False)) to render at 72-ish DPI if you have control over the editor. That may be something else you can try as a work-around.

I tried this, but it didn't change the size of my plot axis labels/numbers.
Here's an example with the application full-screened:

image

@corranwebster
Copy link
Contributor

You can safely ignore the qt4 in path names - this is a historical artefact from earlier iterations of toolkit selection where the toolkit name mapped to directories. The qt4 modules in fact contain code that runs on PyQt5, PySide2 and PyQt6 - we will likely rename them in the next major release of Pyface and TraitsUI, but it would be a potentially breaking change.

The actual mapping between toolkit names and modules is now handled by more standard setuptools entrypoints.

@corranwebster
Copy link
Contributor

Sorry, yes, it is the "kiva.agg" backend. And some of the benchmarks are only in the main, not in the 5.3 release branch, so apologies for any confusion - this is probably good enough.

The output of the benchmark looked normal-ish (there's one that is clearly messed up, it would be good to know which one it was, but I suspect it's not the agg/image backend). You can get more info by opening the HTML file in the output directory.

I am now suspicious that this could be an issue with font selection on Windows. Do you know if the text is still small when you use a regular DPI display?

@capn-freako
Copy link
Author

You can get more info by opening the HTML file in the output directory.

The messed up one is qpainter.

@capn-freako
Copy link
Author

Do you know if the text is still small when you use a regular DPI display?

It is not. Things look normal on a "regular" (i.e. - not high DPI) resolution display.

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

2 participants