[PATCH 06/16] Move the path definitions to Interface and pass it to the Hubs from there

Martin Sivak msivak at redhat.com
Thu Dec 6 15:46:29 UTC 2012


---
 pyanaconda/ui/__init__.py                | 30 +++++++++++++++++-----
 pyanaconda/ui/common.py                  | 14 ++++++++++
 pyanaconda/ui/gui/__init__.py            | 44 +++++++++++++++++++++++---------
 pyanaconda/ui/gui/categories/__init__.py |  2 +-
 pyanaconda/ui/gui/hubs/__init__.py       | 14 ++++------
 pyanaconda/ui/tui/__init__.py            | 24 ++++++++++++++---
 pyanaconda/ui/tui/hubs/__init__.py       |  2 +-
 7 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/pyanaconda/ui/__init__.py b/pyanaconda/ui/__init__.py
index aabc719..26e540a 100644
--- a/pyanaconda/ui/__init__.py
+++ b/pyanaconda/ui/__init__.py
@@ -22,6 +22,7 @@
 __all__ = ["UserInterface"]
 
 import os
+import inspect
 from common import collect
 
 class UserInterface(object):
@@ -59,6 +60,27 @@ class UserInterface(object):
         from pyanaconda.errors import errorHandler
         errorHandler.ui = self
 
+    @property
+    def basepath(self):
+        """returns the directory name for UI subtree"""
+        return os.path.dirname(inspect.getfile(self.__class__))
+
+    @property
+    def basemask(self):
+        """returns the python module name for basepath directory"""
+        return "pyanaconda.ui"
+        
+    @property
+    def paths(self):
+        """return dictionary mapping plugin elements (spokes, hubs, categories)
+           to a list of tuples (module mask, search path)"""
+        return {
+            "spokes": [(self.basemask + ".spokes.%s",
+                       os.path.join(self.basepath, "spokes"))],
+            "hubs": [(self.basemask + ".hubs.%s",
+                     os.path.join(self.basepath, "hubs"))]
+            }
+        
     def setup(self, data):
         """Construct all the objects required to implement this interface.
            This method must be provided by all subclasses.
@@ -121,7 +143,7 @@ class UserInterface(object):
 
         return standalones
     
-    def _orderActionClasses(self, spokes, hubs, standalone_class):
+    def _orderActionClasses(self, spokes, hubs):
         """Order all the Hub and Spoke classes which should be enqueued for
            processing according to their pre/post dependencies.
 
@@ -129,15 +151,9 @@ class UserInterface(object):
                           to the hub dependencies
            :type spokes: list of Spoke instances
 
-           :param path: the directory we are picking up modules from
-           :type path: string
-
            :param hubs: the list of Hub classes we check to be in pre/postForHub
                         attribute of Spokes to pick up
            :type hubs: common.Hub based types
-
-           :param standalone_class: the parent type of Spokes we want to pick up
-           :type standalone_class: common.StandaloneSpoke based types
         """
 
         actionClasses = []
diff --git a/pyanaconda/ui/common.py b/pyanaconda/ui/common.py
index d5ff8af..11f5e0b 100644
--- a/pyanaconda/ui/common.py
+++ b/pyanaconda/ui/common.py
@@ -23,6 +23,14 @@
 import os
 import imp
 import inspect
+import copy
+
+class PathDict(dict):
+    """Dictionary class supporting + operator"""
+    def __add__(self, ext):
+        new_dict = copy.copy(self)
+        new_dict.update(ext)
+        return new_dict
 
 class UIObject(object):
     """This is the base class from which all other UI classes are derived.  It
@@ -377,7 +385,13 @@ class Hub(UIObject):
         self.storage = storage
         self.payload = payload
         self.instclass = instclass
+        self.paths = {}
 
