Skip to content

Feature: Improve lenient parsing: audit compat coverage and expand test cases #637

Description

@allenporter

Summary

Audit the existing ical.compat compatibility layer, document what real-world broken ICS patterns are and are not handled, and expand test coverage with real-world broken calendar file examples.

What We Already Handle

The ical.compat module has a well-designed, PRODID-aware compatibility layer that auto-detects the calendar producer and enables targeted fixups:

Microsoft Exchange Server (PRODID contains "Microsoft Exchange Server")

  • Invalid timezones (enable_allow_invalid_timezones) — tolerates TZID references that don't match any VTIMEZONE definition
  • Extended timezone names (enable_extended_timezones) — handles non-IANA timezone identifiers like "Eastern Standard Time" that Windows/Exchange uses instead of "America/New_York"

Google Calendar (PRODID contains "Google Inc//Google Calendar")

  • DTSTART/UNTIL type mismatch (enable_dtstart_until_compat) — Google Calendar generates RRULE UNTIL as a DATE when DTSTART is DATE-TIME, violating RFC 5545 section 3.3.10. The compat layer silently converts UNTIL to match DTSTART's type.

All Producers (always enabled in compat mode)

  • Same-day DTEND (enable_same_day_dtend_compat) — some providers set DTSTART and DTEND to the same date for all-day events; RFC 5545 requires DTEND to be the next day (non-inclusive)
  • Invalid date formats (enable_allow_invalid_dates) — tolerates DATE properties with time suffixes (e.g., 20240115T000000 where 20240115 is expected)

Design Pattern

The compat layer uses a context manager pattern (enable_compat_mode()) with contextvars for thread-safe state. This is an opt-in API — callers must explicitly wrap their parsing calls. This is a deliberate design choice that keeps the default parsing strict/correct.

What Developers Complain About (Real-World Broken ICS Patterns)

Based on research of Stack Overflow, GitHub issues across iCal libraries, Reddit threads, and tools like ics-fixer and x-wr-timezone:

High Frequency — Most Commonly Reported

  1. X-WR-TIMEZONE without VTIMEZONE blocks — Google Calendar exports sometimes include only a calendar-level X-WR-TIMEZONE header and omit per-event VTIMEZONE definitions entirely. The separate x-wr-timezone library exists solely to normalize this. Status in ical: ❓ Not handled — this is likely the biggest remaining gap.
  2. Missing VTIMEZONE with valid IANA TZID — Many generators include TZID=America/New_York but skip the VTIMEZONE block, assuming the client knows standard IANA zones. Technically a spec violation, but trivially resolvable since we have the tzdata package. Status: ❓ Partially handled via Exchange compat, but should work for all producers.

Moderate Frequency

  1. Improper line folding — RFC 5545 requires lines >75 octets to be folded (newline + space). Many generators produce long unfoldedlines, especially in DESCRIPTION and LOCATION fields. Status: ❓ Needs investigation — pyparsing grammar may already handle this.
  2. Missing UID on events — Some generators omit the UID property entirely. This causes issues for recurrence and deduplication. Status: ❓ Needs investigation.
  3. Smart quotes and encoding issues — Descriptions copy-pasted from Word/rich-text contain smart quotes (U+201C/U+201D), em-dashes (U+2014), etc. These may cause issues if not properly UTF-8 encoded. Status: ❓ Needs investigation.

Lower Frequency

  1. Malformed ORGANIZER/ATTENDEE — Empty values, missing mailto: prefix, bare email addresses. Common from Exchange and older GroupWise systems. Status: ❓ Needs investigation.
  2. DURATION vs DTEND conflicts — Both specified on the same event, which is explicitly forbidden by RFC 5545. Status: ❓ Needs investigation.

Proposed Actions

1. Investigate and document current behavior

For each pattern above, create a test .ics file that exercises the broken pattern and document whether ical handles it (with and without compat mode).

2. Expand test coverage

Add test cases in tests/compat/ with real-world broken ICS samples. Each test should:

  • Parse the broken ICS without compat mode and verify it either fails gracefully or succeeds
  • Parse the broken ICS with enable_compat_mode() and verify it produces correct results
  • Document which calendar producer generates this pattern

3. Priority fixes

Based on frequency, the highest-value fixes are:

  1. X-WR-TIMEZONE handling (covers a huge class of Google Calendar exports)
  2. Missing VTIMEZONE with valid IANA TZID for all producers (not just Exchange)
  3. Long line handling (if not already supported)

4. Documentation

The compat layer is a genuinely great feature that's currently invisible. Document it prominently:

  • Add a "Handling broken ICS files" section to the docs
  • Show the enable_compat_mode() context manager pattern in the README or quickstart

Contributions Welcome

If you encounter a broken ICS file that ical doesn't handle, please open an issue with:

  1. The (sanitized) ICS content
  2. What calendar application produced it
  3. What you expected to happen vs. what actually happened

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions