-
Notifications
You must be signed in to change notification settings - Fork 0
/
address_book.py
201 lines (159 loc) · 5.61 KB
/
address_book.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
from collections import UserDict
from collections.abc import Iterator
from datetime import datetime, date
import re
import pickle
import csv
class Field:
def __init__(self, value) -> None:
self.value = value
@property
def value(self):
return self._value
@value.setter
def value(self, new_value):
self.validate(new_value)
self._value = new_value
def validate(self, value):
pass
def __str__(self) -> str:
return self.value
class Name(Field):
def __init__(self, value) -> None:
super().__init__(value)
self.value = value
def __str__(self) -> str:
return self.value
class Phone(Field):
def __init__(self, phone: str) -> None:
super().__init__(phone)
self._value = phone
def __str__(self) -> str:
return self._value
@property
def phone(self):
return self._value
@phone.setter
def phone(self, phone_number):
self.validate(phone_number)
self._value = phone_number
def validate(self, value):
# +380441234567; +38(044)1234567; +38(044)123-45-67; 0441234567;
# 044-123-4567; (073)123-4567; (099)123-4567
regex = r"^(?:\+38)?(?:\(\d{3}\)[0-9]{3}-?[0-9]{2}-?[0-9]{2}|0\d{2}-?[0-9]{3}-?[0-9]{2}-?[0-9]{2})$"
if not re.findall(regex, value, re.M):
print("Invalid phone number format")
raise ValueError
class Birthday(Field):
def __init__(self, value) -> None:
super().__init__(value)
self.__value = None
self.value = value
@property
def value(self):
return self.__value
@value.setter
def value(self, value):
date_format = "%Y-%m-%d"
try:
birthdate = datetime.strptime(str(value), date_format).date()
self.__value = birthdate
except:
self.__value = None
print('Wrong format. Enter date in format "%Y-%m-%d"')
raise ValueError
def __str__(self):
return self.__value.strftime("%Y-%m-%d")
class Record:
def __init__(self, name: Name, phone: Phone = None, birthdate: Birthday = None) -> None:
self.name = name
self.phones = [] if phone else None
if phone:
self.phones.append(phone)
self.birthdate = birthdate
def add_phone(self, phone: Phone):
if self.phones is None:
self.phones = []
self.phones.append(phone)
def add_phones(self, phones):
if self.phones is None:
self.phones = phones
return
for phone in phones:
self.phones.append(phone)
def remove_phone(self, phone: Phone):
if phone not in self.phones:
raise ValueError(
f"The phone number '{phone.phone}' is not listed in the records.")
self.phones.remove(phone)
def update_phone(self, old_phone: Phone, new_phone: Phone):
try:
index = self.phones.index(old_phone)
self.phones[index] = new_phone
except ValueError:
raise ValueError(
f"The phone number '{old_phone.phone}' is not listed in the records.")
def add_birthday(self, birthdate: Birthday):
self.birthdate = birthdate
def days_to_birthday(self):
current_date = date.today()
birthday_this_year = date(
current_date.year, self.birthdate.phone.month, self.birthdate.phone.day)
birthday_next_year = date(
current_date.year + 1, self.birthdate.phone.month, self.birthdate.phone.day)
delta = (birthday_this_year - current_date).days
if delta >= 0:
return delta
else:
return (birthday_next_year - current_date).days
def __str__(self) -> str:
phones = "; ".join(str(p)
for p in self.phones) if self.phones else "not added"
bd = self.birthdate if self.birthdate else "----------"
return f"Name: {self.name},\tPhone numbers: {phones},\tBirthday: {bd}"
def __repr__(self) -> str:
return str(self)
class AddressBook(UserDict):
def __init__(self):
self.data = {}
def add_record(self, record: Record):
key = record.name.value
self.data[key] = record
def __iter__(self, n=1):
self._index = 0
self._items = list(self.data.values())
self._step = n
return self
def __next__(self):
if self._index < len(self._items):
item = self._items[self._index]
self._index += self._step
return item
else:
raise StopIteration
def save_to_file_pickle(self, file_path):
with open(file_path, "wb") as fh:
pickle.dump(self.data, fh)
def load_from_file_pickle(self, file_path):
with open(file_path, "rb") as fh:
data = pickle.load(fh)
self.data.update(data)
def save_to_file(self, file_path):
with open(file_path, "w", newline="") as file:
writer = csv.writer(file)
print(self.data)
for rec in self.data.values():
print(rec)
name = rec.name.value
phones = [phone.value for phone in rec.phones]
birthday = rec.birthdate.value.strftime(
"%Y-%m-%d") if rec.birthdate else ""
writer.writerow([name, "|".join(phones), birthday])
def load_from_file(self, file_path):
with open(file_path, "r") as f:
reader = csv.reader(f)
for row in reader:
print(row)
if __name__ == "__main__":
ad = AddressBook()
ad.load_from_file("data.csv")