# HG changeset patch # User Matti Hamalainen # Date 1642888702 -7200 # Node ID d3135eff1bab7652cf7cc7fb6ccf5f8ad502b811 # Parent 4bf07e58baa84ca5abbc8b2ac2a7e67e482b9772 Cleanup. diff -r 4bf07e58baa8 -r d3135eff1bab multimerge.py --- a/multimerge.py Tue Oct 06 09:04:19 2020 +0300 +++ b/multimerge.py Sat Jan 22 23:58:22 2022 +0200 @@ -70,7 +70,7 @@ ## Fatal error handler def gcm_fatal(smsg): - gcm_print(u"ERROR: "+ smsg) + gcm_print("ERROR: "+ smsg) if cfg.email_ok and cfg.email != "off": ## If e-mail is not "off", send e-mail msg = MIMEText(("\n".join(gcm_msgbuf)).encode("UTF-8"), "plain") @@ -100,7 +100,7 @@ p = Popen([cfg.email_sendmail, "-t", "-oi"], stdin=PIPE) p.communicate(msg.as_string()) except Exception as e: - gcm_print(u"FATAL: Oh noes, e-mail sending failed: {0}".format(str(e))) + gcm_print("FATAL: Oh noes, e-mail sending failed: {0}".format(str(e))) sys.exit(1) @@ -110,14 +110,14 @@ def gcm_debug(level, smsg): if gcm_check_debug(level): - gcm_print(u"DBG: {0}".format(smsg)) + gcm_print("DBG: {0}".format(smsg)) else: - gcm_msgbuf.append(u"DBG: {0}".format(smsg)) + gcm_msgbuf.append("DBG: {0}".format(smsg)) ## Handler for SIGINT signals def gcm_signal_handler(signal, frame): - gcm_print(u"\nQuitting due to SIGINT / Ctrl+C!") + gcm_print("\nQuitting due to SIGINT / Ctrl+C!") sys.exit(0) @@ -126,19 +126,19 @@ try: store = oauth2client.file.Storage(credential_file) except Exception as e: - gcm_fatal(u"Failed to read credential file:\n{0}\n\nERROR: {1}\n".format(credential_file, str(e))) + gcm_fatal("Failed to read credential file:\n{0}\n\nERROR: {1}\n".format(credential_file, str(e))) credentials = store.get() if not credentials or credentials.invalid: try: flow = client.flow_from_clientsecrets(secret_file, mcfg.scope) except Exception as e: - gcm_fatal(u"Failed to fetch client secret:\n{0}\n\nERROR: {1}\n".format(secret_file, str(e))) + gcm_fatal("Failed to fetch client secret:\n{0}\n\nERROR: {1}\n".format(secret_file, str(e))) flow.user_agent = mcfg.app_name credentials = tools.run_flow(flow, store, mcfg) if not credentials or credentials.invalid: - gcm_fatal(u"Failed to authenticate / invalid credentials.") + gcm_fatal("Failed to authenticate / invalid credentials.") return credentials @@ -150,7 +150,7 @@ ev_end = event["end"].get("dateTime", event["end"].get("date")) if "end" in event else "?" summary = event["summary"] if "summary" in event else "?" status = "*" if event["status"] != u"cancelled" else "!" - gcm_print(u"[{0}] {1:25} - {2:25} : {3} [{4}] [{5}]".format(status, ev_start, ev_end, summary, event["iCalUID"], event["id"])) + gcm_print("[{0}] {1:25} - {2:25} : {3} [{4}] [{5}]".format(status, ev_start, ev_end, summary, event["iCalUID"], event["id"])) ## Generate gcm IDs for given list of events @@ -194,7 +194,7 @@ pageToken=ev_token, ).execute() except Exception as e: - gcm_fatal(u"Failed to fetch calendar events for {0}:\n\nERROR: {1}\n".format(calendarId, str(e))) + gcm_fatal("Failed to fetch calendar events for {0}:\n\nERROR: {1}\n".format(calendarId, str(e))) events.extend(result.get("items", [])) ev_token = result.get("nextPageToken") @@ -221,13 +221,13 @@ self.g = int(src[3:5], 16) self.b = int(src[6:7], 16) else: - gcm_fatal(u"Expected hex-triplet string for GCMColor() initializer: {0}".format(src)) + gcm_fatal("Expected hex-triplet string for GCMColor() initializer: {0}".format(src)) elif isinstance(src, GCMColor): self.r = src.r self.g = src.g self.b = src.b else: - gcm_fatal(u"Invalid initializer for GCMColor() object.") + gcm_fatal("Invalid initializer for GCMColor() object.") def to_hexrgb(): return "{0:02X}{1:02X}{2:02X}".format(self.r, self.g, self.b) @@ -282,12 +282,12 @@ if name in self.m_data: return self.m_data[name] else: - gcm_fatal(u"GCMSettings.__getattr__(): No such attribute '"+ name +"'.") + gcm_fatal("GCMSettings.__getattr__(): No such attribute '"+ name +"'.") def mvalidate(self, name, value): if name in self.m_validate and self.m_validate[name]: if not self.m_validate[name](value): - gcm_fatal(u"GCMSettings.mvalidate(): Invalid value for attribute '{0}': {1}".format(name, value)) + gcm_fatal("GCMSettings.mvalidate(): Invalid value for attribute '{0}': {1}".format(name, value)) def mtranslate(self, name, value): if name in self.m_translate and self.m_translate[name]: @@ -307,7 +307,7 @@ if name in self.m_data: self.m_data[name] = self.mtranslate(name, value) else: - gcm_fatal(u"GCMSettings.mset(): No such attribute '"+ name +"'.") + gcm_fatal("GCMSettings.mset(): No such attribute '"+ name +"'.") def mget(self, name): if name in self.m_data: @@ -320,7 +320,7 @@ if cfg_parser.has_option(sect, name): value = cfg_parser.get(sect, name) self.mset(name, value) - gcm_debug(4, u"{0} -> '{1}' == {2}".format(name, value, self.mget(name))) + gcm_debug(4, "{0} -> '{1}' == {2}".format(name, value, self.mget(name))) def is_str(self, mvalue): return isinstance(mvalue, str) @@ -341,7 +341,7 @@ if not self.is_str(mvalue): return False else: - return mvalue.lower() in [u"off", u"sendmail", u"smtp"] + return mvalue.lower() in [u"off", "sendmail", "smtp"] def trans_email_state(self, mvalue): return mvalue.lower() @@ -365,7 +365,7 @@ def is_bool(self, mvalue): mval = self.trans_bool(mvalue) if not isinstance(mval, bool): - gcm_fatal(u"GCMSettings.is_bool(): Invalid boolean value '{0}', should be true|false|1|0|on|off|yes|no.".format(mvalue)) + gcm_fatal("GCMSettings.is_bool(): Invalid boolean value '{0}', should be true|false|1|0|on|off|yes|no.".format(mvalue)) else: return True @@ -374,9 +374,9 @@ if self.is_str(mvalue): mvalue = re.split("\s*,\s*", mvalue, flags=re.IGNORECASE) if not isinstance(mvalue, list): - gcm_fatal(u"GCMSettings.trans_list(): Could not parse list '{0}'.".format(mvalue)) + gcm_fatal("GCMSettings.trans_list(): Could not parse list '{0}'.".format(mvalue)) elif not isinstance(mvalue, list): - gcm_fatal(u"GCMSettings.trans_list(): Invalid value '{0}'.".format(mvalue)) + gcm_fatal("GCMSettings.trans_list(): Invalid value '{0}'.".format(mvalue)) return mvalue def is_list(self, mvalue): @@ -399,7 +399,7 @@ if mvalue != None: for email in mvalue: if not self.is_email(email): - gcm_fatal(u"Invalid e-mail address '{0}' in list {1}.".format(email, ", ".join(mvalue))) + gcm_fatal("Invalid e-mail address '{0}' in list {1}.".format(email, ", ".join(mvalue))) return True @@ -419,11 +419,11 @@ cfg.mdef("debug", True, cfg.is_bool, cfg.trans_bool, False) cfg.mdef("email_ok", False, None, None, False) -cfg.mdef("email", True, cfg.is_email_state, cfg.trans_email_state, u"off") +cfg.mdef("email", True, cfg.is_email_state, cfg.trans_email_state, "off") cfg.mdef("email_to", True, cfg.is_email_list, cfg.trans_email_list, None) cfg.mdef("email_sender", True, cfg.is_email, None, None) -cfg.mdef("email_subject", True, cfg.is_string, None, u"Google Calendar MultiMerge status") +cfg.mdef("email_subject", True, cfg.is_string, None, "Google Calendar MultiMerge status") cfg.mdef("email_sendmail", True, cfg.is_string, None, "/usr/sbin/sendmail") cfg.mdef("email_smtp_tls", True, cfg.is_bool, cfg.trans_bool, False) @@ -431,7 +431,7 @@ cfg.mdef("email_smtp_user", True, cfg.is_string, None, None) cfg.mdef("email_smtp_password", True, cfg.is_string, None, None) -cfg.mdef("src_regex", True, cfg.is_string, None, u"^R:\s*(.*?)\s*\(\s*(.+?)\s*\)\s*$") +cfg.mdef("src_regex", True, cfg.is_string, None, "^R:\s*(.*?)\s*\(\s*(.+?)\s*\)\s*$") cfg.mdef("src_regmap", False, cfg.is_list, cfg.trans_list, [1, 2]) cfg.mdef("src_regmap_len", False, None, None, len(cfg.src_regmap)) @@ -454,20 +454,20 @@ ## Check if we have arguments if len(sys.argv) <= 1: - gcm_fatal(u"No configuration file specified.\nUsage: {0} ".format(sys.argv[0])) + gcm_fatal("No configuration file specified.\nUsage: {0} ".format(sys.argv[0])) ## Read, parse and validate configuration file -gcm_debug(3, u"Reading configuration from '{0}'.".format(sys.argv[1])) +gcm_debug(3, "Reading configuration from '{0}'.".format(sys.argv[1])) try: cfg_parser = ConfigParser.RawConfigParser() cfg_parser.readfp(codecs.open(sys.argv[1], "r", "UTF-8")) except Exception as e: - gcm_fatal(u"Failed to read configuration file '{0}': {1}".format(sys.argv[1], str(e))) + gcm_fatal("Failed to read configuration file '{0}': {1}".format(sys.argv[1], str(e))) # Check that the required section exists if not cfg_parser.has_section(cfg_section): - gcm_fatal(u"Invalid configuration, missing '{0}' section.".format(cfg_section)) + gcm_fatal("Invalid configuration, missing '{0}' section.".format(cfg_section)) # Debug setting is a special case, we need to get it # set before everything else, so do it here .. @@ -481,27 +481,27 @@ ## Validate settings if cfg.email != "off": if cfg.email_subject == None or len(cfg.email_subject) == 0: - gcm_fatal(u"E-mail enabled but email_subject not set.") + gcm_fatal("E-mail enabled but email_subject not set.") elif cfg.email_sender == None: - gcm_fatal(u"E-mail enabled but email_sender not set.") + gcm_fatal("E-mail enabled but email_sender not set.") elif cfg.email_to == None: - gcm_fatal(u"E-mail enabled but email_to not set.") + gcm_fatal("E-mail enabled but email_to not set.") else: cfg.mset("email_ok", True) if len(cfg.src_regmap) != cfg.src_regmap_len: - gcm_fatal(u"Setting src_regmap list must be {0} items.".format(cfg.src_regmap_len)) + gcm_fatal("Setting src_regmap list must be {0} items.".format(cfg.src_regmap_len)) else: # Force convert values to integers try: cfg.src_regmap = [int(x) for x in cfg.src_regmap] except Exception as e: - gcm_fatal(u"Invalid src_regmap: {0}".format(str(e))) + gcm_fatal("Invalid src_regmap: {0}".format(str(e))) if not cfg.dst_regex and not cfg.dst_id: - gcm_fatal(u"Target calendar ID or name required, but not set.") + gcm_fatal("Target calendar ID or name required, but not set.") ## Initialize and authorize API connection @@ -511,7 +511,7 @@ ## Fetch complete calendar list -gcm_debug(3, u"Fetching available calendars ..") +gcm_debug(3, "Fetching available calendars ..") calendars = [] cal_token = None while True: @@ -523,7 +523,7 @@ pageToken=cal_token ).execute() except Exception as e: - gcm_fatal(u"Failed to fetch calendar list:\n\nERROR: {0}\n".format(str(e))) + gcm_fatal("Failed to fetch calendar list:\n\nERROR: {0}\n".format(str(e))) calendars.extend(result.get("items", [])) cal_token = result.get("nextPageToken") @@ -531,9 +531,9 @@ break if len(calendars) == 0: - gcm_fatal(u"No calendars found?") + gcm_fatal("No calendars found?") -gcm_debug(3, u"{0} calendars total found.".format(len(calendars))) +gcm_debug(3, "{0} calendars total found.".format(len(calendars))) ## Filter desired SOURCE calendars based on specified regexp @@ -561,38 +561,38 @@ calendar["gcm_id"] = mre.group(cfg.src_regmap[1]) src_calendars.append(calendar) -gcm_debug(3, u"{0} source calendars found.".format(len(src_calendars))) +gcm_debug(3, "{0} source calendars found.".format(len(src_calendars))) ## Check if we have destination calendar ID if not dst_calendar: - gcm_fatal(u"Could not find target/destination calendar ID for '"+ cfg.dst_name +"'.") + gcm_fatal("Could not find target/destination calendar ID for '"+ cfg.dst_name +"'.") else: - gcm_debug(3, u"Target calendar '{0}' [ ID: {1} ]".format(dst_calendar["summary"], dst_calendar["id"])) + gcm_debug(3, "Target calendar '{0}' [ ID: {1} ]".format(dst_calendar["summary"], dst_calendar["id"])) ## Fetch calendar colors data try: colors = service.colors().get().execute() except Exception as e: - gcm_fatal(u"Failed to fetch calendar color settings:\n\n{0}".format(str(e))) + gcm_fatal("Failed to fetch calendar color settings:\n\n{0}".format(str(e))) ## Now, fetch and collect events from source calendars -gcm_debug(3, u"Fetching calendar events .. ") +gcm_debug(3, "Fetching calendar events .. ") src_events = [] for calendar in src_calendars: - gcm_debug(4, u"- {0} ({1})".format(calendar["id"], calendar["summary"])) + gcm_debug(4, "- {0} ({1})".format(calendar["id"], calendar["summary"])) # Find matching color from the source calendar for the event, if one has been set c_found = None if "colorId" in calendar and calendar["colorId"] in colors["calendar"]: - gcm_debug(4, u" Calendar color: {0}".format(colors["calendar"][calendar["colorId"]])) + gcm_debug(4, " Calendar color: {0}".format(colors["calendar"][calendar["colorId"]])) c_found = gcm_find_nearest_color(colors["event"], colors["calendar"][calendar["colorId"]], 100) if c_found: - gcm_debug(4, u" Found nearest event color ID: {0}, {1}".format(c_found, colors["event"][c_found])) + gcm_debug(4, " Found nearest event color ID: {0}, {1}".format(c_found, colors["event"][c_found])) else: - gcm_debug(4, u" No matching event color found!") + gcm_debug(4, " No matching event color found!") # Fetch and add events, if any, to main source events list events = gcm_generate_ids(gcm_fetch_events(calendar["id"], False), calendar["id"], "___", "id") @@ -614,13 +614,13 @@ ## Fetch current events from the target -gcm_debug(3, u"Fetching current target calendar events.") +gcm_debug(3, "Fetching current target calendar events.") dst_events = gcm_generate_ids(gcm_fetch_events(cfg.dst_id, True), "", "", "iCalUID") -gcm_debug(3, u"Found {0} event(s).".format(len(dst_events))) +gcm_debug(3, "Found {0} event(s).".format(len(dst_events))) ## Start populating/updating events .. -gcm_debug(3, u"Re-merging events to target calendar ..") +gcm_debug(3, "Re-merging events to target calendar ..") dst_ids = frozenset([x["gcm_id"] for x in dst_events]) src_ids = frozenset([x["gcm_id"] for x in src_events]) @@ -630,11 +630,11 @@ # Does the event exist already in the target? if event["gcm_id"] in dst_ids: # Check if event NEEDS updating .. aka compare data - gcm_debug(4, u"Event {0} [{1}] exists, checking ..".format(event["id"], event["gcm_id"])) + gcm_debug(4, "Event {0} [{1}] exists, checking ..".format(event["id"], event["gcm_id"])) d_event = gcm_get_event_by_gcm_id(dst_events, event["gcm_id"]) if not gcm_compare_events(event, d_event): # Seems we need to update - gcm_debug(4, u"Updating event {0} [{1}]".format(event["id"], event["gcm_id"])) + gcm_debug(4, "Updating event {0} [{1}]".format(event["id"], event["gcm_id"])) try: # We need to remove the sequence and id fields, as they will be replaced by target event.pop("sequence", None) @@ -643,13 +643,13 @@ new_event = service.events().update(calendarId=cfg.dst_id, eventId=d_event["id"], body=event).execute() evn_updated += 1 except Exception as e: - gcm_fatal(u"Failed to update event {0} [{1}]:\n\n{2}\n\nERROR: {3}\n".format(event["id"], event["gcm_id"], event, str(e))) + gcm_fatal("Failed to update event {0} [{1}]:\n\n{2}\n\nERROR: {3}\n".format(event["id"], event["gcm_id"], event, str(e))) else: evn_unchanged += 1 - gcm_debug(4, u"No need to update event {0} [{1}]".format(event["id"], event["gcm_id"])) - elif event["status"] not in [u"cancelled", u"confirmed"]: + gcm_debug(4, "No need to update event {0} [{1}]".format(event["id"], event["gcm_id"])) + elif event["status"] not in [u"cancelled", "confirmed"]: # Event does not seem to exist. Insert new event. - gcm_debug(4, u"Inserting new event {0} [{1}]".format(event["id"], event["gcm_id"])) + gcm_debug(4, "Inserting new event {0} [{1}]".format(event["id"], event["gcm_id"])) # Remove original id field, otherwise it will clash event.pop("id", None) event["iCalUID"] = event["gcm_id"] # Replace Google generated ID with our own @@ -657,23 +657,23 @@ new_event = service.events().insert(calendarId=cfg.dst_id, body=event).execute() evn_new += 1 except Exception as e: - gcm_fatal(u"Failed to insert new event:\n\n{0}\n\nERROR: {1}\n".format(event, str(e))) + gcm_fatal("Failed to insert new event:\n\n{0}\n\nERROR: {1}\n".format(event, str(e))) gcm_debug(3, "{0} new events, {1} updated, {2} unchanged.".format(evn_new, evn_updated, evn_unchanged)) ## Remove "stale" events -gcm_debug(3, u"Purging stale events ..") +gcm_debug(3, "Purging stale events ..") evn_purged = 0 for event in dst_events: - gcm_debug(4, u"Checking event {0}".format(event["gcm_id"])) + gcm_debug(4, "Checking event {0}".format(event["gcm_id"])) if not event["gcm_id"] in src_ids and event["status"] != u"cancelled": - gcm_debug(4, u"Deleting event {0} [{1}]".format(event["id"], event["gcm_id"])) + gcm_debug(4, "Deleting event {0} [{1}]".format(event["id"], event["gcm_id"])) evn_purged += 1 try: service.events().delete(calendarId=cfg.dst_id, eventId=event["id"]).execute() except Exception as e: - gcm_fatal(u"Failed to delete stale event:\n{0}\n\nERROR: {1}\n".format(event, str(e))) + gcm_fatal("Failed to delete stale event:\n{0}\n\nERROR: {1}\n".format(event, str(e))) gcm_debug(3, "{0} events purged.".format(evn_purged)) @@ -683,16 +683,16 @@ ## t_time = time.localtime() t_str = time.strftime("%d.%m.%Y %H:%M", t_time) -gcm_debug(3, u"Updating target calendar name timestamp {0}".format(t_str)) +gcm_debug(3, "Updating target calendar name timestamp {0}".format(t_str)) try: dst_calendar["summary"] = cfg.dst_name.format(t_str) new_calendar = service.calendars().update(calendarId=cfg.dst_id, body=dst_calendar).execute() except Exception as e: - gcm_fatal(u"Failed to update target calendar:\n{0}\n\nERROR: {1}\n".format(dst_calendar, str(e))) + gcm_fatal("Failed to update target calendar:\n{0}\n\nERROR: {1}\n".format(dst_calendar, str(e))) gcm_bench_end = time.time() gcm_bench_elapsed = gcm_bench_end - gcm_bench_start -gcm_debug(3, u"Finished. {0} seconds elapsed.".format(gcm_bench_elapsed)) +gcm_debug(3, "Finished. {0} seconds elapsed.".format(gcm_bench_elapsed))