Last active
November 29, 2019 15:47
-
-
Save CarstenSchelp/e22795157ea24bdd470d8c38598d363a to your computer and use it in GitHub Desktop.
Simple interactive IPython- or Jupyter Notebook widget-based file selection dialog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
A simple interactive file selection class based on IPython "Selection" widget. | |
Navigates through directories and displays all files that match the "file_pattern" | |
parameter. | |
''' | |
import ipywidgets as widgets | |
import glob | |
import os | |
class FileSelection: | |
''' | |
Initialize a selection object, optionally taking the start | |
directory and the file pattern as parameters. | |
''' | |
def __init__(self, start_directory=None, caption='Select File', file_pattern='*'): | |
self._path = start_directory | |
self._caption = caption | |
self._file_pattern = file_pattern | |
self._widget = None | |
if not self._path or not os.path.isdir(self._path): | |
self._path = os.path.abspath(os.path.curdir) | |
def select_file(self, success): | |
''' | |
Start the actual selection. "success" is a callback/handler that gets called | |
when a file has been selected. The only parameter of the "success" handler is | |
the selected filepath. | |
''' | |
self._success = success | |
self._widget = widgets.Select(disabled=False) | |
self._update_widget() | |
display(self._widget) | |
def _update_widget(self): | |
self._widget.options = self._collect_dir_entries() | |
self._widget.index = None | |
self._widget.description = f"{self._caption} {os.path.abspath(self._path)}" | |
self._widget.observe(self._file_selection_change) | |
def _collect_dir_entries(self): | |
all_entries = glob.glob(os.path.join(self._path, '*')) | |
dir_entries =[entry for entry in all_entries if os.path.isdir(entry)] | |
dir_entries.extend(glob.glob(f'{self._path}/{self._file_pattern}')) | |
dir_entries = [os.path.basename(os.path.normpath(entry)) for entry in dir_entries] | |
dir_entries.insert(0, '..') | |
return dir_entries | |
def _file_selection_change(self, change): | |
if not change.owner.value: | |
return | |
if not isinstance(change.new, str): | |
return | |
change.owner.unobserve(self._file_selection_change) | |
self._path = os.path.abspath(os.path.join(self._path, change.owner.value)) | |
if os.path.isdir(self._path): | |
self._update_widget() | |
else: | |
change.owner.close() | |
self._widget = None | |
self._success(self._path) | |
if __name__ == '__main__': | |
# Demo: | |
fs = FileSelection(file_pattern='*.py') | |
fs.select_file(lambda p: print('selected file:', p)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment