Solution: Random Password
Contents
Solution: Random Password#
Write a function that works as a Random Strong Password Generator.
Rules#
Function returns a string
Length between 8 and 24 characters
At least one uppercase letter (
A-Z
)At least one lowercase letter (
a-z
)At least one digit (
0-9
)It contains at least one special character (
!@#$%^&*()+=
)Maximum of 2 repeated characters (regardless of order)
Always return a different password
You can use any
random function
from therandom
module
Useful Links#
-
Specially:
isdigit()
,islower()
,isupper()
,join()
-
Specially:
all()
,any()
,len()
Function Definition#
from random import choice, choices
def password_generator():
def password_validator(password):
type = isinstance(password, str) # rule 1: type: string
length = 8 <= len(password) <= 24 # rule 2: length: 8-24
upper = any(char.isupper() for char in password) # rule 3: upper-letter
lower = any(char.islower() for char in password) # rule 4: lower-letter
numeric = any(char.isdigit() for char in password) # rule 5: numeric character
special = any(char in "!@#$%^&*()+=" for char in password) # rule 6: special character
repeated = all(password.count(char)<3 for char in password) # rule 7: max 2 repeated characters
rules = (type, length, upper, lower, numeric, special, repeated)
return all(rules) # if any rule is false, then return false.
# Parameters definition
min_length = 8
upper_letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" # or "".join([chr(i) for i in range(ord("A"), ord("Z")+1, 1)])
lower_letters = "abcdefghijklmnopqrstuvwxyz" # or "".join([chr(i) for i in range(ord("a"), ord("z")+1, 1)]) # or upper_letters.lower()
numbers = "0123456789" # or "".join([chr(i) for i in range(ord("0"), ord("9")+1, 1)])
special_characters = "!@#$%^&*()+="
all_characters = "".join([upper_letters, lower_letters, numbers, special_characters])
# Base password generation
password = "".join(choices(all_characters, k=min_length))
# Verify if all requirements are fulfilled
strong = password_validator(password)
# If not: Add a new character every iteration until fulfil all requirements
while not strong:
password += choice(all_characters)
strong = password_validator(password)
# Note that after a while the validator will always fail for length and repeated
# To avoid infinity iterations, reset password after reach 24 chr size.
if len(password)>24:
password = "".join(choices(all_characters, k=min_length))
return password
Testing#
Check if your function returns the expected value using the cell below.
import unittest
class UnitTests(unittest.TestCase):
def setUp(self):
self.password = password_generator()
self.passwords = [password_generator() for _ in range(10)]
def test_password_type(self):
self.assertTrue(isinstance(self.password, str), 'The function should return a string')
def test_password_min_size(self):
self.assertGreater(len(self.password), 7, "The function should return a password with minimum length of 8 characters")
def test_password_max_size(self):
self.assertLess(len(self.password), 25, "The function should return a password with maximum length of 24 characters")
def test_upper(self):
self.assertTrue(any(char.isupper() for char in self.password), "The function should return a password with at least 1 upper-case letter")
def test_lower(self):
self.assertTrue(any(char.islower() for char in self.password), "The function should return a password with at least 1 lower-case letter")
def test_numeric(self):
self.assertTrue(any(char.isdigit() for char in self.password), "The function should return a password with at least 1 number")
def test_special(self):
self.assertTrue(any(char in "!@#$%^&*()+=" for char in self.password), "The function should return a password with at least 1 special character")
def test_repeated_char(self):
self.assertTrue(all(self.password.count(char)<3 for char in self.password), "The function should return a password with a maximum of 2 repeated character")
def test_unique_password(self):
self.assertEqual(len(self.passwords), len(set(self.passwords)), "The function should return an unique password")
unittest.main(argv=[''], verbosity=2,exit=False)
test_lower (__main__.UnitTests) ...
ok
test_numeric (__main__.UnitTests) ...
ok
test_password_max_size (__main__.UnitTests) ...
ok
test_password_min_size (__main__.UnitTests) ...
ok
test_password_type (__main__.UnitTests) ...
ok
test_repeated_char (__main__.UnitTests) ...
ok
test_special (__main__.UnitTests) ...
ok
test_unique_password (__main__.UnitTests) ...
ok
test_upper (__main__.UnitTests) ...
ok
----------------------------------------------------------------------
Ran 9 tests in 0.009s
OK
<unittest.main.TestProgram at 0x7ff7208edf50>