How to Generate Random Passwords Using Python: A Step-by-Step Guide

Generating secure passwords is crucial for protecting your online accounts and personal information. In this tutorial, we will walk you through a Python script that generates random passwords based on user-specified criteria, such as length, the inclusion of digits, special characters, and types of alphabets. This script uses the argparse module to handle command-line arguments and can be run directly from your terminal.

Prerequisites

Before we begin, ensure you have Python installed on your system. You can download it from python.org. Also make sure you have coding environment already set up on your computer. I'm using Visual Studio Code with Python Extension Pack installed.

Step 1: Import Necessary Modules

We start by importing the required Python modules:

  • string and random for generating the password.
  • argparse for handling command-line arguments.
import string
import random
import argparse

Step 2: Define Helper Functions

Next, we define helper functions to validate the user's input and to generate the password.

  1. Validate Password Length:
    This function ensures the password length is between 8 and 15 characters.

    def get_password_length(length: int) -> int:
        if 8 <= length <= 15:
            return length
        else:
            raise ValueError("Please enter a number between 8 and 15.")
    
  2. Validate Alphabet Choice:
    This function checks if the user's choice for alphabets is valid.

    def get_alphabets_choice(choice: str) -> str:
        if choice in ['caps', 'small', 'mix', 'none']:
            return choice
        else:
            raise ValueError("Invalid choice for alphabets. Please choose caps, small, mix, or none.")
    
  3. Validate Digits Choice:
    This function ensures the user's choice for including digits is valid.

    def get_digits_choice(choice: str) -> str:
        if choice in ['yes', 'no']:
            return choice
        else:
            raise ValueError("Invalid choice for digits. Please choose yes or no.")
    
  4. Validate Special Characters Choice:
    This function checks if the user's choice for including special characters is valid.

    def get_special_characters_choice(choice: str) -> str:
        if choice in ['yes', 'no']:
            return choice
        else:
            raise ValueError("Invalid choice for special characters. Please choose yes or no.")
    

The raise ValueError statement in Python is used to generate an exception of type ValueError. An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions. Specifically, a ValueError is raised when a function receives an argument of the right type but an inappropriate value, such as a number outside of an expected range.

In every function, when the validation fails, we have raised ValueError exception.

Step 3: Generate the Password

The core function of our script is generate_password, which creates the random password based on the user's criteria.

The logic is simple. First, we will build a character array by picking up the characters based on the options set by the User. Next, we will make random.choice to pick characters randomly from this array and will join the new random character derived with the previous one, until the length of joined characters is less than the desired password length specified by the User.

Let's do it.

def generate_password(length: int, alphabets: str, digits: str, special_chars: str) -> str:
    password_chars = ''
    
    if alphabets == 'caps':
        password_chars += string.ascii_uppercase
    elif alphabets == 'small':
        password_chars += string.ascii_lowercase
    elif alphabets == 'mix':
        password_chars += string.ascii_letters

    if digits == 'yes':
        password_chars += string.digits

    if special_chars == 'yes':
        password_chars += string.punctuation

    if not password_chars:
        raise ValueError("No characters selected to generate password.")

    password = ''.join(random.choice(password_chars) for _ in range(length))
    return password