+    def set_path(self, path_id, paths):
+        """Update the paths attribute with list of tuples in the form (module
+           name format string, directory name)"""
+        self.paths[path_id] = paths
+        
 def collect(module_pattern, path, pred):
     """Traverse the directory (given by path), import all files as a module
        module_pattern % filename and find all classes within that match
diff --git a/pyanaconda/ui/gui/__init__.py b/pyanaconda/ui/gui/__init__.py
index f9b51e2..a09ce20 100644
--- a/pyanaconda/ui/gui/__init__.py
+++ b/pyanaconda/ui/gui/__init__.py
@@ -28,6 +28,7 @@ from pyanaconda.product import distributionText, isFinal
 from pyanaconda.ui import UserInterface, common
 from pyanaconda.ui.gui.utils import enlightbox, gtk_thread_wait
 from pyanaconda.product import isFinal, productName, productVersion
+import os.path
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
@@ -62,17 +63,19 @@ class GraphicalUserInterface(UserInterface):
         import ctypes
         ctypes.CDLL("libAnacondaWidgets.so.0", ctypes.RTLD_GLOBAL)
 
+    @property
+    def basemask(self):
+        return "pyanaconda.ui.gui"
+        
     def _list_hubs(self):
-        from hubs.summary import SummaryHub
-        from hubs.progress import ProgressHub
+        """Return a list of Hub classes to be imported to this interface"""
+        from .hubs.summary import SummaryHub
+        from .hubs.progress import ProgressHub
         return [SummaryHub, ProgressHub]
 
-    def _list_standalone_paths(self):
-        path = os.path.join(os.path.dirname(__file__), "spokes")
-        return [("pyanaconda.ui.gui.spokes.%s", path)]
-    
     def _is_standalone(self, obj):
-        from spokes import StandaloneSpoke
+        """Is the spoke passes as obj standalone?"""
+        from .spokes import StandaloneSpoke
         return isinstance(obj, StandaloneSpoke)
 
     def setup(self, data):
@@ -82,13 +85,25 @@ class GraphicalUserInterface(UserInterface):
         self.data = data
 
     def getActionClasses(self, hubs):
-        from spokes import StandaloneSpoke
+        """Grab all relevant standalone spokes, add them to the passed
+           list of hubs and order the list according to the
+           relationships between hubs and standalones."""
+        from .spokes import StandaloneSpoke
 
         # First, grab a list of all the standalone spokes.
-        standalones = self._collectActionClasses(self._list_standalone_paths(), StandaloneSpoke)
+        standalones = self._collectActionClasses(self.paths["spokes"], StandaloneSpoke)
 
         # Second, order them according to their relationship
-        return self._orderActionClasses(standalones, hubs, StandaloneSpoke)
+        return self._orderActionClasses(standalones, hubs)
+
+    @property
+    def paths(self):
+        _paths = UserInterface.paths.fget(self)
+        _paths.update({"categories": [(self.basemask + ".categories.%s",
+                                      os.path.join(self.basepath, "categories"))]
+                      })
+        return _paths
+
 
     def _instantiateAction(self, actionClass):
         from spokes import StandaloneSpoke
@@ -97,10 +112,15 @@ class GraphicalUserInterface(UserInterface):
         # spoke API and setting up continue/quit signal handlers.
         obj = actionClass(self.data, self.storage, self.payload, self.instclass)
 
+        # set spoke search paths in Hubs
+        if hasattr(obj, "set_path"):
+            obj.set_path("spokes", self.paths["spokes"])
+            obj.set_path("categories", self.paths["categories"])
+            
         # If we are doing a kickstart install, some standalone spokes
-        # could already be filled out.  In that case, we do not want
+        # could already be filled out.  In taht case, we do not want
         # to display them.
-        if isinstance(obj, StandaloneSpoke) and obj.completed:
+        if self._is_standalone(obj) and obj.completed:
             del(obj)
             return None
 
diff --git a/pyanaconda/ui/gui/categories/__init__.py b/pyanaconda/ui/gui/categories/__init__.py
index c318901..14dc2a0 100644
--- a/pyanaconda/ui/gui/categories/__init__.py
+++ b/pyanaconda/ui/gui/categories/__init__.py
@@ -77,7 +77,7 @@ def collect_categories(mask_paths):
     """
     categories = []
     for mask, path in mask_paths:
