1import re
2import inspect
3from collections import Counter
4import random
5
6
7class Santa:
8 _instance = None
9
10 def __new__(cls, *args, **kwargs):
11 if cls._instance is None:
12 cls._instance = super(Santa, cls).__new__(cls)
13 cls._instance.child_ages = {}
14 cls._instance.current_wishes = {}
15 return cls._instance
16
17 def __call__(self, child, message):
18 if not isinstance(child, KidBase):
19 raise TypeError("Expected an instance of a Kid.")
20 if not isinstance(message, str):
21 raise TypeError("Message must be a string.")
22
23 gift = self.extract_gift(message)
24 if gift:
25 self.current_wishes[child] = gift
26 print(f"Phone call from {child.__class__.__name__} (ID: {id(child)}): wants '{gift}'")
27 else:
28 print("Invalid message: No valid gift found.")
29
30 def __matmul__(self, letter):
31 if not isinstance(letter, str):
32 raise TypeError("Letter must be a string.")
33
34 gift = self.extract_gift(letter)
35 child_id = self.extract_signature(letter)
36
37 if gift and child_id:
38 child = self.find_child_by_id(child_id)
39 if child:
40 self.current_wishes[child] = gift
41 print(f"Received a letter from child with ID {child_id}: wants '{gift}'")
42 else:
43 print(f"Warning: No child found with ID {child_id}.")
44 elif not gift:
45 print("Invalid letter: No valid gift found.")
46 elif not child_id:
47 print("Invalid letter: No valid signature found.")
48
49 @staticmethod
50 def extract_gift(text):
51 match = re.search(r'["\']([a-zA-Z0-9 ]+)["\']', text)
52 return match.group(1) if match else None
53
54 @staticmethod
55 def extract_signature(text):
56 match = re.search(r'^\s*(\d+)\s*$', text, re.MULTILINE)
57 return int(match.group(1)) if match else None
58
59 def find_child_by_id(self, child_id):
60 for child in KidBase.all_children:
61 if id(child) == child_id:
62 return child
63 return None
64
65 def xmas(self):
66 if not self.current_wishes:
67 print("No wishes this year. Santa is taking a break.")
68 return
69
70 wish_counter = Counter(self.current_wishes.values())
71 most_common = wish_counter.most_common(1)
72 most_desired_gift = most_common[0][0] if most_common else None
73
74 for child in KidBase.all_children:
75 if child not in self.child_ages:
76 self.child_ages[child] = 0
77 if self.child_ages[child] >= 5:
78 print(f"{child.__class__.__name__} is too old for gifts!")
79 continue
80 self.child_ages[child] += 1
81
82 gift = self.current_wishes.get(child, most_desired_gift)
83
84 if not child.is_nice():
85 gift = "coal"
86
87 child(gift)
88
89 self.current_wishes.clear()
90
91
92class Kid(type):
93 def __new__(cls, name, bases, dct):
94 # Проверяваме дали "__call__" съществува в текущия клас или базовите му класове
95 if not any("__call__" in dir(base) for base in bases) and "__call__" not in dct:
96 raise NotImplementedError(
97 f"Classes using the Kid metaclass must implement a __call__ method."
98 )
99 return super().__new__(cls, name, bases, dct)
100
101
102class KidBase(metaclass=Kid):
103 all_children = []
104
105 def __init__(self):
106 self._methods_called = {}
107 KidBase.all_children.append(self)
108
109 def __call__(self, gift):
110 print(f"{self.__class__.__name__} received '{gift}'")
111
112 def is_nice(self):
113 return all(errors == 0 for errors in self._methods_called.values())
114
115 def __getattribute__(self, name):
116 attr = object.__getattribute__(self, name)
117 if inspect.ismethod(attr) and not name.startswith("_"):
118 def wrapper(*args, **kwargs):
119 try:
120 return attr(*args, **kwargs)
121 except Exception:
122 self._methods_called[name] = self._methods_called.get(name, 0) + 1
123 raise
124 return wrapper
125 return attr
126
127
128class BulgarianKid(KidBase):
129 def be_naughty(self):
130 raise RuntimeError("Няма да си изям зеленчуците!")
131
132
133class ChineseKid(KidBase):
134 pass
..EEEE
Stdout:
Warning: No child found with ID 133690676232160.
Warning: No child found with ID 133690676825504.
E
Stdout:
Warning: No child found with ID 133690676825456.
Warning: No child found with ID 133690676833712.
EF
Stdout:
Warning: No child found with ID 133690676838272.
Warning: No child found with ID 133690676838368.
Warning: No child found with ID 133690676824208.
No wishes this year. Santa is taking a break.
.EEEE..EEE
Stdout:
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
E
======================================================================
ERROR: test_call (test.TestSanta.test_call)
Test sending message via calling.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 54, in test_call
self.santa(kid1, "'toy1'")
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_call_and_mail_same_kid (test.TestSanta.test_call_and_mail_same_kid)
Test that calls and mails work for the same kid.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 69, in test_call_and_mail_same_kid
self.santa(kid1, "'toy1'")
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_iterable (test.TestSanta.test_iterable)
Ensure Santa can be iterated multiple times including overwriting presents.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 126, in test_iterable
self.santa(kid1, '"something"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_mail (test.TestSanta.test_mail)
Test sending message via email.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 64, in test_mail
self.assertEqual(list(self.santa), ['toy1', 'toy2'])
^^^^^^^^^^^^^^^^
TypeError: 'Santa' object is not iterable
Stdout:
Warning: No child found with ID 133690676232160.
Warning: No child found with ID 133690676825504.
======================================================================
ERROR: 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 '])
^^^^^^^^^^^^^^^^
TypeError: 'Santa' object is not iterable
Stdout:
Warning: No child found with ID 133690676825456.
Warning: No child found with ID 133690676833712.
======================================================================
ERROR: 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 255, in test_santa_gift_order
self.santa(kid2, '"toy2"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_xmass (test.TestSanta.test_xmass)
Test a simple Christmas case.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 137, in test_xmass
self.santa(kid1, '"toy1"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_xmass_kid_with_multiple_wishes (test.TestSanta.test_xmass_kid_with_multiple_wishes)
Test a Christmas with a kid who sends multiple wishes.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 183, in test_xmass_kid_with_multiple_wishes
self.santa(kid1, '"toy1"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_xmass_kid_without_a_wish (test.TestSanta.test_xmass_kid_without_a_wish)
Test a Christmas with a kids that hasn't sent a wish.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 171, in test_xmass_kid_without_a_wish
self.santa(kid1, '"toy1"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
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 220, in test_xmass_naughty
self.santa(kid1, "'sirenie'")
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: 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 234, in test_xmass_private_with_error
self.santa(kid1, "'sirenie'")
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
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 245, in test_xmass_public_with_no_error
self.santa(kid1, "'sirenie'")
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
ERROR: test_xmass_years_5_and_over (test.TestSanta.test_xmass_years_5_and_over)
Test with passing years with kid aged 5 and over.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 211, in test_xmass_years_5_and_over
self.santa(kid1, '"toy"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
Stdout:
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
No wishes this year. Santa is taking a break.
======================================================================
ERROR: test_xmass_years_under_5 (test.TestSanta.test_xmass_years_under_5)
Test with passing years with a kid under 5 years old.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 192, in test_xmass_years_under_5
self.santa(kid1, '"toy1"')
File "/tmp/solution.py", line 19, in __call__
raise TypeError("Expected an instance of a Kid.")
TypeError: Expected an instance of a Kid.
======================================================================
FAIL: test_signature_matching (test.TestSanta.test_signature_matching)
Test matching present in the letter / call.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 118, in test_signature_matching
self.assertEqual(kid1.SECRET_PRESENT, 'toy1')
AssertionError: None != 'toy1'
Stdout:
Warning: No child found with ID 133690676838272.
Warning: No child found with ID 133690676838368.
Warning: No child found with ID 133690676824208.
No wishes this year. Santa is taking a break.
----------------------------------------------------------------------
Ran 20 tests in 0.038s
FAILED (failures=1, errors=14)
15.12.2024 14:55
15.12.2024 14:56