diff options
author | henryk <henryk@f711b948-2313-0410-aaa9-d29f33439f0b> | 2005-10-12 02:09:15 +0000 |
---|---|---|
committer | henryk <henryk@f711b948-2313-0410-aaa9-d29f33439f0b> | 2005-10-12 02:09:15 +0000 |
commit | 31225977e2479e061dd92635df98c353aaeb78f6 (patch) | |
tree | 243b95e6b79daae23ff7be94dec5eae11d2de838 /cards | |
parent | 6003cc1fc01413cd7825ea0c9cdb9dd5d60a3828 (diff) |
Cardmultiplexer object. Should allow to dynamically bind and unbind classes from a card object.
git-svn-id: svn+ssh://localhost/home/henryk/svn/cyberflex-shell/trunk@43 f711b948-2313-0410-aaa9-d29f33439f0b
Diffstat (limited to 'cards')
-rw-r--r-- | cards/__init__.py | 110 | ||||
-rw-r--r-- | cards/generic_card.py | 5 |
2 files changed, 107 insertions, 8 deletions
diff --git a/cards/__init__.py b/cards/__init__.py index 2e535de..c0b9c95 100644 --- a/cards/__init__.py +++ b/cards/__init__.py @@ -8,6 +8,7 @@ from the generic_card.Card class.""" from sys import modules as _modules from dircache import listdir as _listdir +from new import classobj as _classobj for filename in _listdir(_modules[__name__].__path__[0]): if filename[-3:].lower() == ".py": @@ -25,12 +26,109 @@ for filename in _listdir(_modules[__name__].__path__[0]): del filename, possible_module, module, possible_class -def find_class(ATR): - """Find a card class that supports the card identified by ATR. - Returns the generic card class when no better match is found.""" +def new_card_object(card): + """Return a new object that will incorporate all classes that + think that they can handle the given card. The object will always + contain the Card class.""" + + card_classes = [Card] + for card_class in dir(_modules[__name__]): card_class = getattr(_modules[__name__], card_class) + + if card_class in card_classes: + continue + if hasattr(card_class, "can_handle"): - if card_class.can_handle(ATR): - return card_class - return Card + if card_class.can_handle(card): + card_classes.append(card_class) + + return Cardmultiplexer( tuple(card_classes), card ) + +class Cardmultiplexer: + """This class will provide an object that 'multiplexes' several card classes + into one. + + This is somewhat different from multiple inheritance in that classes can + be dynamically added and removed from instances of this class. It also + provides support for merging some list and dictionary class attributes + of the participating classes instead of overriding them.""" + + def __init__(self, classes, *args, **kwargs): + """Creates a new Cardmultiplexer object. + + The first positional argument must be a list of classes that you want + to initially melt together. + + Any additional positional or keyword arguments that you give will be saved + and provided to the __init__ methods of all classes that you add. + (You may change the saved arguments at a later time with + set_init_arguments().)""" + + self._classes = [] + self._classes_needed = [] + self._init_args = args + self._init_kwargs = kwargs + + self.add_classes(classes) + + + def add_classes(self, classes): + """Add some new classes to this Cardmultiplexer object. classes + should be a sequence of class objects. + + Note that there are two tricky parts in this process: + 1. We wouldn't want to add superclasses of classes that + already are here. This usually makes no sense, because + Python can handle the method resolution order in this + case for itself pretty fine. + 2. The way to get bound methods is kind of hackish: + As soon as the list of classes changes we create a new + class object incorporating all classes from _classes as + well as this class (Cardmultiplexer) and then set our + __class__ attribute to this new object.""" + + (newcls, delcls) = self._update_classes(list(classes), []) + for cls in newcls: + cls.__init__(self, *self._init_args, **self._init_kwargs) + + def remove_classes(self, classes): + """Remove classes from this Cardmultiplexer object.""" + (newcls, delcls) = self._update_classes([], list(classes)) + + def _update_classes(self, addclasses, delclasses): + """This handles the task of figuring out which classes to actually + melt together. It uses two lists: new_classes and classes_needed: + new_classes contains all the classes the user wishes to melt. Then + classes will be continually added from new_classes to classes_needed + unless there is already a subclass in this list. If a class is added + then all superclasses of it will be removed from the list.""" + new_classes = self._classes + addclasses + for cls in delclasses: + new_classes.remove(cls) + + classes_needed = [] + + for new_class in new_classes: + already_covered = False + + ## Check if this class is already covered by classes_needed + for potential_sub in classes_needed: + if issubclass(potential_sub, new_class): + already_covered = True + break + + if not already_covered: + ## Remove all super classes of this class and then add the class itself + classes_needed = [cls for cls in classes_needed + if not issubclass(new_class, cls)] + classes_needed.append(new_class) + + diffplus = [cls for cls in classes_needed if cls not in self._classes_needed] + diffminus = [cls for cls in self._classes_needed if cls not in classes_needed] + + self._classes = new_classes + self._classes_needed = classes_needed + self.__class__ = _classobj("Cardmultiplexer (merged)", + tuple(classes_needed + [Cardmultiplexer]), {}) + return (diffplus,diffminus) diff --git a/cards/generic_card.py b/cards/generic_card.py index 6d1ea10..9db16af 100644 --- a/cards/generic_card.py +++ b/cards/generic_card.py @@ -100,8 +100,9 @@ class Card: return result - def can_handle(cls, ATR): - """Determine whether this class can handle a card with that ATR.""" + def can_handle(cls, card): + """Determine whether this class can handle a given pycsc object.""" + ATR = card.status().get("ATR","") for (knownatr, mask) in cls.ATRS: if len(knownatr) != len(ATR): continue |