You've got format_campaign working — campaign name in, formatted label out. But what does HubSpot actually hand you when you export campaigns?
A mess. I ran an export this morning and got things like " email blast ", "PAID_SEARCH", "Brand Awareness Q2 " — different casing, stray spaces, underscores where there should be spaces. I'd usually fix it in Excel with TRIM and LOWER.
Python has all three of those as one-liners. .strip() is TRIM — kills leading and trailing whitespace. .lower() is LOWER. And .replace("_", " ") swaps underscores for spaces. Chain them and a raw export string becomes something format_campaign can actually use:
raw = " PAID_SEARCH "
clean = raw.strip().lower().replace("_", " ")
print(clean) # paid searchWait — I'm reading this right to left. Does Python run .strip() first, then .lower(), then .replace()? Because if .replace() fires on the original casing it might miss things.
Left to right, one at a time. Each method returns a new string, and the next method runs on that result — the same way Excel nests TRIM(LOWER(SUBSTITUTE(A2, "_", " "))), except you read it in the order things actually happen. So the full cleaning function looks like this:
def clean_campaign_name(raw: str) -> str:
clean = raw.strip().lower().replace("_", " ")
label = format_campaign(clean, 0.0)
print(f"Cleaned: {clean} | Preview: {label}")
return cleanIt calls format_campaign inside — so I can immediately see how the cleaned name will look in an actual standup label. That's what "composes" means. I've been writing functions that don't talk to each other this whole time.
They've been talking — you just gave them something worth saying. format_campaign was always waiting for clean input.
Three weeks of TRIM and LOWER in Excel. Eight characters of Python. I'm going to need a moment.
Take it — but file this away: .strip() only removes whitespace at the edges, not in the middle. "Brand Awareness" stays "Brand Awareness". And strings in Python are immutable — every method returns a new string, it never edits in place. If you forget to assign the result, the original is unchanged and you'll wonder why nothing worked.
Python strings expose a clean toolkit for normalising messy exports:
| Method | What it does | Excel equivalent |
|---|---|---|
.strip() | Removes leading/trailing whitespace | TRIM() |
.lower() | Lowercases every character | LOWER() |
.replace(old, new) | Swaps every occurrence of old for new | SUBSTITUTE() |
.split(sep) | Splits into a list on a delimiter | TEXTSPLIT() |
Method chaining applies each operation left to right. Each call returns a new string — Python strings are immutable.
Forget to assign the result and the original string is unchanged:
raw = " EMAIL BLAST "
raw.strip() # returns ' EMAIL BLAST' — but raw is unchanged
clean = raw.strip() # correctYou've got format_campaign working — campaign name in, formatted label out. But what does HubSpot actually hand you when you export campaigns?
A mess. I ran an export this morning and got things like " email blast ", "PAID_SEARCH", "Brand Awareness Q2 " — different casing, stray spaces, underscores where there should be spaces. I'd usually fix it in Excel with TRIM and LOWER.
Python has all three of those as one-liners. .strip() is TRIM — kills leading and trailing whitespace. .lower() is LOWER. And .replace("_", " ") swaps underscores for spaces. Chain them and a raw export string becomes something format_campaign can actually use:
raw = " PAID_SEARCH "
clean = raw.strip().lower().replace("_", " ")
print(clean) # paid searchWait — I'm reading this right to left. Does Python run .strip() first, then .lower(), then .replace()? Because if .replace() fires on the original casing it might miss things.
Left to right, one at a time. Each method returns a new string, and the next method runs on that result — the same way Excel nests TRIM(LOWER(SUBSTITUTE(A2, "_", " "))), except you read it in the order things actually happen. So the full cleaning function looks like this:
def clean_campaign_name(raw: str) -> str:
clean = raw.strip().lower().replace("_", " ")
label = format_campaign(clean, 0.0)
print(f"Cleaned: {clean} | Preview: {label}")
return cleanIt calls format_campaign inside — so I can immediately see how the cleaned name will look in an actual standup label. That's what "composes" means. I've been writing functions that don't talk to each other this whole time.
They've been talking — you just gave them something worth saying. format_campaign was always waiting for clean input.
Three weeks of TRIM and LOWER in Excel. Eight characters of Python. I'm going to need a moment.
Take it — but file this away: .strip() only removes whitespace at the edges, not in the middle. "Brand Awareness" stays "Brand Awareness". And strings in Python are immutable — every method returns a new string, it never edits in place. If you forget to assign the result, the original is unchanged and you'll wonder why nothing worked.
Python strings expose a clean toolkit for normalising messy exports:
| Method | What it does | Excel equivalent |
|---|---|---|
.strip() | Removes leading/trailing whitespace | TRIM() |
.lower() | Lowercases every character | LOWER() |
.replace(old, new) | Swaps every occurrence of old for new | SUBSTITUTE() |
.split(sep) | Splits into a list on a delimiter | TEXTSPLIT() |
Method chaining applies each operation left to right. Each call returns a new string — Python strings are immutable.
Forget to assign the result and the original string is unchanged:
raw = " EMAIL BLAST "
raw.strip() # returns ' EMAIL BLAST' — but raw is unchanged
clean = raw.strip() # correctDev exports campaign names from HubSpot and gets inconsistent strings like `" email blast "`, `"PAID_SEARCH"`, and `"Brand Awareness Q2 "` — casing varies, whitespace leaks in, and underscores appear where spaces belong. Write `clean_campaign_name(raw)` that strips whitespace, lowercases, and replaces underscores with spaces so the result is ready to pass into `format_campaign`.
Tap each step for scaffolded hints.
No blank-editor panic.