aboutsummaryrefslogtreecommitdiffstats
path: root/cards
diff options
context:
space:
mode:
authorhenryk <henryk@f711b948-2313-0410-aaa9-d29f33439f0b>2005-10-12 02:09:15 +0000
committerhenryk <henryk@f711b948-2313-0410-aaa9-d29f33439f0b>2005-10-12 02:09:15 +0000
commit31225977e2479e061dd92635df98c353aaeb78f6 (patch)
tree243b95e6b79daae23ff7be94dec5eae11d2de838 /cards
parent6003cc1fc01413cd7825ea0c9cdb9dd5d60a3828 (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__.py110
-rw-r--r--cards/generic_card.py5
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