V3.2 release candidate#668
Merged
Merged
Conversation
Code quality pass per #634: * Remove unused imports (copy, lxml.etree, caldav.compatibility_hints, CalendarSet, cdav/dav, Optional, timezone, Event/Todo TYPE_CHECKING stubs, bare `import niquests` availability check) * Replace bare `except:` with specific types (KeyError, AttributeError, Exception) across lib/error, lib/debug, lib/vcal, elements/cdav, calendarobjectresource, collection, compatibility_hints, davobject * Remove unused local variables (old_id, status, i, path, rv, feat_type, sup, feature_info, rc) across library modules * Use `# noqa: F401` for vobject availability checks in calendarobjectresource AI-generated commit, this is tedious work, well-suited for AI-assistance Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This is mostly AI-generated, unfortunately the prompts are missing. The compatibility hints file is not (yet) considered an important part of the library. Reorganizations are considered to be tedious work, well suited for AI generation with human oversight. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Nextcloud 33 introduced (or changed) soft-delete behaviour: when a calendar is deleted via CalDAV, both the calendar and its objects are soft-deleted to a trashbin. When tests delete and re-create a calendar with the same slug, Nextcloud reuses the same calendarid, and the soft-deleted objects (with their UIDs) remain in oc_calendarobjects. Trying to add a new event with the same UID then fails with "UNIQUE constraint failed: calendarid, calendartype, uid". Fix: set calendarRetentionObligation=0 in setup_nextcloud.sh. When this config value is the string '0', CalDavBackend::deleteCalendar and deleteCalendarObject skip the trashbin entirely and hard-delete immediately (see apps/dav/lib/CalDAV/CalDavBackend.php lines 940-941, 1572). Also run dav:retention:clean-up at startup to purge any leftover soft-deleted entries from prior runs. Also update the nextcloud compatibility hints to reflect the changed behaviour of scheduling.mailbox.inbox-delivery in Nextcloud 33: the server now delivers the iTIP notification to the inbox AND auto-schedules into the attendee's calendar (quirk), whereas previously it only delivered to the inbox (full). Prompt: `pytest -k nextcloud --last-failed` gives lots of failures. It seems to be something wrong with the nextcloud container. Looks a bit like the problems are due to the setup (user provisioning) is not being compatible with the latest version of the image. Please investigate. This commit was AI-generated, according to the AI-POLICY it's acceptable to use AI on the test server framework. Without AI help, we would still only have radicale, xandios and personal testing accounts available for integration tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Earlier work on scheduling testing stalled a bit due to lack of proper testing accounts. Docker test servers (Baikal, Nextcloud, Cyrus, SOGo, DAViCal, Davis, CCS, Zimbra, Stalwart) now all pre-create multiple users for scheduling tests. This commit adds a testing framework for multi-account testing plus various tests. Prompt: The sync integration tests in tests/caldav_test.py has a _TestSchedulingBase class, for tests that requires several users - `save_with_invites` is tested there. The class has a TODO-comment, "Stalled a bit due to lack of proper testing accounts" is for sure not true, I believe the whole comment is obsoleted, please verify. The async tests should be made as symmetric and similar to the sync tests as possible. There is a todo-comment there that FreeBusy isn't tested (FreeBusy as defined in RFC663), please make tests for it, both for sync and freesync. (some followup-prompts appears to be missing here) Test code is AI-generated, tests are among the things identified as particularly suitable for AI-assisted codeing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prompt: The previous commit adds a _async_schedule_inbox to collection.py, this method is only used from the test. Why is this? Shouldn't it be possible to get the inbox through the public API while doing async operations? Prompt: pytest -k 'not compat' --last-failed -k 'test_invite_and_respond' breaks now This was predominantly written by Claude. Trivial refactoring and bugfixing. More work on async is done in a later commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This is a combination of various work done on the compatibility hints. The compatibility hints are still a bit "work in progress", so it's considered OK to do breaking changes here even on minor-versions. It's used mostly in the test code, but also internally in the library to work around various compatibility problems. The aim of the work is to get rid of all the old "compatibility issue flags", all the new "features" should be tested by the caldav-server-tester, this file should contain everything needed by the code and by the tests, in addition to other useful/interessting features checked by the caldav-server-tester project. The work here is predominantly done by Claude - maintaining this file is tedious work and not part of the core logic. Quite some of the prompts have gone missing, quite much of the work has been done in the caldav-server-tester project. I have noticed Claude hallucinating up RFC references, so it's important to ask it to actually read the RFCs and verify the references. Here are some of the prompts: prompt: (in caldav-server-tester project ) Create a check for freebusy-query.rfc6638 followup-prompt: this being a RFC6638-thing, it's meant to be used in a multi-user-scenario, so consider usage of ServerQuirkChecker.extra_principals. (Also, rename the old FreeBusy check class with a name consistent with the new FreeBusy class) followup-prompt: rename the feature to scheduling.freebusy-query (not freebusy-query.rfc6638) followup-prompt: but then freebusy-query.rfc4791 becomes a bit redundant, it can be removed and merged into freebusy-query, with the description of freebusy-query emphasizing that it's a check for freebusy as given in rfc4791 (with reference to scheduling.freebusy-query for the rfc6638-variant) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This is a combination of various work done on the compatibility hints. The compatibility hints are still a bit "work in progress", so it's considered OK to do breaking changes here even on minor-versions. It's used mostly in the test code, but also internally in the library to work around various compatibility problems. The aim of the work is to get rid of all the old "compatibility issue flags", all the new "features" should be tested by the caldav-server-tester, this file should contain everything needed by the code and by the tests, in addition to other useful/interessting features checked by the caldav-server-tester project. This commit is a combination of many commits, many of them AI-generated. Maintaining this file is tedious work and not part of the core logic. Quite some of the prompts have gone missing, quite much of the work has been done in the caldav-server-tester project. I do believe the changes have been through sufficient scrutiny. Claude does have a history of messing up this file - hallucinating up RFC references, and frequently flipping compatibility support instead of doing research on why the feature support is "fragile". Here are some of the prompts: prompt: (in caldav-server-tester project ) Create a check for freebusy-query.rfc6638 followup-prompt: this being a RFC6638-thing, it's meant to be used in a multi-user-scenario, so consider usage of ServerQuirkChecker.extra_principals. (Also, rename the old FreeBusy check class with a name consistent with the new FreeBusy class) followup-prompt: rename the feature to scheduling.freebusy-query (not freebusy-query.rfc6638) followup-prompt: but then freebusy-query.rfc4791 becomes a bit redundant, it can be removed and merged into freebusy-query, with the description of freebusy-query emphasizing that it's a check for freebusy as given in rfc4791 (with reference to scheduling.freebusy-query for the rfc6638-variant) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The scheduling freebusy-requests were completely untested and didn't work at all. logic was human-written, test-code by Claude Prompt: look into https://datatracker.ietf.org/doc/html/rfc6638#appendix-B.5 and make a pure unit test with a mocked-up response to a freebusy scheduling request, exercising the handling part of it. This will break with a NotImplementedError as for now. Only fix the test, do not fix the code logic. Consider the TODO-comment in response.py, line 247, and give me an opinion on weather it makes sense to reuse the _find_objects_and_props for scheduling response or if it's better to create a dedicated separate method for this.
Adds the pycalendar/ai-prompt-auto-commit hooks so that Claude Code prompts are automatically appended to commit messages. - unstage-ai-prompts: keeps .prompts/ out of the index - append-ai-prompts (prepare-commit-msg): injects prompts into message - archive-ai-prompts (post-commit): moves .prompts/ to committed/ - prepare-ai-repository (manual): one-time setup already run Also installs prepare-commit-msg and post-commit git hooks locally. prompt: ~/.claude/skills/python-project-modernization.md is now updated with the https://github.com/pycalendar/ai-prompt-auto-commit tool. Please fix set this up for the caldav repo. AI-generated: This is considered to be CI-infrastructure, one of the areas identified to be particularly suitable for AI assistance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ref RFC 6638 §3.2-3.3 Schedule-Tag implementation: - `save()` and `add_event()` capture the Schedule-Tag from the response header and stores it in `self.props` (same logic with etag). - `save()` sends `If-Schedule-Tag-Match` or `If-Match`-header if etag or schedule-tag is set. - raises `ScheduleTagMismatchError` or `ETagMismatchError` on 412. - `_reply_to_invite_request()`: when the server auto-schedules the event into the attendee's calendar (`scheduling.auto-schedule` supported), search all attendee calendars first and update the existing copy in place to preserve the server-assigned Schedule-Tag. Fall through to `add_event()` only for non-auto-schedule servers. - Assume SEQUENCE:0 default when SEQUENCE property is absent (RFC 5546 section 2.1.4 requires incrementing for significant changes). test: add failing tests for Schedule-Tag support (RFC 6638) Also adds design docs: - docs/design/TODO_SCHEDULE_TAG.md (analysis and implementation plan, refs #660) - docs/design/TODO_COMPATIBILITY_HINTS.md (FeatureSet cleanup analysis, refs #659) The schedule-tag logic was predominantly hand-written (with some trivial bugfixing done by Claude). Claude contributed with design suggestions, which have been partly followed. Test code is predominantly AI-written. prompt: (exact prompt is lost, but I was discussing the schedule-tags, and the output is in the new file docs/design/TODO_SCHEDULE_TAG.md) prompt: Please write up test code (unit tests + integration tests) on the schedule tags. Don't fix the code yet. prompt: Please write up test code (unit tests + integration tests) on the schedule tags. Don't fix the code yet. followup-prompts: (discussions on test breakages. While debugging, Claude has been insisting on searching for the Schedule-Tag by using a PropFind if it wasn't included in the headers, but that does not make sense) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude has been trying to disable rate-limiting in Stalwart. I still got up some RateLimit errors while doing testing on the scheduling, but while asking Claude to continue debugging it, the problems disappeared and never came back. Hm. prompt: The stalwart docker image stops working every now and then when running test code due to ratelimiting errors. Any possibilities for deactivating this in the docker image? (followup-promps complaining that it isn't working) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Invite-handling (accept_invite, decline_invite, tentatively_accept_invite) now returns awaitable coroutines when used in async mode. SynchronizableCalendarObjectCollection.sync() has also been dealt with, togheter with `MailBox.get_items()` and `DAVObject.children()` Also adds design docs: - docs/design/TODO_SCHEDULE_TAG.md (analysis and implementation plan, refs #660) - docs/design/TODO_COMPATIBILITY_HINTS.md (FeatureSet cleanup analysis, refs #659) The code logic here is partly human-created, mostly partly AI-created, certainly under human guideance. The final secision on how to handle async in 3.x has been carved in stone by a human. Test code is predominantly AI-created. The AI-generation involves tedious code duplication work and tedious routine refactoring, chances for mistakes are bigger when doing it by hand than by AI. I've been looking through the changes, and I trust the tests to uncover any errors slipping through. Some of the (many) commits dealing with this have been squashed into this commit. The return type of cached properties should always be an awaitable coroutine in async mode. prompt: Please make an async version of the get_items method in `caldav/collections.py` followup-prompt: I don't want workarounds in _async_get_items for async-unaware get_objects_by_sync_token. Fix _async_get_items assuming get_objects_by_sync_token will be made async-aware. followup-prompt: Please make an async-version of get_objects_by_sync_token prompt: Please investigate those failures: FAILED tests/test_async_integration.py::TestAsyncSchedulingForStalwart (...) prompt: make an async version of _reply_to_invite_request in `caldav/calendarobjectresource.py` prompt: In collection.py and calendarobjectresource.py and possibly in some of the other files as well, many methods are split up into a sync version and an async version. Please make appropriate type-hints for all methods that in async mode will yield a coroutine rather than an object Prompt: Let's refactor the async methods where it's possible. The existing pattern goes like this: * we have a sync version `foo` or `_foo` * we have an async version of the same method, `_async_foo` * `foo` is *most of the time* doing `if self.is_async_client: return self._async_foo(...)` I'd like to reduce the amount of duplicated code as well as to split out the IO-logic as much as possible. As for now, I want to go with this pattern: * `foo` should *always* do the `if self.is_async_client: return self._async_foo(...)`-logic * `self._async_foo` should never be called upon other places * Quite many of the methods are doing some preparations, firing off some other method causing I/O, and then doing some processing of the data returned from the server. Other methods are more complex, having mutliple code lines causing I/O. * For methods containing significant amount of logic (like, two or more code lines) before doing any IO, the `if self.is_async_client: return self._async_foo(...)`-logic should be moved to the last possible point in the method. * For methods containing significant amount of logic after doing the IO, split the logic out in a `_post_foo`-method. (the rules above was later moved to a document and tweaked a bit) prompt: Apply the rules from `docs/design/ASYNC_DUAL_MODE.md` for the `def sync` and `def async_sync` in `collection.py` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After an audit of caldav/operations/ and caldav/protocol/ (documented in docs/design/OPERATIONS_PROTOCOL_AUDIT.md), both directories are deleted, the code that was in use have been moved elsewhere. The code changes are predominantly AI-written. Tedious refactoring work, chances for mistakes are bigger when doing it by hand than by AI. I've been looking through the changes, and I trust the tests to uncover any errors slipping through. prompt: During the great attempt on Sans-IO refactoring, a directory `caldav/operations/` was made. Please check up how much code is duplicated and/or dead there, and come with recommendations on whether to keep "operations" there or not. Same with the protocols folder. followup-prompt: Save the analysis to the docs/design folder followup-prompt: Kill the operations directory ref the document followup-prompt: All response-related logic in the protocol directory should be moved back to the response class. Make sure there is no duplicated code or logic. followup-prompt: move xml builders to the dav base client, and ensure sync and async code paths uses the same builder methods prompt: Deal with the code duplication in response.py followup-prompt: It seems like the last commit, with purpose "remove code duplication in response.py" has more code additions than removed code? Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Funding.json is some kind of industry standard on how to beg for funding. Added it. Fixes #608 aka 95b9f5e. The funding file was partially generated with Claude Code - I asked the AI to help reading the specs and setting up the json structure accordingly. The async support has proven a lot more fragile than what I had hoped for, so it's appropriate to add some warnings in the async documentation. Git commit messages should now follow the industry standard. CHANGELOG prepared for v3.2.0 release The commit is predominantly human-written, with the following exceptions: * The code review document was AI-generated, human-updated * Changelog was AI-maintained, but most of it has been rewritten by hand prompt: Make a code review of all changes since v3.0.0 followup-prompt: write the review to a file under docs/design/ followup-prompt: The code review was not committed. Commit, then work on the code duplication in response.py prompt: the ChangeLog should be maintained Assisted-By: Claude Sonnet 4.6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
... just waiting for more tests to pass ...