from datetime import date
from subprocess import Popen, PIPE
from itertools import chain
from os import path
__all__ = ['GetDate', 'GetFilename', 'GetDirectory', 'GetSavename', 'GetText',
'InfoMessage', 'Question', 'Warning', 'ErrorMessage',
'Notification', 'TextInfo', 'Progress','List' ]
__doc__ = """PyZenity is an easy to use interface to Zenity for Python.
Zenity is normally called from scripts by invoking it with a multitude of
command line parameters that it uses to construct its interfaces. This
module hides the details of invoking the command and presents simple API
functions like:
cancel = Question('Should I cancel the operation?')
Each function takes optional kwargs parameters. This is to allow the use of
general Zenity parameters such as:
title - Set the dialog title
window_icon - Set the window icon
ok_label - Set the text for the Ok label
cancel_label - Set the text for the Cancel label
height - Set the height
width - Set the width
timeout - Set the dialog timeout in seconds"""
zen_exec = 'zenity'
def run_zenity(type, *args):
return Popen([zen_exec, type] + list(args), stdin=PIPE, stdout=PIPE)
kw_subst = {
'window_icon': 'window-icon',
'ok_label': 'ok-label',
'cancel_label': 'cancel-label'
}
def kwargs_helper(kwargs):
"""This function preprocesses the kwargs dictionary to sanitize it."""
args = []
for param, value in kwargs.items():
param = kw_subst.get(param, param)
args.append((param, value))
return args
def GetDate(text=None, selected=None, **kwargs):
"""Prompt the user for a date.
This will raise a Zenity Calendar Dialog for the user to pick a date.
It will return a datetime.date object with the date or None if the
user hit cancel.
text - Text to be displayed in the calendar dialog.
selected - A datetime.date object that will be the pre-selected date.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--date-format=%d/%m/%Y']
if text:
args.append('--text=%s' % text)
if selected:
args.append('--day=%d' % selected.day)
args.append('--month=%d' % selected.month)
args.append('--year=%d' % selected.year)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--calendar', *args)
if p.wait() == 0:
retval = p.stdout.read().strip()
day, month, year = [int(x) for x in retval.split('/')]
return date(year, month, day)
def GetFilename(multiple=False, sep='|', **kwargs):
"""Prompt the user for a filename.
This will raise a Zenity File Selection Dialog. It will return a list with
the selected files or None if the user hit cancel.
multiple - True to allow the user to select multiple files.
sep - Token to use as the path separator when parsing Zenity's return
string.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
if multiple:
args.append('--multiple')
if sep != '|':
args.append('--separator=%s' % sep)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--file-selection', *args)
if p.wait() == 0:
return p.stdout.read()[:-1].split('|')
def GetDirectory(multiple=False, selected=None, sep=None, **kwargs):
"""Prompt the user for a directory.
This will raise a Zenity Directory Selection Dialog. It will return a
list with the selected directories or None if the user hit cancel.
multiple - True to allow the user to select multiple directories.
selected - Path to the directory to be selected on startup.
sep - Token to use as the path separator when parsing Zenity's return
string.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--directory']
if multiple:
args.append('--multiple')
if selected:
if not path.lexists(selected):
raise ValueError("File %s does not exist!" % selected)
args.append('--filename=%s' % selected)
if sep:
args.append('--separator=%s' % sep)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--file-selection', *args)
if p.wait() == 0:
return p.stdout.read().strip().split('|')
def GetSavename(default=None, **kwargs):
"""Prompt the user for a filename to save as.
This will raise a Zenity Save As Dialog. It will return the name to save
a file as or None if the user hit cancel.
default - The default name that should appear in the save as dialog.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--save']
if default:
args.append('--filename=%s' % default)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--file-selection', *args)
if p.wait() == 0:
return p.stdout.read().strip().split('|')
def Notification(text=None, window_icon=None, **kwargs):
"""Put an icon in the notification area.
This will put an icon in the notification area and return when the user
clicks on it.
text - The tooltip that will show when the user hovers over it.
window_icon - The stock icon ("question", "info", "warning", "error") or
path to the icon to show.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
if text:
args.append('--text=%s' % text)
if window_icon:
args.append('--window-icon=%s' % window_icon)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--notification', *args)
p.wait()
def List(column_names, title=None, boolstyle=None, editable=False,
select_col=None, sep='|', data=[], **kwargs):
"""Present a list of items to select.
This will raise a Zenity List Dialog populated with the colomns and rows
specified and return either the cell or row that was selected or None if
the user hit cancel.
column_names - A tuple or list containing the names of the columns.
title - The title of the dialog box.
boolstyle - Whether the first columns should be a bool option ("checklist",
"radiolist") or None if it should be a text field.
editable - True if the user can edit the cells.
select_col - The column number of the selected cell to return or "ALL" to
return the entire row.
sep - Token to use as the row separator when parsing Zenity's return.
Cells should not contain this token.
data - A list or tuple of tuples that contain the cells in the row. The
size of the row's tuple must be equal to the number of columns.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
for column in column_names:
args.append('--column=%s' % column)
if title:
args.append('--title=%s' % title)
if boolstyle:
if not (boolstyle == 'checklist' or boolstyle == 'radiolist'):
raise ValueError('"%s" is not a proper boolean column style.'
% boolstyle)
args.append('--' + boolstyle)
if editable:
args.append('--editable')
if select_col:
args.append('--print-column=%s' % select_col)
if sep != '|':
args.append('--separator=%s' % sep)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
for datum in chain(*data):
args.append(str(datum))
p = run_zenity('--list', *args)
if p.wait() == 0:
return p.stdout.read().strip().split(sep)
def ErrorMessage(text, **kwargs):
"""Show an error message dialog to the user.
This will raise a Zenity Error Dialog with a description of the error.
text - A description of the error.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--text=%s' % text]
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
run_zenity('--error', *args).wait()
def InfoMessage(text, **kwargs):
"""Show an info message dialog to the user.
This will raise a Zenity Info Dialog displaying some information.
text - The information to present to the user.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--text=%s' % text]
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
run_zenity('--info', *args).wait()
def Question(text, **kwargs):
"""Ask the user a question.
This will raise a Zenity Question Dialog that will present the user with an
OK/Cancel dialog box. It returns True if the user clicked OK; False on
Cancel.
text - The question to ask.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--text=%s' % text]
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
return run_zenity('--question', *args).wait() == 0
def Warning(text, **kwargs):
"""Show a warning message dialog to the user.
This will raise a Zenity Warning Dialog with a description of the warning.
It returns True if the user clicked OK; False on cancel.
text - A description of the warning.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = ['--text=%s' % text]
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
return run_zenity('--warning', *args).wait() == 0
def Progress(text='', percentage=0, auto_close=False, pulsate=False, **kwargs):
"""Show a progress dialog to the user.
This will raise a Zenity Progress Dialog. It returns a callback that
accepts two arguments. The first is a numeric value of the percent
complete. The second is a message about the progress.
NOTE: This function sends the SIGHUP signal if the user hits the cancel
button. You must connect to this signal if you do not want your
application to exit.
text - The initial message about the progress.
percentage - The initial percentage to set the progress bar to.
auto_close - True if the dialog should close automatically if it reaches
100%.
pulsate - True is the status should pulsate instead of progress.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
if text:
args.append('--text=%s' % text)
if percentage:
args.append('--percentage=%s' % percentage)
if auto_close:
args.append('--auto-close=%s' % auto_close)
if pulsate:
args.append('--pulsate=%s' % pulsate)
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = Popen([zen_exec, '--progress'] + args, stdin=PIPE, stdout=PIPE)
def update(percent, message=''):
if type(percent) == float:
percent = int(percent * 100)
p.stdin.write(str(percent) + '\n')
if message:
p.stdin.write('# %s\n' % message)
return p.returncode
return update
def GetText(text='', entry_text='', password=False, **kwargs):
"""Get some text from the user.
This will raise a Zenity Text Entry Dialog. It returns the text the user
entered or None if the user hit cancel.
text - A description of the text to enter.
entry_text - The initial value of the text entry box.
password - True if text entered should be hidden by stars.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
if text:
args.append('--text=%s' % text)
if entry_text:
args.append('--entry-text=%s' % entry_text)
if password:
args.append('--hide-text')
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--entry', *args)
if p.wait() == 0:
return p.stdout.read()[:-1]
def TextInfo(filename=None, editable=False, **kwargs):
"""Show the text of a file to the user.
This will raise a Zenity Text Information Dialog presenting the user with
the contents of a file. It returns the contents of the text box.
filename - The path to the file to show.
editable - True if the text should be editable.
kwargs - Optional command line parameters for Zenity such as height,
width, etc."""
args = []
if filename:
args.append('--filename=%s' % filename)
if editable:
args.append('--editable')
for generic_args in kwargs_helper(kwargs):
args.append('--%s=%s' % generic_args)
p = run_zenity('--text-info', *args)
if p.wait() == 0:
return p.stdout.read()