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
86 changes: 43 additions & 43 deletions _data/events.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2104,7 +2104,7 @@
- title: |
Java Bootcamp: The Grand Finale Hack Hour
description: |
The Women Coding Community (WCC) is wrapping up our Java Bootcamp with a high-energy, hands-on Hack Hour session.
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
uid: "event_313574241@meetup.com"
category_name: Tech Talk
Expand All @@ -2121,6 +2121,26 @@
title: View meetup event
target: _target

- title: |
Vibe Coding in London: Java, AI Agents & MCP Hands-On
description: |
The Women Coding Community (WCC) is celebrating International Women's Week with a high-energy, hands-on Vibe Coding in London.
category_style: tech-talk
uid: "event_313681243@meetup.com"
category_name: Tech Talk
date: FRI, MAR 13, 2026
expiration: "20260313"
host: ""
speaker: ""
time: 06:00 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/7/d/6/c/600_533072108.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313681243/
title: View meetup event
target: _target

- title: |
Own your voice: Assertive Communication for Women in Tech
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"
Expand Down Expand Up @@ -2160,8 +2180,27 @@
title: View meetup event
target: _target

- title: Design Patterns Course
description: |
Join Women Coding Community for our next session on design patterns! Design Patterns Course In this series of events, we will explore popular design patterns and their implementations in Python and Java, using "Head First Design Patterns" as our reference book.
category_style: tech-talk
uid: "event_313672586@meetup.com"
category_name: Tech Talk
date: TUE, MAR 24, 2026
expiration: "20260324"
host: "Irina Kamalova"
speaker: ""
time: 07:00 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/5/d/b/1/600_533063985.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313672586/
title: View meetup event
target: _target

- title: |
March Book Club: AI Engineering pt 2 and Showcase
March Book Club: AI Engineering part 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
Expand All @@ -2181,9 +2220,9 @@
target: _target

- title: |
From Idea to Execution: The Clarity of Building With Purpose
From Idea to Impact: Building Products That Actually Matter
description: |
From Idea to Execution How to define real user problems, prioritize effectively, and lead cross-functional teams to deliver meaningful results.
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
uid: "event_313608754@meetup.com"
category_name: Tech Talk
Expand All @@ -2199,42 +2238,3 @@
path: https://www.meetup.com/women-coding-community/events/313608754/
title: View meetup event
target: _target

- title: |
Vibe Coding in London: Java, AI Agents & MCP Hands-On
description: |
The Women Coding Community (WCC) is celebrating International Women's Week with a high-energy, hands-on Vibe Coding in London.
category_style: tech-talk
uid: "event_313681243@meetup.com"
category_name: Tech Talk
date: FRI, MAR 13, 2026
expiration: "20260313"
host: ""
speaker: ""
time: 06:00 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/7/d/6/c/600_533072108.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313681243/
title: View meetup event
target: _target

- title: Design Patterns Course
description: |
Join Women Coding Community for our next session on design patterns! Design Patterns Course In this series of events, we will explore popular design patterns and their implementations in Python and Java, using "Head First Design Patterns" as our reference book.
category_style: tech-talk
uid: "event_313672586@meetup.com"
category_name: Tech Talk
date: TUE, MAR 24, 2026
expiration: "20260324"
host: "Irina Kamalova"
speaker: ""
time: 07:00 PM GMT
image:
path: "https://secure.meetupstatic.com/photos/event/5/d/b/1/600_533063985.jpeg"
alt: WCC Meetup event image
link:
path: https://www.meetup.com/women-coding-community/events/313672586/
title: View meetup event
target: _target
36 changes: 23 additions & 13 deletions tools/meetup_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class MeetupEvent(BaseModel):
uid: str
category_name: Optional[str] = "Tech Talk"
date: str
expiration: Optional[str] = ""
expiration: str = ""
host: Optional[str] = ""
speaker: Optional[str] = ""
time: Optional[str] = ""
Expand Down Expand Up @@ -180,12 +180,9 @@ def get_upcoming_meetups_from_ical_file(ical_path: str) -> list[MeetupEvent]:
with open(ical_path, "r", encoding="utf-8") as f:
calendar = Calendar(f.read())

