You're staring at the lab prompt. It says something about password requirements — minimum length, uppercase, lowercase, digit, special character. And you're thinking: *how hard can this be?
Then you start coding. Three hours later you're questioning every life choice that led you to this moment.
Been there. The 2.In real terms, 14 lab warm up (creating passwords) is one of those assignments that looks deceptively simple on paper. And most students walk in expecting a quick win. They walk out realizing string validation is sneakier than it looks.
Let's break down what this lab actually asks for, why it trips people up, and how to solve it without losing your mind.
What Is the 2.14 Lab Warm Up
If you're working through zyBooks, CodeHS, or a similar intro programming curriculum, you've hit the password creation lab. Consider this: the numbering varies by platform — sometimes it's 2. Even so, 14, sometimes 4. 2, sometimes Lab 3 — but the core task is nearly always the same.
Write a program that:
- Prompts the user for a password
- Checks it against a set of rules
- Keeps asking until the password passes all checks
- Then prints something like "Password created successfully"
The typical requirements:
- At least 8 characters long
- Contains at least one uppercase letter
- Contains at least one lowercase letter
- Contains at least one digit (0–9)
- Contains at least one special character (!, @, #, $, %, etc.)
Some versions add: no spaces allowed, maximum length cap, or a banned password list. But the five rules above? That's the standard set.
Why This Lab Exists
It's not about passwords. Not really. Your instructor doesn't care if you build the next LastPass.
This lab exists to force you to practice:
- Loop control — specifically
whileloops with compound conditions - String traversal — checking each character one by one
- Boolean flags — tracking multiple independent conditions simultaneously
- Character classification — using methods like
.So naturally, isupper(),. islower(), `.
The password scenario is just a convenient wrapper. The skills transfer directly to form validation, data cleaning, API input sanitization, and a hundred other tasks.
Why It Matters (And Why Students Struggle)
Here's the thing: the logic isn't complex. But the implementation has sharp edges Simple, but easy to overlook..
Most students fail this lab in one of three ways:
1. They try to check everything in one giant if statement.
Something like:
if len(pw) >= 8 and any(c.isupper() for c in pw) and any(c.islower() for c in pw) ...
This works. It's also hard to debug, hard to read, and hard to modify when the requirements change (and they will) No workaround needed..
2. They forget to reset their flags inside the loop.
You declare has_upper = False outside the while loop. First attempt fails. Second attempt — the flags are still True from the first pass. Infinite success. You submit. Autograder fails. You cry Worth knowing..
3. They confuse "contains at least one" with "every character must be."
A password like Abcdefg1! passes. But a student writes a loop that rejects it because b isn't uppercase. They're checking the wrong condition.
The lab matters because it teaches you to manage state across iterations. And not a Python skill. Which means that's a fundamental programming skill. A programming skill Most people skip this — try not to. Nothing fancy..
How It Works — Step by Step
Let's walk through a clean, readable solution. I'll use Python since that's what most intro courses use for this lab, but the logic translates to Java, C++, JavaScript — whatever.
The High-Level Flow
prompt for password
while password is not valid:
check each requirement
if any requirement fails:
print what's missing
prompt again
print success message
That's it. The devil is in the "check each requirement" part.
Setting Up the Validation Loop
Start with the skeleton:
def is_valid_password(password):
# check all rules here
return True or False
password = input("Enter password: ")
while not is_valid_password(password):
print("Invalid password. Requirements:")
print(" - At least 8 characters")
print(" - At least one uppercase letter")
print(" - At least one lowercase letter")
print(" - At least one digit")
print(" - At least one special character")
password = input("Enter password: ")
print("Password created successfully")
Clean. Here's the thing — readable. The validation logic lives in its own function — so the main loop stays simple.
Writing the Validation Function
Here's where most students either overcomplicate or underthink it.
def is_valid_password(password):
if len(password) < 8:
return False
has_upper = False
has_lower = False
has_digit = False
has_special = False
special_chars = "!@#$%^&*()-_=+[]{}|;:,.<>?/~`"
for char in password:
if char.isupper():
has_upper = True
elif char.islower():
has_lower = True
elif char.isdigit():
has_digit = True
elif char in special_chars:
has_special = True
return has_upper and has_lower and has_digit and has_special
Let's talk about why this works.
The flags start as False. Each character in the password gets examined exactly once. If it matches a category, that flag flips to True. Once True, it stays True — we don't need to count how many uppercase letters, just whether any exist The details matter here..
The elif chain matters. A character can't be both uppercase and a digit. Using elif instead of separate if statements saves a few nanoseconds per character — negligible here, but it's a good habit. More importantly, it makes the logic mutually exclusive by design.
The special character check uses a string lookup. char in special_chars is readable and fast enough for passwords under 100 characters. Could use a set for O(1) lookup. Doesn't matter at this scale. Readability wins Simple, but easy to overlook..
All four flags must be True at the end. The return line is explicit. No clever one-liners. Future you (or your TA) will thank you Not complicated — just consistent. That alone is useful..
Handling Edge Cases
Some lab variants add wrinkles. Here's how to handle the common ones:
No spaces allowed:
if ' ' in password:
return False
Add this early in the function. Fast fail.
Maximum length (e.g., 20 chars):
if len(password) > 20:
return False
Banned passwords list:
banned = {"password", "12345678", "qwerty123!", "admin123!"}
if password.lower() in banned:
return False
Case-insensitive check. Real systems do this Worth knowing..
Must not contain username:
if username.lower() in password.lower():
return False
You'd need username passed in or available
as a global variable. Prefer parameter passing.
Testing Your Validation
Don't trust your code until you've tested it. Create a simple test harness:
def test_password_validation():
test_cases = [
("Abcdefg1!", True), # Valid
("short1!", False), # Too short
("alllowercase1!", False), # No uppercase
("ALLUPPERCASE1!", False), # No lowercase
("NoNumbers!", False), # No digits
("NoSpecial1", False), # No special chars
("ValidPass123@", True), # Valid
]
for pwd, expected in test_cases:
result = is_valid_password(pwd)
status = "PASS" if result == expected else "FAIL"
print(f"{status}: '{pwd}' -> {result} (expected {expected})")
test_password_validation()
Run this before accepting user input. Catch edge cases early.
Security Considerations
This implementation handles basic validation, but real systems need more:
- Hash passwords before storage using bcrypt or argon2
- Rate limiting prevents brute force attacks
- Password strength meters give users feedback
- Common password blacklists block known weak passwords
The lab focuses on validation logic, not full security implementation.
Code Organization Options
For larger projects, consider these alternatives:
Using regular expressions:
import re
def is_valid_password(password):
if len(password) < 8:
return False
has_upper = bool(re.@#$%^&*()\-_=+\[\]{}|;:,.search(r'\d', password))
has_special = bool(re.search(r'[a-z]', password))
has_digit = bool(re.search(r'[A-Z]', password))
has_lower = bool(re.search(r'[!<>?
**Using any() with generator expressions:**
```python
def is_valid_password(password):
if len(password) < 8:
return False
special_chars = set("!@#$%^&*()-_=+[]{}|;:,.<>?/~`")
return (any(c.isupper() for c in password) and
any(c.islower() for c in password) and
any(c.isdigit() for c in password) and
any(c in special_chars for c in password))
Both approaches work well. Choose based on team preferences and performance requirements.
Final Thoughts
Password validation seems simple but involves many decisions. The key is balancing security requirements with user experience. Start simple, add complexity only when needed, and always test thoroughly Less friction, more output..
Remember: this lab teaches validation logic, not comprehensive password security. Production systems require additional layers of protection.
The clean structure we've built—separating validation from user interaction—makes testing easier and code more maintainable. This pattern applies far beyond password validation.
Keep practicing these fundamentals. They form the foundation for writing solid, readable code in any domain.