-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Sat, 30 Aug 2008 01:49:26 +0200
Luca Bruno <[EMAIL PROTECTED]> wrote:

> Continued the work, as usual I've attached the .py file.
> It's almost complete for basic bug reporting.
> Please let me know what you think about.
> 

The frontend is now almost complete. It's missing the wrapper for querying a 
single report and submit more informations.
I've added the copyright.
I'm now trying to get it working in trunk.

Best regards,

- -- 
http://syx.googlecode.com - Smalltalk YX
http://lethalman.blogspot.com - Thoughts about computer technologies
http://www.ammazzatecitutti.org - Ammazzateci tutti
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAki5080ACgkQw9Qj+8Kak3FXIgCdEWon06/x62tweYtqxGuXLZUH
Yg4AoJBioO1ds7djAWP4cagUAnejkUmz
=LHID
-----END PGP SIGNATURE-----
# reportbuglib/reportbug_ui_gnome2.py
# GTK+ user interface for reportbug
#   Written by Luca Bruno <[EMAIL PROTECTED]>
#   Based on gnome-reportbug work done by Philipp Kern <[EMAIL PROTECTED]>
#   Copyright (C) 2006 Philipp Kern
#   Copyright (C) 2008 Luca Bruno
#
# This program is freely distributable per the following license:
#
##  Permission to use, copy, modify, and distribute this software and its
##  documentation for any purpose and without fee is hereby granted,
##  provided that the above copyright notice appears in all copies and that
##  both that copyright notice and this permission notice appear in
##  supporting documentation.
##
##  I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
##  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL I
##  BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
##  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
##  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
##  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
##  SOFTWARE.
#
# Version ##VERSION##; see changelog for revision history

import gtk
import sys
from gtk import gdk
import gobject
import re
import os

gdk.threads_init ()

from Queue import Queue
import threading

if __name__ == '__main__':
    sys.path.append ('..')

from reportbug_ui_text import ewrite
from reportbug_exceptions import NoPackage, NoBugs, NoNetwork, NoReport

ISATTY = True

# Utilities

def highlight (s):
    return '<b>%s</b>' % s

re_markup_free = re.compile ("<.*?>")

def markup_free (s):
    return re_markup_free.sub ("", s)

def ask_free (s):
    s = s.strip ()
    if s[-1] in ('?', ':'):
        return s[:-1]
    return s

def create_scrollable (widget):
    scrolled = gtk.ScrolledWindow ()
    scrolled.set_shadow_type (gtk.SHADOW_ETCHED_IN)
    scrolled.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    scrolled.add (widget)
    return scrolled

class ErrorDialog (gtk.MessageDialog):
    def __init__ (self, application):
        gtk.MessageDialog.__init__ (self, assistant, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                                    gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE)
        self.application = application
        self.connect ('response', self.on_response)

    def on_response (self, dialog, res):
        self.destroy ()

    def execute_operation (self, msg, yeshelp, nohelp, default=True, nowrap=False, ui=None):
        self.set_markup (msg+"?")
        self.show_all ()        

def error_dialog (message):
    dialog = gtk.MessageDialog (self, assistant, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                                gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, essage)
    dialog.connect ('response', lambda *args: dialog.destroy)
    dialog.set_title ('Reportbug')
    dialog.show_all ()

# BTS

class Bug (object):
    def __init__ (self, raw):
        # Skip the '#'
        raw = raw[1:]
        bits = re.split(r'[: ]', raw, 2)
        self.id, self.tag, self.data = bits
        # Remove [ and ]
        self.tag = self.tag[1:-1]
        self.data = self.data.strip ()
        self.package = self.data.split(']', 1)[0][1:]

        self.reporter = self.get_data ("Reported by:")
        self.date = self.get_data ("Date:")
        self.severity = self.get_data("Severity:").capitalize ()
        self.version = self.get_data ("Found in version")
        self.filed_date = self.get_data ("Filed")
        self.modified_date = self.get_data ("Modified")

        # Get rid of [package] which has been stored in self.package
        self.info = self.data.split(']', 1)[1][:self.data.index ("Reported by:")].strip ()
        if not self.info:
            self.info = '(no subject)'   

    def get_data (self, token):
        info = ''
        try:
            index = self.data.lower().index (token.lower ())
        except:
            return '(unknown)'

        i = index + len(token)
        while True:
            c = self.data[i]
            if c == ';':
                break
            info += c
            i += 1
        return info.strip ()

    def __iter__ (self):
        yield self.id
        yield self.tag
        yield self.package
        yield self.info
        yield self.reporter
        yield self.date
        yield self.severity
        yield self.version
        yield self.filed_date
        yield self.modified_date

