Day 062 - Project 62 : My Private Diary

Hi @skillstackblue , are you still solving these tutorials? I want to know, why did you choose to iterate over the database instead of getting the keys into a list and then iterating over that.

Question:
Am I not understanding how db.prefix() works correctly? I’m getting no matches on line 55, even when the date is entered correctly.
Repl link:
https://replit.com/@KurtHoernig/Day62100Days#main.py

    year = input('Year? > ')
    month = input('Month? > ')
    day = input('Day? > ')
    date = (f'{year}-{month}-{day}')
    print(f'Searching for: {date}')
    time.sleep(1)
    matches = db.prefix(date)

I checked David’s code for the answer, but he doesn’t do the extra credit part unfortunately.

Thanks @KurtHoernig , great spot. I’ll make sure this feedback is passed on so an update can be made.

1 Like

Hi, hope this code can help you a lil.

from replit import db
import datetime,os,time

def add():
  add = input("Input your thought > ")
  timestamp = datetime.datetime.now()
  db[timestamp]= add
  time.sleep(1)
  os.system("clear")
  menu()

def view():
  keys = db.keys()
  for key in keys:
    time.sleep(1)
    os.system("clear")
    print(f"{key}: {db[key]}")
    print()
    ask = input("Next/Exit > ").capitalize()
    if ask=='Next':
      os.system("clear")
    elif ask=='Exit':
      os.system("clear")
      menu()
      break

def menu():
  print("~Welcome To Secret Place Of Thoughts~")
  print()
  print("""1. Add
2. View""")
  print()
  enter = input("> ")
  if enter=='1':
    add()
  elif enter=='2':
    view()

while True:
  pw = input("Please enter your password > ")
  if pw=="banana139":
    os.system("clear")
    menu()
  else:
    print("WHO ARE YOU?! GET OUT! YOU AREN'T AN OWNER!")
    exit()

I’m trying to hide the user’s password as they are entering it, but not entirely like with from getpass import getpass as input but rather for each key stroke an asterisk will appear :

password : abcdef    -> ******
           (enters)     (shows)

I tried importing various libraries like getpass and mscvrt
then Replit ai generated this for me :

image


and the password = entry.get() part here:

"1

Which gives me this :


Cool I like this, I almost understand how it’s working but not entirely.
It works and I like how this works here is the whole thing :

from replit import db
import os , time, datetime
import tkinter as tk # ?

def menumenu():
  menu = input("1.(A)dd an entry. \n 2.(V)iew entries?").strip().lower()
  if menu[0] == "1" or menu[0] =="a":
    

    print("")
def get_password():
    trycounter = 0
    password = entry.get()    # ??
    if password == db["correctpassword"]:
      print("🔐Access Granted🔓")
      #menumenu()
    else:
      print("🚨🔒Wrong Password🚨")
      trycounter +=1
      while True:
        tryagain = input("Try again")
        if tryagain != db["correctpassword"]:
          trycounter +=1
          if trycounter == 3:
            print("👮Your actions have not gone unnoticed.")
            exit()


root = tk.Tk()
root.attributes('-fullscreen', True)
root.title("Password Input")
label = tk.Label(root, text="What is your password?")
label.pack()
entry = tk.Entry(root, show="*")
entry.pack()
button = tk.Button(root, text="Submit", command=get_password)
button.pack()
root.mainloop()#👈

But then I tried to add a signup and login.
If the user tried to sign up, it would ask for them to create a username, and then check if that username already existed. If it existed it would tell them the username was taken and ask them to try again.
If it was not taken they would be prompted to enter a password and comfirm it,
then their username and password would be added to their database as
db[createusername] = confirmpassword.
I had finished the sign up part and started working on the login.

For login it would check if the username existed in their database and if it did: display “please login in the output window.” which I also managed to get working.
I was getting a couple errors though or inconsistencies, so I had to tinker with the order and structure of everything and I ended up getting to a point where password = entry.get() was no longer reachable, or defined or bound , (I cant remember.)

it was something similar to this I’m not sure if this was it exactly :

2
from replit import db
import os , time, datetime
import tkinter as tk # ?

print("")
def menumenu():
  menu = input("1.(A)dd.\n2.(V)iew.").strip().lower()
  if menu[0] == "1" or menu[0] == "a":
    add()
  elif menu[0] == "2" or menu[0] == "v":
    view()