# sort events to ensure order by event date
sorted_events = sorted(calendar.events, key=lambda e: e.begin)

upcoming_meetups: list[MeetupEvent] = []

for event in sorted_events:
for event in calendar.events:
title = event.name
date_obj = event.begin.datetime
expiration = date_obj.strftime("%Y%m%d")
Expand Down Expand Up @@ -297,18 +294,31 @@ def get_event_key(event: Union[MeetupEvent, dict]) -> str:
return event.uid

def add_upcoming_events_to_existing_events(upcoming_events: list[MeetupEvent], existing_events: list[dict]) -> list[dict]:
"""Merges upcoming events with existing events, removes duplicates based on UID, and sorts by expiration date (upcoming events first)."""
from datetime import datetime

# Merge all events by UID (upcoming overwrites existing)
all_events_dict = {get_event_key(event): event for event in existing_events}
added_event_count = 0
logging.info("Upcoming Meetup Events:")
for future_event in upcoming_events:
event_key = get_event_key(future_event)
all_events_dict[event_key] = future_event.model_dump()
if event_key in all_events_dict:
logging.info(f"{event_key} already exists in events.yml")
else:
added_event_count += 1
logging.info(f"Added {added_event_count} new event(s) to events.yml.")
return list(all_events_dict.values())

all_events = list(all_events_dict.values())

# Split into past and future events based on expiration - note that some existing_events might be in the future
today = datetime.now().strftime("%Y%m%d")
def is_future(event):
exp = event.get("expiration", "") if isinstance(event, dict) else getattr(event, "expiration", "")
return exp >= today

past_events = [e for e in all_events if not is_future(e)]
future_events = [e for e in all_events if is_future(e)]

# Sort only the future events by expiration - past events will already be sorted by date
future_events_sorted = sorted(future_events, key=lambda e: e.get("expiration", "") if isinstance(e, dict) else getattr(e, "expiration", ""))

# Concatenate past (already sorted) + sorted future
return past_events + future_events_sorted

def write_all_events_to_yaml_file(file_path, all_events: list[dict]):
try:
Expand Down
17 changes: 14 additions & 3 deletions tools/tests/meetup_import_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ def test_add_upcoming_events_to_existing_events_removes_duplicates_even_with_cha

def test_get_added_events_with_empty_existing():
existing = []
upcoming = [MeetupEvent(title='Talk', date='JAN 1, 2025', uid='event-1', description='')]
upcoming = [MeetupEvent(title='Talk', date='JAN 1, 2025', expiration='20250101', uid='event-1', description='')]
all_events = add_upcoming_events_to_existing_events(upcoming, existing)
assert len(all_events) == 1
assert all_events[0]['uid'] == 'event-1'

def test_get_added_events_with_empty_upcoming():
existing = [{'title': 'Talk', 'date': 'JAN 1, 2025', 'uid': 'event-1', 'description': ''}]
existing = [{'title': 'Talk', 'date': 'JAN 1, 2025', 'expiration': '20250101', 'uid': 'event-1', 'description': ''}]
upcoming = []
all_events = add_upcoming_events_to_existing_events(upcoming, existing)
assert len(all_events) == 1
Expand Down Expand Up @@ -167,4 +167,15 @@ def test_process_meetup_data_fields():
assert isinstance(result['title'], (LiteralString, str))
assert isinstance(result['expiration'], QuotedString)
assert isinstance(result['image']['path'], (QuotedString, NoQuoteString))
assert isinstance(result['link']['title'], (QuotedString, NoQuoteString))
assert isinstance(result['link']['title'], (QuotedString, NoQuoteString))

def test_events_are_sorted_by_date_after_adding_upcoming():
existing = [
{'title': 'Event A', 'date': 'APR 1, 2026', 'expiration': '20260401', 'uid': 'event-a', 'description': ''},
]
upcoming = [
MeetupEvent(title='Event B', date='MAR 13, 2025', expiration='20250313', uid='event-b', description='')
]
all_events = add_upcoming_events_to_existing_events(upcoming, existing)
assert len(all_events) == 2
assert all_events[0]['uid'] == 'event-b' # Event B is earlier than Event A