Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 40 additions & 53 deletions _data/events.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1953,9 +1953,9 @@
path: https://www.meetup.com/women-coding-community/events/313256761/
title: View meetup event
target: _target

- title: |
Java bootcamp - Session 5
uid: "event_313256771@meetup.com"
description: |
Do you want to build strong Java skills but don't know where to start? Do you feel overwhelmed juggling tutorials, documentation, and scattered resources while trying to learn Java on your own? Our Java Bootcamp is designed to give you a clear, structured path to build practical Java skills through hands-on coding, not endless theory.
category_style: tech-talk
Expand All @@ -1974,45 +1974,48 @@
target: _target

- title: |
Java bootcamp - Session 6
Java Bootcamp: Vibe Coding with AI Agents & MCP
uid: "event_313257077@meetup.com"
description: |
Do you want to build strong Java skills but don't know where to start? Do you feel overwhelmed juggling tutorials, documentation, and scattered resources while trying to learn Java on your own? Our Java Bootcamp is designed to give you a clear, structured path to build practical Java skills through hands-on coding, not endless theory.
Ready to build a Java project even if you've never written a line of Java before? This special edition of our Java Bootcamp series brings together everything we've been building with you, and takes it one step further.
category_style: tech-talk
category_name: Tech Talk
date: THU, MAR 12, 2026
expiration: "20260312"
host: "Zaynah Ahmed"
speaker: "Adriana Zencke Zimmermann, Sonali Goel"
time: 07:00 PM GMT
host: ""
speaker: ""
time: 06:30 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/2/4/4/9/600_532629289.jpeg"
path: "https://secure.meetupstatic.com/photos/event/5/4/a/2/600_532941666.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313257077/
title: View meetup event
target: _target

- title: |
March Book Club: TBD
Java Bootcamp: The Grand Finale Hack Hour
uid: "event_313574241@meetup.com"
description: |
Women Coding Community Book Club! March 2026 Book: TBD If you would like to have a say in our next book club read, do join our channel progbookclub.
category_style: book-club
category_name: Book Club
date: MON, MAR 30, 2026
expiration: "20260330"
host: "Silke Nodwell and Prabha Venkatesh"
The Women Coding Community (WCC) is wrapping up our Java Fullstack Bootcamp with a high-energy, hands-on Hack Hour session.
category_style: tech-talk
category_name: Tech Talk
date: FRI, MAR 13, 2026
expiration: "20260313"
host: ""
speaker: ""
time: 07:00 PM BST
time: 06:00 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/a/6/e/d/600_521202733.jpeg"
path: "https://secure.meetupstatic.com/photos/event/9/4/0/7/600_532957895.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313316083/
path: https://www.meetup.com/women-coding-community/events/313574241/
title: View meetup event
target: _target

- title: |
Own your voice: Assertive Communication for Women in Tech
uid: "event_313463081@meetup.com"
description: "We\u2019re thrilled to re-launch the Women Coding Community Career Club! We are kicking off with a powerful session led by Yasuko Ohtake, a leading technologist who will share candid insights from her career and practical strategies for visibility and influence in tech.\n"
category_style: tech-talk
category_name: Tech Talk
Expand All @@ -2029,27 +2032,9 @@
title: View meetup event
target: _target

- title: |
March Book Club: AI Engineering pt.2 and Showcase
description: |
Women Coding Community Book Club! March 2026 Book: AI Engineering by Chip Huyen (continued) With a small showcase of AI engineering projects by WCC members If you would like to have a say in our next book club read, do join our channel progbookclub.
category_style: book-club
category_name: Book Club
date: MON, MAR 30, 2026
expiration: "20260330"
host: "Silke Nodwell, Prabha Venkatesh"
speaker: ""
time: 07:00 PM BST
image:
path: "https://secure.meetupstatic.com/photos/event/7/0/d/7/600_532888887.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313316083/
title: View meetup event
target: _target

- title: |
2026 International Women's Day Celebration - Feast, Talks & Tech Community
uid: "event_313538360@meetup.com"
description: |
In partnership with Nando's Women in Engineering Celebrate IWD with the best women in tech and incredible food! This International Women's Day, a number of London's most powerful women-in-tech communities are coming together for an unforgettable evening of inspiring talks, a delicious feast, a candid panel discussion, and genuine connection.
category_style: tech-talk
Expand All @@ -2068,39 +2053,41 @@
target: _target

