home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / serpentine / operations.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  16.2 KB  |  451 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. """
  5. Contains three groups of classes. Events, listeners and operations.
  6.  
  7. The Operation is used in the OperationsQueue, which is an Operation itself, to
  8. process other operations in a sequenced way. They use gobject's main loop.
  9. """
  10. import gobject
  11.  
  12. class OperationListener(object):
  13.     
  14.     def on_finished(self, event):
  15.         pass
  16.  
  17.  
  18. SUCCESSFUL = 0
  19. ABORTED = 1
  20. ERROR = 2
  21.  
  22. class Event(object):
  23.     
  24.     def __init__(self, source):
  25.         self.source = source
  26.  
  27.  
  28.  
  29. class FinishedEvent(Event):
  30.     
  31.     def __init__(self, source, id, error = None):
  32.         Event.__init__(self, source)
  33.         self.id = id
  34.         self.error = error
  35.  
  36.  
  37.  
  38. class Listenable(object):
  39.     
  40.     def __init__(self):
  41.         self._Listenable__listeners = []
  42.  
  43.     listeners = property(fget = (lambda self: self._Listenable__listeners), doc = 'The list of available listeners.')
  44.  
  45.  
  46. class Operation(Listenable):
  47.     """
  48.     An operation is run assynchrounously. It is a Listenable and as such
  49.     classes which extend this one should call the event on_finished of it's
  50.     listeners when this operation is finished.
  51.     """
  52.     title = None
  53.     description = None
  54.     can_start = property((lambda self: not (self.running)), doc = "Checks if the operation can start. By default you can start an operation when it's not running.")
  55.     can_stop = property((lambda self: self.running), doc = 'Checks if this operation can stop. By default you can stop operations that are running.')
  56.     running = property(doc = 'Tests if the operation is running.')
  57.     
  58.     def start(self):
  59.         pass
  60.  
  61.     
  62.     def stop(self):
  63.         pass
  64.  
  65.     
  66.     def _notify(self, method_name, *args, **kw):
  67.         for l in self.listeners:
  68.             meth = getattr(l, method_name, None)
  69.             if meth:
  70.                 meth(*args, **kw)
  71.                 continue
  72.         
  73.  
  74.     
  75.     def _send_finished_event(self, status, error = None, source = None):
  76.         '''
  77.         Broadcasts to all listeners the finished event. Simplifies the 
  78.         task of creating the event and iterating over listeners.
  79.         '''
  80.         if source is None:
  81.             source = self
  82.         
  83.         e = FinishedEvent(source, status, error)
  84.         for l in self.listeners:
  85.             if hasattr(l, 'on_finished'):
  86.                 l.on_finished(e)
  87.                 continue
  88.         
  89.  
  90.     
  91.     def _propagate(self, evt, source = None):
  92.         self._send_finished_event(evt.id, evt.error, source)
  93.  
  94.  
  95.  
  96. class FailledOperation(Operation):
  97.     
  98.     def __init__(self, error = None, source = None):
  99.         if source is None:
  100.             source = self
  101.         
  102.         self.error = error
  103.         self.source = source
  104.         super(FailledOperation, self).__init__()
  105.  
  106.     
  107.     def start(self):
  108.         self._send_finished_event(ERROR, self.error, self.source)
  109.  
  110.     can_start = property((lambda : True))
  111.     can_stop = property((lambda : False))
  112.     running = property((lambda : False))
  113.  
  114.  
  115. def operation_factory(func):
  116.     '''
  117.     This decorator protects operation factories (functions wich return
  118.     operators by wrapping a try catch, if the function, by any chance, raises
  119.     an exception a FailledOperation is returned instead.
  120.     '''
  121.     
  122.     def wrapper(*args, **kwargs):
  123.         
  124.         try:
  125.             return func(*args, **kwargs)
  126.         except Exception:
  127.             err = None
  128.             return FailledOperation(error = err)
  129.  
  130.  
  131.     wrapper.func_name = func.func_name
  132.     return wrapper
  133.  
  134.  
  135. class CallableOperation(Operation):
  136.     '''Simple operations that takes a callable object (ie: function) and creates
  137.     an non-measurable Operation.'''
  138.     can_start = property((lambda : True))
  139.     can_stop = property((lambda : False))
  140.     running = property((lambda : False))
  141.     
  142.     def __init__(self, callable):
  143.         self.callable = callable
  144.         Operation.__init__(self)
  145.  
  146.     
  147.     def start(self):
  148.         self.callable()
  149.         self._send_finished_event(SUCCESSFUL)
  150.  
  151.  
  152.  
  153. try:
  154.     import subprocess
  155.     import os
  156.     
  157.     class SubprocessOperation(Operation):
  158.         
  159.         def __init__(self, *args, **kwargs):
  160.             super(SubprocessOperation, self).__init__()
  161.             self.args = args
  162.             self.kwargs = kwargs
  163.  
  164.         pid = property((lambda self: self._SubprocessOperation__pid))
  165.         can_start = property((lambda self: self.pid is not None))
  166.         can_stop = property((lambda self: self.pid is not None))
  167.         running = property((lambda self: self.pid is not None))
  168.         
  169.         def start(self):
  170.             
  171.             try:
  172.                 proc = subprocess.Popen(*self.args, **self.kwargs)
  173.                 self._SubprocessOperation__pid = proc.pid
  174.                 self._SubprocessOperation__id = gobject.child_watch_add(self.pid, self._SubprocessOperation__on_finish)
  175.             except Exception:
  176.                 e = None
  177.                 print 'Error:', e
  178.  
  179.  
  180.         
  181.         def stop(self):
  182.             
  183.             try:
  184.                 os.kill(self.pid, 9)
  185.             except OSError:
  186.                 pass
  187.  
  188.  
  189.         
  190.         def __on_finish(self, pid, status):
  191.             if status == 0:
  192.                 status = SUCCESSFUL
  193.             else:
  194.                 status = ERROR
  195.             self._send_finished_event(status)
  196.             self._SubprocessOperation__pid = None
  197.  
  198.  
  199. except ImportError:
  200.     pass
  201.  
  202.  
  203. class MeasurableOperation(Operation):
  204.     progress = property(doc = "Returns the operation's progress.")
  205.  
  206.  
  207. class OperationsQueueListener(OperationListener):
  208.     
  209.     def before_operation_starts(self, event, operation):
  210.         pass
  211.  
  212.  
  213.  
  214. class OperationsQueue(MeasurableOperation, OperationListener):
  215.     '''
  216.     Operation Queuees allow a user to enqueue a number of operations and run
  217.     them sequentially.
  218.     If one of the operations is aborted or has an error the whole queue is 
  219.     aborted or returns an error too. The error returned is the same returned
  220.     by the problematic operation. All the elements remaining on the queue are
  221.     removed.
  222.     '''
  223.     
  224.     def __init__(self, operations = None):
  225.         Operation.__init__(self)
  226.         if operations is None:
  227.             operations = []
  228.         
  229.         self._OperationsQueue__operations = operations
  230.         self._OperationsQueue__done = 0
  231.         self._OperationsQueue__curr_oper = None
  232.         self._OperationsQueue__progress = 0.0
  233.         self._OperationsQueue__total = 0
  234.         self._OperationsQueue__abort_on_failure = True
  235.  
  236.     
  237.     def __is_running(self):
  238.         return self._OperationsQueue__curr_oper != None
  239.  
  240.     running = property(__is_running)
  241.     
  242.     def __get_progress(self):
  243.         if not self.running:
  244.             if len(self._OperationsQueue__operations) == 0 and self._OperationsQueue__done:
  245.                 return 1.0
  246.             else:
  247.                 return 0.0
  248.         
  249.         total = self._OperationsQueue__total
  250.         partial = 0.0
  251.         if isinstance(self._OperationsQueue__curr_oper, MeasurableOperation):
  252.             partial = self._OperationsQueue__curr_oper.progress
  253.         
  254.         return (self._OperationsQueue__done + partial) / total
  255.  
  256.     progress = property(__get_progress)
  257.     
  258.     def __set_abort_on_failure(self, val):
  259.         self._OperationsQueue__abort_on_failure = val
  260.  
  261.     abort_on_failure = property((lambda self: self._OperationsQueue__abort_on_failure), __set_abort_on_failure, doc = 'If one operation stops abort progress and propagate event.')
  262.     
  263.     def start(self):
  264.         '''
  265.         Starts all the operations on queue, sequentially.
  266.         '''
  267.         self._OperationsQueue__done = 0
  268.         self._OperationsQueue__total = len(self._OperationsQueue__operations)
  269.         self._OperationsQueue__progress = 0.0
  270.         self._OperationsQueue__started = True
  271.         gobject.idle_add(self._OperationsQueue__start_next)
  272.  
  273.     
  274.     def append(self, oper):
  275.         self._OperationsQueue__operations.append(oper)
  276.  
  277.     
  278.     def insert(self, index, oper):
  279.         self._OperationsQueue__operations.insert(index, oper)
  280.  
  281.     
  282.     def __start_next(self):
  283.         if len(self._OperationsQueue__operations):
  284.             oper = self._OperationsQueue__operations[0]
  285.             del self._OperationsQueue__operations[0]
  286.             e = Event(self)
  287.             for l in self.listeners:
  288.                 if hasattr(l, 'before_operation_starts'):
  289.                     l.before_operation_starts(e, oper)
  290.                     continue
  291.             
  292.             oper.listeners.append(self)
  293.             self._OperationsQueue__curr_oper = oper
  294.             oper.start()
  295.         else:
  296.             self._OperationsQueue__started = False
  297.             e = FinishedEvent(self, SUCCESSFUL)
  298.             for l in self.listeners:
  299.                 if hasattr(l, 'on_finished'):
  300.                     l.on_finished(e)
  301.                     continue
  302.             
  303.  
  304.     
  305.     def on_finished(self, evt):
  306.         evt.source.listeners.remove(self)
  307.         self._OperationsQueue__done += 1
  308.         self._OperationsQueue__curr_oper = None
  309.         if self.abort_on_failure and evt.id != SUCCESSFUL:
  310.             self._OperationsQueue__operations = []
  311.             evt.source = self
  312.             for l in self.listeners:
  313.                 l.on_finished(evt)
  314.             
  315.         else:
  316.             self._OperationsQueue__start_next()
  317.  
  318.     can_stop = property((lambda self: if self.running:
  319. passself._OperationsQueue__curr_oper.can_stop))
  320.     
  321.     def stop(self):
  322.         self._OperationsQueue__curr_oper.stop()
  323.  
  324.     
  325.     __len__ = lambda self: len(self._OperationsQueue__operations)
  326.     
  327.     def __repr__(self):
  328.         return '{%s: %s}' % (super(OperationsQueue, self).__repr__(), self._OperationsQueue__operations.__repr__())
  329.  
  330.  
  331.  
  332. class SyncListener(OperationListener):
  333.     
  334.     def __init__(self, mainloop):
  335.         self.mainloop = mainloop
  336.  
  337.     
  338.     def on_finished(self, event):
  339.         self.result = event
  340.         self.mainloop.quit()
  341.  
  342.  
  343.  
  344. def syncOperation(oper):
  345.     '''
  346.     This function can run an operation synchronously and returns the event
  347.     object. This only affects GObject related operations.
  348.     '''
  349.     mainloop = gobject.MainLoop()
  350.     listener = SyncListener(mainloop)
  351.     oper.listeners.append(listener)
  352.     oper.start()
  353.     mainloop.run()
  354.     return listener.result
  355.  
  356.  
  357. def syncableMethod(kwarg = 'sync', default_value = False):
  358.     """
  359.     This is a decorator that accepts a keyword argument (defaults to 'sync')
  360.     with a kwarg default value (defaults to `False`).
  361.     When you call the method you can use the extra keyword argument to
  362.     specify if the method call is going to be sync or async.
  363.     
  364.     The decorated method should be one that returns an operation.
  365.     """
  366.     
  367.     def decorator(func):
  368.         
  369.         def wrapper(*args, **kwargs):
  370.             is_sync = kwargs.get(kwarg, default_value)
  371.             if is_sync:
  372.                 del kwargs[kwarg]
  373.                 return syncOperation(func(*args, **kwargs))
  374.             else:
  375.                 return func(*args, **kwargs)
  376.  
  377.         return wrapper
  378.  
  379.     return decorator
  380.  
  381. sync = syncableMethod(default_value = True)
  382. async = syncableMethod()
  383.  
  384. class MapFunctor(object):
  385.     
  386.     def __init__(self, funcs):
  387.         self._MapFunctor__funcs = funcs
  388.  
  389.     
  390.     def __call__(self, *args, **keyws):
  391.         r = []
  392.         for f in self._MapFunctor__funcs:
  393.             r.append(f(*args, **keyws))
  394.         
  395.         return tuple(r)
  396.  
  397.  
  398.  
  399. class MapProxy(object):
  400.     '''
  401.     This class acts as a hub or a proxy for calling methods on multiple objects.
  402.     The method called from an instance of this class will be transparently
  403.     called in all elements contained in this instance. The added elements is of
  404.     a dictionary type and can be accessed by the __getitem__ and __setitem__ of
  405.     this instance.
  406.     '''
  407.     
  408.     def __init__(self, elements):
  409.         self._MapProxy__elements = elements
  410.  
  411.     
  412.     def __getattr__(self, attr):
  413.         funcs = []
  414.         for key in self._MapProxy__elements:
  415.             funcs.append(getattr(self._MapProxy__elements[key], attr))
  416.         
  417.         return MapFunctor(funcs)
  418.  
  419.     
  420.     def __getitem__(self, key):
  421.         return self._MapProxy__elements[key]
  422.  
  423.     
  424.     def __setitem__(self, key, value):
  425.         self._MapProxy__elements[key] = value
  426.  
  427.     
  428.     def __delitem__(self, key):
  429.         del self._MapProxy__elements[key]
  430.  
  431.     
  432.     def has_key(self, key):
  433.         return self._MapProxy__elements.has_key(key)
  434.  
  435.  
  436. if __name__ == '__main__':
  437.     import sys
  438.     import gtk
  439.     
  440.     class Listener:
  441.         
  442.         def on_finished(self, evt):
  443.             gtk.main_quit()
  444.  
  445.  
  446.     oper = SubprocessOperation(sys.argv[1:])
  447.     oper.listeners.append(Listener())
  448.     oper.start()
  449.     gtk.main()
  450.  
  451.