def createusernamefunction():
    createusername = str(input("Create your username."))
    keys = db.keys()
    for key in keys:
      if createusername == key:
        print("usernametaken")
        print("try another username")
        print("or type menu to go back to the menu")
        createusernamefunction()
      elif createusername == "menu":
        signuporlogin()
      else:
        while True:
          createpassword = input("Create a password")
          confirmpassword = input("confirm your password")
          if confirmpassword != createpassword:
            print("Try again.")
            time.sleep(0.75)
          else:
            db[createusername] = confirmpassword
            print("User+PW created.")
            print("Welcome to your personal diary")
            time.sleep(1.25)
            os.system("clear")
            break
            
def get_password():
    trycounter = 0
    password = entry.get()    # ??
    if password == db["correctpassword"]:
      print("🔐Access Granted🔓")
      menumenu()
    else:
      print("🚨🔒Wrong Password🚨")
      trycounter +=1
      while True:
        tryagain = input("Try again")
        if tryagain != db["correctpassword"]:
          trycounter +=1
          if trycounter == 3:
            print("👮Your actions have not gone unnoticed.")
            exit()
            
def loginpassword():
  root = tk.Tk()#👈👇?
  root.attributes('-fullscreen', True)
  root.title("Password Input")
  label = tk.Label(root, text="What is your password?")
  label.pack()
  entry = tk.Entry(root, show="*")
  entry.pack()
  button = tk.Button(root, text="Submit", command=get_password)
  button.pack()
  root.mainloop()#👈👆?
def signuporlogin():
  login = input("Sign up or Log In?").strip().lower()
  if login[0] == "s" or login[0] == "1":
    createusernamefunction()
  elif login[0] == "l" or login[0] =="2":
    askusername = input("what is your username?")
    keys = db.keys()
    for key in keys:
      #print(key)
      if askusername == key:
        print("Check the output window/tab")
        loginpassword()
    if askusername not in keys:
      print("Username not found")
    
signuporlogin()
def createusername():
  createusername = str(input("Create your username."))
  keys = db.keys()
  for key in keys:
    while createusername == key:
      print("usernametaken")
      print("try another username")
      createusername()
    else:
      while True:
        createpassword = input("Create a password")
        confirmpassword = input("confirm your password")
        if confirmpassword != createpassword:
          print("Try again.")
          time.sleep(0.75)
        else:
          db[createusername] = confirmpassword
          print("User+PW created.")
          print("Welcome to your personal diary")
          time.sleep(1.25)
          os.system("clear")
          break (also tried exit() to end the program and the user has to restart to login) 

This will go through the sign up process . create a username and password, and then welcome you to the “personal diary” but then goes back to create a username or password instead of taking me to the add or view diary entries.
(This is just one of the copies i made of main.)
help

Eventually I got it to exit the program instead of incorrectly asking for another password input.
I had this

3


which would give me an error when i entered a valid username to try to login :

So I tried moving password = entry.get() from again where it was (line 60) :

to : (line 44)

which now shows :


and


(correct password entered)

so I declared askusername and entry as global

which gets rid of their undefined name errors

but still gives me :

So my question is where do I put everything to make it work . This is the furthest i’ve gotten.

I feel like it would work if I put everything I have in its right place but I honestly don’t know. At this point I can no longer tell where things should go.

from replit import db
import os , time, datetime
import tkinter as tk # ?
global askusername

print("")
def menumenu():
  menu = input("1.(A)dd.\n2.(V)iew.").strip().lower()
  if menu[0] == "1" or menu[0] == "a":
    add()
  elif menu[0] == "2" or menu[0] == "v":
    view()
import time
import os

def create_username_function():
    while True:
        create_username = input("Create your username: ")
        keys = db.keys()

        if create_username in keys:
            print("Username taken. Try another username or type 'menu' to go back.")
        else:
            create_password = input("Create a password: ")
            confirm_password = input("Confirm your password: ")

            if confirm_password != create_password:
                print("Passwords do not match. Try again.")
                time.sleep(0.75)
            else:
                db[create_username] = confirm_password
                print("User+PW created.")
                print("Welcome to your personal diary.")
                time.sleep(1.25)
                os.system("clear")
                break

