HomeOperationsAutomated OperationsMoving up the stack - time to learn Python - part 8

Moving up the stack – time to learn Python – part 8

In our last article on my journey into Python, we talked at depth about Python Packages.  If you managed to plough your way through that post, my hat off to you.

To refresh your memory on the first seven articles, you can read them at the links shown below:

Our last article was the last to be focused on a single concept the Package, this means that we have effectively finished learning the basics.  It is now time to start looking at doing something useful with the program.

What we are going to look at today is building an interactive password generator, this will be more complicated than the command line version we wrote in our last article.

Requirements

It has become apparent that many personal in your company are using passwords that are too simple, we know that passwords are a critical part of a secure authentication process, they prevent unauthorised access to critical company information.  Therefore, your manager has tasked you with creating a Random Password Generator to be issued to staff to create complex passwords you have decided to use Python to carry out this task.   We have the following functional requirements that must be included in the program.

  • The password must contain a combination of lowercase, uppercase, symbols, and digits.
  • The password will contain a mixture of all four
  • The password will be a minimum of 10 characters, unless a longer one is requested.

As we have already shown we could just have this program work from the command line, but it is a fact of modern life, 99% of the world uses a graphical interface to interact with their devices, so this will require a graphical interface. Therefore, we have the following non-functional requirement

  • The program will be run with a graphical interface for ease of use

Why is this called a non-functional requirement? It is because the program will work perfectly well from the CLI, we will be able to enforce the combination of differing characters and minimum password length, but all the the graphical interface brings to the party is a simplicity of use.

Preparing the Python environment.

This is a very simple program, that is not to say that there are no significant complexities in it, in fact as computer programs go this is not that much higher up the evolutionary tree than the ubuquitious “hello world”.   We are, however, introducing a couple of new concepts, but 90% of what we are looking at today is stuff we have already covered in our earlier articles.

Project Prerequisites:

This Python password generator requires no extra installation of modules.  The Random and String modules are predefined and the tkinter module should already be available on your system as it is a built-in module deployed with the Python installation routine. However, If when you import the modules into your script you receive an error, you can either reinstall python or use the following command if you are running on a linux system:

sudo apt-get install python3-tkinter

Python Project File Structure:

As this is a simple first useful program we will not be setting up modules, but creating this as a single file.  First lets create a new directory in our python environment, I called mine “NewPassword”. We then moved into the folder and created a file called “newpassword.py”

For ease we are going to break this programme down in to several sections,  this is the process that I used to build our password generator python project:

  1. Import the relevant modules in this case the string, random and tkinter modules
  2. Define password generator function
  3. Define character string
  4. Create the user interface
  5. Add input widgets
  6. Button to call the translate function

Building and explaining our script.

The first thing we do is import the string, random and tkinter modules, these modules provide additional functionality to the core python language.  The “random” module is a built-in module that is used to generate random subsets or substrings of a string, list, or array.  We use it to generate our password from our list of characters. We use the string module in Python to provide a set of constants and functions that are useful for working with strings. It includes constants such as “string.ascii_letters”“string.digits”, and “string.punctuation”, which contain the ASCII letters, digits, and punctuation characters, respectively, we use it to manipulate our strings.  Finally, we import “tkinter” is a Python module that provides a set of tools for creating graphical user interfaces (GUIs). It is the standard GUI package for Python and comes pre-installed with Python, so there is no need to install it separately.

Now you may be wondering why we have two importations of the tkinter module in this script, especially as the second uses a wildcard so logically that would dictate that all of the module was imported.  This is not actually the case here. When you import “tkinter” using from “from tkinter import *”, it only imports the names listed in the “__all__” variable of the “tkinter” module.  The messagebox module is not included as a part of the “__all__” variable, therefore, we need to explicitly import it using “from tkinter import messagebox”.

#Import the necessary modules
import random
import string
from tkinter import messagebox
from tkinter import *

So continuing on we will define our password generator function this is the first of a few functions we will be creating and for ease we will split this is to sections, as per normal as this is a function we must define it with the “def” keyword.

#Password generator function
def generate_password():

The first section defines the length and states whether any of the characters can be repeated in the password or not.  It introduces a new set of keywords “try:” and “except”.  both are Python keywords used for exception handling. The “try” block contains the code that may raise an exception, while the “except” block contains the code that is executed if an exception occurs, The syntax is similar to the “if/else” statement.  Try/except is often used to capture errors as we have here.

We have also introduced another control into this function, this one is aligned to password length, as we defined in our requirements the password must be a minimum of 10 characters in length.

Both of the captures result in the imposition of a message box that must be cancelled to carry on with the execution of the program.

    try:
        length = int(length_entry.get())
        if length < 10:
            messagebox.showerror(message="Password must be at least 10 characters")
            return
        repeat = int(repeat_entry.get())
    except:
        messagebox.showerror(message="Please key in the required inputs")
        return

This second code block generates a random password of length length using the characters in “character_string”, this will be discussed later in this article. If “repeat” is equal to 1, the function “random.sample()” is used to generate a password with no repeated characters. Otherwise, the function “random.choices()” is used to generate a password with possible repeated characters

    #Check if user allows repetition of characters
    if repeat == 1:
        password = random.sample(character_string,length)
    else:
        password = random.choices(character_string,k=length)

Our next line converts the list created in the previous snippet to a string.  This code converts the list into a string by concatenating all the elements contained in the list. The “join()” method is called on an empty string  and takes the list as an argument returning a string that is the concatenation of all the elements in the list, with no separators between the characters.

    #Since the returned value is a list, we convert to a string using join
    password=''.join(password)

These two lines create a ”StringVar” object called “password_v”. “StringVar” is a class in the tkinter module that provides a way to store and manipulate strings in Tkinter GUIs. The second line of code creates a string called password that contains the generated password. The “str()” function is used to convert the password from a list to a string, so that it can be displayed in the GUI

    #Declare a string variable
    password_v = StringVar()
    password="Created password: "+str(password)

This line of code strips the first 18 characters of the created password, these characters are “Created password: “,  this variable is used later in our script.

#Remove the first 18 characters from the password
    password2 = password[18:]

This line sets the value of the “StringVar” object “password_v” to the value of the password variable. The “set()” method is called on the “password_v” object and takes the password variable as an argument. This updates the value of “password_v” to be equal to the value of password, which is then displayed in the read-only entry box, we also fill the variable “password2” using the same process.

    #Assign the password to the declared string variables
    password_v.set(password)
    password2_v.set(password2)

This code creates a read-only entry box called “password_label” in the “password_gen” window. The “Entry()” function is called with several arguments to configure the appearance and behaviour of the entry box. The “textvariable” argument is set to “password_v”, which is a “StringVar” object that contains the generated password. The state argument is set to “readonly”, which makes the entry box read-only. The “place()” method is called on the “password_label” object to position it in the window

    #Create a read only entry box to view the output, position using place
    password_label = Entry(password_gen, bd=0, bg="gray85", textvariable=password_v, state="readonly")
    password_label.place(x=10, y=140, height=50, width=320)

Our next section effectively defines our character lexicon, as you can see it contains the standard latin alphabet in upper and lower case, together with the numbers 0 through to 9 and a large selections of special characters.

#Define a string containing letters, symbols and numbers
character_string="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()*+,-./:;<=>?@[\]^_`{|}~"

This is the variable we referred to in the lines:

    if repeat == 1:
        password = random.sample(character_string,length)
    else:
        password = random.choices(character_string,k=length)

Next we start to create the password generator’s user interface.  The first thing we do is initalise the class “tkinter”,  we then create a gui frame that is 350 pixels wide by 200 pixels high, and finally we give it a pithy title in our case “Amizac Password Generator”.

#Define the user interface
password_gen = Tk()
password_gen.geometry("350x200")
password_gen.title("Amizac’s Password Generator")

Next we declare our global variable “password2_v”, you may find this positioning rather odd as usually global variables are declared at the beginning of a script, however this placement is expected as we must first declare our class before we can use or populate the variable.,

# Declare password2_v as a global variable
password2_v = StringVar()

if it is not placed here, bad things happen.

python error
opps, that’s not good

Sometimes you just have to go with the flow.

Next we move on to Adding our input widgets, these are fairly logical.  Our first section creates a title for the frame, the rather cool and trendy “Amazics Amazing Python Password Generator” and we can even define the font.

#Mention the title of the app
title_label = Label(password_gen, text="Amizac’s Amazing Python Password Generator", font=('Ubuntu Mono',12))
title_label.pack()

Next we place our two inputs, starting with the request for the length of the password, we have defined the exact placement, and defined the entry box as having the capability to accept three characters.

#Read length
length_label = Label(password_gen, text="Enter length of password: ")
length_label.place(x=20,y=30)
length_entry = Entry(password_gen, width=3)
length_entry.place(x=190,y=30)

Our third entry places the entry box that defines whether we have repeating characters or not in our generated password

#Read repetition
repeat_label = Label(password_gen, text="Repetition? 1: no repetition, 2: otherwise: ")
repeat_label.place(x=20,y=60)
repeat_entry = Entry(password_gen, width=3)
repeat_entry.place(x=300,y=60)

It may be good to explain the keywords above in slightly details.

title_label, length_label, repeat_label: Labels to place non-editable text on an applications graphical interface. The parameters are window of the screen, text to display and an optional font styling.

repeat_entry, length_entry: To read user input, the “Entry” widget is used. Alternatively, Text can also be used. To use the widget we have passed the following parameters: “password_gen”-the screen of the python password generator app and the width of the widget.

widget.place() and widget.pack(): Any widgets or labels will be visible only after positioning it on the window or screen of the app. This is achieved by using “pack()” and “place()”. “pack() center” will for example align text along a row.  We have however used the place() statement to place our lables. This enables customized positioning of the widget and a finer granular control to placement.

Finally we create the buttons to trigger the password generation.   The code you provided is written in Python and uses the tkinter library to create a graphical user interface (GUI) with a button that generates a password when clicked.

The Button class is used to create a button widget with the specified text and command. In this case, the text is “Generate Password” and the command is “generate_password”, which is a function that generates a password.

The place method is used to place the button at a specific location on the GUI. In this case, the button is placed at coordinates (130, 90).

#Generate password
password_button = Button(password_gen, text="Generate Password", command=generate_password)
password_button.place(x=130,y=90)

Now we have the second of the two functions in our script, “copy_password()” the first thing we can see is that we are brining into the function the value the variable “password2_v”, if you remember this is the result of the stripping the first 18 characters off the “password” variable.  Then we clear the current value of the local machines clipboard and then add the contents of “password2” into the clipboard.  Finally we display a messagebox informing us that the “Password [has been] copied to clipboard”. We then place a button using the tk.button class for us to click.

def copy_password():
    password2 = password2_v.get()  # Get the value of password2 from password2_v
    password_gen.clipboard_clear()
    password_gen.clipboard_append(password2)
    messagebox.showinfo("Success", "Password copied to clipboard!")

copy_button = tk.Button(password_gen, text="Copy Password", command=copy_password)
copy_button.place(x=135, y=190)

The last part of this code closes out the program.

#Exit and close the app
password_gen.mainloop()

So what does this all look like, to run the application.

Issue the command python newpassword.py and press enter,  if all is find and dandy you will be presented with the following

running-our-Python-script
There we go, presented with a wonderfully crafted user interface

I will leave you the reader to do the final testing of the application,  testing that we have enforced a minimum 10 character password policy, and that the program will not allow a password creation without both questions being anwered.

Summary

We have successfully created python password generator.  We have furthered our Python knowledge, learning about tkinter and importing variables across functions.  This script is useable as we have shown by running from the CLI.  However, we still have to make it into a program that does not need a python environment installed on the target host.  This will be the core of our next article in this series.  Thank you for reading.

NEWSLETTER

Receive our top stories directly in your inbox!

Sign up for our Newsletters

spot_img
spot_img
spot_img
spot_img

LET'S CONNECT