I made a simple password-generating app with a GUI written in Python and the tkinter library.
Here's how the GUI looks like:
The passwords are strings composed of random characters. The user can choose the length of the password, and the characters that are allowed to be in it.
Here's the source code:
import string
import tkinter as tk
from tkinter import ttk
import random
from tkinter.constants import DISABLED, E, END, NORMAL, NW, VERTICAL
class GUI(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()
self.widget_vars()
self.create_widgets()
self.style()
def generate_password(self):
passw = Password(self.length.get(), self.lower.get(), self.upper.get(),
self.digits.get(), self.punct.get())
# You can only insert to Text if the state is NORMAL
self.password_text.config(state=NORMAL)
self.password_text.delete("1.0", END) # Clears out password_text
self.password_text.insert(END, passw.password)
self.password_text.config(state=DISABLED)
def widget_vars(self):
self.length = tk.IntVar(self, value=16)
self.lower = tk.BooleanVar(self, value=True)
self.upper = tk.BooleanVar(self, value=True)
self.digits = tk.BooleanVar(self, value=True)
self.punct = tk.BooleanVar(self, value=True)
def create_widgets(self):
# Define widgets
self.lower_checkbtn = ttk.Checkbutton(self, variable=self.lower)
self.lower_label = ttk.Label(self, text="string.ascii_lower")
self.upper_checkbtn = ttk.Checkbutton(self, variable=self.upper)
self.upper_label = ttk.Label(self, text="string.ascii_upper")
self.digits_checkbtn = ttk.Checkbutton(self, variable=self.digits)
self.digits_label = ttk.Label(self, text="string.digits")
self.punct_checkbtn = ttk.Checkbutton(self, variable=self.punct)
self.punct_label = ttk.Label(self, text="string.punctuation")
self.length_spinbox = ttk.Spinbox(self, from_=1, to=128, width=3,
textvariable=self.length)
self.length_label = ttk.Label(self, text="Password length")
self.separator = ttk.Separator(self, orient=VERTICAL)
self.generate_btn = ttk.Button(self, text="Generate password",
command=self.generate_password)
self.password_text = tk.Text(self, height=4, width=32, state=DISABLED)
# Place widgets on the screen
self.length_label.grid(column=0, row=0, rowspan=4, sticky=E)
self.length_spinbox.grid(column=1, row=0, rowspan=4, padx=4, pady=2)
self.lower_label.grid(column=3, row=0, sticky=E, padx=4)
self.lower_checkbtn.grid(column=4, row=0, padx=4, pady=2)
self.upper_label.grid(column=3, row=1, sticky=E, padx=4)
self.upper_checkbtn.grid(column=4, row=1, padx=4, pady=2)
self.digits_label.grid(column=3, row=2, sticky=E, padx=4)
self.digits_checkbtn.grid(column=4, row=2, padx=4, pady=2)
self.punct_label.grid(column=3, row=3, sticky=E, padx=4)
self.punct_checkbtn.grid(column=4, row=3, padx=4, pady=2)
self.separator.grid(column=2, row=0, rowspan=4, ipady=45)
self.generate_btn.grid(columnspan=5, row=4, padx=4, pady=2)
self.password_text.grid(columnspan=5, row=6, padx=4, pady=2)
self.grid(padx=10, pady=10)
def style(self):
self.style = ttk.Style(self)
self.style.theme_use("clam")
class Password:
def __init__(self, length: int,
allow_lowercase: bool,
allow_uppercase: bool,
allow_digits: bool,
allow_punctuation: bool) -> None:
self.length = length
self.allow_lowercase = allow_lowercase
self.allow_uppercase = allow_uppercase
self.allow_digits = allow_digits
self.allow_punctuation = allow_punctuation
self.allowed_chars = self.gen_allowed_chars()
self.password = self.gen_password()
def gen_allowed_chars(self) -> str:
# I use a string, because random.choice doesn't work with sets:
chars = ''
if self.allow_lowercase:
chars += string.ascii_lowercase
if self.allow_uppercase:
chars += string.ascii_uppercase
if self.allow_digits:
chars += string.digits
if self.allow_punctuation:
chars += string.punctuation
return chars
def gen_password(self) -> str:
password = ''
for _ in range(self.length):
password += random.choice(self.allowed_chars)
return password
if __name__ == '__main__':
root = tk.Tk()
root.title("Password Generator")
app = GUI(root)
app.mainloop()
Can this code be improved in any way? Does this code follow common best practices? I'd appreciate some advice, especially on the GUI class (I'm new to tkinter).
Thank You in advance.
