1import gc
2import re
3
4
5class SingletonMeta(type):
6 _instances = {}
7
8 def __call__(cls, *args, **kwargs):
9 if cls not in cls._instances:
10 cls._instances[cls] = super().__call__(*args, **kwargs)
11 return cls._instances[cls]
12
13
14class Santa(metaclass=SingletonMeta):
15
16 _kids_dict = {}
17 _wanted_gifts = 0
18
19 def __call__(self, kid_instance, present_str):
20 gift_pattern = r"(['\"])([A-Za-z0-9\s]+)\1"
21 match = re.search(gift_pattern, present_str)
22
23 if match:
24 gift = match.group(2)
25 self._kids_dict[id(kid_instance)]["present"] = gift
26 self._wanted_gifts += 1
27
28 def __matmul__(self, letter):
29 gift_pattern = r"(['\"])([A-Za-z0-9\s]+?)\1"
30 gift_match = re.search(gift_pattern, letter)
31 if gift_match:
32 gift = gift_match.group(2)
33
34 signature_pattern = r"^\s*(\d+)\s*$"
35 signature_match = re.search(
36 signature_pattern, letter.strip().splitlines()[-1]
37 )
38
39 if signature_match:
40 child_id = signature_match.group(1)
41 self._kids_dict[int(child_id)]["present"] = gift
42 self._wanted_gifts += 1
43
44 def __iter__(self):
45 value = True
46 for kid in self._kids_dict.items():
47 kid_id = kid[0]
48 if self._kids_dict[kid_id]["present"]:
49 value = False
50
51 if value:
52 return
53
54 for key, value in self._kids_dict.items():
55 yield value["present"]
56
57 @staticmethod
58 def add_kid(kid_class):
59 Santa._kids_dict[id(kid_class)] = {"age": 0, "error_cnt": 0, "present": None}
60
61 @staticmethod
62 def add_error(kid_class, error):
63 Santa._kids_dict[id(kid_class)]["error_cnt"] += 1
64
65 def xmas(self):
66 for kid in self._kids_dict.items():
67 kid_id = kid[0]
68 self._kids_dict[kid_id]["age"] += 1
69
70 if self._wanted_gifts < 1:
71 return
72 self._wanted_gifts = 0
73
74 for kid in self._kids_dict.items():
75 kid_id = kid[0]
76 if self._kids_dict[kid_id]["age"] > 5:
77 continue
78
79 if self._kids_dict[kid_id]["error_cnt"] > 0:
80 kid = get_instance_by_id(kid_id)
81 kid("coal")
82 self._kids_dict[kid_id]["error_cnt"] = 0
83 continue
84
85 if kid[1]["present"] is not None:
86 kid_instance = get_instance_by_id(kid_id)
87 kid_instance(kid[1]["present"])
88 continue
89
90 count_sort_arr = {}
91 for present in self:
92 if present is not None:
93 if present is not count_sort_arr:
94 count_sort_arr[present] = 0
95 else:
96 count_sort_arr[present] += 1
97 most_frequent = max(count_sort_arr, key=count_sort_arr.get)
98 kid_instance = get_instance_by_id(kid_id)
99 kid_instance(most_frequent)
100
101 self._kids_dict[kid_id]["age"] += 1
102
103 for kid in self._kids_dict.items():
104 kid_id = kid[0]
105 self._kids_dict[kid_id]["present"] = None
106
107def get_instance_by_id(obj_id):
108 for obj in gc.get_objects():
109 if id(obj) == obj_id:
110 return obj
111 return None
112
113
114class Kid(type):
115 def __call__(cls, *args, **kwargs):
116 instance = super().__call__(*args, **kwargs)
117 Santa.add_kid(instance)
118 return instance
119
120 def __new__(cls, name, bases, dct):
121
122 if "__call__" not in dct:
123 raise NotImplementedError
124
125 for attr_name, attr_value in dct.items():
126 if (
127 callable(attr_value)
128 and not attr_name.startswith("__")
129 and not attr_name.startswith("_")
130 ):
131
132 def wrapper(self, *args, **kwargs):
133 try:
134 return attr_value(self, *args, **kwargs)
135 except Exception as e:
136 Santa.add_error(self, e)
137 raise e
138
139 dct[attr_name] = wrapper
140 return super().__new__(cls, name, bases, dct)
......FF.....E...E..
======================================================================
ERROR: test_xmass_naughty (test.TestSanta.test_xmass_naughty)
Test a Christmas with naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 223, in test_xmass_naughty
kid1.public_with_error()
File "/tmp/solution.py", line 137, in wrapper
raise e
File "/tmp/solution.py", line 134, in wrapper
return attr_value(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/test.py", line 30, in <lambda>
'_private_with_error': lambda self: not_existing,
^^^^^^^^^^^^
NameError: name 'not_existing' is not defined
======================================================================
ERROR: test_xmass_public_with_no_error (test.TestSanta.test_xmass_public_with_no_error)
Test a Christmas with not-so-naughty kids.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 246, in test_xmass_public_with_no_error
self.assertEqual(kid1.public_without_error(), 42)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 137, in wrapper
raise e
File "/tmp/solution.py", line 134, in wrapper
return attr_value(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/test.py", line 30, in <lambda>
'_private_with_error': lambda self: not_existing,
^^^^^^^^^^^^
NameError: name 'not_existing' is not defined
======================================================================
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', None] != ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
First differing element 1:
None
'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 '
- ['toy4', None]
+ ['toy4', 'abcdefgHIJKLMNopQRstUVwxYZ 1 2 3 4567890 ']
======================================================================
FAIL: test_santa_gift_order (test.TestSanta.test_santa_gift_order)
Test ordering of the Santa iterator.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 260, in test_santa_gift_order
self.assertEqual(list(self.santa), ["toy2v2", "toy3", "toy1"])
AssertionError: Lists differ: ['toy1', 'toy2v2', 'toy3'] != ['toy2v2', 'toy3', 'toy1']
First differing element 0:
'toy1'
'toy2v2'
- ['toy1', 'toy2v2', 'toy3']
+ ['toy2v2', 'toy3', 'toy1']
----------------------------------------------------------------------
Ran 20 tests in 0.074s
FAILED (failures=2, errors=2)
f | 1 | import gc | f | 1 | import gc |
2 | import re | 2 | import re | ||
3 | 3 | ||||
4 | 4 | ||||
5 | class SingletonMeta(type): | 5 | class SingletonMeta(type): | ||
6 | _instances = {} | 6 | _instances = {} | ||
7 | 7 | ||||
8 | def __call__(cls, *args, **kwargs): | 8 | def __call__(cls, *args, **kwargs): | ||
9 | if cls not in cls._instances: | 9 | if cls not in cls._instances: | ||
10 | cls._instances[cls] = super().__call__(*args, **kwargs) | 10 | cls._instances[cls] = super().__call__(*args, **kwargs) | ||
11 | return cls._instances[cls] | 11 | return cls._instances[cls] | ||
n | 12 | n | 12 | ||
13 | 13 | ||||
14 | class Santa(metaclass=SingletonMeta): | 14 | class Santa(metaclass=SingletonMeta): | ||
15 | 15 | ||||
16 | _kids_dict = {} | 16 | _kids_dict = {} | ||
17 | _wanted_gifts = 0 | 17 | _wanted_gifts = 0 | ||
18 | 18 | ||||
n | 19 | def __call__(self, kid_class, present_str): | n | 19 | def __call__(self, kid_instance, present_str): |
20 | gift_pattern = r"(['\"])([A-Za-z0-9\s]+)\1" | 20 | gift_pattern = r"(['\"])([A-Za-z0-9\s]+)\1" | ||
21 | match = re.search(gift_pattern, present_str) | 21 | match = re.search(gift_pattern, present_str) | ||
22 | 22 | ||||
23 | if match: | 23 | if match: | ||
24 | gift = match.group(2) | 24 | gift = match.group(2) | ||
n | 25 | self._kids_dict[id(kid_class)]["present"] = gift | n | 25 | self._kids_dict[id(kid_instance)]["present"] = gift |
26 | self._wanted_gifts += 1 | 26 | self._wanted_gifts += 1 | ||
27 | 27 | ||||
28 | def __matmul__(self, letter): | 28 | def __matmul__(self, letter): | ||
29 | gift_pattern = r"(['\"])([A-Za-z0-9\s]+?)\1" | 29 | gift_pattern = r"(['\"])([A-Za-z0-9\s]+?)\1" | ||
30 | gift_match = re.search(gift_pattern, letter) | 30 | gift_match = re.search(gift_pattern, letter) | ||
31 | if gift_match: | 31 | if gift_match: | ||
32 | gift = gift_match.group(2) | 32 | gift = gift_match.group(2) | ||
33 | 33 | ||||
34 | signature_pattern = r"^\s*(\d+)\s*$" | 34 | signature_pattern = r"^\s*(\d+)\s*$" | ||
35 | signature_match = re.search( | 35 | signature_match = re.search( | ||
36 | signature_pattern, letter.strip().splitlines()[-1] | 36 | signature_pattern, letter.strip().splitlines()[-1] | ||
37 | ) | 37 | ) | ||
38 | 38 | ||||
39 | if signature_match: | 39 | if signature_match: | ||
40 | child_id = signature_match.group(1) | 40 | child_id = signature_match.group(1) | ||
41 | self._kids_dict[int(child_id)]["present"] = gift | 41 | self._kids_dict[int(child_id)]["present"] = gift | ||
42 | self._wanted_gifts += 1 | 42 | self._wanted_gifts += 1 | ||
43 | 43 | ||||
44 | def __iter__(self): | 44 | def __iter__(self): | ||
n | n | 45 | value = True | ||
46 | for kid in self._kids_dict.items(): | ||||
47 | kid_id = kid[0] | ||||
48 | if self._kids_dict[kid_id]["present"]: | ||||
49 | value = False | ||||
50 | |||||
51 | if value: | ||||
52 | return | ||||
53 | |||||
45 | for key, value in self._kids_dict.items(): | 54 | for key, value in self._kids_dict.items(): | ||
46 | yield value["present"] | 55 | yield value["present"] | ||
47 | 56 | ||||
48 | @staticmethod | 57 | @staticmethod | ||
49 | def add_kid(kid_class): | 58 | def add_kid(kid_class): | ||
50 | Santa._kids_dict[id(kid_class)] = {"age": 0, "error_cnt": 0, "present": None} | 59 | Santa._kids_dict[id(kid_class)] = {"age": 0, "error_cnt": 0, "present": None} | ||
51 | 60 | ||||
52 | @staticmethod | 61 | @staticmethod | ||
53 | def add_error(kid_class, error): | 62 | def add_error(kid_class, error): | ||
54 | Santa._kids_dict[id(kid_class)]["error_cnt"] += 1 | 63 | Santa._kids_dict[id(kid_class)]["error_cnt"] += 1 | ||
55 | 64 | ||||
56 | def xmas(self): | 65 | def xmas(self): | ||
57 | for kid in self._kids_dict.items(): | 66 | for kid in self._kids_dict.items(): | ||
58 | kid_id = kid[0] | 67 | kid_id = kid[0] | ||
59 | self._kids_dict[kid_id]["age"] += 1 | 68 | self._kids_dict[kid_id]["age"] += 1 | ||
60 | 69 | ||||
61 | if self._wanted_gifts < 1: | 70 | if self._wanted_gifts < 1: | ||
62 | return | 71 | return | ||
63 | self._wanted_gifts = 0 | 72 | self._wanted_gifts = 0 | ||
64 | 73 | ||||
65 | for kid in self._kids_dict.items(): | 74 | for kid in self._kids_dict.items(): | ||
66 | kid_id = kid[0] | 75 | kid_id = kid[0] | ||
n | 67 | if self._kids_dict[kid_id]["age"] > 6: | n | 76 | if self._kids_dict[kid_id]["age"] > 5: |
68 | continue | 77 | continue | ||
69 | 78 | ||||
70 | if self._kids_dict[kid_id]["error_cnt"] > 0: | 79 | if self._kids_dict[kid_id]["error_cnt"] > 0: | ||
71 | kid = get_instance_by_id(kid_id) | 80 | kid = get_instance_by_id(kid_id) | ||
72 | kid("coal") | 81 | kid("coal") | ||
73 | self._kids_dict[kid_id]["error_cnt"] = 0 | 82 | self._kids_dict[kid_id]["error_cnt"] = 0 | ||
74 | continue | 83 | continue | ||
75 | 84 | ||||
76 | if kid[1]["present"] is not None: | 85 | if kid[1]["present"] is not None: | ||
77 | kid_instance = get_instance_by_id(kid_id) | 86 | kid_instance = get_instance_by_id(kid_id) | ||
78 | kid_instance(kid[1]["present"]) | 87 | kid_instance(kid[1]["present"]) | ||
79 | continue | 88 | continue | ||
80 | 89 | ||||
81 | count_sort_arr = {} | 90 | count_sort_arr = {} | ||
82 | for present in self: | 91 | for present in self: | ||
83 | if present is not None: | 92 | if present is not None: | ||
84 | if present is not count_sort_arr: | 93 | if present is not count_sort_arr: | ||
85 | count_sort_arr[present] = 0 | 94 | count_sort_arr[present] = 0 | ||
86 | else: | 95 | else: | ||
87 | count_sort_arr[present] += 1 | 96 | count_sort_arr[present] += 1 | ||
88 | most_frequent = max(count_sort_arr, key=count_sort_arr.get) | 97 | most_frequent = max(count_sort_arr, key=count_sort_arr.get) | ||
89 | kid_instance = get_instance_by_id(kid_id) | 98 | kid_instance = get_instance_by_id(kid_id) | ||
90 | kid_instance(most_frequent) | 99 | kid_instance(most_frequent) | ||
91 | 100 | ||||
92 | self._kids_dict[kid_id]["age"] += 1 | 101 | self._kids_dict[kid_id]["age"] += 1 | ||
93 | 102 | ||||
94 | for kid in self._kids_dict.items(): | 103 | for kid in self._kids_dict.items(): | ||
95 | kid_id = kid[0] | 104 | kid_id = kid[0] | ||
96 | self._kids_dict[kid_id]["present"] = None | 105 | self._kids_dict[kid_id]["present"] = None | ||
97 | 106 | ||||
n | 98 | n | |||
99 | def get_instance_by_id(obj_id): | 107 | def get_instance_by_id(obj_id): | ||
100 | for obj in gc.get_objects(): | 108 | for obj in gc.get_objects(): | ||
101 | if id(obj) == obj_id: | 109 | if id(obj) == obj_id: | ||
102 | return obj | 110 | return obj | ||
103 | return None | 111 | return None | ||
104 | 112 | ||||
105 | 113 | ||||
106 | class Kid(type): | 114 | class Kid(type): | ||
107 | def __call__(cls, *args, **kwargs): | 115 | def __call__(cls, *args, **kwargs): | ||
108 | instance = super().__call__(*args, **kwargs) | 116 | instance = super().__call__(*args, **kwargs) | ||
109 | Santa.add_kid(instance) | 117 | Santa.add_kid(instance) | ||
110 | return instance | 118 | return instance | ||
111 | 119 | ||||
112 | def __new__(cls, name, bases, dct): | 120 | def __new__(cls, name, bases, dct): | ||
n | n | 121 | |||
122 | if "__call__" not in dct: | ||||
123 | raise NotImplementedError | ||||
124 | |||||
113 | for attr_name, attr_value in dct.items(): | 125 | for attr_name, attr_value in dct.items(): | ||
114 | if ( | 126 | if ( | ||
115 | callable(attr_value) | 127 | callable(attr_value) | ||
116 | and not attr_name.startswith("__") | 128 | and not attr_name.startswith("__") | ||
117 | and not attr_name.startswith("_") | 129 | and not attr_name.startswith("_") | ||
118 | ): | 130 | ): | ||
119 | 131 | ||||
120 | def wrapper(self, *args, **kwargs): | 132 | def wrapper(self, *args, **kwargs): | ||
121 | try: | 133 | try: | ||
122 | return attr_value(self, *args, **kwargs) | 134 | return attr_value(self, *args, **kwargs) | ||
123 | except Exception as e: | 135 | except Exception as e: | ||
124 | Santa.add_error(self, e) | 136 | Santa.add_error(self, e) | ||
125 | raise e | 137 | raise e | ||
126 | 138 | ||||
127 | dct[attr_name] = wrapper | 139 | dct[attr_name] = wrapper | ||
128 | return super().__new__(cls, name, bases, dct) | 140 | return super().__new__(cls, name, bases, dct) | ||
t | 129 | t |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|