541 if partscore: |
541 if partscore: |
542 return partscore |
542 return partscore |
543 return 0 |
543 return 0 |
544 return selector |
544 return selector |
545 |
545 |
|
546 |
|
547 # selector base classes and operations ######################################## |
|
548 class Selector(object): |
|
549 """base class for selector classes providing implementation |
|
550 for operators ``&`` and ``|`` |
|
551 |
|
552 This class is only here to give access to binary operators, the |
|
553 selector logic itself should be implemented in the __call__ method |
|
554 """ |
|
555 def __init__(self, *selectors): |
|
556 self.selectors = self.merge_selectors(selectors) |
|
557 |
|
558 @classmethod |
|
559 def merge_selectors(cls, selectors): |
|
560 """merge selectors when possible : |
|
561 |
|
562 AndSelector(AndSelector(sel1, sel2), AndSelector(sel3, sel4)) |
|
563 ==> AndSelector(sel1, sel2, sel3, sel4) |
|
564 """ |
|
565 merged_selectors = [] |
|
566 for selector in selectors: |
|
567 if isinstance(selector, cls): |
|
568 merged_selectors += selector.selectors |
|
569 else: |
|
570 merged_selectors.append(selector) |
|
571 return merged_selectors |
|
572 |
|
573 def __and__(self, other): |
|
574 return AndSelector(self, other) |
|
575 |
|
576 def __or__(self, other): |
|
577 return OrSelector(self, other) |
|
578 |
|
579 __ror__ = __or__ # for cases like (function | selector) |
|
580 __rand__ = __and__ # for cases like (function & selector) |
|
581 # XXX (function | function) or (function & function) not managed yet |
|
582 |
|
583 def __call__(self, cls, *args, **kwargs): |
|
584 return NotImplementedError("selector %s must implement its logic " |
|
585 "in its __call__ method" % self.__class__.__name__) |
|
586 |
|
587 |
|
588 class AndSelector(Selector): |
|
589 """and-chained selectors (formerly known as chainall)""" |
|
590 def __call__(self, cls, *args, **kwargs): |
|
591 score = 0 |
|
592 for selector in self.selectors: |
|
593 partscore = selector(cls, *args, **kwargs) |
|
594 if not partscore: |
|
595 return 0 |
|
596 score += partscore |
|
597 return score |
|
598 |
|
599 |
|
600 class OrSelector(Selector): |
|
601 """or-chained selectors (formerly known as chainfirst)""" |
|
602 def __call__(self, cls, *args, **kwargs): |
|
603 for selector in self.selectors: |
|
604 partscore = selector(cls, *args, **kwargs) |
|
605 if partscore: |
|
606 return partscore |
|
607 return 0 |