HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Password Validation in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
pythonvalidationpassword

Problem

I coded a python solution for the question below. I am after the fastest solution. Also, I would be grateful if you could point out parts that are not pythonic / inefficient.


Question: A website requires the users to input username and password
to register. Write a program to check the validity of password input
by users. Following are the criteria for checking the password:



  • At least 1 letter between [a-z]



  • At least 1 number between [0-9]



  • At least 1 letter between [A-Z]



  • At least 1 character from [$#@]



  • Minimum length of transaction password: 6




import warnings
password = 'P@ss1234'
def check_number(s):
    ''' Check whether the input string is a digit. '''
    try: 
        int(s)
        return True
    except:
        # do not catch error
        return False
def check_validity(pw):
    ''' Return True if input pw is valid, and return False if invalid.'''
    special_chars = ['

P.S: I am not interested in a module / package that can do this faster or more securely. There does not actually exist a website or a username, this is a simple coding exercise.

Also, linked to this post.,'#','@'] if isinstance(pw,str): pw=list(pw) # I could have appointed to a diff var name else: warnings.warn('Password has to be a string object.') res = False valid_dict={'small_let':False, 'num':False, 'special_chars':False, 'cap_let':False, 'len':False } # is using a dict efficient? if len(pw)>= 6: valid_dict['len']=True for i in pw: if i.islower(): valid_dict['small_let'] = True if i in special_chars: valid_dict['special_chars'] = True if i.isupper(): valid_dict['cap_let'] = True if not valid_dict['num']: valid_dict['num'] = check_number(i) if all(valid_dict.values()): res = True return res print check_validity(password)


P.S: I am not interested in a module / package that can do this faster or more securely. There does not actually exist a website or a username, this is a simple coding exercise.

Also, linked to this post.

Solution


  • You shouldn't use bare excepts, this is as it can prevent things like KeyboardInterrupt.


That's just bad.

  • password is a better variable name than pw, at first I was quite confused about what it was.



  • You can return early if you know the password is not valid.


This can save you a lot of checks in your program.

  • Your program goes through each character and checks if it's one of the four valid groups.


Instead you can check if it shares any items with that set.
If it doesn't it's not valid.

-
You're creating warnings un-neededly, currently, excluding the cast, the functionality is the same if it's a list.
Instead of a warning you should either raise an error, or return.

This is as if I pass ['P', 'a', '$', '2', 1, 2] it probably shouldn't return True, which it might on a different implementation.
Instead you can either hard limit your input to strings, or check if the contents of the input are strings. Or both.

In short, just change password to a set, and use & with the groups it needs to be a part of.
This can remove the need to make the function check_number, and makes the code much more readable:

import string

def check_validity(password):
    ''' Return True if input pw is valid, and return False if invalid.'''
    if isinstance(password, str) \
            or not all(isinstance(c, str) for c in password):
        return False

    if len(password) < 6:
        return False

    password = set(password)
    checks = [
        set(string.ascii_lowercase),
        set(string.ascii_uppercase),
        set(string.digits),
        {', '#', '@'},
    ]

    for check in checks:
        if not check & password:
            return False
    return True

print check_validity('P@ss1234')

Code Snippets

import string

def check_validity(password):
    ''' Return True if input pw is valid, and return False if invalid.'''
    if isinstance(password, str) \
            or not all(isinstance(c, str) for c in password):
        return False

    if len(password) < 6:
        return False

    password = set(password)
    checks = [
        set(string.ascii_lowercase),
        set(string.ascii_uppercase),
        set(string.digits),
        {'$', '#', '@'},
    ]

    for check in checks:
        if not check & password:
            return False
    return True

print check_validity('P@ss1234')

Context

StackExchange Code Review Q#142880, answer score: 12

Revisions (0)

No revisions yet.