# Assume db is defined somewhere before calling create_username_function
# db = {}


def get_password():
    global askusername, entry
    trycounter = 0
    password = entry.get()    # ??
    if password == db[askusername]:
      print("🔐Access Granted🔓")
      menumenu()
    else:
      print("🚨🔒Wrong Password🚨")
      trycounter +=1
      while True:
        tryagain = input("Try again")
        if tryagain != db[askusername]:
          trycounter +=1
          if trycounter == 3:
            print("👮Your actions have not gone unnoticed.")
            exit()

def loginpassword():
  root = tk.Tk()#👈👇?
  root.attributes('-fullscreen', True)
  root.title("Password Input")
  label = tk.Label(root, text="What is your password?")
  label.pack()
  entry = tk.Entry(root, show="*")
  entry.pack()
  button = tk.Button(root, text="Submit", command=get_password)
  button.pack()
  root.mainloop()#👈👆?
def signuporlogin():
  login = input("Sign up or Log In?").strip().lower()
  if login[0] == "s" or login[0] == "1":
    create_username_function()
  elif login[0] == "l" or login[0] =="2":
    askusername = input("what is your username?")
    keys = db.keys()
    for key in keys:
      #print(key)
      if askusername == key:
        print("Check the output window/tab")
        loginpassword()
    if askusername not in keys:
      print("Username not found")

signuporlogin()

Can anyone help me please

https://replit.com/@vvithershins/Day62100Days#help.py

:open_mouth: I guess getpass was updated, it used to do what you want it to do.

Yes i had asked the replit ai for various methods and they all kept just showing me asterisks AFTER I hit enter, not as I was typing the password in.
I was contemplating just leaving it as
from getpass import getpass as input
so the entry would be hidden entirely (like in the 2 player rock paper scissors game)
but then as i was testing it i wasnt sure if i accidentally entered a letter twice, and thought “I wish i could see asterisks instead of not seeing anything because then I would be able to tell ‘oh theres 3 asterisks that means I didn’t enter a letter twice on accident,’” or “oh theres 4 aterisks that means I did enter a key twice on accident.”

Then it gave me the tkinter as tk which *does mask my password as 's and I thought it was cool because I haven’t made anything for the output window yet. So I decided to try to use it.

I just asked chat gpt for help and it fixed the NameError: name ‘entry’ is not defined error for me though.

Summary

it said :

It seems that the issue you’re encountering is related to the scope of the entry variable in the get_password function. The entry variable is defined within the loginpassword function, making it local to that function. Therefore, when you try to access it in the get_password function, a NameError occurs because entry is not defined in the global scope or passed as an argument to get_password.

To fix this issue, you can modify the loginpassword function to return the entry widget, and then pass it as an argument to the get_password function. Here’s a modified version of your code:

and gave me this :

from replit import db
import os, time
import tkinter as tk

global askusername

def menumenu():
    menu = input("1.(A)dd.\n2.(V)iew.").strip().lower()
    if menu[0] == "1" or menu[0] == "a":
        add()
    elif menu[0] == "2" or menu[0] == "v":
        view()

import time
import os

def create_username_function():
    while True:
        create_username = input("Create your username: ")
        keys = db.keys()

        if create_username in keys:
            print("Username taken. Try another username or type 'menu' to go back.")
        else:
            create_password = input("Create a password: ")
            confirm_password = input("Confirm your password: ")

            if confirm_password != create_password:
                print("Passwords do not match. Try again.")
                time.sleep(0.75)
            else:
                db[create_username] = confirm_password
                print("User+PW created.")
                print("Welcome to your personal diary.")
                time.sleep(1.25)
                os.system("clear")
                break

def get_password(entry):
    global askusername
    trycounter = 0
    password = entry.get()
    if password == db[askusername]:
        print("🔐Access Granted🔓")
        menumenu()
    else:
        print("🚨🔒Wrong Password🚨")
        trycounter += 1
        while True:
            tryagain = input("Try again: ")
            if tryagain == db[askusername]:
                trycounter = 0
                break
            else:
                trycounter += 1
                if trycounter == 3:
                    print("👮Your actions have not gone unnoticed.")
                    exit()