- title: |
Java Bootcamp: Vibe Coding with AI Agents & MCP
March Book Club: AI Engineering pt.2 and Showcase
uid: "event_313316083@meetup.com"
description: |
Ready to build a Java project even if you've never written a line of Java before? This special edition of our Java Bootcamp series brings together everything we've been building with you, and takes it one step further.
category_style: tech-talk
category_name: Tech Talk
date: THU, MAR 12, 2026
expiration: "20260312"
host: ""
Women Coding Community Book Club! March 2026 Book: AI Engineering by Chip Huyen (continued) With a small showcase of AI engineering projects by WCC members If you would like to have a say in our next book club read, do join our channel progbookclub.
category_style: book-club
category_name: Book Club
date: MON, MAR 30, 2026
expiration: "20260330"
host: "Silke Nodwell, Prabha Venkatesh"
speaker: ""
time: 06:30 PM GMT
time: 07:00 PM BST
image:
path: "https://secure.meetupstatic.com/photos/event/5/4/a/2/600_532941666.jpeg"
path: "https://secure.meetupstatic.com/photos/event/7/0/d/7/600_532888887.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313257077/
path: https://www.meetup.com/women-coding-community/events/313316083/
title: View meetup event
target: _target

- title: |
Java Bootcamp: The Grand Finale Hack Hour
From Idea to Impact: Building Products That Actually Matter
uid: "event_313608754@meetup.com"
description: |
The Women Coding Community (WCC) is wrapping up our Java Fullstack Bootcamp with a high-energy, hands-on Hack Hour session.
From Idea to Impact: Building Products That Actually Matter How to define real user problems, prioritize effectively, and lead cross-functional teams to deliver meaningful results.
category_style: tech-talk
category_name: Tech Talk
date: FRI, MAR 13, 2026
expiration: "20260313"
date: WED, APR 01, 2026
expiration: "20260401"
host: ""
speaker: ""
time: 06:00 PM GMT
time: 07:00 PM BST
image:
path: "https://secure.meetupstatic.com/photos/event/9/4/0/7/600_532957895.jpeg"
path: "https://secure.meetupstatic.com/photos/event/7/4/3/1/600_533009745.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313574241/
path: https://www.meetup.com/women-coding-community/events/313608754/
title: View meetup event
target: _target
31 changes: 21 additions & 10 deletions tools/meetup_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class WebLink(BaseModel):

class MeetupEvents(BaseModel):
title: str
uid: str
description: str
category_style: Optional[str] = "tech-talk"
category_name: Optional[str] = "Tech Talk"
Expand Down Expand Up @@ -191,6 +192,7 @@ def get_upcoming_meetups_from_ical_file(ical_path: str) -> list[MeetupEvents]:
date = date_obj.strftime("%a, %b %d, %Y").upper()
time = event.begin.datetime.strftime("%I:%M %p %Z")
url = event.url or ""
uid = event.uid

full_description = (event.description or "").strip()

Expand Down Expand Up @@ -230,6 +232,7 @@ def get_upcoming_meetups_from_ical_file(ical_path: str) -> list[MeetupEvents]:
speaker=speaker,
image=Image(path=image_url, alt="WCC Meetup event image"),
link=WebLink(path=url),
uid=uid,
)
)
return upcoming_meetups
Expand All @@ -241,21 +244,14 @@ def process_meetup_data(meetup: dict) -> dict:
meetup["expiration"] = QuotedString(meetup["expiration"])
meetup["host"] = QuotedString(meetup.get("host", ""))
meetup["speaker"] = QuotedString(meetup.get("speaker", ""))
meetup["uid"] = to_quoted_str(meetup.get("uid", ""))
if "image" in meetup:
meetup["image"]["path"] = to_quoted_str(meetup["image"]["path"])
meetup["image"]["alt"] = to_quoted_str(meetup["image"]["alt"])
if "link" in meetup and "title" in meetup["link"]:
meetup["link"]["title"] = to_quoted_str(meetup["link"]["title"])
return meetup

