diff --git a/_data/events.yml b/_data/events.yml index 2c35ca9..bb70fd9 100644 --- a/_data/events.yml +++ b/_data/events.yml @@ -2108,7 +2108,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 @@ -2129,6 +2129,26 @@ - https://docs.google.com/presentation/d/1GzJ5OlceIw-fZt6ptiQQY1OgiXxJWv_LKSTZKgBE3uQ/edit?slide=id.p1#slide=id.p1 youtube: https://www.youtube.com/watch?v=x7Fz8BvZb_Q +- 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" @@ -2168,66 +2188,6 @@ 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 - uid: "event_313316083@meetup.com" - 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: | - From Idea to Execution: The Clarity of Building With Purpose - description: | - From Idea to Execution 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 - date: WED, APR 01, 2026 - expiration: "20260401" - host: "" - speaker: "Ezinne Jennifer Aruma" - time: 07:00 PM BST - image: - path: "https://secure.meetupstatic.com/photos/event/7/d/6/d/600_533072109.jpeg" - alt: WCC Meetup event image - link: - 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. @@ -2240,47 +2200,49 @@ speaker: "" time: 07:00 PM GMT image: - path: "https://secure.meetupstatic.com/photos/event/8/c/5/3/600_533195923.jpeg" + 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: Design Patterns Course +- title: | + March Book Club: AI Engineering part 2 and Showcase 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_313778435@meetup.com" - category_name: Tech Talk - date: TUE, MAR 31, 2026 - expiration: "20260331" - host: "Irina Kamalova" + 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 + uid: "event_313316083@meetup.com" + 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/8/c/a/b/600_533196011.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/313778435/ + path: https://www.meetup.com/women-coding-community/events/313316083/ title: View meetup event target: _target -- title: "Capacity Planning \u2013 The Math in System Design" +- title: | + From Idea to Impact: Building Products That Actually Matter description: | - Do you want to design systems that handle real-world loads without breaking a sweat? Do you feel unsure about how mathematical principles can guide your architectural decisions? This event is designed to demystify the critical role of capacity planning in system design through real conversations with speakers who have lived experience and professional expertise. + 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_313858697@meetup.com" + uid: "event_313608754@meetup.com" category_name: Tech Talk - date: SAT, APR 18, 2026 - expiration: "20260418" - host: "Silke Nodwell" - speaker: "Amita Singh" + date: WED, APR 01, 2026 + expiration: "20260401" + host: "" + speaker: "Ezinne Jennifer Aruma" time: 07:00 PM BST image: - path: "https://secure.meetupstatic.com/photos/event/6/8/5/8/600_533426712.jpeg" + path: "https://secure.meetupstatic.com/photos/event/7/d/6/d/600_533072109.jpeg" alt: WCC Meetup event image link: - path: https://www.meetup.com/women-coding-community/events/313858697/ + path: https://www.meetup.com/women-coding-community/events/313608754/ title: View meetup event target: _target diff --git a/tools/meetup_import.py b/tools/meetup_import.py index 89fcb48..fe5412c 100644 --- a/tools/meetup_import.py +++ b/tools/meetup_import.py @@ -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] = "" @@ -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") @@ -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: diff --git a/tools/tests/meetup_import_test.py b/tools/tests/meetup_import_test.py index 509f20a..77349fb 100644 --- a/tools/tests/meetup_import_test.py +++ b/tools/tests/meetup_import_test.py @@ -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 @@ -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)) \ No newline at end of file + 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 \ No newline at end of file