3.05 Boolean Expressions

Source lesson: python/boolean

Learning Objective: Write and evaluate Boolean expressions that compare values and combine several backend requirements with and, or and not.

Submission notes

  • Lesson: CSP 3.05 Boolean Expressions
  • Notebook: https://jupiterian.opencodingsociety.com/python/boolean-hw
  • MCQ 3.05: 4/4 answers: A,C,A,B
  • Popcorn Hacks 1–3 completed during class and copied to notebook: yes
  • Homework tested: supplied 3 records (accept / reject category / reject duplicate) plus 2 extra (empty name, empty date), all rejected for the right reason

Popcorn Hack 1: Check One SFI Part Record

Prediction: all four requirements are present and “Auto Racing” is in the accepted list, so every line prints True and the record is complete.

Code Runner Challenge

Popcorn Hack 1 - Check SFI Part Fields

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 1 - Check SFI Part Fields
part = {
    "product_name": "Replacement Flywheels and Clutch Assemblies",
    "category": "Auto Racing",
    "spec_number": "1.1",
    "effective_date": "Nov. 9, 2001"
}
valid_categories = ["Auto Racing", "Drag Racing"]

has_product_name = part["product_name"] != ""
valid_category = part["category"] in valid_categories
has_spec_number = part["spec_number"] != ""
has_effective_date = part["effective_date"] != ""

print("Has product name:", has_product_name)
print("Valid racing category:", valid_category)
print("Has spec number:", has_spec_number)
print("Has effective date:", has_effective_date)
print("Record complete:", has_product_name and valid_category and has_spec_number and has_effective_date)

# Changed input: same record but a Street Car category
part["category"] = "Street Car"
valid_category = part["category"] in valid_categories
print("After changing category to Street Car -> valid category:", valid_category)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: all four checks and “Record complete” are True. After changing the category to “Street Car”, valid_category flips to False because it isn’t in the accepted list.

Popcorn Hack 2: Backend Create Rule

Create only when every required field is valid and the spec number is not already stored, so the rule is all_fields_valid and not duplicate_spec.

Prediction: spec "1.1" is already in existing_spec_numbers, so the first run should reject. Changing the spec to "3.1" should create.

Code Runner Challenge

Popcorn Hack 2 - Backend Create Rule

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 2 - Backend Create Rule
part = {
    "product_name": "Replacement Flywheels and Clutch Assemblies",
    "category": "Auto Racing",
    "spec_number": "1.1",
    "effective_date": "Nov. 9, 2001"
}
valid_categories = ["Auto Racing", "Drag Racing"]
existing_spec_numbers = ["1.1", "2.1"]

for spec in ["1.1", "3.1"]:   # rejected case, then valid case
    part["spec_number"] = spec

    all_fields_valid = (part["product_name"] != ""
                        and part["category"] in valid_categories
                        and part["spec_number"] != ""
                        and part["effective_date"] != "")
    duplicate_spec = part["spec_number"] in existing_spec_numbers
    should_create = all_fields_valid and not duplicate_spec

    print("Spec", spec, "-> fields valid:", all_fields_valid, "| duplicate:", duplicate_spec, "| create:", should_create)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: spec 1.1 → fields valid True, duplicate True, create False. Spec 3.1 → fields valid True, duplicate False, create True. The only thing that changed is the duplicate check, and not flips it into the create decision.

Popcorn Hack 3: SFI Search Filter

A record matches when (query is in the product name OR query equals the spec number) AND the category is accepted. The parentheses matter: without them, and binds tighter than or, so a spec match would skip the category check.

Prediction: query "1.2" matches only the Multiple Disc Clutch record (spec 1.2, Drag Racing). Query "flywheel" matches both flywheel records (product names), and both are accepted categories.

Code Runner Challenge

Popcorn Hack 3 - SFI Search Filter

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 3 - SFI Search Filter
records = [
    {"product_name": "Replacement Flywheels and Clutch Assemblies", "category": "Auto Racing", "spec_number": "1.1"},
    {"product_name": "Multiple Disc Clutch Assemblies", "category": "Drag Racing", "spec_number": "1.2"},
    {"product_name": "Racing Flywheel Record", "category": "Auto Racing", "spec_number": "2.1"}
]
valid_categories = ["Auto Racing", "Drag Racing"]

for query in ["1.2", "flywheel", "9.9"]:
    print("Query:", query)
    found = False
    for record in records:
        name_match = query.lower() in record["product_name"].lower()
        spec_match = query == record["spec_number"]
        accepted = record["category"] in valid_categories
        if (name_match or spec_match) and accepted:
            print("  Match:", record["spec_number"], "-", record["product_name"])
            found = True
    if not found:
        print("  No matching records")
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: 1.2 → only spec 1.2. flywheel → specs 1.1 and 2.1. 9.9 → no matching records. The search is case-insensitive on the name (.lower() on both sides) and exact on the spec number.

MCQ

**MCQ 3.05: 4/4 answers: A,C,A,B**
  1. 7 >= 7 evaluates to: A True · B False · C 7 · D An error. A, >= includes equality.
  2. Valid only with a name AND a spec number. Which operator? A or · B not · C and · D !=. C, both must be true.
  3. duplicate_spec is False. What is not duplicate_spec? A True · B False · C None · D A string. A, not reverses it.
  4. Which accepts either Auto Racing or Drag Racing? A ... and ... · B category == 'Auto Racing' or category == 'Drag Racing' · C not category · D category != 'Auto Racing'. B, only one comparison needs to be true. (A can never be true, since one category can’t equal both.)

Homework Hack: SFI Backend Validator

validate_record builds one named Boolean per rule, then combines them with and / not. It returns the decision plus the reasons, so every rejection says why. It’s self-contained, so it runs without the cells above.

Rule Boolean
non-empty product name has_product_name = record["product_name"].strip() != ""
accepted category valid_category = record["category"] in valid_categories
non-empty spec number has_spec_number = record["spec_number"].strip() != ""
effective date present has_effective_date = record["effective_date"].strip() != ""
spec not already stored duplicate_spec = record["spec_number"] in existing_spec_numbers
accept has_product_name and valid_category and has_spec_number and has_effective_date and not duplicate_spec

Prediction: record 1 → ACCEPT. Record 2 → REJECT (Street Car is not an accepted category). Record 3 → REJECT (spec 1.1 already exists). Extra record 4 → REJECT (empty product name). Extra record 5 → REJECT (missing effective date).

Code Runner Challenge

Homework Hack - SFI Backend Validator

View IPYNB Source
# CODE_RUNNER: Homework Hack - SFI Backend Validator
existing_spec_numbers = ["1.1", "2.1"]
valid_categories = ["Auto Racing", "Drag Racing"]

test_records = [
    {"product_name": "Multiple Disc Clutch Assemblies", "category": "Auto Racing", "spec_number": "1.2", "effective_date": "Feb. 9, 2006"},
    {"product_name": "Replacement Flywheels", "category": "Street Car", "spec_number": "3.1", "effective_date": "Jan. 1, 2026"},
    {"product_name": "Existing Flywheel Record", "category": "Drag Racing", "spec_number": "1.1", "effective_date": "Jan. 1, 2026"},
    # extra edge cases
    {"product_name": "   ", "category": "Drag Racing", "spec_number": "4.1", "effective_date": "Mar. 3, 2026"},
    {"product_name": "Harmonic Balancer", "category": "Auto Racing", "spec_number": "18.1", "effective_date": ""}
]

def validate_record(record):
    has_product_name = record["product_name"].strip() != ""
    valid_category = record["category"] in valid_categories
    has_spec_number = record["spec_number"].strip() != ""
    has_effective_date = record["effective_date"].strip() != ""
    duplicate_spec = record["spec_number"] in existing_spec_numbers

    is_valid = has_product_name and valid_category and has_spec_number and has_effective_date and not duplicate_spec

    reasons = []
    if not has_product_name:
        reasons.append("missing product name")
    if not valid_category:
        reasons.append("category '" + record["category"] + "' not accepted")
    if not has_spec_number:
        reasons.append("missing spec number")
    if not has_effective_date:
        reasons.append("missing effective date")
    if duplicate_spec:
        reasons.append("spec " + record["spec_number"] + " already exists")
    return is_valid, reasons

accepted = 0
for record in test_records:
    is_valid, reasons = validate_record(record)
    label = record["product_name"].strip() or "(no name)"
    if is_valid:
        accepted += 1
        print("ACCEPT:", label, "(spec " + record["spec_number"] + ")")
    else:
        print("REJECT:", label, "->", ", ".join(reasons))

print("Accepted", accepted, "of", len(test_records), "records")
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Actual output: ACCEPT for Multiple Disc Clutch Assemblies (spec 1.2). REJECT for Replacement Flywheels (category ‘Street Car’ not accepted), Existing Flywheel Record (spec 1.1 already exists), the blank-name record (missing product name), and Harmonic Balancer (missing effective date). 1 of 5 accepted. Matches the prediction.

Test Case Expected Actual
1 valid ACCEPT ACCEPT
2 invalid category REJECT REJECT, category
3 duplicate spec REJECT REJECT, duplicate
4 name is only spaces (edge) REJECT REJECT, name
5 empty date (edge) REJECT REJECT, date

Why the logic is right: every requirement has to pass, so the rules are joined with and. A single False rejects the record. The duplicate rule is phrased as “does NOT already exist”, so it’s not duplicate_spec. Using .strip() before comparing to "" means a name made of spaces counts as empty (test 4). Without it, " " != "" is True and that record would have been accepted.

Pseudocode check (test 3): duplicateSpec ← (specNumber = "1.1") OR (specNumber = "2.1") is true, so NOT duplicateSpec is false. The whole AND chain is then false and the pseudocode displays REJECT RECORD, the same decision as the Python validator.