IPython Notebook: открыть/выбрать файл с графическим интерфейсом (Qt Dialog)

Когда вы выполняете тот же анализ в ноутбуке в разных файлах данных, может быть удобно графически выбирать файл данных.

В моих сценариях python я обычно реализую диалог QT, который возвращает имя файла для выбранного файла:

from PySide import QtCore, QtGui

def gui_fname(dir=None):
    """Select a file via a dialog and return the file name.
    """
    if dir is None: dir ='./'
    fname = QtGui.QFileDialog.getOpenFileName(None, "Select data file...", 
            dir, filter="All files (*);; SM Files (*.sm)")
    return fname[0]

Однако запуск этой функции из ноутбука

full_fname = gui_fname()

заставляет ядро ​​умирать (и перезапускать):

Интересно, что замазка этой 3 команды в 3 отдельные ячейки работает

%matplotlib qt
full_fname = gui_fname()
%matplotlib inline

но когда я помещаю эти команды в одну ячейку, ядро ​​снова умирает.

Это предотвращает создание функции типа gui_fname_ipynb(), которая прозрачно позволяет выбрать файл с графическим интерфейсом.

Для удобства я создал блокнот, иллюстрирующий проблему:

Любое предложение о том, как выполнить диалог выбора файлов из IPython Notebook?

Ответ 1

Используя Anaconda 5.0.0 в Windows (Python 3.6.2, IPython 6.1.0), у меня работают следующие две опции.

ВАРИАНТ 1: Полностью в блокноте Jupyter:

Ячейка 1:

%gui qt

from PyQt5.QtWidgets import QFileDialog

def gui_fname(dir=None):
    """Select a file via a dialog and return the file name."""
    if dir is None: dir ='./'
    fname = QFileDialog.getOpenFileName(None, "Select data file...", 
                dir, filter="All files (*);; SM Files (*.sm)")
    return fname[0]

CELL 2:

gui_fname()

Это работает для меня, но кажется немного... хрупким. Если я объединю эти две вещи в одну и ту же камеру, она рухнет. Или, если я опущу %gui qt, он падает. Если я "перезапустить ядро и запустить все ячейки", это не работает. Так что мне нравится этот другой вариант...

БОЛЬШЕ НАДЕЖНОГО ВАРИАНТА: отдельный скрипт, открывающий диалоговое окно в новом процессе

(На основе кода mkrog здесь.)

ПОСТАВИТЬ СЛЕДУЮЩИЙ В ОТДЕЛЬНОМ ПИФОНЕ СЦЕНАРИЙ blah.py:

from sys import executable, argv
from subprocess import check_output
from PyQt5.QtWidgets import QFileDialog, QApplication

def gui_fname(directory='./'):
    """Open a file dialog, starting in the given directory, and return
    the chosen filename"""
    # run this exact file in a separate process, and grab the result
    file = check_output([executable, __file__, directory])
    return file.strip()

if __name__ == "__main__":
    directory = argv[1]
    app = QApplication([directory])
    fname = QFileDialog.getOpenFileName(None, "Select a file...", 
            directory, filter="All files (*)")
    print(fname[0])

... И В ВАШЕЙ ЗАПИСИ JUPYTER

import blah
blah.gui_fname()

Ответ 2

Это поведение было ошибкой в ​​IPython:

https://github.com/ipython/ipython/issues/4997

который был исправлен здесь:

https://github.com/ipython/ipython/pull/5077

Функция открытия диалога gui должна работать с текущим мастером и в выпуске oncoming 2.0.

На сегодняшний день последняя версия 1.x(1.2.1) не включает резерв исправления.

РЕДАКТИРОВАТЬ: Код примера по-прежнему вызывает сбой IPython 2.x, см. эту проблему.

Ответ 3

У меня есть универсальный код, где он делает свою работу без проблем. Вот мое предположение:

try:
    from tkinter import Tk
    from tkFileDialog import askopenfilenames
except:
    from tkinter import Tk
    from tkinter import filedialog

Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
filenames = filedialog.askopenfilenames() # show an "Open" dialog box and return the path to the selected file

print (filenames)

надеюсь, что это может быть полезно