Preserve explicit VALUE parameter on jCal round-trip (fixes #1426)#1434
Preserve explicit VALUE parameter on jCal round-trip (fixes #1426)#1434gaoflow wants to merge 2 commits into
Conversation
jCal encodes a property's value type in the type field (the third array item) rather than as a VALUE parameter. When reading jCal back, Component.from_jcal only removed a redundant VALUE parameter for the default type and never restored an explicit, non-default one, so properties such as RDATE;VALUE=PERIOD or TRIGGER;VALUE=DATE-TIME silently lost their VALUE parameter. The previous redundancy check compared value classes, which cannot tell the cases apart: vDDDTypes handles DATE, DATE-TIME and DURATION, and RDATE/EXDATE always resolve to vDDDLists, so the class is identical regardless of the type field. Restore the VALUE parameter whenever the jCal type differs from the property's default value type, computed by a new TypesFactory.default_value_type helper that returns the default jCal type even for properties whose internal type name differs from it (for example CATEGORIES, whose jCal type is text). Default types still get no VALUE parameter. Fixes collective#1426
|
Thanks for picking this up, @gaoflow — solid fix. Heads up: I'd been working on #1426 in parallel (@stevepiercy had asked me to look into it), and landed on the same approach — a Tests are the main difference. I ran my suite against your fix and it all passes, so they're purely additive:
One edge case I noticed: for a registered property with jCal type Component.from_jcal(["vevent", [["dtstart", {}, "unknown", "x"]], []]).to_ical()
# #1434: DTSTART;VALUE=UNKNOWN:x
# expected: DTSTART:xNiche, one-line guard; I have a test for it ( Happy to fold the tests + guard into #1434, or pull from my branch: https://github.com/lcampanella98/icalendar/tree/fix-1426-value-param. Whatever's least work for you all — thanks for moving this forward! |
A registered property carried through Component.from_jcal with the jCal
type identifier "unknown" (e.g. ["dtstart", {}, "unknown", "x"]) gained a
VALUE=UNKNOWN parameter, which RFC 7265 section 5.2 forbids -- UNKNOWN is
reserved from iCalendar. Treat "unknown" like the default type so no VALUE
parameter is reconstructed, and cover the registered-property path (which
the existing low-level vUnknown test did not exercise).
Co-authored-by: Lorenzo Campanella <enzocampanella98@gmail.com>
|
Thanks @lcampanella98 — and good catch on the I've folded the guard into this PR (just under the existing comparison — I kept this PR's implementation since it's already under review, but your independent RFC-derived reference table for |
|
@lcampanella98 @gaoflow thanks for your collaboration and coordination.
@gaoflow would you please pull that in, as @lcampanella98 has granted permission to incorporate his work, and add their username to the news fragment to give you both credit? Thank you! |
Summary
A round-trip through jCal (
to_jcal()→from_jcal()) silently drops an explicitVALUEparameter. For exampleRDATE;VALUE=PERIOD:…andTRIGGER;VALUE=DATE-TIME:…come back without theirVALUEparameter. This is #1426, which @stevepiercy confirmed.Cause
jCal stores a property's value type in the type field (the third array item, e.g.
"period"), not as aVALUEparameter.Component.from_jcalonly handled the redundant case — it deletedVALUEwhen the type matched the default — but it never restored aVALUEparameter for a non-default type:That class comparison can't distinguish the cases anyway:
vDDDTypesrepresentsDATE,DATE-TIMEandDURATION, andRDATE/EXDATEalways resolve tovDDDLists, sofor_propertyreturns the same class regardless of the type field. As a result theVALUEparameter was always dropped.Fix
Restore the
VALUEparameter whenever the jCal type differs from the property's default value type, and otherwise leave it off:The new
TypesFactory.default_value_type(name)returns the default jCal value type for a property. It usestypes_map, but for internal type keys that aren't jCal value types themselves (e.g.CATEGORIES→text,RDATE/EXDATE→date-time) it asks the value class for the type it actually serialises to, so default-typed properties never gain a spuriousVALUEparameter.Behaviour
RDATE;VALUE=PERIOD{}{'VALUE': 'PERIOD'}TRIGGER;VALUE=DATE-TIME{}{'VALUE': 'DATE-TIME'}DTEND;VALUE=DATE{}{'VALUE': 'DATE'}DTSTART(default){}{}CATEGORIES(default){}{}Tests
Added
test_jcal_round_trip_preserves_value_parameter, covering both explicit non-default types (preserved) and default types includingCATEGORIES(no spurious parameter). It fails onmainfor the non-default cases and passes with this change. Full suite: 9601 passed, 0 failed; ruff clean. Added anews/1426.bugfixtowncrier fragment.Fixes #1426
📚 Documentation preview 📚: https://icalendar--1434.org.readthedocs.build/en/1434/