@@ -241,6 +241,7 @@ def _query(
241241 expected_return_value is not None and ret .status != expected_return_value
242242 ) or ret .status >= 400 :
243243 ## COMPATIBILITY HACK - see https://github.com/python-caldav/caldav/issues/309
244+ ## TODO: server quirks!
244245 body = to_wire (body )
245246 if (
246247 ret .status == 500
@@ -946,7 +947,11 @@ def save(self):
946947 self ._create (id = self .id , name = self .name , ** self .extra_init_options )
947948 return self
948949
949- def calendar_multiget (self , event_urls : Iterable [URL ]) -> List ["Event" ]:
950+ ## TODO: this is missing test code.
951+ ## TODO: needs refactoring:
952+ ## Objects found may be Todo and Journal, not only Event.
953+ ## Replace the last lines with _request_report_build_resultlist method
954+ def calendar_multiget (self , event_urls : Iterable [URL ]) -> List [_CC ]:
950955 """
951956 get multiple events' data
952957 @author mtorange@gmail.com
@@ -1078,15 +1083,15 @@ def date_search(
10781083
10791084 return objects
10801085
1086+ ## TODO: this logic has been partly duplicated in calendar_multiget, but
1087+ ## the code there is much more readable and condensed than this.
1088+ ## Can code below be refactored?
10811089 def _request_report_build_resultlist (
10821090 self , xml , comp_class = None , props = None , no_calendardata = False
10831091 ):
10841092 """
10851093 Takes some input XML, does a report query on a calendar object
10861094 and returns the resource objects found.
1087-
1088- TODO: similar code is duplicated many places, we ought to do even more code
1089- refactoring
10901095 """
10911096 matches = []
10921097 if props is None :
@@ -1122,7 +1127,6 @@ def _request_report_build_resultlist(
11221127 props = pdata ,
11231128 )
11241129 )
1125-
11261130 return (response , matches )
11271131
11281132 def search (
@@ -1163,7 +1167,7 @@ def search(
11631167 unless the next parameter is set ...
11641168 * include_completed - include completed tasks
11651169 * event - sets comp_class to event
1166- * text attribute search parameters: category, uid, summary, omment ,
1170+ * text attribute search parameters: category, uid, summary, comment ,
11671171 description, location, status
11681172 * no-category, no-summary, etc ... search for objects that does not
11691173 have those attributes. TODO: WRITE TEST CODE!
@@ -2338,6 +2342,8 @@ def copy(self, keep_uid: bool = False, new_parent: Optional[Any] = None) -> Self
23382342 obj .url = self .url
23392343 return obj
23402344
2345+ ## TODO: move get-logics to a load_by_get method.
2346+ ## The load method should deal with "server quirks".
23412347 def load (self , only_if_unloaded : bool = False ) -> Self :
23422348 """
23432349 (Re)load the object from the caldav server.
@@ -2351,7 +2357,10 @@ def load(self, only_if_unloaded: bool = False) -> Self:
23512357 if self .client is None :
23522358 raise ValueError ("Unexpected value None for self.client" )
23532359
2354- r = self .client .request (str (self .url ))
2360+ try :
2361+ r = self .client .request (str (self .url ))
2362+ except :
2363+ return self .load_by_multiget ()
23552364 if r .status == 404 :
23562365 raise error .NotFoundError (errmsg (r ))
23572366 self .data = vcal .fix (r .raw )
@@ -2361,6 +2370,23 @@ def load(self, only_if_unloaded: bool = False) -> Self:
23612370 self .props [cdav .ScheduleTag .tag ] = r .headers ["Schedule-Tag" ]
23622371 return self
23632372
2373+ def load_by_multiget (self ) -> Self :
2374+ """
2375+ Some servers do not accept a GET, but we can still do a REPORT
2376+ with a multiget query
2377+ """
2378+ error .assert_ (self .url )
2379+ href = self .url .path
2380+ prop = dav .Prop () + cdav .CalendarData ()
2381+ root = cdav .CalendarMultiGet () + prop + dav .Href (value = href )
2382+ response = self .parent ._query (root , 1 , "report" )
2383+ results = response .expand_simple_props ([cdav .CalendarData ()])
2384+ error .assert_ (len (results ) == 1 )
2385+ data = results [href ][cdav .CalendarData .tag ]
2386+ error .assert_ (data )
2387+ self .data = data
2388+ return self
2389+
23642390 ## TODO: self.id should either always be available or never
23652391 def _find_id_path (self , id = None , path = None ) -> None :
23662392 """
0 commit comments