home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / pycentral / deskbar-applet / site-packages / deskbar / ModuleLoader.py < prev    next >
Encoding:
Python Source  |  2006-08-29  |  8.1 KB  |  238 lines

  1. import os, sys, pydoc
  2. from os.path import abspath, expanduser, join, basename
  3. import traceback
  4. import gtk, gobject
  5.  
  6. import deskbar, deskbar.Handler, deskbar.Categories
  7. from deskbar.Watcher import DirWatcher
  8. from deskbar.ModuleContext import ModuleContext
  9.  
  10. class ModuleLoader (gobject.GObject):
  11.     """An auxilary class to ModuleList. Create an instance of ModuleLoader by
  12.     specifying the which directories to search and what extension to accept.
  13.     The load_all() method will load all qualified modules into the ModuleList
  14.     specified in the constructor.
  15.     
  16.     Most methods have a _async variant. These methods emits signals that is handled
  17.     by the mainloop.
  18.             
  19.     Hint: If you pass None as the dirs argument the ModuleLoader will not search
  20.     for modules at all. This is useful if you want to reload a single module for
  21.     which you know the path.
  22.     """
  23.     
  24.     __gsignals__ = {
  25.         # Fired when the passed module context is loaded, that is the module's __init__ method has been called
  26.         "module-loaded" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
  27.         # Fired when load_all has loaded every available modules
  28.         "modules-loaded" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []),
  29.         # Fired when the passed module context has successfully run the initialize() method, and is thus ready to be queried
  30.         "module-initialized" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
  31.         # Fired when the passed module context has not run initialize() without errors. The module is no usable anymore
  32.         "module-not-initialized" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
  33.         # Fired when the passed module context has run the stop() method successfully. The module is not usable anymore
  34.         "module-stopped" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
  35.     }
  36.     
  37.     def __init__ (self, dirs, extension=".py"):
  38.         """
  39.         dirs: A list of directories to search. Relative pathnames and paths
  40.               containing ~ will be expanded. If dirs is None the 
  41.               ModuleLoader will not search for modules.
  42.         extension: What extension should this ModuleLoader accept (string).
  43.         """
  44.         gobject.GObject.__init__ (self)
  45.         self.ext = extension
  46.         self.watcher = DirWatcher()
  47.         self.watch_id = self.watcher.connect('changed', self._on_handler_file_changed)
  48.         
  49.         if (dirs):
  50.             self.dirs = [abspath(expanduser(s)) for s in dirs]
  51.             self.build_filelist ()
  52.             self.watcher.add(self.dirs)
  53.         else:
  54.             self.dirs = None
  55.             self.filelist = []
  56.         
  57.     def _on_handler_file_changed(self, watcher, f):
  58.         if f in self.filelist or not self.is_module(f):
  59.             return
  60.         
  61.         self.load(f)
  62.         self.filelist.append(f)
  63.         
  64.     def build_filelist (self):
  65.         """Returns a list containing the filenames of all qualified modules.
  66.         This method is automatically invoked by the constructor.
  67.         """
  68.         res = []
  69.         for d in self.dirs:
  70.             try:
  71.                 if not os.path.exists(d):
  72.                     continue
  73.  
  74.                 for i in [join(d, m) for m in os.listdir (d) if self.is_module(m)]:
  75.                     if basename(i) not in [basename(j) for j in res]:
  76.                         res.append(i)
  77.             except OSError, err:
  78.                 print >> sys.stderr, "Error reading directory %s, skipping." % d
  79.                 traceback.print_exc()
  80.         
  81.         self.filelist = res
  82.             
  83.     def is_module (self, filename):
  84.         """Tests whether the filename has the appropriate extension."""
  85.         return (filename[-len(self.ext):] == self.ext)
  86.                 
  87.     def import_module (self, filename):
  88.         """Tries to import the specified file. Returns the python module on succes.
  89.         Primarily for internal use."""
  90.         try:
  91.             mod = pydoc.importfile (filename)
  92.         except Exception:
  93.             print >> sys.stderr, "Error loading the file: %s." % filename
  94.             traceback.print_exc()
  95.             return
  96.         
  97.         try:
  98.             if (mod.HANDLERS): pass
  99.         except AttributeError:
  100.             print >> sys.stderr, "The file %s is not a valid module. Skipping." %filename
  101.             print >> sys.stderr, "A module must have the variable HANDLERS defined as a dictionary."
  102.             traceback.print_exc()
  103.             return
  104.         
  105.         if mod.HANDLERS == None:
  106.             if not hasattr(mod, "ERROR"):
  107.                 mod.ERROR = "Unspecified Reason"
  108.                 
  109.             print >> sys.stderr, "*** The file %s decided to not load itself: %s" % (filename, mod.ERROR)
  110.             return
  111.         
  112.         for handler, infos in mod.HANDLERS.items():
  113.             if hasattr(getattr(mod, handler), "initialize") and "name" in infos:
  114.                 pass                
  115.             else:
  116.                 print >> sys.stderr, "Class %s in file %s does not have an initialize(self) method or does not define a 'name' attribute. Skipping." % (handler, filename)
  117.                 return
  118.             
  119.             if "requirements" in infos:
  120.                 status, msg, callback = infos["requirements"]()
  121.                 if status == deskbar.Handler.HANDLER_IS_NOT_APPLICABLE:
  122.                     print >> sys.stderr, "***"
  123.                     print >> sys.stderr, "*** The file %s (%s) decided to not load itself: %s" % (filename, handler, msg)
  124.                     print >> sys.stderr, "***"
  125.                     return
  126.         
  127.         return mod
  128.             
  129.     def load (self, filename):
  130.         """Loads the given file as a module and emits a 'module-loaded' signal
  131.         passing a corresponding ModuleContext as argument.
  132.         """
  133.         mod = self.import_module (filename)
  134.         if mod is None:
  135.             return
  136.         
  137.         for handler, infos in mod.HANDLERS.items():
  138.             print "Loading module '%s' from file %s." % (infos["name"], filename)
  139.             mod_instance = getattr (mod, handler) ()
  140.             context = ModuleContext (mod_instance.get_icon(), False, mod_instance, filename, handler, infos)
  141.                     
  142.             self.emit("module-loaded", context)
  143.         
  144.         return context
  145.     
  146.     def load_all (self):
  147.         """Tries to load all qualified modules detected by the ModuleLoader.
  148.         Each time a module is loaded it will emit a 'module-loaded' signal
  149.         passing a corresponding module context.
  150.         """
  151.         if self.dirs is None:
  152.             print >> sys.stderr, "The ModuleLoader at %s has no filelist!" % str(id(self))
  153.             print >> sys.stderr, "It was probably initialized with dirs=None."
  154.             return
  155.             
  156.         for f in self.filelist:
  157.             self.load (f)
  158.         
  159.         self.emit('modules-loaded')
  160.                     
  161.     def initialize_module (self, context):
  162.         """
  163.         Initializes the module in the given context. Emits a 'module-initialized' signal
  164.         when done, passing the (now enabled) contextas argument.
  165.         If module is already initialized, do nothing.
  166.         """
  167.         if context.enabled:
  168.             return
  169.             
  170.         print "Initializing %s" % context.infos["name"]
  171.         
  172.         # Check that the given requirements for the handler are met
  173.         if context.infos.has_key ("requirements"):
  174.             status, message, callback = context.infos["requirements"]()
  175.             if status == deskbar.Handler.HANDLER_HAS_REQUIREMENTS or \
  176.                status == deskbar.Handler.HANDLER_IS_NOT_APPLICABLE :
  177.                 print "Error while initializing %s. Requirements not met." % context.infos["name"]
  178.                 print message
  179.                 context.enabled = False
  180.                 self.emit("module-not-initialized", context)
  181.                 return
  182.         
  183.         try:
  184.             context.module.initialize ()
  185.             
  186.             # Add necessary categories
  187.             if "categories" in context.infos:
  188.                 for catname, catinfo in context.infos["categories"].items():
  189.                     deskbar.Categories.CATEGORIES[catname] = catinfo
  190.         except Exception, msg:
  191.             print "Error while initializing %s: %s" % (context.infos["name"],msg)
  192.             traceback.print_exc()
  193.             context.enabled = False
  194.             self.emit("module-not-initialized", context)
  195.             return
  196.         
  197.         context.enabled = True
  198.         self.emit("module-initialized", context)
  199.     
  200.     def stop_module (self, context):
  201.         """
  202.         Stops the module an sets context.enabled = False. Furthermore the context.module
  203.         instance is also set to None. Emits a 'context-stopped' signal when done passing
  204.         the stopped context as argument.
  205.         """
  206.         
  207.         print "Stopping %s" % context.infos["name"]
  208.         context.module.stop ()
  209.         
  210.         # Remove the category installed by this module
  211.         if "category" in context.infos:
  212.             catname, catinfo = context.infos["category"]
  213.             del deskbar.Categories.CATEGORIES[catname]
  214.                 
  215.         context.enabled = False
  216.         self.emit("module-stopped", context)
  217.             
  218.     def load_all_async (self):
  219.         """
  220.         Same as load_all() except the loading is done in an idle mainloop call.
  221.         """
  222.         gobject.idle_add(self.load_all)
  223.         
  224.     def initialize_module_async (self, context):
  225.         """
  226.         Invokes initialize_module in an idle mainloop call.
  227.         """
  228.         gobject.idle_add(self.initialize_module, context)
  229.         
  230.     def stop_module_async (self, context):
  231.         """
  232.         Invokes stop_module in an idle mainloop call.
  233.         """
  234.         gobject.idle_add(self.stop_module, context)
  235.         
  236. if gtk.pygtk_version < (2,8,0):
  237.     gobject.type_register(ModuleLoader)
  238.