Scan a password in one pass

Write check_password using one for loop over the password. Return "Valid" only when all five rules are satisfied:

  1. at least one uppercase letter;
  2. at least one lowercase letter;
  3. at least one digit;
  4. at least one character from SPECIAL_CHARACTERS; and
  5. at least eight characters in total.

Return "Invalid" when any rule is unsatisfied. Use the special-character string supplied in the listing. This exercise checks the stated rules only.

Complete the supplied function in Listing 1. Keep its signature and use the checks below it.

Listing 1: Starter function and supplied checks for one-pass password validation.
SPECIAL_CHARACTERS = "!@#$%^&*()_+[]{}|;:'\",.<>?"


def check_password(password: str) -> str:
    has_uppercase = False
    has_lowercase = False
    has_digit = False
    has_special = False

    for character in password:
        # Update the four Boolean flags.
        pass

    # Combine the flags with the length requirement.
    raise NotImplementedError


assert check_password("Password123!") == "Valid"
assert check_password("WeakPass") == "Invalid"
assert check_password("SecurePass123") == "Invalid"
assert check_password("Complex@Pswd123") == "Valid"

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false. character.isupper(), character.islower(), and character.isdigit() return Boolean character classifications. For a single character, "A".isupper(), "a".islower(), and "7".isdigit() are True; "!".isdigit() is False. character in SPECIAL_CHARACTERS checks whether that character belongs to the supplied string.