1import csv
2import os
3
4CSV_FILE = "contacts.csv"
5FIELDNAMES = ["name", "phone", "email", "category"]
6
7
8def initialize_storage():
9 """Ensures the CSV file exists with the proper column headers."""
10 if not os.path.exists(CSV_FILE):
11 try:
12 with open(CSV_FILE, mode="w", encoding="utf-8", newline="") as f:
13 writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
14 writer.writeheader()
15 except OSError as err:
16 print(f"Error initializing contact database: {err}")
17
18
19def load_contacts():
20 """Loads and returns all contacts as a list of dictionaries."""
21 contacts = []
22 try:
23 with open(CSV_FILE, mode="r", encoding="utf-8", newline="") as f:
24 reader = csv.DictReader(f)
25 for row in reader:
26 contacts.append(row)
27 except FileNotFoundError:
28 initialize_storage()
29 except OSError as err:
30 print(f"Error reading {CSV_FILE}: {err}")
31 return contacts
32
33
34def save_contacts(contacts):
35 """Overwrites the CSV file with the provided list of contact dictionaries."""
36 try:
37 with open(CSV_FILE, mode="w", encoding="utf-8", newline="") as f:
38 writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
39 writer.writeheader()
40 writer.writerows(contacts)
41 return True
42 except OSError as err:
43 print(f"Failed to save contacts: {err}")
44 return False
45
46
47def add_contact():
48 """Prompts for contact details and appends to CSV."""
49 print("\n--- Add New Contact ---")
50 name = input("Enter Full Name: ").strip()
51 phone = input("Enter Phone Number: ").strip()
52 email = input("Enter Email Address: ").strip()
53 category = input("Enter Category (Family/Work/Friend): ").strip().capitalize()
54
55 if not name or not phone:
56 print("Error: Name and Phone number are required fields!")
57 return
58
59 contacts = load_contacts()
60
61 # Check for duplicate names
62 if any(c["name"].lower() == name.lower() for c in contacts):
63 print(f"A contact named '{name}' already exists.")
64 return
65
66 new_contact = {
67 "name": name,
68 "phone": phone,
69 "email": email or "N/A",
70 "category": category or "General"
71 }
72
73 contacts.append(new_contact)
74 if save_contacts(contacts):
75 print(f"Contact '{name}' added successfully!")
76
77
78def view_contacts():
79 """Displays all contacts in a formatted table."""
80 contacts = load_contacts()
81 if not contacts:
82 print("\nNo contacts found. Add one first!")
83 return
84
85 print("\n" + "=" * 65)
86 print(f"{'NAME':<20} | {'PHONE':<15} | {'CATEGORY':<10} | {'EMAIL'}")
87 print("-" * 65)
88 for c in contacts:
89 print(f"{c['name']:<20} | {c['phone']:<15} | {c['category']:<10} | {c['email']}")
90 print("=" * 65)
91
92
93def search_contact():
94 """Searches contacts by name or category substring."""
95 query = input("\nEnter search term (name or category): ").strip().lower()
96 contacts = load_contacts()
97
98 results = [
99 c for c in contacts
100 if query in c["name"].lower() or query in c["category"].lower()
101 ]
102
103 if not results:
104 print(f"No contacts matching '{query}'.")
105 return
106
107 print(f"\nFound {len(results)} match(es):")
108 for c in results:
109 print(f" - {c['name']} ({c['category']}): {c['phone']} | {c['email']}")
110
111
112def delete_contact():
113 """Deletes a contact by exact name."""
114 name_to_delete = input("\nEnter exact name of contact to delete: ").strip().lower()
115 contacts = load_contacts()
116
117 initial_count = len(contacts)
118 updated_contacts = [c for c in contacts if c["name"].lower() != name_to_delete]
119
120 if len(updated_contacts) == initial_count:
121 print(f"No contact found with name '{name_to_delete}'.")
122 else:
123 if save_contacts(updated_contacts):
124 print("Contact deleted successfully.")
125
126
127def main_menu():
128 """Main user interaction loop."""
129 initialize_storage()
130
131 while True:
132 print("\n===== CONTACT MANAGER (CSV) =====")
133 print("1. View All Contacts")
134 print("2. Add New Contact")
135 print("3. Search Contact")
136 print("4. Delete Contact")
137 print("5. Exit")
138
139 choice = input("Select an option (1-5): ").strip()
140
141 if choice == "1":
142 view_contacts()
143 elif choice == "2":
144 add_contact()
145 elif choice == "3":
146 search_contact()
147 elif choice == "4":
148 delete_contact()
149 elif choice == "5":
150 print("Exiting Contact Manager. Goodbye!")
151 break
152 else:
153 print("Invalid choice. Please choose between 1 and 5.")
154
155
156if __name__ == "__main__":
157 main_menu()