Skip to content

Instantly share code, notes, and snippets.

@CarstenSchelp
Last active November 29, 2019 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CarstenSchelp/e22795157ea24bdd470d8c38598d363a to your computer and use it in GitHub Desktop.
Save CarstenSchelp/e22795157ea24bdd470d8c38598d363a to your computer and use it in GitHub Desktop.
Simple interactive IPython- or Jupyter Notebook widget-based file selection dialog
'''
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