# --- Create a unique key for an event using "title - date" ----
def get_event_key(event):
return f"{event.get('title').strip()} - {event.get('date')}"

# --- Get a Set of keys for existing events ----
def get_existing_event_keys(events):
return {get_event_key(e) for e in events}

# --- Get existing events in yml file ----
def load_existing_events_from_file(file_path):
try:
Expand All @@ -278,6 +274,21 @@ def append_events_to_yaml_file(file_path, data):
logging.error(f"Error appending new events to file '{file_path}': {e}")
raise

def get_event_key(event: dict) -> str:
return event.get("uid", "")

def get_existing_event_keys(existing_events: list[dict]) -> set:
return {get_event_key(event) for event in existing_events}

def get_added_events(upcoming_events: list[dict], existing_events: list[dict]) -> list[dict]:
existing_keys = get_existing_event_keys(existing_events)
added_events = []
for event in upcoming_events:
event_key = get_event_key(event)
if event_key not in existing_keys:
added_events.append(event)
return added_events

# --- Script Start ---
def fetch_events():
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
Expand All @@ -289,15 +300,15 @@ def fetch_events():
upcoming_events = get_upcoming_meetups_from_ical_file(ical_file_path)

existing_events = load_existing_events_from_file(yml_file_path)
existing_keys = get_existing_event_keys(existing_events)
existing_keys = {event.get("uid") for event in existing_events}
added_events = []

logging.info("Upcoming Meetup Events:")
for event in upcoming_events:

logging.info(f"{event.title}")
formatted_event = process_meetup_data(event.model_dump())
event_key = get_event_key(formatted_event)
event_key = formatted_event["uid"]

if event_key not in existing_keys:
added_events.append(formatted_event)
Expand Down
42 changes: 33 additions & 9 deletions tools/tests/meetup_import_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
get_event_image_url,
to_literal_str,
to_quoted_str,
get_event_key,
get_existing_event_keys,
get_added_events,
LiteralString,
QuotedString,
NoQuoteString,
get_event_key,
get_existing_event_keys,
load_existing_events_from_file,
process_meetup_data
)
Expand Down Expand Up @@ -88,14 +89,37 @@ def test_to_literal_and_quoted_str():
assert isinstance(to_quoted_str('Hello!'), QuotedString)
assert isinstance(to_quoted_str('Simple'), NoQuoteString)

def test_get_event_key():
event = {'title': ' Talk ', 'date': 'JAN 1, 2025'}
assert get_event_key(event) == 'Talk - JAN 1, 2025'
def test_no_new_events_are_added_if_all_events_exist():
existing_events = [{'title': 'Talk', 'date': 'JAN 1, 2025', 'uid': 'talk-jan-1-2025'}]
existing_keys = get_existing_event_keys(existing_events)
new_event = {'title': 'Talk (date updated)', 'date': 'JAN 2, 2025', 'uid': 'talk-jan-1-2025'}
new_key = get_event_key(new_event)
assert new_key in existing_keys

def test_get_added_events_only_new():
existing = [{'uid': 'event-1', 'title': 'Talk'}]
upcoming = [
{'uid': 'event-1', 'title': 'Talk'},
{'uid': 'event-2', 'title': 'Workshop'},
{'uid': 'event-3', 'title': 'Panel'}
]
added = get_added_events(upcoming, existing)
assert len(added) == 2
assert added[0]['uid'] == 'event-2'
assert added[1]['uid'] == 'event-3'

def test_get_added_events_with_empty_existing():
existing = []
upcoming = [{'uid': 'event-1', 'title': 'Talk'}]
added = get_added_events(upcoming, existing)
assert len(added) == 1
assert added[0]['uid'] == 'event-1'

def test_get_existing_event_keys():
events = [{'title': 'A', 'date': '1'}, {'title': 'B', 'date': '2'}]
keys = get_existing_event_keys(events)
assert len(keys) == 2 and all(isinstance(k, str) for k in keys)
def test_get_added_events_with_empty_upcoming():
existing = [{'uid': 'event-1', 'title': 'Talk'}]
upcoming = []
added = get_added_events(upcoming, existing)
assert len(added) == 0

def test_load_existing_events_from_file(tmp_path):
events = [{'title': 'E1', 'date': 'D1'}]
Expand Down