Safe Paws Project — Round 3/5
The filtering we built, combined with the unique incremental ID, opens up a lot of options. For animal 235 we can apply additional functionality. That's exactly why we didn't go with a timestamp. Try remembering and typing 2022-04-16,14:32:11 when you need to edit something. A number is enough.
Let's launch the edit function. Several things can change in an animal's profile — but fewer than you'd think. The name stays. The size stays. I haven't heard of a dog becoming a cat yet. Age grows, but that's usually handled with a date field that updates dynamically — we're not going to manually update hundreds of entries. Availability gets its own function. What makes practical sense right now is health status.
Let's say we have news about one of our residents. Lassie had some issues, but she's doing better now. We know Lassie — medium sized dog, four years old. We run the advanced search and find:
ID: 1 - Lassie is a 4 years old, medium sized dog. Health status: ill.
The ID is the simplest way to reference Lassie. Around that 1, we build the edit logic.
def edit_health():
available_paws = {}
adopted_paws = {}
editable = False
for key in paws_dict:
if paws_dict[key][5] == "available":
available_paws[key] = paws_dict[key]
else:
adopted_paws[key] = paws_dict[key]
while True:
try:
id = int(input("Paw id: "))
if id in available_paws.keys():
print("Paw identified!")
editable = True
break
elif id in adopted_paws.keys():
print("Paw is adopted! You can't edit an adopted paw!")
break
except ValueError:
print("Invalid ID. Enter a number.")
if editable:
health = ""
while not health or health.lower() not in ["healthy", "ill"]:
health = input("Paw health status update (healthy/ill only): ")
paws_dict[id][3] = health.lower()
print(f"{paws_dict[id][0].upper()} was successfully updated. New health status is: {paws_dict[id][3].upper()}.")
with open("safe_paws.txt", "w", encoding="utf-8") as f:
for key in paws_dict:
f.write(f"{key};{paws_dict[key][0]};{paws_dict[key][1]};{paws_dict[key][2]};{paws_dict[key][3]};{paws_dict[key][4]};{paws_dict[key][5]}\n")
print("safe_paws.txt was updated!")
load_from_txt()
Let's walk through what happens. We declare two empty dictionaries — available and adopted. The separation matters: an adopted animal shouldn't be editable, but we still want to recognize its ID and return a personalized message instead of a generic error.
editable starts as False. It only becomes True if the ID matches an available animal. That flag controls everything that follows — we could have used if id in available_paws.keys() again, but editable makes the intent clearer. Some things are worth a line of code.
The while loop asks for an ID, validates it's a number, and checks which dictionary it belongs to. If it's available — identified, editable. If it's adopted — message, stop. If it's neither — the loop continues.
If editable is True, we ask for the new health status and update the dictionary. Then we rewrite the file.
Text files support three modes. "r" — read only, no use here. "a" — append, which would create a duplicate entry instead of updating the existing one. "w" — full write, rewrites the entire file from scratch. The only option that works for an update is "w" — we write every entry from the dictionary, including the one we just changed.
After writing, we call load_from_txt(). The dictionary gets repopulated from the fresh file — so everything in memory reflects what's on disk. No stale data.
No return value. No display. This function does one thing and does it quietly. A specialized, silent function that knows its job.
The updated menu:
load_from_txt()
while True:
print("\nSafe Paws Menu")
option = input("1-Add paw\n2-Adv search\n3-Edit paw health\nq-Quit\nChoose your option: ")
if option == "1":
add_paw()
print("Paw added successfully!")
elif option == "2":
if len(adv_search()) > 0:
print_adv_search()
else:
print("No data match your search.")
elif option == "3":
edit_health()
elif option == "q":
break
else:
print("Invalid option!")
Note: edit works best right after an advanced search. Otherwise, you'd need to remember IDs — and that defeats the purpose.
Glad Lassie is doing better. Now let's find her a home. Adoption is next — and that means a second file, a second structure, and a new layer on the fort.
Attached: the current safe_paws.py and a dummy safe_paws.txt to test with. Run the search, edit a health status, check the file. Delete the dummy data when you're done.