From d8c67a867c64fd32feef7e77d770c763b66d27f9 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 10 Jul 2024 23:01:00 +0200 Subject: [PATCH 1/8] Add Excel folder to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2935f83..88513ef 100644 --- a/.gitignore +++ b/.gitignore @@ -168,6 +168,7 @@ cython_debug/ # Project specific exports/* config.py +Excel/* From f7fb4aa01ff22597bacbe11ef94bc57bed28af35 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 30 Sep 2024 23:38:23 +0200 Subject: [PATCH 2/8] Handle filenames better and don't exit if a member does not exist --- attendance.py | 54 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/attendance.py b/attendance.py index c24427f..c6033d7 100644 --- a/attendance.py +++ b/attendance.py @@ -2,6 +2,7 @@ import asyncio import csv import os +import re from datetime import date from config import password, username @@ -38,8 +39,11 @@ async def main(): os.makedirs("./exports") for e in events: + filename = f"{e['startTimestamp']}-{e['heading']}.csv" + filename = str(filename).strip().replace(" ", "_") + filename = re.sub(r"(?u)[^-\w.]", "", filename) filename = os.path.join( - "./exports", f"{e['startTimestamp']}-{e['heading']}.csv" + "./exports", filename ) with open(filename, "w", newline="") as csvfile: spamwriter = csv.writer( @@ -50,8 +54,12 @@ async def main(): ["Start", "End", "Description", "Name", "Answer", "Organizer"] ) for o in e["owners"]: - person = await s.get_person(o["id"]) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(o["id"]) + except KeyError: + full_name = o["id"] + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], @@ -64,8 +72,12 @@ async def main(): ) if args.a is True: for r in e["responses"]["acceptedIds"]: - person = await s.get_person(r) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(r) + except KeyError: + full_name = r + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], @@ -76,8 +88,12 @@ async def main(): ] ) for r in e["responses"]["declinedIds"]: - person = await s.get_person(r) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(r) + except KeyError: + full_name = r + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], @@ -88,8 +104,12 @@ async def main(): ] ) for r in e["responses"]["unansweredIds"]: - person = await s.get_person(r) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(r) + except KeyError: + full_name = r + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], @@ -100,8 +120,12 @@ async def main(): ] ) for r in e["responses"]["unconfirmedIds"]: - person = await s.get_person(r) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(r) + except KeyError: + full_name = r + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], @@ -112,8 +136,12 @@ async def main(): ] ) for r in e["responses"]["waitinglistIds"]: - person = await s.get_person(r) - full_name = person["firstName"] + " " + person["lastName"] + try: + person = await s.get_person(r) + except KeyError: + full_name = r + else: + full_name = person["firstName"] + " " + person["lastName"] spamwriter.writerow( [ e["startTimestamp"], From 42e86959a7188a64bcf50291e6297951727a4b75 Mon Sep 17 00:00:00 2001 From: Elliot <3186037+elliot-100@users.noreply.github.com> Date: Wed, 2 Oct 2024 11:27:17 +0100 Subject: [PATCH 3/8] Revert "Add Excel folder to .gitignore" This reverts commit d8c67a867c64fd32feef7e77d770c763b66d27f9. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 88513ef..2935f83 100644 --- a/.gitignore +++ b/.gitignore @@ -168,7 +168,6 @@ cython_debug/ # Project specific exports/* config.py -Excel/* From 68c7820cf9d018d2664436c071e5a9d02f06868d Mon Sep 17 00:00:00 2001 From: elliot-100 <3186037+elliot-100@users.noreply.github.com> Date: Sun, 20 Oct 2024 12:06:58 +0100 Subject: [PATCH 4/8] Format with black --- attendance.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/attendance.py b/attendance.py index 7a62f51..e606aea 100644 --- a/attendance.py +++ b/attendance.py @@ -55,7 +55,7 @@ async def main(): ) for o in e["owners"]: try: - person = await s.get_person(o["id"]) + person = await s.get_person(o["id"]) except KeyError: full_name = o["id"] else: @@ -73,7 +73,7 @@ async def main(): if args.a is True: for r in e["responses"]["acceptedIds"]: try: - person = await s.get_person(r) + person = await s.get_person(r) except KeyError: full_name = r else: @@ -89,7 +89,7 @@ async def main(): ) for r in e["responses"]["declinedIds"]: try: - person = await s.get_person(r) + person = await s.get_person(r) except KeyError: full_name = r else: @@ -105,7 +105,7 @@ async def main(): ) for r in e["responses"]["unansweredIds"]: try: - person = await s.get_person(r) + person = await s.get_person(r) except KeyError: full_name = r else: @@ -121,7 +121,7 @@ async def main(): ) for r in e["responses"]["unconfirmedIds"]: try: - person = await s.get_person(r) + person = await s.get_person(r) except KeyError: full_name = r else: @@ -137,7 +137,7 @@ async def main(): ) for r in e["responses"]["waitinglistIds"]: try: - person = await s.get_person(r) + person = await s.get_person(r) except KeyError: full_name = r else: From 8984e6974c4449b21569927761dba7edde47dac4 Mon Sep 17 00:00:00 2001 From: elliot-100 <3186037+elliot-100@users.noreply.github.com> Date: Sun, 20 Oct 2024 12:32:21 +0100 Subject: [PATCH 5/8] Refactor: extract `_sanitise_chars()` --- attendance.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/attendance.py b/attendance.py index e606aea..d77982b 100644 --- a/attendance.py +++ b/attendance.py @@ -39,12 +39,8 @@ async def main(): os.makedirs("./exports") for e in events: - filename = f"{e['startTimestamp']}-{e['heading']}.csv" - filename = str(filename).strip().replace(" ", "_") - filename = re.sub(r"(?u)[^-\w.]", "", filename) - filename = os.path.join( - "./exports", filename - ) + base_filename = _sanitise_chars(f"{e['startTimestamp']}-{e['heading']}") + filename = os.path.join("./exports", base_filename + ".csv") with open(filename, "w", newline="") as csvfile: spamwriter = csv.writer( csvfile, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL @@ -155,6 +151,11 @@ async def main(): await s.clientsession.close() +def _sanitise_chars(input_str: str) -> str: + output_str = str(input_str).strip().replace(" ", "_") + return re.sub(r"(?u)[^-\w.]", "", output_str) + + loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asyncio.run(main()) From 5221e0ed7e0aad47bdd0f696def1920ed36d7f39 Mon Sep 17 00:00:00 2001 From: elliot-100 <3186037+elliot-100@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:57:21 +0100 Subject: [PATCH 6/8] Revert "Refactor: extract `_sanitise_chars()`" This reverts commit 8984e6974c4449b21569927761dba7edde47dac4. --- attendance.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/attendance.py b/attendance.py index d77982b..e606aea 100644 --- a/attendance.py +++ b/attendance.py @@ -39,8 +39,12 @@ async def main(): os.makedirs("./exports") for e in events: - base_filename = _sanitise_chars(f"{e['startTimestamp']}-{e['heading']}") - filename = os.path.join("./exports", base_filename + ".csv") + filename = f"{e['startTimestamp']}-{e['heading']}.csv" + filename = str(filename).strip().replace(" ", "_") + filename = re.sub(r"(?u)[^-\w.]", "", filename) + filename = os.path.join( + "./exports", filename + ) with open(filename, "w", newline="") as csvfile: spamwriter = csv.writer( csvfile, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL @@ -151,11 +155,6 @@ async def main(): await s.clientsession.close() -def _sanitise_chars(input_str: str) -> str: - output_str = str(input_str).strip().replace(" ", "_") - return re.sub(r"(?u)[^-\w.]", "", output_str) - - loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asyncio.run(main()) From 4edc7710ad0386099d5f525039aa328285859669 Mon Sep 17 00:00:00 2001 From: elliot-100 <3186037+elliot-100@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:59:52 +0100 Subject: [PATCH 7/8] Refactor: extract `_sanitise_filename()` --- attendance.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/attendance.py b/attendance.py index e606aea..8b8b13d 100644 --- a/attendance.py +++ b/attendance.py @@ -39,12 +39,8 @@ async def main(): os.makedirs("./exports") for e in events: - filename = f"{e['startTimestamp']}-{e['heading']}.csv" - filename = str(filename).strip().replace(" ", "_") - filename = re.sub(r"(?u)[^-\w.]", "", filename) - filename = os.path.join( - "./exports", filename - ) + base_filename = _sanitise_filename(f"{e['startTimestamp']}-{e['heading']}") + filename = os.path.join("./exports", base_filename + ".csv") with open(filename, "w", newline="") as csvfile: spamwriter = csv.writer( csvfile, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL @@ -155,6 +151,13 @@ async def main(): await s.clientsession.close() +def _sanitise_filename(input_str: str) -> str: + """Strip leading/trailing whitespace, spaces to underscores, remove chars not + alphanumeric/underscore/hyphen.""" + output_str = str(input_str).strip().replace(" ", "_") + return re.sub(r"(?u)[^-\w.]", "", output_str) + + loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) asyncio.run(main()) From 20ae96c7d6d25f22d9f8bc485d2ab5490ea4623c Mon Sep 17 00:00:00 2001 From: elliot-100 <3186037+elliot-100@users.noreply.github.com> Date: Sun, 20 Oct 2024 14:08:04 +0100 Subject: [PATCH 8/8] Refactor: extract duplicated code --- attendance.py | 69 ++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/attendance.py b/attendance.py index 8b8b13d..6ae451b 100644 --- a/attendance.py +++ b/attendance.py @@ -32,8 +32,8 @@ async def main(): - s = spond.Spond(username=username, password=password) - events = await s.get_events(min_start=args.f, max_start=args.t) + session = spond.Spond(username=username, password=password) + events = await session.get_events(min_start=args.f, max_start=args.t) if not os.path.exists("./exports"): os.makedirs("./exports") @@ -50,105 +50,84 @@ async def main(): ["Start", "End", "Description", "Name", "Answer", "Organizer"] ) for o in e["owners"]: - try: - person = await s.get_person(o["id"]) - except KeyError: - full_name = o["id"] - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, o["id"]) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, o["response"], "X", ] ) if args.a is True: for r in e["responses"]["acceptedIds"]: - try: - person = await s.get_person(r) - except KeyError: - full_name = r - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, r) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, "accepted", ] ) for r in e["responses"]["declinedIds"]: - try: - person = await s.get_person(r) - except KeyError: - full_name = r - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, r) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, "declined", ] ) for r in e["responses"]["unansweredIds"]: - try: - person = await s.get_person(r) - except KeyError: - full_name = r - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, r) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, "unanswered", ] ) for r in e["responses"]["unconfirmedIds"]: - try: - person = await s.get_person(r) - except KeyError: - full_name = r - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, r) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, "unconfirmed", ] ) for r in e["responses"]["waitinglistIds"]: - try: - person = await s.get_person(r) - except KeyError: - full_name = r - else: - full_name = person["firstName"] + " " + person["lastName"] + name = await _derive_member_name(session, r) spamwriter.writerow( [ e["startTimestamp"], e["endTimestamp"], e["heading"], - full_name, + name, "waitinglist", ] ) - await s.clientsession.close() + await session.clientsession.close() + + +async def _derive_member_name(spond_session, member_id: str) -> str: + """Return full name, or id if member can't be matched.""" + try: + person = await spond_session.get_person(member_id) + except KeyError: + return member_id + return f"{person['firstName']} {person['lastName']}" def _sanitise_filename(input_str: str) -> str: