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

Exception in callback (canvas error) on exit. #360

Closed
mpmc opened this Issue Feb 3, 2018 · 1 comment

Comments

Projects
None yet
2 participants
@mpmc
Contributor

mpmc commented Feb 3, 2018

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9297, in __checkCopyAndPaste
    self.copyAndPaste.setUp(widget)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 12737, in setUp
    if widget.tag_ranges("sel"):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3400, in tag_ranges
    self._w, 'tag', 'ranges', tagName))
_tkinter.TclError: invalid command name ".!canvasdnd.!frame2.!ajtext"
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 3331, in <lambda>
    return lambda *args: funcName(param)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9537, in <lambda>
    ('Copy', lambda e: self.__copyAndPasteHelper("Copy"), "C", False),
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9319, in __copyAndPasteHelper
    self.copyAndPaste.setUp(widget)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 12737, in setUp
    if widget.tag_ranges("sel"):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3400, in tag_ranges
    self._w, 'tag', 'ranges', tagName))
_tkinter.TclError: invalid command name ".!canvasdnd.!frame2.!ajtext"
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 3331, in <lambda>
    return lambda *args: funcName(param)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9539, in <lambda>
    ('Select All', lambda e: self.__copyAndPasteHelper("Select All"), "A", True if gui.GET_PLATFORM() == gui.MAC else False),
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9319, in __copyAndPasteHelper
    self.copyAndPaste.setUp(widget)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 12737, in setUp
    if widget.tag_ranges("sel"):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3400, in tag_ranges
    self._w, 'tag', 'ranges', tagName))
_tkinter.TclError: invalid command name ".!canvasdnd.!frame2.!ajtext"
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9297, in __checkCopyAndPaste
    self.copyAndPaste.setUp(widget)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 12737, in setUp
    if widget.tag_ranges("sel"):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3400, in tag_ranges
    self._w, 'tag', 'ranges', tagName))
_tkinter.TclError: invalid command name ".!canvasdnd.!frame2.!ajtext"
Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 1702, in __call__
    return self.func(*args)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 3331, in <lambda>
    return lambda *args: funcName(param)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9539, in <lambda>
    ('Select All', lambda e: self.__copyAndPasteHelper("Select All"), "A", True if gui.GET_PLATFORM() == gui.MAC else False),
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 9319, in __copyAndPasteHelper
    self.copyAndPaste.setUp(widget)
  File "/home/mark/.local/lib/python3.6/site-packages/appJar/appjar.py", line 12737, in setUp
    if widget.tag_ranges("sel"):
  File "/usr/lib/python3.6/tkinter/__init__.py", line 3400, in tag_ranges
    self._w, 'tag', 'ranges', tagName))
_tkinter.TclError: invalid command name ".!canvasdnd.!frame2.!ajtext"
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  gui5.py
#
#  Copyright 2018 Mark Clarkstone <git@markclarkstone.co.uk>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#
#
import gettext
import traceback
import appJar
import hs602

gettext.install('Hs602util')


class Gui(appJar.gui):
    """Simple HS602 utility using appJar."""
    def __init__(self, *args):
        super().__init__()
        # Set title, enable edit menu and setup controller.
        self.title = _('HS602 Utility')
        self.addMenuEdit(False)
        self.controller = hs602.Controller()
        self.controller_cache = {}
        # Start the app!
        self.start()

    # Helper methods.
    def start(self, *args):
        """Trigger the default window."""
        # self.discover()
        self.error('foobar!')

    def callback(self, method, callback=None, *args, **kwargs):
        """Simple (queued) callback.

        :param method: Method to thread.
        :param callback: Optional method to receive the result.
        :param args: Positional arguments (for the threaded method).
        :param kwargs: Keyword arguments (for the threaded method).
        """
        text = _('Callback "{}" isn\'t callable').format(callback)

        def run():
            """Run the method in a new thread, catch errors."""
            try:
                ret = method(*args, **kwargs)
                # Queue the run_callback!
                self.queueFunction(run_callback, ret)
            except Exception as exc:
                self.error(exc)

        def run_callback(result):
            """Run the callback, pass the result, catch errors."""
            try:
                # Only run if callable!
                if callable(callback):
                    callback(result)
                else:
                    self.warn(text)
            except Exception as exc:
                self.error(exc)

        # Run!
        self.thread(run)

    def values(self, **kwargs):
        """Get all values, merge, convert & return as dictionary.

        kwargs will be _appended_ to the input list.

        :param convert: Convert.
        """
        merge = dict()
        convert = kwargs.get('convert', True)

        # All available inputs.
        inputs = [
                  self.getAllOptionBoxes(),
                  self.getAllEntries(),
                  self.getAllCheckBoxes(),
                  self.getAllRadioButtons(),
                  self.getAllProperties(),
                  self.getAllScales(),
                  self.getAllMeters(),
                  self.getAllSpinBoxes(),
                  self.getAllListBoxes(),
                  self.getAllDatePickers(),
                  kwargs,
        ]
        for dictionary in inputs:
            merge.update(dictionary)
            for key, value in merge.items():
                # Remove start/end spaces from values.
                if isinstance(value, str):
                    merge[key] = value.strip()
                if convert is True:
                    if isinstance(value, float):
                        merge[key] = int(round(value))

        return merge

    # User interface methods.
    def error(self, exc):
        """Display an error."""
        # Properties.
        # Label.
        label_text = _('Sorry there\'s a problem, the details of '
                       'which are below.\nIf the problem persists, '
                       'please report it.\n\nThank you.')
        # Button.
        button_text = _('Quit')
        button_tooltip = _('Close the utility')
        # Textarea.
        textarea_text = _('No traceback available')
        # Attempt to get the traceback.
        try:
            textarea_text = ''.join(traceback.format_tb(
                                    exc.__traceback__))
        except AttributeError:
            pass

        # Format.
        textarea_text = _('{}\n\n{}').format(exc, textarea_text)
        label_text = '{}'.format(label_text)
        button_text = '{}'.format(button_text)

        def show():
            """Display the error."""
            # Reset the GUI!
            self.removeAllWidgets()

            # Add widgets - error label (top).
            self.label(label_text, sticky='nw', stretch='none',
                       pos=(0, 0))
            self.setLabelAlign(label_text, 'left')

            # Quit button (bottom).
            self.button(button_text, self.stop, pos=(2, 0),
                        sticky='nesw', stretch='none')
            self.setButtonTooltip(button_text,
                                  '{}'.format(button_tooltip))
            # Text area.
            self.text(textarea_text, textarea_text, pos=(1, 0),
                      sticky='nesw', stretch='both')
            self.disableTextArea(textarea_text)

        show()

    def msg(self, text=None):
        """Clear the widgets and a show message - used during callbacks.

        text: Optional message to show.
        """
        text = text or _('\u231B Please wait..')
        text = '{}'.format(text)
        # Clear and display the message.
        self.removeAllWidgets()
        self.label(text)
        self.setLabelAlign(text, 'center')

    def discover(self):
        """Find and display available devices."""
        # Nested method to display discovered devices.
        def show(devices):
            # Show an error if no devices are found.
            title = _('No Devices')
            msg = _('There were no devices found on your network!\n'
                    'Try again (Yes) or connect manually (No)?')

            if not isinstance(devices, list) or not len(devices) > 0:
                ret = self.popUp('{}'.format(title),
                                 '{}'.format(msg), 'yesno')
                if ret:
                    return self.discover()
                return self.manual()

            # Show the device list.
            print(devices)

        # Show msg & launch callback.
        self.msg(_('\u231B Searching for devices, please wait..'))
        self.callback(self.controller._devices_get, show)

    def manual(self):
        """Manual connection."""
        print('Manual!')


def main(args):
    app = Gui(*args)
    app.go()
    return 0


if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv))

Tried to reproduce it again (by trying to copy/paste the text), but can't, I must've hit something that rarely occurs.

The GUI quit but the script was still running, it lagged then barfed that error & exited.

@jarvisteach jarvisteach added the bug label Feb 14, 2018

@jarvisteach jarvisteach added this to the 1.0 milestone Feb 14, 2018

@jarvisteach

This comment has been minimized.

Owner

jarvisteach commented Feb 14, 2018

Closing this, as I hope #375 changes will prevent it from occurring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment