Generating Random Password in Python - Practical Guide

spaceofmiah

Osazuwa J. Agbonze

Posted on March 30, 2020

Generating Random Password in Python - Practical Guide

When following a registration process, everything goes well until we are to fill in password. Choosing a password has always linger the registration flow. In this post we'll learn how to create a password generator program in python.

Pre-requisite

All that is required to follow along is a basic knowledge of python and an IDE(Integrated Development Environment).

Folder Structure

I have app.py file in a folder py-password and i'll be working on this file in this post.

Password is often a combination of letters (lowercase and uppercase), digits and punctuation. Lets create some global variables to store letters (lowercase and uppercase), digits and punctuation respectively. To achieve this task, python have a builtin string library which contains a collection of string constants.

app.py

import string
import random

LETTERS = string.ascii_letters
NUMBERS = string.digits  
PUNCTUATION = string.punctuation    

print( LETTERS )
print( NUMBERS )
print( PUNCTUATION )
Enter fullscreen mode Exit fullscreen mode

From above code, string library was imported and we accessed it's properties ascii_letters, digits and punctuation which returns lowercase and uppercase characters, numbers and punctuation respectively.

Let's see the actual values of those variables. Run the application using python app.py

terminal result

$
   abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
   0123456789
   !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
$
Enter fullscreen mode Exit fullscreen mode

NOTE:
python's builtin string library have printable property that can generate alphanumerical character sequence, but for the purpose of this application, we will stick to the current approach of having them separated.

Clean up code base by removing all print statement.

It'll be nice if we can specify how long a password should be, for that we'll create a function that receives a password length as an input from a user.

app.py

...
...

def get_password_length():
    '''
      Retrieves the length of a password
      :returns number <class 'int'>
    '''
    length = input("How long do you want your password: ")
    return int(length)
Enter fullscreen mode Exit fullscreen mode

The above code utilizes python's builtin input function to retrieve a value and converts it to numeric using python's builtin int function.

NOTE:
When python's builtin input function is used to retrieve value from a user, the value is always a string. This was why it was necessary to convert the given value to numeric using python's builtin int function.

To generate unique random passwords, we'll make use of python's builtin random library. Below is a method which generates a unique random password with a specified length.

app.py

...
...

def password_generator(length=8):
    '''
    Generates a random password having the specified length
    :length -> length of password to be generated. Defaults to 8
        if nothing is specified.
    :returns string <class 'str'>
    '''
    # create alphanumerical from string constants
    printable = f'{LETTERS}{NUMBERS}{PUNCTUATION}'

    # convert printable from string to list and shuffle
    printable = list(printable)
    random.shuffle(printable)

    # generate random password and convert to string
    random_password = random.choices(printable, k=length)
    random_password = ''.join(random_password)
    return random_password
Enter fullscreen mode Exit fullscreen mode

The above function is defined with one parameter length which defaults to 8 (the recommended minimum length of a password is 8). Let's give above code some explanations:

# create alphanumerical from string constants

We already have some global variables declared, which holds string constants (digits, punctuation, characters(lowercase and uppercase) respectively). Those constants are concatenated using python's F string and saved in a variable named printable.

# convert printable from string to list and shuffle

printable variable which holds an alphanumerical value (string: character sequence) is converted to a list (this is compulsory). Shuffling the list makes it difficult to have same password generated twice. random.shuffle() takes a list as it's argument and changes the list item position randomly.

Error that may occur
If printable is passed to random.shuffle() without converting it first to a list, it'll result to a TypeError
TypeError: 'str' object does not support item assignment

# generate random password and convert to string

random.choices takes couple of arguments but we are more concerned about the first and last argument. The first argument( population ) accepts an iterable and the last argument ( k ) specifies the number of items that will be randomly choosen from the given iterable. When calling random.choices we passed printable as the first argument and length (a parameter on our function) as the last argument.

join method was passed a result from random.choices (which returns a list as result) and called on an empty string ( ' ' ) that acts as a separator. This just help to join (like it's name says) all list item returned from random.choices as a single string with no spaces.

Alright, now that we've gone through all code statement, lets' test the application.

app.py

def password_generator(length=8):
    ....
    ....

# testing password generator with it's default length of 8
password_one = password_generator()

# testing password generator using user's input as length
password_length = get_password_length()
password_two = password_generator(password_length)

print("password one (" + str(len(password_one)) + "):\t\t" + password_one )
print("password one (" + str(len(password_two)) + "):\t\t" + password_two )
Enter fullscreen mode Exit fullscreen mode

If you run the file from your terminal/command prompt using python app.py you should have a result that resembles (but not exactly) what i have below

terminal result

C:\Users\spaceofmiah\dev\Python\core\py-password (master -> origin)
$ python app.py
  How long do you want your password: 12
  password one (8):               }8yI;[(%
  password one (12):              N@DAiQncR^1t
Enter fullscreen mode Exit fullscreen mode

Alright, we now have a functional app. If you've come this far WELL DONE!!! šŸŽ‰šŸŽŠ

App is functioning well, but can be improved on.

Including a functionality that allows us to determine if we want our password to be all digits, letters, punctuation or a combination of either digits, punctuation or letters would be a great addition to the application. Let's see how that can be achieved.

To begin with, let's clean up our code by removing those tests included previously. Completed code clean up ? alright, let's move on.

To complete this task, we'll create two functions. First function will be used to retrieve a user's choice for password character combination (digits, punctuation, letters or mixture of either one or more).

app.py

......
......


def password_combination_choice():
    '''
    Prompt a user to choose password character combination which could either be digits, letters, 
    punctuation or combibation of either of them.

    :returns list <class 'list'> of boolean. Defaults to [True, True, True] for invalid choice
        0th list item represents digits
        1st list item represents letters
        2nd list item represents punctuation
    '''
    # retrieve a user's password character combination choice
    want_digits = input("Want digits ? (True or False) : ")
    want_letters = input("Want letters ? (True or False): ")
    want_puncts = input("Want punctuation ? (True or False): ")

    # convert those choices from string to boolean type
    try:
        want_digits = eval(want_digits.title())
        want_puncts = eval(want_puncts.title())
        want_letters = eval(want_letters.title())
        return [want_digits, want_letters, want_puncts]

    except NameError as e:
        print("Invalid value. Use either True or False")
        print("Invalidity returns a default, try again to regenerate")

    return [True, True, True]
Enter fullscreen mode Exit fullscreen mode

The above code retrieves user input which must be either True or False, if anything else is specified a default is returned.

Let's create another function which will utilize a user's choice (for password character combination) to generate string value that'll be used to create random password.

app.py

def fetch_string_constant(choice_list):
    '''
    Returns a string constant based on users choice_list.
    Returned string constant can either be digits, letters, punctuation or
    combination of them.
    : choice_list --> list <class 'list'> of boolean
        0th list item represents digits    
            True to add digits to constant False otherwise
        1st list item represents letters   
            True to add letters to constant False otherwise
        2nd list item represents punctuation
            True to add punctuation to constant False otherwise
    '''
    string_constant = ''
    string_constant += NUMBERS if choice_list[0] else ''
    string_constant += LETTERS if choice_list[1] else ''
    string_constant += PUNCTUATION if choice_list[2] else ''
    return string_constant
Enter fullscreen mode Exit fullscreen mode

The above function returns a string constant base on the choice_list. Ternary if operator was used to create the string constant. Now that we have our string constant generator,let's update password_generator function to utilize it, change it's signature definition and update doctype.

def password_generator(cbl, length=8):
    '''
    Generates a random password having the specified length
    :length -> length of password to be generated. Defaults to 8
        if nothing is specified
    :cbl-> a list of boolean values representing a user choice for 
        string constant to be used to generate password.
        0th list item represents digits    
             True to add digits to constant False otherwise
        1st list item represents letters   
             True to add letters to constant False otherwise
        2nd list item represents punctuation
             True to add punctuation to constant False otherwise
    :returns string <class 'str'>
    '''
    # create alphanumerical by fetching string constant
    printable = fetch_string_constant(cbl)
Enter fullscreen mode Exit fullscreen mode

One more step before testing our password generator app. Let's create an entry point for the application.

def fetch_string_constant():
    .......
    .......

# application entry point 
if __name__ == '__main__':
    length = get_password_length()
    choice_list = password_combination_choice()
    password = password_generator(choice_list, length)
    print(password)
Enter fullscreen mode Exit fullscreen mode

Alright, now we have our password generator application all set up. Let's give it a test :- launch the application by running the below command on your terminal/command prompt

python app.py

terminal result

C:\Users\spaceofmiah\dev\Python\core\py-password (master -> origin)
Ī» python app.py

  How long do you want your password: 12
  Want digits ? (True or False) : True
  Want letters ? (True or False): True
  Want punctuation ? (True or False): False

  yjGmG09xpt07
Enter fullscreen mode Exit fullscreen mode

Kindly note: your result gotten will be different from mine as the password is randomly generated.

If you've come this far, you not only have a working password generator application, you've as well gotten familiar with python's builtin string and random library.

Click the Like button to pop my heart red šŸ™‚.
Don't leave without clicking the Follow button ( Thank You For Doing So āœŒ)

Link to the complete code base can be found on my github
If you've spot any errors, have questions or contributions, i will be more than glad to hear it. Kindly leave a comment below.

Click on the Share button to help get this post around

šŸ’– šŸ’Ŗ šŸ™… šŸš©
spaceofmiah
Osazuwa J. Agbonze

Posted on March 30, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related