class BugReport (object):
    def __init__ (self, message):
        lines = message.split ('\n')
        i = 0

        self.headers = []
        while i < len (lines):
            line = lines[i]
            i += 1
            if not line.strip ():
                break
            self.headers.append (line)

        store = 0
        info = []
        while i < len (lines):
            line = lines[i]
            info.append (line)
            i += 1
            if store < 2 and not line.strip():
                store += 1
                continue
            if store == 2 and (line.startswith ('-- ') or line.startswith ('** ')):
                break
            store = 0
        self.original_info = '\n'.join (info[:-3])

        self.others = '\n'.join (lines[i-1:])

    def get_others (self):
        return self.others

    def get_original_info (self):
        return self.original_info

    def get_subject (self):
        for header in self.headers:
            if 'Subject' in header:
                return header[len ('Subject: '):]

    def set_subject (self, subject):
        for i in range (len (self.headers)):
            if 'Subject' in self.headers[i]:
                self.headers[i] = 'Subject: '+subject
                break

    def create_message (self, info):
        message = """%s

%s


%s""" % ('\n'.join (self.headers), info,self.others)
        return message

        
# Application

class ReportbugApplication (threading.Thread):
    def __init__ (self):
        threading.Thread.__init__ (self)
        self.queue = Queue ()
        
    def run (self):
        gtk.main ()

    def get_last_value (self):
        return self.queue.get ()

    def put_next_value (self):
        self.queue.put (self.next_value)
        self.next_value = None
    
    def set_next_value (self, value):
        self.next_value = value

    @staticmethod
    def create_idle_callback (func, *args, **kwargs):
        def callback ():
            func (*args, **kwargs)
            return False
        return callback

    def run_once_in_main_thread (self, func, *args, **kwargs):
        gobject.idle_add (self.create_idle_callback (func, *args, **kwargs))

application = ReportbugApplication ()

# Connection with reportbug

# Syncronize "pipe" with reportbug

class SyncError (RuntimeError):
    def __init__ (self, result):
        RuntimeError.__init__ ()
        self.result = result

class ReportbugConnector (object):
    def execute_operation (self, *args, **kwargs):
        pass

    def sync_pre_operation (cls, *args, **kwargs):
        return args, kwargs
        
# Assistant

class Page (ReportbugConnector):
    next_page_num = 0
    page_type = gtk.ASSISTANT_PAGE_CONTENT
    default_complete = False
    side_image = "/usr/share/pixmaps/debian-logo.png"

    def __init__ (self, assistant):
        self.assistant = assistant
        self.application = assistant.application
        self.widget = self.create_widget ()
        self.widget.page = self
        self.widget.set_border_width (6)
        self.widget.show_all ()
        self.page_num = Page.next_page_num
        Page.next_page_num += 1

    def execute_operation (self, *args, **kwargs):
        self.switch_in ()
        self.connect_signals ()
        self.execute (*args, **kwargs)

    def connect_signals (self):
        pass

    def set_page_complete (self, complete):
        self.assistant.set_page_complete (self.widget, complete)

    def set_page_type (self, type):
        self.assistant.set_page_type (self.widget, type)

    def set_page_title (self, title):
        if title:
            self.assistant.set_page_title (self.widget, title)

    # The user will see this as next page
    def switch_in (self):
        self.assistant.insert_page (self.widget, self.page_num)
        self.set_page_complete (self.default_complete)
        self.set_page_type (self.page_type)
        self.assistant.set_page_side_image (self.widget, gdk.pixbuf_new_from_file (self.side_image))
        self.assistant.set_next_page (self)
        self.set_page_title ("Reportbug")

    # The user forwarded the assistant to see the next page
    def switch_out (self):
        pass

    def is_valid (self, value):
        return bool (value)

    def validate (self, *args, **kwargs):
        value = self.get_value ()
        if self.is_valid (value):
            self.assistant.application.set_next_value (value)
            self.set_page_complete (True)
        else:
            self.set_page_complete (False)