def loginpassword():
    root = tk.Tk()
    root.attributes('-fullscreen', True)
    root.title("Password Input")
    label = tk.Label(root, text="What is your password?")
    label.pack()
    entry = tk.Entry(root, show="*")
    entry.pack()
    button = tk.Button(root, text="Submit", command=lambda: get_password(entry))
    button.pack()
    root.mainloop()

def signuporlogin():
    login = input("Sign up or Log In?").strip().lower()
    if login[0] == "s" or login[0] == "1":
        create_username_function()
    elif login[0] == "l" or login[0] == "2":
        global askusername
        askusername = input("What is your username?")
        keys = db.keys()
        for key in keys:
            if askusername == key:
                print("Check the output window/tab")
                loginpassword()
                break
        else:
            print("Username not found")

signuporlogin()

This should resolve the NameError issue. The lambda: get_password(entry) in the command parameter of the submit button ensures that the entry widget is passed to the get_password function when the button is clicked.

Which works how I wanted it to.

or

So I’m all good now haha.
Sorry for the post then (ai) answering my own question.


er actually it’s still giving me an error if i enter a wrong password more than once,


but I’ll try to figure this out for a while and come back if(probably WHEN😂) I need help (again)


I guess I could just exit() if they enter the wrong password the first time.


but if i wanted to use my 3 strikes :

(i was using password = input(“what is your password?”)
(but if they entered a wrong password i was using tryagain = input("try again")#what is your password?
So I tried changing tryagain= to password= but still get the Runtime error can’t re-enter line .


(just for password instead of tryagain)
^
https://replit.com/@vvithershins/Day62100Days#Runtimeerrorversion1.py
for this error right now.

I got it now :grin:. I just gotta fix the try counter.


from replit import db
import os, time
import tkinter as tk

global askusername

def menumenu():
    menu = input("1.(A)dd.\n2.(V)iew.").strip().lower()
    if menu[0] == "1" or menu[0] == "a":
        add()
    elif menu[0] == "2" or menu[0] == "v":
        view()

import time
import os

def create_username_function():
    while True:
        create_username = input("Create your username: ")
        keys = db.keys()

        if create_username in keys:
            print("Username taken. Try another username or type 'menu' to go back.")
        else:
            create_password = input("Create a password: ")
            confirm_password = input("Confirm your password: ")

            if confirm_password != create_password:
                print("Passwords do not match. Try again.")
                time.sleep(0.75)
            else:
                db[create_username] = confirm_password
                print("User+PW created.")
                print("Welcome to your personal diary.")
                time.sleep(1.25)
                os.system("clear")
                break

def get_password(entry):
    global askusername
    trycounter = 0
    password = entry.get()
    if password == db[askusername]:
        print("🔐Access Granted🔓")
        menumenu()
    else:
        print("🚨🔒Wrong Password🔒🚨")
        trycounter += 1
        while True:
            print("Try again: ")
            loginpassword()
            password = entry.get()
            if passwowrd == entry.get():
              trycounter = 0
              break
            else:
              trycounter += 1
              if trycounter == 3:
                print("👮Your actions have not gone unnoticed.")
                exit()

def loginpassword():
    root = tk.Tk()
    root.attributes('-fullscreen', True)
    root.title("Password Input")
    label = tk.Label(root, text="What is your password?")
    label.pack()
    entry = tk.Entry(root, show="*")
    entry.pack()
    button = tk.Button(root, text="Submit", command=lambda: get_password(entry))
    button.pack()
    root.mainloop()

def signuporlogin():
    login = input("Sign up or Log In?").strip().lower()
    if login[0] == "s" or login[0] == "1":
        create_username_function()
    elif login[0] == "l" or login[0] == "2":
        global askusername
        askusername = input("What is your username?")
        keys = db.keys()
        for key in keys:
            if askusername == key:
                print("Check the output window/tab")
                loginpassword()
                break
        else:
            print("Username not found")

signuporlogin()

I thought hmm what if i just use the loginpassword function again instead of just a regular input and it worked.


lol i see something that’s wrong with the try counter now I was using

 password = entry.get()
 if passwowrd == entry.get():   #lol
    trycounter = 0
    break

I meant to say

password = entry.get()
if passwowrd == db[askusername]:  
   trycounter = 0
   break

I got it now :person_facepalming:

again sorry for the lengthy post, i have been stuck on this for like 3 days now.

Oh I think I misunderstood what you want it to do then

You can use this

from pwinput import pwinput as input
1 Like

That happens to me alot, I’m sorry. I don’t talk to people often.


it works
Saving

in my notes.

I changed it to just from pwinput import pwinput
so I can turn it on and off easier.

Details
from pwinput import pwinput
createusername = input("Create Username")
print(createusername)
yourpw = pwinput("make a password")
print(yourpw)

shows :
image

I also have this version which uses the output window (spoiler in case anyone wants to try to think about how to do it first):

import tkinter as tk

def pwinput(prompt, mask_password=True):
    result = None

    def get_password(entry):
        nonlocal result
        result = entry.get()
        root.destroy()

    root = tk.Tk()
    root.attributes('-fullscreen', True)
    root.title("Password Input")

    label = tk.Label(root, text=prompt)
    label.pack()

    entry = tk.Entry(root, show="*" if mask_password else "")
    entry.pack()

    button = tk.Button(root, text="Submit", command=lambda: get_password(entry))
    button.pack()

    root.mainloop()

    return result

# Example usage
print("check the output window")
yourpw = pwinput("Make a password")
print("you entered:", yourpw)

hello = pwinput("Enter a greeting", mask_password=False) 
print("you entered:", hello)

greeting = input("enter a greeting")
print(greeting)
1 Like

I’m stuck again please help.

What does this mean?


I copy and paste everything verbatim in a new repl and it works fine it’s just specifically not working for my day 62?

I tried to delete day 62 and start over, with the same code verbatim, and it still gives me the same error.


It’s working now nvm.

Stuck in the view part: regard showing the most previous entry and then choosing next and then showing the previous entry backwards until the end… Help please…

from replit import db
import datetime
import os, time


def Add():
  entry = input("type your thoughts:")
  timestamp = datetime.datetime.now()
  key = f"content {timestamp}"
  db[key] = entry

def View():
  matches = db.prefix("content")
  matches = matches[::-1]
  for timestamp in matches[:1]:
    print(f"""{timestamp}: {db[timestamp]}""")
  time.sleep(2)
  os.system("clear")
  while True:
    option = input("next or exit:")
    if option == "next":
      for timestamp in matches[1:]:
        print(f"""{timestamp}: {db[timestamp]}""")
      time.sleep(2)
      os.system("clear")
    elif option == "exit":
      break
    
password = "Mylife"

guess = input("what's the password >").strip().capitalize()
if password != guess:
  exit()
else:
  print("Welcome!")
  
  while True:  
    menu = input("Add or View?:").strip().title()
    if menu == "Add":
      Add()
      continue
    elif menu == "View":
      View()
      continue
    

The way you have it now, when you select to view next, it prints out all of the remaining database entries, instead of 1 at a time.
This is because of these lines

for timestamp in matches[1:]:
    print(f"""{timestamp}: {db[timestamp]}""")
time.sleep(2)

You can just use 1 for loop to get everything instead of printing the first one with a for loop, and then using while True: and another for loop to print the rest.
Instead of using

for timestamp in matches[:1]:
    print(f"""{timestamp}: {db[timestamp]}""")

just use

for timestamp in matches:
    print(f"""{timestamp}: {db[timestamp]}""")

Then within that for loop ask the user if they want to show the next one or stop

def View():
  matches = db.prefix("content")
  matches = matches[::-1]
  for timestamp in matches:
    print(f"""{timestamp}: {db[timestamp]}""")
    option = input("next or exit:")
    if option == "exit":
      break
  time.sleep(2)
  os.system("clear")

I believe this should work fine but you should tweak it to your liking.


In the solution video, David uses db.keys() instead of db.prefix() and tries to reverse it with keys = keys[::-1] but as we discussed for the previous day’s lesson this won’t work, it gives him the TypeError: ‘set’ object is not subscriptable.

So he then removes keys = keys[::-1], and tries it normally and finds that it shows them in reverse order by default.

Starting at 5:30 in the video

But for us it isn’t reversed.
image
I removed the os.system(“clear”) line in order to be able to show multiple entries at once here.

You could just leave it as it is, and use the solution code David provides, and just deal with it not being in the proper order.

Or, in the video, David also shows a way to reverse it without using .prefix() that we can use.
He shows that with keys = list(keys)[::-1] he can cast the set as a list which is reversible.

image

So it should be

def View():
  keys = db.keys() #Just use keys not prefix
  keys = list(keys)[::-1] #Convert set to list and reverse it
  for key in keys: #Start the loop and loop through 1 key at a time
    os.system("clear")
    time.sleep(1)
    print(f"""{key}
    {db[key]}""")
    print()
    opt = input("Next or exit? > ")#Ask the user to continue or stop
    if(opt.lower()[0]=="e"): #If user entered e or E for the first letter
      break # stop.

If you use this you should remove the line where you prefix content to the key
key = f"content {timestamp}" since it is no longer needed since we’re not using prefix.

You could also use this though, if you wanted to keep using prefix
def View():
  matches = db.prefix("content")
  matches = matches[::-1]
  i = 0 # start a counter
  m = len(matches) # get the length of matches to use as a limit
  while True:
    if i < m: # stop when there are no entries left
      print(matches[i][8:], db[matches[i]]) #Print the info
      nxt = input("Next or exit?") # ask the user to continue
      if nxt == "next":
        os.system("clear")
        i += 1 #increment the counter by 1 and continue the loop
        continue
      else: #if not break out of the loop and return to the add or view menu
        time.sleep(1)
        os.system("clear")
        break
    else: # when there are no entries left , break out of the loop and return to menu
      print("That's all")
      break

Here we use matches[i][8:], db[matches[i]]
as we increment i by 1, matches[i] will loop through all of the entries. We just use [8:] to ignore the prefix "content " and just print starting from the timestamp.
Note that db[matches[i]] is not the same as db[matches][i], we are printing the database value corresponding to the database key with the name of matches[i], not the [i] index of db[matches]

You should use whichever one makes the most sense to you or see if you could think of another way to do it.
If you have any questions about any of these or anything let me know.

1 Like

So this is from my own lack of fully understanding of the “for loop” function I guess, but I’m confused why this loop only show one entry at time. Shouldn’t it list all entries at the same time considering that the matches or the keys category isn’t specified in terms of ranges?

matches = db.prefix("content")
  matches = matches[::-1]
  for timestamp in matches:
    print(f"""{timestamp}: {db[timestamp]}""")

Or

 keys = db.keys() 
  keys = list(keys)[::-1]
  for key in keys:
    os.system("clear")
    time.sleep(1)
    print(f"""{key}
    {db[key]}""")

Another one that I’m trying to solve but can’t seem to do is the viewing the exact date. So here’s my code:

def ExactDate():
  while True:
    day = int(input("input the day:"))
    month = int(input("input the month:"))
    year = int(input("input the year:"))
    exact = datetime.date(year, month, day)
    keys = db.prefix(exact)
    for i in keys:
      print(f"""{i}: {(db[i])}""")
    else:
      break

The issue here is it only show the exact entry only for 8th June 2024 for some reason but not 9th, 10th or any other days. I have no idea why?

1 Like

It would, if all we were doing in the loop is printing the entries, but since after we print one we ask the user to stop or not it only prints one at a time.

It’s not just

for timestamp in matches:
    print(f"""{timestamp}: {db[timestamp]}""")

It’s

for timestamp in matches:
    print(f"""{timestamp}: {db[timestamp]}""")
    option = input("next or exit:")
    if option == "exit":
      break
    
Example = ["a","b","c"]
for letter in Example:
    print(letter)# all at once 
while True:
    for letter in Example:
        print(letter)# one at a time
        stop = input("continue or stop? ")
        if stop == "stop":
            break
    print("done")
    break

It could be because some of your database entries that you’ve added have different prefixes.
At the start of your code try printing all the keys,

keys = db.keys()
for key in keys:
    print(key)

and you may see that not all of them start with the date, they probably start with the other prefixes you were using before.

When you try to find matches with .prefix(exact), it’ll only match if it starts with exact, not just if it has exact in it.

from replit import db

db["abc"] = "first one"
db["zabc"] = "second one"
db["abc3"] = "third one"

keys = db.prefix("abc")
for key in keys:
  print(key, db[key])

outputs
abc first one
abc3 third one

The second one is skipped, even though it has abc in it, it doesn’t start with abc, it starts with z.

2 Likes