Dedupe edits to a single instance of a recurring event - #565
Conversation
|
Thank you for the contribution, very much appreciated. Iit may take me a little time to review as i'm about to do some work travel -- but in the mean time: Would you be able to add test coverage for the cases covered beyond the snapshot updates? You could also add tests for the uncovered cases you plan to fix in the future. In particular, i've known the specific issues here in the past, but do not currently remember them, so I think it would be very helpful to spell out in great detail all the corner cases, otherwise it'll probably take longer to review to know the impact of this change. Thank you agian. |
|
Maybe said another way: Editing recurring events does NOT duplicate them in all scenarios -- just some particular scenario being hit here. Understanding the difference would be helpful. There should be many existing examples in the tests of editing recurring events that do not duplicate the events, so showing why the behavior works there but fails here would be helpful. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #565 +/- ##
==========================================
+ Coverage 97.15% 97.16% +0.01%
==========================================
Files 53 53
Lines 3234 3248 +14
==========================================
+ Hits 3142 3156 +14
Misses 92 92 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
allenporter
left a comment
There was a problem hiding this comment.
I worry this has performance problems. Can you have a test that reproduces the issue you are trying to fix so we can understand if there are other approaches? e.g. if the original event information is wrong, we fix it there. I'm still not sure i exactly understand the gap here in the current event editing code.
| ] | ||
| ) | ||
| else: | ||
| # Recurring item - filter out dates that have been overridden |
There was a problem hiding this comment.
Won't this iterate over the entire series inline? that seems like a problem.
|
Converting to draft, you can mark as ready for review when ready. |
allenporter
left a comment
There was a problem hiding this comment.
Let me clarify for the test: I'd like you to reproduce the issue using the Store APIs that support editing. There are existing tests of editing events and returning the results without dupicating things unnecessarily and they should be putting events in the corret state. So i'm wondering: is this not handling events edited by other systems? is there a difference between how the store edit is applied (it's incorrect?) vs other calendars?
|
Thank you, this context is very helpful. In that case, using the .ics itself is fine. For all I know what they are doing is the "propper" fix and the approach this library takes is a hack :) Is the .ics used in the test / example the same one produced in the screen shots or similar? I think trying to group by |
|
Are you seeing this with remote calendar integration? I wonder if we should only enable this behavior in Edit: On second thought, i can imagine this also happening with uploaded files of remote calendar, which i don't think enables compat mode yet. |
|
This screenshot is from the remote calendar integration. The ICS file I included is curl'd from the URL Google gave me to paste into HA. I went through a few iterations with AI on how to do this, trying to see if there was a way to have this library work with only recurrence-id, but most of them were kind of far reaching and didn't look like a good fit. IMO this PR is the best one, but in case the serialized data is important to you, I made #572. It uses something similar to the initial method, but makes a set for fast lookup. |
I think everyone is just hacking. In Apple Calendar it was surprisingly easy to get phantom events, I saw some surprises from Google too. Neither app will make edits to "this and future events" the way it's specified in the spec, they truncate the original event and make a new one. |
| # Group by UID | ||
| by_uid: dict[str, list[Event | Todo | Journal]] = {} | ||
| for item in items: | ||
| if item.uid: |
There was a problem hiding this comment.
Is it (a) correct and (b) faster for this to only look at values with either rrule or recurrence-id?
| by_uid.setdefault(item.uid, []).append(item) | ||
|
|
||
| for uid_items in by_uid.values(): | ||
| # Find the parent recurring event (has rrule, no recurrence_id) |
There was a problem hiding this comment.
What do you do if there are two with rrule? doe that happen? (e.g. with multiple edits or multiple edits where one has "THISANDFUTURE"?)
I worry there are a lot more corner cases that need to be considered.
There was a problem hiding this comment.
Do you have test data with this situation where we could delete the EXDATE? It's going to be very hard for me to recreate this, the tools I use to make calendars make a new event when you check the "this and future events" checkbox.
There was a problem hiding this comment.
The best I can think of is the home assistant local calendar can do THISANDFUTURE edits -- but you'll probably get ics that will work here since this library created it...
There was a problem hiding this comment.
I’m not saying this couldn’t be a corner case, but you’d need a this and future without an exdate. Is that allowed?
There was a problem hiding this comment.
(looking into this now, will be a follow up)
| ) -> None: | ||
| """Reconcile recurrence overrides for a list of components.""" | ||
| # Group by UID | ||
| by_uid: dict[str, list[Event | Todo | Journal]] = {} |
There was a problem hiding this comment.
I think this can be done with itertools.groupby(items, key=lambda x: x.uid)
There was a problem hiding this comment.
itertools.groupby requires pre-sorted input, so it wouldn't work directly here. It looks like filtering the data and using items_by_uuid will work.
| if ( | ||
| isinstance(exdate, datetime.datetime) | ||
| and isinstance(parent.dtstart, datetime.datetime) | ||
| and parent.dtstart.tzinfo |
There was a problem hiding this comment.
it needs to have a timezone? utc values won't work?
There was a problem hiding this comment.
You can edit a recurrence to be in a different time zone than the original. This captures that edge case.
|
|
||
| # Feb 2 - edited instance with RECURRENCE-ID | ||
| assert events[1].summary == "Edited Title" | ||
| assert events[1].recurrence_id == "20260202T100000" |
There was a problem hiding this comment.
My impression is our recur adapter always adds a recurrence_id. Is there something unique about this check or should all of the emitted instances from the timeline have it?
There was a problem hiding this comment.
This checks to ensure that it shows the correct recurrence_id and that it's not a duped event.
|
In case you've just finished the super bowl and sitting down to read PR reviews, this PR is almost definitely better suited to handle the THISANDFUTURE case. The tests pass, so everything generated from this library is working, but it's not likely that we'd be able to get THISANDFUTURE from less functional calendar libraries working in the other PR. I'm going to take a shot at making that work here. |
|
I gave the AI the whole spec, it chugged through a few dollars worth of tokens and said we shouldn't do anything for THISANDFUTURE. So I dug in and ended up agreeing. All the cases this library currently works for will continue to work, and the changes today do reduce the scope of the change. Same for #572. I tried THISANDFUTURE in the big calendar apps, and came away surprised at how bad they are. I understand your passion for calendar libraries.
If we were to make test data for this it would be complex to create, and entirely hypothetical. We can't generate failing data from an existing product like we can for the single event bug. It's outside of the scope of this PR, but it might be worth testing to see if Thunderbird and MS display THISANDFUTURE updates correctly. I have no strong opinion on which PR is better, but my entire family begs you accept one of these, or add the test data to #513 and accept it if the test passes. note: I didn't include broken data from Apple in the test data. Google displays the broken calendars correctly. I don't know if this library will |
|
I believe #572 has obsoleted this, and this can now be closed, but let me know if that is not the case. |



This PR dedupes edited recurring events. Right now if a recurring event is edited, the original shows alongside the edited version, making a duplicate entry. An example of this is even in the existing snapshot data.
This PR does not fully fix #278, but it will fix the issue almost all the time, as many calendar clients delete the old event and create a new one when "this and all recurring events" is chosen instead of "just this event".
This scratches my personal itch.
I have another PR coming that will properly handle recurring events, it will include this PR, but is a much larger change.
In this PR:
There should be no breaking changes.