class IntroPage (Page):
    page_type = gtk.ASSISTANT_PAGE_INTRO
    default_complete = True

    def create_widget (self):
        vbox = gtk.VBox ()
        vbox.pack_start (gtk.Label ("ReportBUG"))
        return vbox

class GetStringPage (Page):
    def create_widget (self):
        vbox = gtk.VBox (spacing=12)
        self.label = gtk.Label ()
        self.label.set_line_wrap (True)
        self.entry = gtk.Entry ()
        vbox.pack_start (self.label, expand=False)
        vbox.pack_start (self.entry, expand=False)
        return vbox

    def connect_signals (self):
        self.entry.connect ('changed', self.validate)

    def get_value (self):
        return self.entry.get_text ()

    def execute (self, prompt, options=None, force_prompt=False, default=''):
        self.label.set_text (prompt)
        self.entry.grab_focus ()

class TreePage (Page):
    value_column = None

    def __init__ (self, *args, **kwargs):
        Page.__init__ (self, *args, **kwargs)
        self.selection = self.view.get_selection()

    def connect_signals (self):
        self.selection.connect ('changed', self.validate)

    def get_value (self):
        model, paths = self.selection.get_selected_rows ()
        multiple = self.selection.get_mode () == gtk.SELECTION_MULTIPLE
        result = []
        for path in paths:
            result.append (markup_free (model.get_value (model.get_iter (path), self.value_column)))
        if result and not multiple:
            return result[0]
        return result

class MenuPage (TreePage):
    value_column = 0

    def create_widget (self):
        vbox = gtk.VBox (spacing=12)
        self.label = gtk.Label ()
        vbox.pack_start (self.label, expand=False)

        self.view = gtk.TreeView ()
        scrolled = create_scrollable (self.view)
        vbox.pack_start (scrolled)
        vbox.show_all ()
        return vbox

    def is_valid (self, value):
        if self.empty_ok:
            return True
        else:
            return bool (value)

    def execute (self, par, options, prompt, default=None, any_ok=False,
                 order=None, extras=None, multiple=False, empty_ok=False):
        self.empty_ok = empty_ok

        self.label.set_text (par)

        self.model = gtk.ListStore (str, str)
        self.view.set_model (self.model)

        if multiple:
            self.selection.set_mode (gtk.SELECTION_MULTIPLE)

        self.view.append_column (gtk.TreeViewColumn ('Option', gtk.CellRendererText (), markup=0))
        self.view.append_column (gtk.TreeViewColumn ('Description', gtk.CellRendererText (), text=1))

        default_iter = None
        if isinstance (options, dict):
            for option, desc in options.iteritems ():
                iter = self.model.append ((highlight (option), desc))
                if option == default:
                    default_iter = iter
        else:
            for row in options:
                iter = self.model.append ((highlight (row[0]), row[1]))
                if row[0] == default:
                    default_iter = iter

        if default_iter:
            self.selection.select_iter (default_iter)

class HandleBTSQueryPage (TreePage):
    default_complete = True
    value_column = 0

    def sync_pre_operation (self, package, bts, mirrors=None, http_proxy="", queryonly=False, screen=None,
                            archived='no', source=False, version=None):
        import debianbts

        sysinfo = debianbts.SYSTEMS[bts]
        root = sysinfo.get('btsroot')
        if not root:
            ewrite("%s bug tracking system has no web URL; bypassing query.\n",
                   sysinfo['name'])
            return

        if isinstance(package, basestring):
            pkgname = package
            if source:
                pkgname += ' (source)'

            progress_label = 'Querying %s bug tracking system for reports on %s' % (debianbts.SYSTEMS[bts]['name'], pkgname)
        else:
            progress_label = 'Querying %s bug tracking system for reports %s' % (debianbts.SYSTEMS[bts]['name'], ' '.join([str(x) for x in package]))


        self.application.run_once_in_main_thread (self.assistant.set_progress_label, progress_label)

        result = None
        try:
            (count, sectitle, hierarchy) = debianbts.get_reports (
                package, bts, mirrors=mirrors, version=version,
                http_proxy=http_proxy, archived=archived, source=source)

            if not count:
                if hierarchy == None:
                    raise NoPackage
                else:
                    raise NoBugs
            else:
                if count > 1:
                    sectitle = '%d bug reports found' % (count,)
                else:
                    sectitle = 'One bug report found'

                report = []
                for category, bugs in hierarchy:
                    buglist = []
                    for bug in bugs:
                        buglist.append (Bug (bug))
                    report.append ((category, buglist))

                return (report, sectitle), {}

        except (IOError, NoNetwork):
            error_dialog ("Unable to connect to %s BTS." % sysinfo['name'])
        except NoPackage:
            error_dialog ('No record of this package found.')
            raise NoPackage

        if result and result < 0:
            raise NoReport

        raise SyncReturn (result)

    def create_widget (self):
        vbox = gtk.VBox (spacing=12)
        self.label = gtk.Label ("List of bugs. Select a bug to retrieve and submit more informations.")
        vbox.pack_start (self.label, expand=False)

        self.view = gtk.TreeView ()
        scrolled = create_scrollable (self.view)
        vbox.pack_start (scrolled)
        return vbox

    def is_valid (self, value):
        return True

    def get_value (self):
        return None

    def execute (self, buglist, sectitle):
        self.label.set_text ("%s. Double-click a bug to retrieve and submit more informations." % sectitle)

        columns = ['ID', 'Tag', 'Package', 'Description', 'Reporter', 'Date', 'Severity', 'Version',
                   'Filed date', 'Modified date']

        self.model = gtk.TreeStore (*([str] * len (columns)))
        self.view.set_model (self.model)

        for col in zip (columns, range (len (columns))):
            self.view.append_column (gtk.TreeViewColumn (col[0], gtk.CellRendererText (), text=col[1]))

        for category in buglist:
            row = [None] * len (columns)
            row[3] = category[0]
            iter = self.model.append (None, row)
            for bug in category[1]:
                self.model.append (iter, list (bug))

class DisplayReportPage (Page):
    default_complete = True

    def create_widget (self):
        self.view = gtk.TextView ()
        self.view.set_editable (False)
        scrolled = create_scrollable (self.view)
        return scrolled

    def execute (self, message, *args):
        self.view.get_buffer().set_text (message % args)

class LongMessagePage (Page):
    default_complete = True
    
    def create_widget (self):
        self.label = gtk.Label ()
        eb = gtk.EventBox ()
        eb.add (self.label)
        return eb

    def execute (self, message, *args):
        message = message % args
        self.label.set_text (message)
        # Reportbug should use final_message, so emulate it
        if ('999999' in message):
            self.set_page_type (gtk.ASSISTANT_PAGE_CONFIRM)
            self.set_page_title ("Thanks for your report")

class FinalMessagePage (LongMessagePage):
    page_type = gtk.ASSISTANT_PAGE_CONFIRM
    default_complete = True

    def execute (self, *args, **kwargs):
        LongMessagePage.execute (self, *args, **kwargs)
        self.set_page_title ("Thanks for your report")

class GetMultilinePage (Page):
    default_complete = True

    def create_widget (self):
        vbox = gtk.VBox (spacing=12)
        self.label = gtk.Label ()
        vbox.pack_start (self.label, expand=False)

        view = gtk.TextView ()
        self.buffer = view.get_buffer ()
        scrolled = create_scrollable (view)
        vbox.pack_start (scrolled)
        return vbox

    def is_valid (self, value):
        return True

    def connect_signals (self):
        self.buffer.connect ('changed', self.validate)

    def get_value (self):
        return self.buffer.get_text (self.buffer.get_start_iter (), self.buffer.get_end_iter ())

    def execute (self, prompt):
        self.label.set_text (prompt)

class EditorPage (Page):
    def create_widget (self):
        vbox = gtk.VBox (spacing=6)
        hbox = gtk.HBox (spacing=12)
        hbox.pack_start (gtk.Label ("Subject: "), expand=False)
        self.subject = gtk.Entry ()
        hbox.pack_start (self.subject)
        vbox.pack_start (hbox, expand=False)

        view = gtk.TextView ()
        self.info_buffer = view.get_buffer ()
        scrolled = create_scrollable (view)
        vbox.pack_start (scrolled)

        expander = gtk.Expander ("Other system informations")
        view = gtk.TextView ()
        self.others_buffer = view.get_buffer ()
        scrolled = create_scrollable (view)
        expander.add (scrolled)
        vbox.pack_start (expander)
        return vbox

    def switch_out (self):
        f = file (self.filename, "w")
        f.write (self.get_value()[0])
        f.close ()

    def connect_signals (self):
        self.info_buffer.connect ('changed', self.validate)
        self.subject.connect ('changed', self.validate)

    def get_value (self):
        info = self.info_buffer.get_text (self.info_buffer.get_start_iter (),
                                          self.info_buffer.get_end_iter ())
        if not info.strip ():
            return None
        subject = self.subject.get_text().strip ()
        if not subject.strip ():
            return None

        self.report.set_subject (subject)
        message = self.report.create_message (info)
        message = message.decode (self.charset, 'replace')
        return (message, message != self.message)

    def execute (self, message, filename, editor, charset='utf-8'):
        self.message = message
        self.report = BugReport (message)
        self.filename = filename
        self.charset = charset
        self.subject.set_text (self.report.get_subject ())
        self.info_buffer.set_text (self.report.get_original_info ())
        self.others_buffer.set_text (self.report.get_others ())

class SelectOptionsPage (Page):
    default_complete = True

    def create_widget (self):
        self.label = gtk.Label ()
        self.vbox = gtk.VBox (spacing=6)
        self.vbox.pack_start (self.label, expand=False, padding=6)
        return self.vbox

    def on_clicked (self, button, menuopt):
        self.application.set_next_value (menuopt)
        self.assistant.set_current_page (self.assistant.forward (self.page_num))

    def execute (self, prompt, menuopts, options):
        self.label.set_text (prompt)

        default = None
        buttons = []
        for menuopt in menuopts:
            desc = options[menuopt.lower ()]
            # do we really need to launch an external editor?
            if 'Change editor' in desc:
                continue
            button = gtk.Button (options[menuopt.lower ()])
            button.connect ('clicked', self.on_clicked, menuopt)
            if menuopt.isupper ():
                default = button
                buttons.insert (0, gtk.HSeparator ())
                buttons.insert (0, button)
            else:
                buttons.append (button)

        for button in buttons:
            self.vbox.pack_start (button, expand=False)

        if default:
            default.set_flags (gtk.CAN_DEFAULT | gtk.HAS_DEFAULT)
            default.grab_default ()
            default.grab_focus ()

        self.vbox.show_all ()

class ProgressPage (Page):
    page_type = gtk.ASSISTANT_PAGE_PROGRESS

    def pulse (self):
        self.progress.pulse ()
        return True

    def create_widget (self):
        vbox = gtk.VBox (spacing=6)
        self.label = gtk.Label ()
        self.progress = gtk.ProgressBar ()
        self.progress.set_pulse_step (0.01)
        vbox.pack_start (self.label, expand=False)
        vbox.pack_start (self.progress, expand=False)
        gobject.timeout_add (10, self.pulse)
        return vbox

    def set_label (self, text):
        self.label.set_text (text)

    def reset_label (self):
        self.set_label ("This operation may take a while")

class ReportbugAssistant (gtk.Assistant):
    def __init__ (self, application):
        gtk.Assistant.__init__ (self)
        self.set_title ('Reportbug')
        self.application = application
        self.showing_page = None
        self.requested_page = None
        self.progress_page = None
        self.set_forward_page_func (self.forward)
        self.connect_signals ()
        self.setup_pages ()

    def connect_signals (self):
        self.connect ('cancel', self.close)
        self.connect ('prepare', self.on_prepare)
        self.connect ('delete-event', self.close)
        self.connect ('apply', self.close)
        
    def on_prepare (self, assistant, widget):
        # If the user goes back then forward, we must ensure the feedback value to reportbug must be sent
        # when the user clicks on "Forward" to the requested page by reportbug
        if self.showing_page and self.showing_page == self.requested_page and self.get_current_page () > self.showing_page.page_num:
            self.application.put_next_value ()
            # Reportbug doesn't support going back, so make widgets insensitive
            self.showing_page.widget.set_sensitive (False)
            self.showing_page.switch_out ()

        self.showing_page = widget.page
        # Some pages might have changed the label in the while
        if self.showing_page == self.progress_page:
            self.progress_page.reset_label ()

    def close (self, *args):
        sys.exit (0)
        
    def forward (self, page_num):
        return page_num + 1

    def set_next_page (self, page):
        self.requested_page = page
        # If we're in progress immediately show this guy
        if self.showing_page == self.progress_page:
            self.set_current_page (page.page_num)

    def set_progress_label (self, text, *args, **kwargs):
        self.progress_page.set_label (text % args)

    def setup_pages (self):
        # We insert pages between the intro and the progress, so that we give the user the feedback
        # that the applications is still running when he presses the "Forward" button
        self.showing_page = IntroPage (self)
        self.progress_page = ProgressPage (self)
        Page.next_page_num = 1
        self.showing_page.switch_in ()
        self.progress_page.switch_in ()
        self.set_current_page (0)

assistant = ReportbugAssistant (application)
assistant.show_all ()


# Dialogs


class YesNoDialog (ReportbugConnector, gtk.MessageDialog):
    def __init__ (self, application):
        gtk.MessageDialog.__init__ (self, assistant, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                                    gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO)
        self.application = application
        self.connect ('response', self.on_response)

    def on_response (self, dialog, res):
        self.application.set_next_value (res == gtk.RESPONSE_YES)
        self.application.put_next_value ()
        self.destroy ()

    def execute_operation (self, msg, default=True, nowrap=False):
        self.set_markup (msg+"?")
        self.show_all ()
             
class GetFilenameDialog (ReportbugConnector, gtk.FileChooserDialog):
    def __init__ (self, application):
        gtk.FileChooserDialog.__init__ (self, '', assistant, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                                                      gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        self.application = application
        self.connect ('response', self.on_response)

    def on_response (self, dialog, res):
        value = None
        if res == gtk.RESPONSE_OK:
            value = self.get_filename ()

        self.application.set_next_value (value)
        self.application.put_next_value ()
        self.destroy ()

    def execute_operation (self, title, force_prompt=False):
        self.set_title (ask_free (title))
        self.show_all ()
   
log_message = assistant.set_progress_label
display_failure = ewrite

def select_multiple (*args, **kwargs):
    kwargs['multiple'] = True
    kwargs['empty_ok'] = True
    return menu (*args, **kwargs)

pages = { 'get_string': GetStringPage,
          'menu': MenuPage,
          'handle_bts_query': HandleBTSQueryPage,
          'long_message': LongMessagePage,
          'display_report': DisplayReportPage,
          'final_message': FinalMessagePage,
          'spawn_editor': EditorPage,
          'select_options': SelectOptionsPage }
dialogs = { 'yes_no': YesNoDialog,
            'get_filename': GetFilenameDialog }

# Begin the circle

application.start ()

def create_forwarder (parent, klass):
    def func (*args, **kwargs):
        op = klass (parent)
        try:
            args, kwargs = op.sync_pre_operation (*args, **kwargs)
        except SyncError, e:
            return e.result
        application.run_once_in_main_thread (op.execute_operation, *args, **kwargs)
        return application.get_last_value ()
    return func
      
def forward_operations (parent, operations):
    for operation, klass in operations.iteritems ():
        globals()[operation] = create_forwarder (parent, klass)

forward_operations (assistant, pages)
forward_operations (application, dialogs)

def test ():
    print "Write some tests here"

if __name__ == '__main__':
    test ()

_______________________________________________
Reportbug-maint mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/reportbug-maint

Reply via email to