Прерывистый сбой ModalView с Pyinstaller - PullRequest
0 голосов
/ 25 апреля 2018

У меня есть App, который открывает ModalView всплывающее окно из Thread с помощью Clock.schedule_once() и использует Queue для ожидания закрытия всплывающего окна.Это прекрасно работает около 90% времени.Но иногда поток ожидает отклонения без отображения всплывающего окна.Этот сбой происходит только при запуске exe, созданного Pyinstaller, и только с первой попытки (т. Е. При первом нажатии кнопки «Выполнить тест»).Если первая попытка завершится успешно, все следующие попытки также будут успешными.

Я использую:

  • Pyinstaller версия 3.3.dev0 + 483c819
  • Windows 10

Я занимаюсь разработкой с использованием Python 3, но Pyinstaller создает код для запуска Python 2.7.14.Выходные данные отладки показывают только ожидаемые различия между успехом и неудачей.

Этот пример взят из гораздо более сложного приложения.Если кто-то может увидеть проблему или порекомендовать более надежный способ открытия ModalView из Thread, пожалуйста, сообщите мне.

main.py:

import threading

from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.modalview import ModalView

from kivy.compat import PY2
if PY2:
    from Queue import Queue
else:
    from queue import Queue


class TestLayout(FloatLayout):
    def __init__(self):
        super(TestLayout, self).__init__()

    def do_test(self, *arg):
        self.th = AThread()
        self.th.start()


class MyPopup(object):
    def __init__(self, callback):
        self.buttonCallback = callback
        dismiss_button = Button(text='Dismiss')
        dismiss_button.bind(on_press=self.butt)
        self.popup = ModalView(size_hint=(.5, .5), auto_dismiss=False)
        self.popup.add_widget(dismiss_button)

    def butt(self, *args):
        if self.popup is not None:
            self.popup.dismiss()
        if self.buttonCallback is not None:
            self.buttonCallback()

    def open(self, *args):
        self.popup.open()


class AThread(threading.Thread):
    def __init__(self):
        super(AThread, self).__init__()
        self.daemon = True
        self.pop = None
        self.queue = None

    def run(self):
        print('running')
        self.queue = Queue()
        self.pop = MyPopup(lambda: self.queue.put(None, False))
        Clock.schedule_once(self.pop.open)    # This should open the popup, but occasionally it does not
        print('waiting')
        self.queue.get(True)
        print('done waiting')
        self.queue = None


root = Builder.load_string( '''
TestLayout:
    Button:
        text: 'Run Test'
        on_press: root.do_test()
''')


class testApp(App):
    def build(self):
        return root


testApp().run()

main.spec:

# -*- mode: python -*-

from kivy.deps import sdl2, glew

block_cipher = None


a = Analysis(['main.py'],
             pathex=['C:\\Users\\John\\PyCharmProjects\\popupbug'],
             binaries=[],
             datas=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
          name='Test',
          debug=True,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True)

1 Ответ

0 голосов
/ 01 мая 2018

Оказывается, проблема в том, что основной поток висит в Kivy Clock (проверено путем некоторой трассировки) и фактически не выполняет метод self.pop.open.Похоже, это происходит только для Pyinstaller EXE-файла в Windows.Я тестировал тот же код с Pyinstaller в Ubuntu, без сбоев.Исправление / обходной путь заключается в использовании другого kivy Clock путем вставки следующего кода в начале main.py:

from kivy.config import Config
Config.set('kivy', 'kivy_clock', 'interrupt')

Это заставляет kivy использовать другой Clock и устраняетпроблема

...