-        categories.extend(collect(mask, path, lambda obj: getattr(obj, "displayOnHub", None) != None)
+        categories.extend(collect(mask, path, lambda obj: getattr(obj, "displayOnHub", None) != None))
         
     return categories
 
diff --git a/pyanaconda/ui/gui/hubs/__init__.py b/pyanaconda/ui/gui/hubs/__init__.py
index 4447367..f9cc933 100644
--- a/pyanaconda/ui/gui/hubs/__init__.py
+++ b/pyanaconda/ui/gui/hubs/__init__.py
@@ -22,7 +22,9 @@
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
 
+
 # pylint: disable-msg=E0611
+import os
 from gi.repository import GLib
 
 from pyanaconda.flags import flags
@@ -111,12 +113,6 @@ class Hub(GUIObject, common.Hub):
             action.apply()
             action.execute()
 
-    def _list_spokes_mask_paths(self):
-        return [("pyanaconda.ui.gui.spokes.%s", os.path.join(os.path.dirname(__file__), "spokes"))]
-
-    def _list_categories_mask_paths(self):
-        return [("pyanaconda.ui.gui.categories.%s", os.path.join(os.path.dirname(__file__), "categories"))]
-            
     def _collectCategoriesAndSpokes(self):
         """collects categories and spokes to be displayed on this Hub
 
@@ -128,10 +124,10 @@ class Hub(GUIObject, common.Hub):
         
         # Collect all the categories this hub displays, then collect all the
         # spokes belonging to all those categories.
-        categories = sorted(filter(lambda c: c.displayOnHub == self.__class__, collect_categories(self._list_categories_mask_paths())),
+        categories = sorted(filter(lambda c: c.displayOnHub == self.__class__, collect_categories(self.paths["categories"])),
                             key=lambda c: c.title)
         for c in categories:
-            ret[c] = collect_spokes(self._list_spokes_mask_paths(), c.__name__)
+            ret[c] = collect_spokes(self.paths["spokes"], c.__name__)
 
         return ret
             
@@ -250,7 +246,7 @@ class Hub(GUIObject, common.Hub):
 
     @property
     def continuePossible(self):
-        return len(self._incompleteSpokes) == 0 and len(self._notReadySpokes) == 0
+        return len(self._incompleteSpokes)==0 and len(self._notReadySpokes) == 0
         
     def _updateContinueButton(self):
         self.continueButton.set_sensitive(self.continuePossible)
diff --git a/pyanaconda/ui/tui/__init__.py b/pyanaconda/ui/tui/__init__.py
index c4a15a0..cccbf70 100644
--- a/pyanaconda/ui/tui/__init__.py
+++ b/pyanaconda/ui/tui/__init__.py
@@ -129,27 +129,43 @@ class TextUserInterface(ui.UserInterface):
         ui.UserInterface.__init__(self, storage, payload, instclass)
         self._app = None
 
+    @property
+    def basemask(self):
+        return "pyanaconda.ui.tui"
+    
+    def _list_hubs(self):
+        """returns the list of hubs to use"""
+        return [SummaryHub, ProgressHub]
+
+    def _is_standalone(self, spoke):
+        """checks if the passed spoke is standalone"""
+        return isinstance(spoke, StandaloneSpoke)
+    
     def setup(self, data):
         """Construct all the objects required to implement this interface.
            This method must be provided by all subclasses.
         """
         self._app = tui.App(u"Anaconda", yes_or_no_question = YesNoDialog)
-        self._hubs = [SummaryHub, ProgressHub]
+        _hubs = self._list_hubs()
 
         # First, grab a list of all the standalone spokes.
         path = os.path.join(os.path.dirname(__file__), "spokes")
-        actionClasses = self.getActionClasses("pyanaconda.ui.tui.spokes.%s", path, self._hubs, StandaloneSpoke)
-
+        spokes = self._collectActionClasses(self.paths["spokes"], StandaloneSpoke)
+        actionClasses = self._orderActionClasses(spokes, _hubs)
+        
         for klass in actionClasses:
             obj = klass(self._app, data, self.storage, self.payload, self.instclass)
 
             # If we are doing a kickstart install, some standalone spokes
             # could already be filled out.  In taht case, we do not want
             # to display them.
-            if isinstance(obj, StandaloneSpoke) and obj.completed:
+            if self._is_standalone(obj) and obj.completed:
                 del(obj)
                 continue
 
+            if hasattr(obj, "set_path"):
+                obj.set_path("spokes", self.paths["spokes"])
+
             self._app.schedule_screen(obj)
 
     def run(self):
diff --git a/pyanaconda/ui/tui/hubs/__init__.py b/pyanaconda/ui/tui/hubs/__init__.py
index 0f505f7..d669bc7 100644
--- a/pyanaconda/ui/tui/hubs/__init__.py
+++ b/pyanaconda/ui/tui/hubs/__init__.py
@@ -52,7 +52,7 @@ class TUIHub(TUIObject, common.Hub):
 
         # look for spokes having category present in self.categories
         for c in self.categories:
-            spokes = collect_spokes([("pyanaconda.ui.tui.spokes.%s", os.path.join(os.path.dirname(__file__), "spokes"))], c)
+            spokes = collect_spokes(self.paths["spokes"], c)
 
             # sort them according to their priority
             for s in sorted(spokes, key = lambda s: s.priority):
-- 
1.7.11.7



More information about the anaconda-patches mailing list