Let me walk you through the code of this function.

  1. Initialize password_chars:
    We start with an empty string password_chars which will hold all possible characters that can be used in the password.

  2. Add Alphabet Characters:
    Depending on the user's choice (caps, small, mix), we append the corresponding alphabet characters to password_chars.

    • caps: Adds uppercase letters.
    • small: Adds lowercase letters.
    • mix: Adds both uppercase and lowercase letters.
  3. Add Digit Characters:
    If the user chose yes for digits, we add numeric digits (0-9) to password_chars.

  4. Add Special Characters:
    If the user chose yes for special characters, we add punctuation characters (e.g., !@#$%^&*()) to password_chars.

  5. Check for Valid Characters:
    If password_chars is still empty after processing all choices, we raise an error because there are no characters to generate the password from.

  6. Generate the Password:
    Using random.choice(), we randomly select characters from password_chars to form a password of the desired length. The resulting characters are joined together to form the final password.

Step 4: Handle Command-Line Arguments

We use argparse to handle the command-line arguments and call the helper functions to validate the inputs. argparse is a module in Python's standard library used to parse command-line arguments. It provides a way to handle user inputs from the command line, allowing you to write flexible and user-friendly command-line interfaces for your programs.

def main() -> None:
    parser = argparse.ArgumentParser(description='Generate a random password.')
    parser.add_argument('--length', type=int, default=8, help='The length of the password (between 8 and 15)')
    parser.add_argument('--alphabets', type=str, choices=['caps', 'small', 'mix', 'none'], default='mix', help='Alphabets: caps, small, mix, none')
    parser.add_argument('--digits', type=str, choices=['yes', 'no'], default='yes', help='Digits: yes, no')
    parser.add_argument('--special_chars', type=str, choices=['yes', 'no'], default='yes', help='Special Characters: yes, no')

    args = parser.parse_args()

    try:
        length = get_password_length(args.length)
        alphabets = get_alphabets_choice(args.alphabets)
        digits = get_digits_choice(args.digits)
        special_chars = get_special_characters_choice(args.special_chars)

        password = generate_password(length, alphabets, digits, special_chars)
        print(f"Generated Password: {password}")
    except ValueError as e:
        print(e)
        
  1. Set Up Argument Parser:
    We create an ArgumentParser object and add four arguments:

    • --length: The desired length of the password (default is 8).
    • --alphabets: The type of alphabets to include (default is mix).
    • --digits: Whether to include digits (default is yes).
    • --special_chars: Whether to include special characters (default is yes).
  2. Parse Arguments:
    The parser.parse_args() method parses the command-line arguments and stores them in args.

  3. Validate Inputs:
    We call our helper functions to validate the user's inputs for length, alphabets, digits, and special characters. These functions will raise a ValueError if any input is invalid.

  4. Generate and Print Password:
    If all inputs are valid, we call generate_password to create the password and print it. If there is a ValueError, we catch it and print the error message.

Step 5: Call main() inside if __name__ == "__main__

if __name__ == "__main__":
    main()

It is a common Python idiom used to ensure that certain code is only executed when the script is run directly, and not when it is imported as a module in another script.

  • __name__ is a special built-in variable in Python that represents the name of the current module.
  • When a Python file is run directly, the __name__ variable is set to "__main__".
  • When a Python file is imported as a module in another script, the __name__ variable is set to the name of the file (e.g., "password_generator" if the file is named password_generator.py).
  • Finally, by placing main() function call inside the if __name__ == "__main__": block, we ensure that main() is only executed when the script is run directly, and not when it is imported.

Here is the complete code:

import string
import random
import argparse

def get_password_length(length: int) -> int:
    if 8 <= length <= 15:
        return length
    else:
        raise ValueError("Please enter a number between 8 and 15.")

def get_alphabets_choice(choice: str) -> str:
    if choice in ['caps', 'small', 'mix', 'none']:
        return choice
    else:
        raise ValueError("Invalid choice for alphabets. Please choose caps, small, mix, or none.")

def get_digits_choice(choice: str) -> str:
    if choice in ['yes', 'no']:
        return choice
    else:
        raise ValueError("Invalid choice for digits. Please choose yes or no.")

def get_special_characters_choice(choice: str) -> str:
    if choice in ['yes', 'no']:
        return choice
    else:
        raise ValueError("Invalid choice for special characters. Please choose yes or no.")

def generate_password(length: int, alphabets: str, digits: str, special_chars: str) -> str:
    password_chars = ''
    
    if alphabets == 'caps':
        password_chars += string.ascii_uppercase
    elif alphabets == 'small':
        password_chars += string.ascii_lowercase
    elif alphabets == 'mix':
        password_chars += string.ascii_letters

    if digits == 'yes':
        password_chars += string.digits

    if special_chars == 'yes':
        password_chars += string.punctuation

    if not password_chars:
        raise ValueError("No characters selected to generate password.")

    password = ''.join(random.choice(password_chars) for _ in range(length))
    return password

def main() -> None:
    parser = argparse.ArgumentParser(description='Generate a random password.')
    parser.add_argument('--length', type=int, default=8, help='The length of the password (between 8 and 15)')
    parser.add_argument('--alphabets', type=str, choices=['caps', 'small', 'mix', 'none'], default='mix', help='Alphabets: caps, small, mix, none')
    parser.add_argument('--digits', type=str, choices=['yes', 'no'], default='yes', help='Digits: yes, no')
    parser.add_argument('--special_chars', type=str, choices=['yes', 'no'], default='yes', help='Special Characters: yes, no')

    args = parser.parse_args()

    try:
        length = get_password_length(args.length)
        alphabets = get_alphabets_choice(args.alphabets)
        digits = get_digits_choice(args.digits)
        special_chars = get_special_characters_choice(args.special_chars)

        password = generate_password(length, alphabets, digits, special_chars)
        print(f"Generated Password: {password}")
    except ValueError as e:
        print(e)

if __name__ == "__main__":
    main()

Run the Script

To generate a password, open your terminal and run the script with the desired options. For example:

python password_generator.py --length 12 --alphabets mix --digits yes --special_chars yes

This command generates a 12-character password containing a mix of uppercase and lowercase letters, digits, and special characters.

Conclusion

This Python script is a simple yet powerful tool for generating random passwords. By customizing the length, alphabet type, and inclusion of digits and special characters, you can create strong and unique passwords to enhance your security. Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *