Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overwriting CalendarObjectResource.data with new data as string #346

Open
yuwash opened this issue Nov 25, 2023 · 4 comments
Open

Overwriting CalendarObjectResource.data with new data as string #346

yuwash opened this issue Nov 25, 2023 · 4 comments

Comments

@yuwash
Copy link
Contributor

yuwash commented Nov 25, 2023

Although the data field has a setter, it’s rather difficult to use if you (apparently?) can’t just put a string into it, but it uses some internal model that I couldn’t figure out. The only bad hack that seems to get it updated is (context)

            try:
                save_ = caldav.Todo.save
                caldav.Todo.save = lambda *args, **kwargs: None
                temp_todo = davcalendar.add_todo(serialized)
            finally:
                caldav.Todo.save = save_
            existing_todo.data = temp_todo.data

Another related difficulty is though that python-caldav represents each VTODO as a complete VCALENDAR when getting Todo.data whilst the library I’m using for VTODO (ics) doesn’t. The serialized string here thus only contains the VTODO part. Still add_todo does seem to work.

@yuwash yuwash changed the title Overwriting CalendarObjectResource.data of a with new data as string Overwriting CalendarObjectResource.data with new data as string Nov 25, 2023
@tobixen
Copy link
Member

tobixen commented Nov 26, 2023

Although the data field has a setter, it’s rather difficult to use if you (apparently?) can’t just put a string into it,

That should always work, it would be nice to see a test case or a scenario where it doesn't work.

Obviously you should put valid icalendar data into it, but I don't remember if there is any validation done when setting the data field. I think not.

@tobixen
Copy link
Member

tobixen commented Nov 26, 2023

I have never heard about the ics-py libary.

The library currently is supporting vobject and icalendar, it has setters and getters for vobject_instance, icalendar_instance (and also icalendar_component) . If the ics-py library is good, I would consider accepting a pull-request supporting the ics-py library in the same way.

There is some magic concerning those setters and getters, internally the state is always represented in one of those three formats, when it's needed with a different kind of format the data is converted.

This efficiently means that accessing the attribute causes side-effects, and that's bad. Just accessing event.icalendar_component or event.data may cause:

  • data to be altered, as the conversion from one data representation to another is never guaranteed to keep the data 100% consistent.
  • an unexpected runtime error in case the icalendar data is or is perceived to be invalid during the conversion.
  • "object coupling" to be lost. Currently, event.icalendar_component['description'] = 'new description' followed by event.save() will save the new description back to the calendar, at the other hand the code below will NOT alter the description on the calendar server. I consider this to be a relatively serious bug.
component = event.icalendar_component
if 'old description' in event.data:
    component['description'] = 'New description'
event.save()

Those attributes are also accessed internally in the library, causing the problems above to happen rather unexpectedly.

At some point I will redesign a bit and create a 2.0-interface (but I'm really serious on backward compability - everything that works under 1.0 should continue working until 3.0 is released). Most likely I will remove (deprecate) those attributes from the 2.0-interface and replace them with explicit methods for converting the data.

@yuwash
Copy link
Contributor Author

yuwash commented Nov 26, 2023

Thank you very much for the detailed response! I was missing the part that python-caldav uses icalendar and VObject for representing ical objects. I just recently started with a project and chose ics because that project seems to be the most active one (VObject being stale since 5 years), but perhaps I’ll look into switching to icalendar to make the whole thing simpler. Unlike my initial assumption about the lack of a VCALENDAR layer in the string that I used, the minimal offline example did work as expected. Have to check again why it seems to have not updated Todo.data the last time I did it with a real online client.

>>> import caldav                                                                                                                                                       
>>> import types
>>> put_response = types.SimpleNamespace(status=204)                                                                                                                    
>>> client = types.SimpleNamespace(put=lambda url, body, headers: put_response)
>>> cal = caldav.Calendar(client=client, url="")               
>>> vtodo = "BEGIN:VTODO\nDTSTAMP:20231123T215645\nSUMMARY:Do something nice\nUID:bc7\nEND:VTODO\n"                                                                                   
>>> t = cal.add_todo(vtodo)
>>> t.data = "BEGIN:VTODO\nDTSTAMP:20231123T215645\nSUMMARY:Do something else\nUID:bc7\nEND:VTODO\n"  # Changed the summary
>>> t.data
'BEGIN:VTODO\nDTSTAMP:20231123T215645\nSUMMARY:Do something else\nUID:bc7\nEND:VTODO\n'

@tobixen
Copy link
Member

tobixen commented Nov 27, 2023

vobject is stale, yes, it's historic reasons why vobject is supported. I've had multiple pull requests on replacing vobjects with the icalendar library, but couldn't do it due to backward compability - so event.instance will still yield a vobject. I came up with the vobject_instance and icalendar_instance properties so it's possible to choose, but vobject_instance will probably be deprecated at some point in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants