Repository navigation
Honor a legacy CHARSET property parameter when parsing bytes - #2080
rahul05ranjan wants to merge 2 commits into
Conversation
|
Thanks for the pull request, @rahul05ranjan! A maintainer will review it shortly. |
Automation signalsActivity patterns show signs of automation. Evidence
Last 2 PRs: This is an automated analysis by AgentScan |
|
One or more PR-quality checks did not pass. Review the PR Quality Checks summary in the workflow run for the failed checks and their details, then make any necessary updates. Checklist items may remain unchecked while work is in progress. Please tick each item as you complete it. If you used AI assistance, follow the project's Responsible AI use policy and provide the required disclosures. |
3cf74d7 to
ea787e1
Compare
…ytes from_ical(bytes) decoded non-UTF-8 input with errors=replace before the property parameters were ever looked at, so a value that explicitly declared its encoding with a legacy CHARSET parameter (the marker pre-RFC 5545 producers left behind) still came back as U+FFFD soup. Decode each content line with the charset its CHARSET parameter declares; lines without the parameter keep the previous best-effort UTF-8 decoding, and an unknown charset falls back the same way. Fixes PyCalendar#2078 AI: GLM-5.3 (z-ai, via OpenRouter). How used: AI coding assistant. I supplied the repro from issue PyCalendar#2078 and the fix design (decode per content line, restricted to the parameter section before the first colon); the model drafted the patch, the regression tests and this message from my instructions. I reviewed the change and verified it by running the test suite. Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
ea787e1 to
d84f9ce
Compare
| NEWLINE_BYTES = re.compile(rb"\r?\n") | ||
| # a legacy CHARSET parameter declares the encoding of one property value | ||
| CHARSET_PARAM_BYTES = re.compile( | ||
| rb";[ \t]*CHARSET[ \t]*=[ \t]*([^;:\r\n]+)", re.IGNORECASE |
There was a problem hiding this comment.
Can you please use the possessive quantifier.
|
|
||
| def test_charset_text_inside_quoted_param_value_is_not_a_directive_issue_2078(): | ||
| """UTF-8 text with a quoted parameter value mentioning CHARSET= must | ||
| still decode as UTF-8, not as the encoding named in the quotes.""" |
There was a problem hiding this comment.
Where does this come from?
|
Thanks for the review @angatha — on both points: Possessive quantifier: happy to switch the capture group to "Where does this come from?" (test_charset_text_inside_quoted_param_value...): that case is one I constructed defensively — it is not from a real-world file or from issue #2078 itself. The scenario behind the PR (legacy |
Description
from_ical(bytes)runs the input throughto_unicode(), whoseerrors="replace"fallback fires before property parameters are ever looked at. So when an .ics file is not valid UTF-8 but a property explicitly declares its charset with the legacyCHARSETparameter — the marker pre-RFC 5545 producers left behind — the information needed to decode correctly is available and still ignored:This PR decodes each content line with the charset its
CHARSETparameter declares:CHARSET=is restricted to the parameter section (before the first:), so a quoted parameter value mentioningCHARSET=...is not mistaken for a directive;CHARSETparameter keep the previous best-effort UTF-8 decoding, byte for byte;Old exports from Outlook/Lotus tooling that spell non-UTF-8 text this way still circulate (migration dumps, mailing-list archives); for every non-ASCII value in them the summary/location/description currently comes back as U+FFFD soup.
Checklist
Additional information
Verification: three new tests in
src/icalendar/tests/test_encoding.py— the latin-1 repro (fails on current main with U+FFFD, passes here), the unknown-charset graceful fallback, and the quoted-CHARSET=-text guard. Targeted run (test_parsing.py,test_components_break_on_bad_ics.py,test_encoding.py,test_bom_calendar.py,tests/prop): 1,909 passed / 12 failed, where all 12 are the timezone-data-relatedtzidhost artifacts that reproduce identically on unmodified main on this machine (Python 3.13.5, run from a checkout without installing; the same 12 are listed in the full-suite evidence on my related #2079). No API change, so no docs were touched.