1import re
2from collections import OrderedDict, Counter
3
4
5class Singleton(type):
6 def __new__(cls, name, bases, attrs):
7 def singleton_new(cls):
8 if not hasattr(cls, 'instance'):
9 cls.instance = object.__new__(cls)
10 return cls.instance
11 attrs['__new__'] = singleton_new
12 return super().__new__(cls, name, bases, attrs)
13
14
15class Santa(metaclass=Singleton):
16 """HOHOHO."""
17
18 kid_present = OrderedDict()
19
20 def __init__(self):
21 self.presents_iter = None
22
23 def __call__(self, kid, wish: str):
24 extracted_info = Wish(wish)
25 self.kid_present[kid] = extracted_info.present
26
27 def __matmul__(self, letter: str):
28 extracted_info = Wish(letter)
29 self.kid_present[Kid.find_kid(extracted_info.kid_id)] = extracted_info.present
30
31 def __iter__(self):
32 return iter(self.kid_present.values())
33
34 def xmas(self):
35 Kid.increment_age_of_all_kids()
36
37 # if there are no wishes return
38 if not self.kid_present:
39 return
40
41 counted = Counter(self.__iter__())
42 most_common_present = counted.most_common(1)[0][0]
43
44 for kid in Kid.kids_created:
45 if kid.age > 5:
46 continue
47
48 if kid.naughty:
49 kid('coal')
50 kid.naughty = False
51 continue
52
53 present = self.kid_present.get(kid, most_common_present)
54 kid(present)
55
56 # remove kid from wishlist
57 if kid in self.kid_present:
58 self.kid_present.pop(kid)
59
60
61class Wish:
62 """Decipher wish and extract only relevant info."""
63
64 def __init__(self, wish: str):
65 self.present = None
66 self.kid_id = None
67
68 # find present
69 present_pattern = r'([\'\"])(?P<present>(\s*\w+\s*)+)(\1)'
70 match = re.search(present_pattern, wish)
71 if match:
72 self.present = match.group('present')
73
74 # find id if there is one
75 id_pattern = r'\n\s*(?P<kid_id>\d+)\s*(\n|$)'
76 match = re.search(id_pattern, wish)
77 if match:
78 self.kid_id = int(match.group('kid_id'))
79
80
81class Kid(type):
82
83 kids_created = [] # who knows how exactly
84
85 def __new__(cls, name, bases, attrs):
86 # add naughty flag and age to all kids
87 attrs['naughty'] = False
88 attrs['age'] = 0
89
90 # check if kid is callable
91 if not attrs.get('__call__', None):
92 raise NotImplementedError('kur cici kurviiiiiiiiiiii - съобщение от човек не в курса')
93
94 # decorate __new__ if it exists in child class and create it if it doesn't
95 try:
96 attrs['__new__'] = cls.new_kid_decorator(attrs['__new__'])
97 except Exception:
98 attrs['__new__'] = cls.new_kid
99
100 # wrap all public methods in decorator to check for naughtiness
101 for name, attr in attrs.items():
102 if callable(attr) and not name.startswith('__'):
103 attrs[name] = cls.naughty_decorator(attr)
104
105 return super().__new__(cls, name, bases, attrs)
106
107 @classmethod
108 def find_kid(cls, kid_id: int):
109 for kid in cls.kids_created:
110 if id(kid) == kid_id:
111 return kid
112
113 @staticmethod
114 def new_kid_decorator(func):
115 def decorated(self, *args, **kwargs):
116 Kid.kids_created.append(self)
117 return func(self, *args, **kwargs)
118 return decorated
119
120 @staticmethod
121 def new_kid(cls_kid):
122 instance = object.__new__(cls_kid)
123 Kid.kids_created.append(instance)
124 return instance
125
126 @staticmethod
127 def naughty_decorator(func):
128 def decorated(self, *args, **kwargs):
129 try:
130 res = func(self, *args, **kwargs)
131 except Exception:
132 self.naughty = True
133 raise
134 return res
135 return decorated
136
137 @classmethod
138 def increment_age_of_all_kids(cls):
139 for kid in cls.kids_created:
140 kid.age += 1
......F.........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: ['кавички', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
First differing element 0:
'кавички'
'toy4'
- ['кавички', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
? ^^^^^^^
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
? ^^^^
======================================================================
FAIL: test_xmass_private_with_error (test.TestSanta.test_xmass_private_with_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 240, in test_xmass_private_with_error
self.assertEqual(kid1.SECRET_PRESENT, 'sirenie')
AssertionError: 'coal' != 'sirenie'
- coal
+ sirenie
----------------------------------------------------------------------
Ran 20 tests in 0.040s
FAILED (failures=2)
f | 1 | import re | f | 1 | import re |
2 | from collections import OrderedDict, Counter | 2 | from collections import OrderedDict, Counter | ||
3 | 3 | ||||
4 | 4 | ||||
5 | class Singleton(type): | 5 | class Singleton(type): | ||
6 | def __new__(cls, name, bases, attrs): | 6 | def __new__(cls, name, bases, attrs): | ||
7 | def singleton_new(cls): | 7 | def singleton_new(cls): | ||
8 | if not hasattr(cls, 'instance'): | 8 | if not hasattr(cls, 'instance'): | ||
9 | cls.instance = object.__new__(cls) | 9 | cls.instance = object.__new__(cls) | ||
10 | return cls.instance | 10 | return cls.instance | ||
11 | attrs['__new__'] = singleton_new | 11 | attrs['__new__'] = singleton_new | ||
12 | return super().__new__(cls, name, bases, attrs) | 12 | return super().__new__(cls, name, bases, attrs) | ||
13 | 13 | ||||
14 | 14 | ||||
15 | class Santa(metaclass=Singleton): | 15 | class Santa(metaclass=Singleton): | ||
16 | """HOHOHO.""" | 16 | """HOHOHO.""" | ||
17 | 17 | ||||
18 | kid_present = OrderedDict() | 18 | kid_present = OrderedDict() | ||
19 | 19 | ||||
20 | def __init__(self): | 20 | def __init__(self): | ||
21 | self.presents_iter = None | 21 | self.presents_iter = None | ||
22 | 22 | ||||
23 | def __call__(self, kid, wish: str): | 23 | def __call__(self, kid, wish: str): | ||
24 | extracted_info = Wish(wish) | 24 | extracted_info = Wish(wish) | ||
25 | self.kid_present[kid] = extracted_info.present | 25 | self.kid_present[kid] = extracted_info.present | ||
26 | 26 | ||||
27 | def __matmul__(self, letter: str): | 27 | def __matmul__(self, letter: str): | ||
28 | extracted_info = Wish(letter) | 28 | extracted_info = Wish(letter) | ||
29 | self.kid_present[Kid.find_kid(extracted_info.kid_id)] = extracted_info.present | 29 | self.kid_present[Kid.find_kid(extracted_info.kid_id)] = extracted_info.present | ||
30 | 30 | ||||
31 | def __iter__(self): | 31 | def __iter__(self): | ||
t | 32 | self.presents_iter = iter(self.kid_present.values()) | t | 32 | return iter(self.kid_present.values()) |
33 | return self.presents_iter | ||||
34 | |||||
35 | def __next__(self): | ||||
36 | return next(self.presents_iter) | ||||
37 | 33 | ||||
38 | def xmas(self): | 34 | def xmas(self): | ||
39 | Kid.increment_age_of_all_kids() | 35 | Kid.increment_age_of_all_kids() | ||
40 | 36 | ||||
41 | # if there are no wishes return | 37 | # if there are no wishes return | ||
42 | if not self.kid_present: | 38 | if not self.kid_present: | ||
43 | return | 39 | return | ||
44 | 40 | ||||
45 | counted = Counter(self.__iter__()) | 41 | counted = Counter(self.__iter__()) | ||
46 | most_common_present = counted.most_common(1)[0][0] | 42 | most_common_present = counted.most_common(1)[0][0] | ||
47 | 43 | ||||
48 | for kid in Kid.kids_created: | 44 | for kid in Kid.kids_created: | ||
49 | if kid.age > 5: | 45 | if kid.age > 5: | ||
50 | continue | 46 | continue | ||
51 | 47 | ||||
52 | if kid.naughty: | 48 | if kid.naughty: | ||
53 | kid('coal') | 49 | kid('coal') | ||
54 | kid.naughty = False | 50 | kid.naughty = False | ||
55 | continue | 51 | continue | ||
56 | 52 | ||||
57 | present = self.kid_present.get(kid, most_common_present) | 53 | present = self.kid_present.get(kid, most_common_present) | ||
58 | kid(present) | 54 | kid(present) | ||
59 | 55 | ||||
60 | # remove kid from wishlist | 56 | # remove kid from wishlist | ||
61 | if kid in self.kid_present: | 57 | if kid in self.kid_present: | ||
62 | self.kid_present.pop(kid) | 58 | self.kid_present.pop(kid) | ||
63 | 59 | ||||
64 | 60 | ||||
65 | class Wish: | 61 | class Wish: | ||
66 | """Decipher wish and extract only relevant info.""" | 62 | """Decipher wish and extract only relevant info.""" | ||
67 | 63 | ||||
68 | def __init__(self, wish: str): | 64 | def __init__(self, wish: str): | ||
69 | self.present = None | 65 | self.present = None | ||
70 | self.kid_id = None | 66 | self.kid_id = None | ||
71 | 67 | ||||
72 | # find present | 68 | # find present | ||
73 | present_pattern = r'([\'\"])(?P<present>(\s*\w+\s*)+)(\1)' | 69 | present_pattern = r'([\'\"])(?P<present>(\s*\w+\s*)+)(\1)' | ||
74 | match = re.search(present_pattern, wish) | 70 | match = re.search(present_pattern, wish) | ||
75 | if match: | 71 | if match: | ||
76 | self.present = match.group('present') | 72 | self.present = match.group('present') | ||
77 | 73 | ||||
78 | # find id if there is one | 74 | # find id if there is one | ||
79 | id_pattern = r'\n\s*(?P<kid_id>\d+)\s*(\n|$)' | 75 | id_pattern = r'\n\s*(?P<kid_id>\d+)\s*(\n|$)' | ||
80 | match = re.search(id_pattern, wish) | 76 | match = re.search(id_pattern, wish) | ||
81 | if match: | 77 | if match: | ||
82 | self.kid_id = int(match.group('kid_id')) | 78 | self.kid_id = int(match.group('kid_id')) | ||
83 | 79 | ||||
84 | 80 | ||||
85 | class Kid(type): | 81 | class Kid(type): | ||
86 | 82 | ||||
87 | kids_created = [] # who knows how exactly | 83 | kids_created = [] # who knows how exactly | ||
88 | 84 | ||||
89 | def __new__(cls, name, bases, attrs): | 85 | def __new__(cls, name, bases, attrs): | ||
90 | # add naughty flag and age to all kids | 86 | # add naughty flag and age to all kids | ||
91 | attrs['naughty'] = False | 87 | attrs['naughty'] = False | ||
92 | attrs['age'] = 0 | 88 | attrs['age'] = 0 | ||
93 | 89 | ||||
94 | # check if kid is callable | 90 | # check if kid is callable | ||
95 | if not attrs.get('__call__', None): | 91 | if not attrs.get('__call__', None): | ||
96 | raise NotImplementedError('kur cici kurviiiiiiiiiiii - съобщение от човек не в курса') | 92 | raise NotImplementedError('kur cici kurviiiiiiiiiiii - съобщение от човек не в курса') | ||
97 | 93 | ||||
98 | # decorate __new__ if it exists in child class and create it if it doesn't | 94 | # decorate __new__ if it exists in child class and create it if it doesn't | ||
99 | try: | 95 | try: | ||
100 | attrs['__new__'] = cls.new_kid_decorator(attrs['__new__']) | 96 | attrs['__new__'] = cls.new_kid_decorator(attrs['__new__']) | ||
101 | except Exception: | 97 | except Exception: | ||
102 | attrs['__new__'] = cls.new_kid | 98 | attrs['__new__'] = cls.new_kid | ||
103 | 99 | ||||
104 | # wrap all public methods in decorator to check for naughtiness | 100 | # wrap all public methods in decorator to check for naughtiness | ||
105 | for name, attr in attrs.items(): | 101 | for name, attr in attrs.items(): | ||
106 | if callable(attr) and not name.startswith('__'): | 102 | if callable(attr) and not name.startswith('__'): | ||
107 | attrs[name] = cls.naughty_decorator(attr) | 103 | attrs[name] = cls.naughty_decorator(attr) | ||
108 | 104 | ||||
109 | return super().__new__(cls, name, bases, attrs) | 105 | return super().__new__(cls, name, bases, attrs) | ||
110 | 106 | ||||
111 | @classmethod | 107 | @classmethod | ||
112 | def find_kid(cls, kid_id: int): | 108 | def find_kid(cls, kid_id: int): | ||
113 | for kid in cls.kids_created: | 109 | for kid in cls.kids_created: | ||
114 | if id(kid) == kid_id: | 110 | if id(kid) == kid_id: | ||
115 | return kid | 111 | return kid | ||
116 | 112 | ||||
117 | @staticmethod | 113 | @staticmethod | ||
118 | def new_kid_decorator(func): | 114 | def new_kid_decorator(func): | ||
119 | def decorated(self, *args, **kwargs): | 115 | def decorated(self, *args, **kwargs): | ||
120 | Kid.kids_created.append(self) | 116 | Kid.kids_created.append(self) | ||
121 | return func(self, *args, **kwargs) | 117 | return func(self, *args, **kwargs) | ||
122 | return decorated | 118 | return decorated | ||
123 | 119 | ||||
124 | @staticmethod | 120 | @staticmethod | ||
125 | def new_kid(cls_kid): | 121 | def new_kid(cls_kid): | ||
126 | instance = object.__new__(cls_kid) | 122 | instance = object.__new__(cls_kid) | ||
127 | Kid.kids_created.append(instance) | 123 | Kid.kids_created.append(instance) | ||
128 | return instance | 124 | return instance | ||
129 | 125 | ||||
130 | @staticmethod | 126 | @staticmethod | ||
131 | def naughty_decorator(func): | 127 | def naughty_decorator(func): | ||
132 | def decorated(self, *args, **kwargs): | 128 | def decorated(self, *args, **kwargs): | ||
133 | try: | 129 | try: | ||
134 | res = func(self, *args, **kwargs) | 130 | res = func(self, *args, **kwargs) | ||
135 | except Exception: | 131 | except Exception: | ||
136 | self.naughty = True | 132 | self.naughty = True | ||
137 | raise | 133 | raise | ||
138 | return res | 134 | return res | ||
139 | return decorated | 135 | return decorated | ||
140 | 136 | ||||
141 | @classmethod | 137 | @classmethod | ||
142 | def increment_age_of_all_kids(cls): | 138 | def increment_age_of_all_kids(cls): | ||
143 | for kid in cls.kids_created: | 139 | for kid in cls.kids_created: | ||
144 | kid.age += 1 | 140 | kid.age += 1 |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
15.12.2024 12:33
15.12.2024 14:28
15.12.2024 12:58
15.12.2024 12:57