1import re
  2
  3
  4class Singleton(type):
  5    _instances = {}
  6
  7    def __call__(cls, *args, **kwargs):
  8        if cls not in cls._instances:
  9            cls._instances[cls] = super().__call__(*args, **kwargs)
 10        return cls._instances[cls]
 11    
 12
 13class Santa(metaclass=Singleton):
 14    _MAX_AGE = 5
 15
 16    def __init__(self):
 17        self._wishes = {}
 18
 19    def _get_wish(self, text):
 20        """Get the wish from the letter/call"""
 21        
 22        pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']'
 23        wish = re.search(pattern, text)
 24        if wish:
 25            return wish.group(1)
 26
 27    def __call__(self, kid, text):
 28        wish = self._get_wish(text)
 29        if wish:
 30           self._wishes[id(kid)] = wish  
 31                
 32    def _get_signature(self, text):
 33        """Get the signature of the kid from the letter"""
 34
 35        pattern = r'\b\d+\b(?=\s*$)'
 36        signature = re.search(pattern, text)
 37        if signature:
 38            return signature.group().strip()
 39    
 40    def __matmul__(self, text):
 41        signature = self._get_signature(text)
 42        wish = self._get_wish(text)
 43        if signature and wish:
 44           self._wishes[int(signature)] = wish  
 45
 46    def __iter__(self):
 47        for val in self._wishes.values():
 48            yield val
 49    
 50    @property
 51    def _get_most_wanted_gift(self):
 52        """Get the most wanted gift"""
 53
 54        wishes = list(self._wishes.values())
 55        return max(wishes, key=wishes.count)
 56    
 57    def _clear_xmas(self):
 58        """Clear the wishes and _naughty_kids"""
 59
 60        self._wishes.clear()
 61        Kid._naughty_kids.clear()
 62
 63    def xmas(self):
 64        Kid._increment_ages()
 65
 66        if not self._wishes:
 67            return
 68        
 69        most_wanted_gift = self._get_most_wanted_gift
 70        for identity, kid in Kid._kids_instances.items():
 71            if Kid._kids_ages[identity] <= self._MAX_AGE:
 72                if kid in Kid._naughty_kids:
 73                    kid('coal')
 74                else:
 75                    if identity in self._wishes:
 76                        wish = self._wishes[identity]
 77                    else:
 78                        wish = most_wanted_gift
 79                    kid(wish)
 80
 81        self._clear_xmas()
 82        
 83
 84class Kid(type):
 85    _kids_ages = {}
 86    _kids_instances = {}
 87    _naughty_kids = set()
 88    
 89    @classmethod
 90    def _check_naughty(cls, method):
 91        def wrapper(self, *args, **kwargs):
 92            """Add the instance to _naughty_kids if an exception is raised in method"""
 93
 94            try:
 95                return method(self, *args, **kwargs)
 96            except Exception:
 97                cls._naughty_kids.add(self)
 98                raise
 99        return wrapper
100
101    def __new__(cls, name, bases, dct):
102        if '__call__' not in dct:
103            raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)')
104        
105        for attribute_name, attribute_val in dct.items():
106            if callable(attribute_val):
107                if not attribute_name.startswith('_'):
108                    dct[attribute_name] = cls._check_naughty(attribute_val)
109
110        return super().__new__(cls, name, bases, dct)
111    
112    def __call__(cls, *args, **kwargs):      
113        new_kid = super().__call__(*args, **kwargs)
114        identity = id(new_kid)
115        cls._kids_ages[identity] = 0
116        cls._kids_instances[identity] = new_kid
117        return new_kid
118        
119    @classmethod
120    def _increment_ages(cls):
121        """Increment the age of each kid by one year"""
122
123        for identity, age in cls._kids_ages.items():
124            cls._kids_ages[identity] += 1 
......F.............
======================================================================
FAIL: test_present_matching (test.TestSanta.test_present_matching)
Test matching signature in the letter.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/test.py", line 92, in test_present_matching
    self.assertEqual(list(self.santa), ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890   '])
AssertionError: Lists differ: ['toy4'] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890   ']
Second list contains 1 additional elements.
First extra element 1:
'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890   '
- ['toy4']
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890   ']
----------------------------------------------------------------------
Ran 20 tests in 0.039s
FAILED (failures=1)
| f | 1 | import re | f | 1 | import re | 
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Singleton(type): | 4 | class Singleton(type): | ||
| 5 | _instances = {} | 5 | _instances = {} | ||
| 6 | 6 | ||||
| 7 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
| 8 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
| 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
| 10 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
| n | n | 14 | _MAX_AGE = 5 | ||
| 15 | |||||
| 14 | def __init__(self): | 16 | def __init__(self): | ||
| 15 | self._wishes = {} | 17 | self._wishes = {} | ||
| 16 | 18 | ||||
| 17 | def _get_wish(self, text): | 19 | def _get_wish(self, text): | ||
| 18 | """Get the wish from the letter/call""" | 20 | """Get the wish from the letter/call""" | ||
| 19 | 21 | ||||
| 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 22 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
| 21 | wish = re.search(pattern, text) | 23 | wish = re.search(pattern, text) | ||
| 22 | if wish: | 24 | if wish: | ||
| 23 | return wish.group(1) | 25 | return wish.group(1) | ||
| 24 | 26 | ||||
| 25 | def __call__(self, kid, text): | 27 | def __call__(self, kid, text): | ||
| 26 | wish = self._get_wish(text) | 28 | wish = self._get_wish(text) | ||
| 27 | if wish: | 29 | if wish: | ||
| 28 | self._wishes[id(kid)] = wish | 30 | self._wishes[id(kid)] = wish | ||
| 29 | 31 | ||||
| 30 | def _get_signature(self, text): | 32 | def _get_signature(self, text): | ||
| 31 | """Get the signature of the kid from the letter""" | 33 | """Get the signature of the kid from the letter""" | ||
| 32 | 34 | ||||
| 33 | pattern = r'\b\d+\b(?=\s*$)' | 35 | pattern = r'\b\d+\b(?=\s*$)' | ||
| 34 | signature = re.search(pattern, text) | 36 | signature = re.search(pattern, text) | ||
| 35 | if signature: | 37 | if signature: | ||
| 36 | return signature.group().strip() | 38 | return signature.group().strip() | ||
| 37 | 39 | ||||
| 38 | def __matmul__(self, text): | 40 | def __matmul__(self, text): | ||
| 39 | signature = self._get_signature(text) | 41 | signature = self._get_signature(text) | ||
| 40 | wish = self._get_wish(text) | 42 | wish = self._get_wish(text) | ||
| 41 | if signature and wish: | 43 | if signature and wish: | ||
| 42 | self._wishes[int(signature)] = wish | 44 | self._wishes[int(signature)] = wish | ||
| n | 43 | n | |||
| 44 | @property | ||||
| 45 | def _generator(self): | ||||
| 46 | for key, val in self._wishes.items(): | ||||
| 47 | yield self._wishes[key] | ||||
| 48 | 45 | ||||
| 49 | def __iter__(self): | 46 | def __iter__(self): | ||
| n | 50 | return self._generator | n | ||
| 51 | |||||
| 52 | def _count_wish_occurence(self, wish): | ||||
| 53 | """Count the number of times a gift has been wished""" | ||||
| 54 | |||||
| 55 | count = 0 | ||||
| 56 | for key, val in self._wishes.items(): | 47 | for val in self._wishes.values(): | ||
| 57 | if(val == wish): | 48 | yield val | ||
| 58 | count += 1 | ||||
| 59 | return count | ||||
| 60 | |||||
| 61 | @property | ||||
| 62 | def _get_most_wanted_gift_count(self): | ||||
| 63 | """Get the number of times the most wanted gift has been wished""" | ||||
| 64 | |||||
| 65 | max_count = 0 | ||||
| 66 | for key, val in self._wishes.items(): | ||||
| 67 | curr_count = self._count_wish_occurence(val) | ||||
| 68 | if curr_count > max_count: | ||||
| 69 | max_count = curr_count | ||||
| 70 | return max_count | ||||
| 71 | 49 | ||||
| 72 | @property | 50 | @property | ||
| 73 | def _get_most_wanted_gift(self): | 51 | def _get_most_wanted_gift(self): | ||
| 74 | """Get the most wanted gift""" | 52 | """Get the most wanted gift""" | ||
| 75 | 53 | ||||
| n | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | n | 54 | wishes = list(self._wishes.values()) | 
| 77 | for key, val in self._wishes.items(): | 55 | return max(wishes, key=wishes.count) | ||
| 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||||
| 79 | return val | ||||
| 80 | 56 | ||||
| 81 | def _clear_xmas(self): | 57 | def _clear_xmas(self): | ||
| 82 | """Clear the wishes and _naughty_kids""" | 58 | """Clear the wishes and _naughty_kids""" | ||
| 83 | 59 | ||||
| 84 | self._wishes.clear() | 60 | self._wishes.clear() | ||
| 85 | Kid._naughty_kids.clear() | 61 | Kid._naughty_kids.clear() | ||
| 86 | 62 | ||||
| 87 | def xmas(self): | 63 | def xmas(self): | ||
| 88 | Kid._increment_ages() | 64 | Kid._increment_ages() | ||
| 89 | 65 | ||||
| 90 | if not self._wishes: | 66 | if not self._wishes: | ||
| 91 | return | 67 | return | ||
| 92 | 68 | ||||
| 93 | most_wanted_gift = self._get_most_wanted_gift | 69 | most_wanted_gift = self._get_most_wanted_gift | ||
| 94 | for identity, kid in Kid._kids_instances.items(): | 70 | for identity, kid in Kid._kids_instances.items(): | ||
| n | 95 | if Kid._kids_ages[identity] <= 5: | n | 71 | if Kid._kids_ages[identity] <= self._MAX_AGE: | 
| 96 | if kid in Kid._naughty_kids: | 72 | if kid in Kid._naughty_kids: | ||
| 97 | kid('coal') | 73 | kid('coal') | ||
| 98 | else: | 74 | else: | ||
| 99 | if identity in self._wishes: | 75 | if identity in self._wishes: | ||
| 100 | wish = self._wishes[identity] | 76 | wish = self._wishes[identity] | ||
| 101 | else: | 77 | else: | ||
| 102 | wish = most_wanted_gift | 78 | wish = most_wanted_gift | ||
| 103 | kid(wish) | 79 | kid(wish) | ||
| 104 | 80 | ||||
| 105 | self._clear_xmas() | 81 | self._clear_xmas() | ||
| 106 | 82 | ||||
| 107 | 83 | ||||
| 108 | class Kid(type): | 84 | class Kid(type): | ||
| 109 | _kids_ages = {} | 85 | _kids_ages = {} | ||
| 110 | _kids_instances = {} | 86 | _kids_instances = {} | ||
| 111 | _naughty_kids = set() | 87 | _naughty_kids = set() | ||
| 112 | 88 | ||||
| 113 | @classmethod | 89 | @classmethod | ||
| 114 | def _check_naughty(cls, method): | 90 | def _check_naughty(cls, method): | ||
| 115 | def wrapper(self, *args, **kwargs): | 91 | def wrapper(self, *args, **kwargs): | ||
| 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | 92 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
| 117 | 93 | ||||
| 118 | try: | 94 | try: | ||
| 119 | return method(self, *args, **kwargs) | 95 | return method(self, *args, **kwargs) | ||
| 120 | except Exception: | 96 | except Exception: | ||
| 121 | cls._naughty_kids.add(self) | 97 | cls._naughty_kids.add(self) | ||
| 122 | raise | 98 | raise | ||
| 123 | return wrapper | 99 | return wrapper | ||
| 124 | 100 | ||||
| 125 | def __new__(cls, name, bases, dct): | 101 | def __new__(cls, name, bases, dct): | ||
| 126 | if '__call__' not in dct: | 102 | if '__call__' not in dct: | ||
| 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 103 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
| 128 | 104 | ||||
| 129 | for attribute_name, attribute_val in dct.items(): | 105 | for attribute_name, attribute_val in dct.items(): | ||
| t | 130 | if hasattr(attribute_val, '__call__'): | t | 106 | if callable(attribute_val): | 
| 131 | if not attribute_name.startswith('_'): | 107 | if not attribute_name.startswith('_'): | ||
| 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | 108 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
| 133 | 109 | ||||
| 134 | return super().__new__(cls, name, bases, dct) | 110 | return super().__new__(cls, name, bases, dct) | ||
| 135 | 111 | ||||
| 136 | def __call__(cls, *args, **kwargs): | 112 | def __call__(cls, *args, **kwargs): | ||
| 137 | new_kid = super().__call__(*args, **kwargs) | 113 | new_kid = super().__call__(*args, **kwargs) | ||
| 138 | identity = id(new_kid) | 114 | identity = id(new_kid) | ||
| 139 | cls._kids_ages[identity] = 0 | 115 | cls._kids_ages[identity] = 0 | ||
| 140 | cls._kids_instances[identity] = new_kid | 116 | cls._kids_instances[identity] = new_kid | ||
| 141 | return new_kid | 117 | return new_kid | ||
| 142 | 118 | ||||
| 143 | @classmethod | 119 | @classmethod | ||
| 144 | def _increment_ages(cls): | 120 | def _increment_ages(cls): | ||
| 145 | """Increment the age of each kid by one year""" | 121 | """Increment the age of each kid by one year""" | ||
| 146 | 122 | ||||
| 147 | for identity, age in cls._kids_ages.items(): | 123 | for identity, age in cls._kids_ages.items(): | ||
| 148 | cls._kids_ages[identity] += 1 | 124 | cls._kids_ages[identity] += 1 | 
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 
 | 
 | |||||||||
| f | 1 | import re | f | 1 | import re | 
| 2 | 2 | ||||
| 3 | 3 | ||||
| 4 | class Singleton(type): | 4 | class Singleton(type): | ||
| 5 | _instances = {} | 5 | _instances = {} | ||
| 6 | 6 | ||||
| 7 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
| 8 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
| 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
| 10 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
| 11 | 11 | ||||
| 12 | 12 | ||||
| 13 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
| 14 | def __init__(self): | 14 | def __init__(self): | ||
| 15 | self._wishes = {} | 15 | self._wishes = {} | ||
| 16 | 16 | ||||
| 17 | def _get_wish(self, text): | 17 | def _get_wish(self, text): | ||
| 18 | """Get the wish from the letter/call""" | 18 | """Get the wish from the letter/call""" | ||
| 19 | 19 | ||||
| 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
| 21 | wish = re.search(pattern, text) | 21 | wish = re.search(pattern, text) | ||
| 22 | if wish: | 22 | if wish: | ||
| 23 | return wish.group(1) | 23 | return wish.group(1) | ||
| 24 | 24 | ||||
| 25 | def __call__(self, kid, text): | 25 | def __call__(self, kid, text): | ||
| 26 | wish = self._get_wish(text) | 26 | wish = self._get_wish(text) | ||
| 27 | if wish: | 27 | if wish: | ||
| 28 | self._wishes[id(kid)] = wish | 28 | self._wishes[id(kid)] = wish | ||
| 29 | 29 | ||||
| 30 | def _get_signature(self, text): | 30 | def _get_signature(self, text): | ||
| 31 | """Get the signature of the kid from the letter""" | 31 | """Get the signature of the kid from the letter""" | ||
| 32 | 32 | ||||
| 33 | pattern = r'\b\d+\b(?=\s*$)' | 33 | pattern = r'\b\d+\b(?=\s*$)' | ||
| 34 | signature = re.search(pattern, text) | 34 | signature = re.search(pattern, text) | ||
| 35 | if signature: | 35 | if signature: | ||
| 36 | return signature.group().strip() | 36 | return signature.group().strip() | ||
| 37 | 37 | ||||
| 38 | def __matmul__(self, text): | 38 | def __matmul__(self, text): | ||
| 39 | signature = self._get_signature(text) | 39 | signature = self._get_signature(text) | ||
| 40 | wish = self._get_wish(text) | 40 | wish = self._get_wish(text) | ||
| 41 | if signature and wish: | 41 | if signature and wish: | ||
| 42 | self._wishes[int(signature)] = wish | 42 | self._wishes[int(signature)] = wish | ||
| 43 | 43 | ||||
| 44 | @property | 44 | @property | ||
| 45 | def _generator(self): | 45 | def _generator(self): | ||
| 46 | for key, val in self._wishes.items(): | 46 | for key, val in self._wishes.items(): | ||
| 47 | yield self._wishes[key] | 47 | yield self._wishes[key] | ||
| 48 | 48 | ||||
| 49 | def __iter__(self): | 49 | def __iter__(self): | ||
| 50 | return self._generator | 50 | return self._generator | ||
| 51 | 51 | ||||
| 52 | def _count_wish_occurence(self, wish): | 52 | def _count_wish_occurence(self, wish): | ||
| 53 | """Count the number of times a gift has been wished""" | 53 | """Count the number of times a gift has been wished""" | ||
| 54 | 54 | ||||
| 55 | count = 0 | 55 | count = 0 | ||
| 56 | for key, val in self._wishes.items(): | 56 | for key, val in self._wishes.items(): | ||
| 57 | if(val == wish): | 57 | if(val == wish): | ||
| 58 | count += 1 | 58 | count += 1 | ||
| 59 | return count | 59 | return count | ||
| 60 | 60 | ||||
| 61 | @property | 61 | @property | ||
| 62 | def _get_most_wanted_gift_count(self): | 62 | def _get_most_wanted_gift_count(self): | ||
| 63 | """Get the number of times the most wanted gift has been wished""" | 63 | """Get the number of times the most wanted gift has been wished""" | ||
| 64 | 64 | ||||
| 65 | max_count = 0 | 65 | max_count = 0 | ||
| 66 | for key, val in self._wishes.items(): | 66 | for key, val in self._wishes.items(): | ||
| 67 | curr_count = self._count_wish_occurence(val) | 67 | curr_count = self._count_wish_occurence(val) | ||
| 68 | if curr_count > max_count: | 68 | if curr_count > max_count: | ||
| 69 | max_count = curr_count | 69 | max_count = curr_count | ||
| 70 | return max_count | 70 | return max_count | ||
| 71 | 71 | ||||
| 72 | @property | 72 | @property | ||
| 73 | def _get_most_wanted_gift(self): | 73 | def _get_most_wanted_gift(self): | ||
| 74 | """Get the most wanted gift""" | 74 | """Get the most wanted gift""" | ||
| 75 | 75 | ||||
| 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | ||
| 77 | for key, val in self._wishes.items(): | 77 | for key, val in self._wishes.items(): | ||
| 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||
| 79 | return val | 79 | return val | ||
| 80 | 80 | ||||
| 81 | def _clear_xmas(self): | 81 | def _clear_xmas(self): | ||
| 82 | """Clear the wishes and _naughty_kids""" | 82 | """Clear the wishes and _naughty_kids""" | ||
| 83 | 83 | ||||
| 84 | self._wishes.clear() | 84 | self._wishes.clear() | ||
| 85 | Kid._naughty_kids.clear() | 85 | Kid._naughty_kids.clear() | ||
| 86 | 86 | ||||
| 87 | def xmas(self): | 87 | def xmas(self): | ||
| 88 | Kid._increment_ages() | 88 | Kid._increment_ages() | ||
| 89 | 89 | ||||
| 90 | if not self._wishes: | 90 | if not self._wishes: | ||
| 91 | return | 91 | return | ||
| 92 | 92 | ||||
| 93 | most_wanted_gift = self._get_most_wanted_gift | 93 | most_wanted_gift = self._get_most_wanted_gift | ||
| 94 | for identity, kid in Kid._kids_instances.items(): | 94 | for identity, kid in Kid._kids_instances.items(): | ||
| 95 | if Kid._kids_ages[identity] <= 5: | 95 | if Kid._kids_ages[identity] <= 5: | ||
| 96 | if kid in Kid._naughty_kids: | 96 | if kid in Kid._naughty_kids: | ||
| t | 97 | kid("coal") | t | 97 | kid('coal') | 
| 98 | else: | 98 | else: | ||
| 99 | if identity in self._wishes: | 99 | if identity in self._wishes: | ||
| 100 | wish = self._wishes[identity] | 100 | wish = self._wishes[identity] | ||
| 101 | else: | 101 | else: | ||
| 102 | wish = most_wanted_gift | 102 | wish = most_wanted_gift | ||
| 103 | kid(wish) | 103 | kid(wish) | ||
| 104 | 104 | ||||
| 105 | self._clear_xmas() | 105 | self._clear_xmas() | ||
| 106 | 106 | ||||
| 107 | 107 | ||||
| 108 | class Kid(type): | 108 | class Kid(type): | ||
| 109 | _kids_ages = {} | 109 | _kids_ages = {} | ||
| 110 | _kids_instances = {} | 110 | _kids_instances = {} | ||
| 111 | _naughty_kids = set() | 111 | _naughty_kids = set() | ||
| 112 | 112 | ||||
| 113 | @classmethod | 113 | @classmethod | ||
| 114 | def _check_naughty(cls, method): | 114 | def _check_naughty(cls, method): | ||
| 115 | def wrapper(self, *args, **kwargs): | 115 | def wrapper(self, *args, **kwargs): | ||
| 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
| 117 | 117 | ||||
| 118 | try: | 118 | try: | ||
| 119 | return method(self, *args, **kwargs) | 119 | return method(self, *args, **kwargs) | ||
| 120 | except Exception: | 120 | except Exception: | ||
| 121 | cls._naughty_kids.add(self) | 121 | cls._naughty_kids.add(self) | ||
| 122 | raise | 122 | raise | ||
| 123 | return wrapper | 123 | return wrapper | ||
| 124 | 124 | ||||
| 125 | def __new__(cls, name, bases, dct): | 125 | def __new__(cls, name, bases, dct): | ||
| 126 | if '__call__' not in dct: | 126 | if '__call__' not in dct: | ||
| 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
| 128 | 128 | ||||
| 129 | for attribute_name, attribute_val in dct.items(): | 129 | for attribute_name, attribute_val in dct.items(): | ||
| 130 | if hasattr(attribute_val, '__call__'): | 130 | if hasattr(attribute_val, '__call__'): | ||
| 131 | if not attribute_name.startswith('_'): | 131 | if not attribute_name.startswith('_'): | ||
| 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
| 133 | 133 | ||||
| 134 | return super().__new__(cls, name, bases, dct) | 134 | return super().__new__(cls, name, bases, dct) | ||
| 135 | 135 | ||||
| 136 | def __call__(cls, *args, **kwargs): | 136 | def __call__(cls, *args, **kwargs): | ||
| 137 | new_kid = super().__call__(*args, **kwargs) | 137 | new_kid = super().__call__(*args, **kwargs) | ||
| 138 | identity = id(new_kid) | 138 | identity = id(new_kid) | ||
| 139 | cls._kids_ages[identity] = 0 | 139 | cls._kids_ages[identity] = 0 | ||
| 140 | cls._kids_instances[identity] = new_kid | 140 | cls._kids_instances[identity] = new_kid | ||
| 141 | return new_kid | 141 | return new_kid | ||
| 142 | 142 | ||||
| 143 | @classmethod | 143 | @classmethod | ||
| 144 | def _increment_ages(cls): | 144 | def _increment_ages(cls): | ||
| 145 | """Increment the age of each kid by one year""" | 145 | """Increment the age of each kid by one year""" | ||
| 146 | 146 | ||||
| 147 | for identity, age in cls._kids_ages.items(): | 147 | for identity, age in cls._kids_ages.items(): | ||
| 148 | cls._kids_ages[identity] += 1 | 148 | cls._kids_ages[identity] += 1 | 
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 
 | 
 | |||||||||
| f | 1 | import re | f | 1 | import re | 
| t | 2 | from unittest.mock import Mock | t | ||
| 3 | 2 | ||||
| 4 | 3 | ||||
| 5 | class Singleton(type): | 4 | class Singleton(type): | ||
| 6 | _instances = {} | 5 | _instances = {} | ||
| 7 | 6 | ||||
| 8 | def __call__(cls, *args, **kwargs): | 7 | def __call__(cls, *args, **kwargs): | ||
| 9 | if cls not in cls._instances: | 8 | if cls not in cls._instances: | ||
| 10 | cls._instances[cls] = super().__call__(*args, **kwargs) | 9 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
| 11 | return cls._instances[cls] | 10 | return cls._instances[cls] | ||
| 12 | 11 | ||||
| 13 | 12 | ||||
| 14 | class Santa(metaclass=Singleton): | 13 | class Santa(metaclass=Singleton): | ||
| 15 | def __init__(self): | 14 | def __init__(self): | ||
| 16 | self._wishes = {} | 15 | self._wishes = {} | ||
| 17 | 16 | ||||
| 18 | def _get_wish(self, text): | 17 | def _get_wish(self, text): | ||
| 19 | """Get the wish from the letter/call""" | 18 | """Get the wish from the letter/call""" | ||
| 20 | 19 | ||||
| 21 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | 20 | pattern = r'[\"\']([A-Za-z0-9 ]+)[\"\']' | ||
| 22 | wish = re.search(pattern, text) | 21 | wish = re.search(pattern, text) | ||
| 23 | if wish: | 22 | if wish: | ||
| 24 | return wish.group(1) | 23 | return wish.group(1) | ||
| 25 | 24 | ||||
| 26 | def __call__(self, kid, text): | 25 | def __call__(self, kid, text): | ||
| 27 | wish = self._get_wish(text) | 26 | wish = self._get_wish(text) | ||
| 28 | if wish: | 27 | if wish: | ||
| 29 | self._wishes[id(kid)] = wish | 28 | self._wishes[id(kid)] = wish | ||
| 30 | 29 | ||||
| 31 | def _get_signature(self, text): | 30 | def _get_signature(self, text): | ||
| 32 | """Get the signature of the kid from the letter""" | 31 | """Get the signature of the kid from the letter""" | ||
| 33 | 32 | ||||
| 34 | pattern = r'\b\d+\b(?=\s*$)' | 33 | pattern = r'\b\d+\b(?=\s*$)' | ||
| 35 | signature = re.search(pattern, text) | 34 | signature = re.search(pattern, text) | ||
| 36 | if signature: | 35 | if signature: | ||
| 37 | return signature.group().strip() | 36 | return signature.group().strip() | ||
| 38 | 37 | ||||
| 39 | def __matmul__(self, text): | 38 | def __matmul__(self, text): | ||
| 40 | signature = self._get_signature(text) | 39 | signature = self._get_signature(text) | ||
| 41 | wish = self._get_wish(text) | 40 | wish = self._get_wish(text) | ||
| 42 | if signature and wish: | 41 | if signature and wish: | ||
| 43 | self._wishes[int(signature)] = wish | 42 | self._wishes[int(signature)] = wish | ||
| 44 | 43 | ||||
| 45 | @property | 44 | @property | ||
| 46 | def _generator(self): | 45 | def _generator(self): | ||
| 47 | for key, val in self._wishes.items(): | 46 | for key, val in self._wishes.items(): | ||
| 48 | yield self._wishes[key] | 47 | yield self._wishes[key] | ||
| 49 | 48 | ||||
| 50 | def __iter__(self): | 49 | def __iter__(self): | ||
| 51 | return self._generator | 50 | return self._generator | ||
| 52 | 51 | ||||
| 53 | def _count_wish_occurence(self, wish): | 52 | def _count_wish_occurence(self, wish): | ||
| 54 | """Count the number of times a gift has been wished""" | 53 | """Count the number of times a gift has been wished""" | ||
| 55 | 54 | ||||
| 56 | count = 0 | 55 | count = 0 | ||
| 57 | for key, val in self._wishes.items(): | 56 | for key, val in self._wishes.items(): | ||
| 58 | if(val == wish): | 57 | if(val == wish): | ||
| 59 | count += 1 | 58 | count += 1 | ||
| 60 | return count | 59 | return count | ||
| 61 | 60 | ||||
| 62 | @property | 61 | @property | ||
| 63 | def _get_most_wanted_gift_count(self): | 62 | def _get_most_wanted_gift_count(self): | ||
| 64 | """Get the number of times the most wanted gift has been wished""" | 63 | """Get the number of times the most wanted gift has been wished""" | ||
| 65 | 64 | ||||
| 66 | max_count = 0 | 65 | max_count = 0 | ||
| 67 | for key, val in self._wishes.items(): | 66 | for key, val in self._wishes.items(): | ||
| 68 | curr_count = self._count_wish_occurence(val) | 67 | curr_count = self._count_wish_occurence(val) | ||
| 69 | if curr_count > max_count: | 68 | if curr_count > max_count: | ||
| 70 | max_count = curr_count | 69 | max_count = curr_count | ||
| 71 | return max_count | 70 | return max_count | ||
| 72 | 71 | ||||
| 73 | @property | 72 | @property | ||
| 74 | def _get_most_wanted_gift(self): | 73 | def _get_most_wanted_gift(self): | ||
| 75 | """Get the most wanted gift""" | 74 | """Get the most wanted gift""" | ||
| 76 | 75 | ||||
| 77 | most_wanted_gift_count = self._get_most_wanted_gift_count | 76 | most_wanted_gift_count = self._get_most_wanted_gift_count | ||
| 78 | for key, val in self._wishes.items(): | 77 | for key, val in self._wishes.items(): | ||
| 79 | if self._count_wish_occurence(val) == most_wanted_gift_count: | 78 | if self._count_wish_occurence(val) == most_wanted_gift_count: | ||
| 80 | return val | 79 | return val | ||
| 81 | 80 | ||||
| 82 | def _clear_xmas(self): | 81 | def _clear_xmas(self): | ||
| 83 | """Clear the wishes and _naughty_kids""" | 82 | """Clear the wishes and _naughty_kids""" | ||
| 84 | 83 | ||||
| 85 | self._wishes.clear() | 84 | self._wishes.clear() | ||
| 86 | Kid._naughty_kids.clear() | 85 | Kid._naughty_kids.clear() | ||
| 87 | 86 | ||||
| 88 | def xmas(self): | 87 | def xmas(self): | ||
| 89 | Kid._increment_ages() | 88 | Kid._increment_ages() | ||
| 90 | 89 | ||||
| 91 | if not self._wishes: | 90 | if not self._wishes: | ||
| 92 | return | 91 | return | ||
| 93 | 92 | ||||
| 94 | most_wanted_gift = self._get_most_wanted_gift | 93 | most_wanted_gift = self._get_most_wanted_gift | ||
| 95 | for identity, kid in Kid._kids_instances.items(): | 94 | for identity, kid in Kid._kids_instances.items(): | ||
| 96 | if Kid._kids_ages[identity] <= 5: | 95 | if Kid._kids_ages[identity] <= 5: | ||
| 97 | if kid in Kid._naughty_kids: | 96 | if kid in Kid._naughty_kids: | ||
| 98 | kid("coal") | 97 | kid("coal") | ||
| 99 | else: | 98 | else: | ||
| 100 | if identity in self._wishes: | 99 | if identity in self._wishes: | ||
| 101 | wish = self._wishes[identity] | 100 | wish = self._wishes[identity] | ||
| 102 | else: | 101 | else: | ||
| 103 | wish = most_wanted_gift | 102 | wish = most_wanted_gift | ||
| 104 | kid(wish) | 103 | kid(wish) | ||
| 105 | 104 | ||||
| 106 | self._clear_xmas() | 105 | self._clear_xmas() | ||
| 107 | 106 | ||||
| 108 | 107 | ||||
| 109 | class Kid(type): | 108 | class Kid(type): | ||
| 110 | _kids_ages = {} | 109 | _kids_ages = {} | ||
| 111 | _kids_instances = {} | 110 | _kids_instances = {} | ||
| 112 | _naughty_kids = set() | 111 | _naughty_kids = set() | ||
| 113 | 112 | ||||
| 114 | @classmethod | 113 | @classmethod | ||
| 115 | def _check_naughty(cls, method): | 114 | def _check_naughty(cls, method): | ||
| 116 | def wrapper(self, *args, **kwargs): | 115 | def wrapper(self, *args, **kwargs): | ||
| 117 | """Add the instance to _naughty_kids if an exception is raised in method""" | 116 | """Add the instance to _naughty_kids if an exception is raised in method""" | ||
| 118 | 117 | ||||
| 119 | try: | 118 | try: | ||
| 120 | return method(self, *args, **kwargs) | 119 | return method(self, *args, **kwargs) | ||
| 121 | except Exception: | 120 | except Exception: | ||
| 122 | cls._naughty_kids.add(self) | 121 | cls._naughty_kids.add(self) | ||
| 123 | raise | 122 | raise | ||
| 124 | return wrapper | 123 | return wrapper | ||
| 125 | 124 | ||||
| 126 | def __new__(cls, name, bases, dct): | 125 | def __new__(cls, name, bases, dct): | ||
| 127 | if '__call__' not in dct: | 126 | if '__call__' not in dct: | ||
| 128 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | 127 | raise NotImplementedError('Sorry, but the instance of the class should be callable (dont get angry, please) :)') | ||
| 129 | 128 | ||||
| 130 | for attribute_name, attribute_val in dct.items(): | 129 | for attribute_name, attribute_val in dct.items(): | ||
| 131 | if hasattr(attribute_val, '__call__'): | 130 | if hasattr(attribute_val, '__call__'): | ||
| 132 | if not attribute_name.startswith('_'): | 131 | if not attribute_name.startswith('_'): | ||
| 133 | dct[attribute_name] = cls._check_naughty(attribute_val) | 132 | dct[attribute_name] = cls._check_naughty(attribute_val) | ||
| 134 | 133 | ||||
| 135 | return super().__new__(cls, name, bases, dct) | 134 | return super().__new__(cls, name, bases, dct) | ||
| 136 | 135 | ||||
| 137 | def __call__(cls, *args, **kwargs): | 136 | def __call__(cls, *args, **kwargs): | ||
| 138 | new_kid = super().__call__(*args, **kwargs) | 137 | new_kid = super().__call__(*args, **kwargs) | ||
| 139 | identity = id(new_kid) | 138 | identity = id(new_kid) | ||
| 140 | cls._kids_ages[identity] = 0 | 139 | cls._kids_ages[identity] = 0 | ||
| 141 | cls._kids_instances[identity] = new_kid | 140 | cls._kids_instances[identity] = new_kid | ||
| 142 | return new_kid | 141 | return new_kid | ||
| 143 | 142 | ||||
| 144 | @classmethod | 143 | @classmethod | ||
| 145 | def _increment_ages(cls): | 144 | def _increment_ages(cls): | ||
| 146 | """Increment the age of each kid by one year""" | 145 | """Increment the age of each kid by one year""" | ||
| 147 | 146 | ||||
| 148 | for identity, age in cls._kids_ages.items(): | 147 | for identity, age in cls._kids_ages.items(): | ||
| 149 | cls._kids_ages[identity] += 1 | 148 | cls._kids_ages[identity] += 1 | 
| Legends | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 
 | 
 | |||||||||