Find the minimum number of characters to add to make password strong
Code length is one factor in readability, but it isn't the only factor. "Is this code easy to read and modify" is a more important question to ask.

It looks like you've gotten a method skeleton here, which kind of leads you down the path of stuffing everything in one function, which is a bit of a shame. Let's look at what we actually need here.


Length of at least 6
One lowercase English character
One uppercase English character
One digit
One special character


What if we split this up into a bunch of separate functions, which each do one thing. We'll just write the function names down for now, and leave the implementation blank.

def lower_required(text):
    pass

def upper_required(text):
    pass

def digits_required(text):
    pass

def length_required(text):
    pass

def special_required(text):
    pass


Now, Python has a string module that is (semi)deprecated (much of what was in it is now on string objects themselves), but that has some still useful things, namely, string.ascii_lowercase, string.ascii_uppercase, and string.digit. We can use these in the implementations for some of our functions. Let's just write them as simply as possible for now.

import string

def lower_required(text):
    for char in text:
        if char in string.ascii_lowercase:
            return 0
    return 1

def upper_required(text):
    for char in text:
        if char in string.ascii_uppercase:
            return 0
    return 1

def digit_required(text):
    for char in text:
        if char in string.digits:
            return 0
    return 1


There's quite a bit of repetition here that we can factor out.

def num_required(text, characters):
    if any((x in characters for x in text)):
        return 0
    return 1


Then our previous functions can just call this:

def lower_required(text):
    return num_required(text, string.ascii_lowercase)


And similarly for the upper_required and digit_required.

In fact, we can do this with our special characters as well:

SPECIAL_CHARS = '!@#$%^&amp;*()-+'

def special_required(text):
    return num_required(text, SPECIAL_CHARS)


The last function we need to implement is length_required:

MINIMUM_LENGTH = 6

def length_required(text):
    if len(text) &gt;= MINIMUM_LENGTH:
        return 0
    return MINIMUM_LENGTH - len(text)


Now we can stitch these all together within minimumNumber (note that Python functions should be named using snake_case, so it should be minimum_number here - but I assume this function name was given to you, so I won't harp on about it too much).

def minimumNumber(text):
    test_functions = [lower_required, upper_required,
                      digits_required, special_required]
    min_chars_required = sum([test_fn(text) for test_fn in test_functions])
    missing_length = length_required(text)
    if missing_length &gt; min_chars_required:
        return missing_length
    return min_chars_required


The benefit of doing this is the fact that we can easily add extra checks. What if a new requirement comes along? We can just create a new function an add it to test_functions; the amount of existing code we have to touch is minimal.

Just to drive home the point about size vs readability, here is a (slightly) code golfed version:

import string

def minimumRequired(password):
    if len(password) &lt; 6:
        return 6 - len(password)
    unique_pw = frozenset(password)
    char_sets = (frozenset(string.ascii_lowercase), frozenset(string.ascii_uppercase),
                 frozenset(string.digits), frozenset('!@#$%^&amp;*()-+'))
    required_extra = 0
    for char_set in char_sets:
        if not char_set &amp; unique_pw:
            required_extra += 1
    return required_extra


This (probably - I haven't really tested it) satisfies the requirements, but how do I make changes to it? Is it obvious how it does what it does (I'd argue not really).