Skip to content

fix: preserve non-BMP unicode characters (emojis) in double-quoted strings - #319

Open
david-hong-invitae wants to merge 1 commit into
lyz-code:mainfrom
david-hong-invitae:fix/unicode-emoji-preservation
Open

fix: preserve non-BMP unicode characters (emojis) in double-quoted strings#319
david-hong-invitae wants to merge 1 commit into
lyz-code:mainfrom
david-hong-invitae:fix/unicode-emoji-preservation

Conversation

@david-hong-invitae

@david-hong-invitae david-hong-invitae commented Aug 6, 2026

Copy link
Copy Markdown

Summary

Fixes #300, fixes #227 — non-BMP unicode characters (emojis) in double-quoted strings are replaced with \Uxxxxxxxx escape sequences.

Root cause: ruyaml's Emitter.write_double_quoted (v0.91.0, latest on PyPI) only considers characters up to U+FFFD as "allowed unicode":

self.allow_unicode
and ('\xA0' <= ch <= '\uD7FF' or '\uE000' <= ch <= '\uFFFD')

This excludes the supplementary plane (U+10000–U+10FFFF) where emojis live, causing them to be escaped when inside double-quoted strings.

Note: This bug is already fixed on ruyaml's main branch (pycontribs/ruyaml@d6a82e8), but was never released to PyPI — the latest available version is still 0.91.0 which has the bug. Until a new ruyaml release is published, yamlfix needs to work around it.

Fix: Monkey-patch the emitter at module load to extend the allowed unicode range to include '\U00010000' <= ch <= '\U0010FFFF' (supplementary planes). The patch is identical to what ruyaml's unreleased main branch already has.

Related issues

Test plan

  • Added regression test test_fix_code_preserves_unicode_emojis_in_double_quoted_strings
  • Verified idempotency (running yamlfix twice produces same output)
  • Verified BMP characters (e.g. é, ñ) still work correctly
  • Verified behavior with and without preserve_quotes
  • Verified with quote_basic_values=True + quote_representation='"' (issue Unexpected unicode escaping #227 repro)

@david-hong-invitae
david-hong-invitae force-pushed the fix/unicode-emoji-preservation branch 4 times, most recently from 728b587 to 2cae265 Compare August 6, 2026 05:41
…rings

The ruyaml emitter (v0.91.0, latest on PyPI) escapes supplementary plane
characters (U+10000-U+10FFFF, including all emojis) in double-quoted
strings as \Uxxxxxxxx sequences because its allow_unicode range only
covers up to U+FFFD.

This is fixed on ruyaml's main branch but not yet released. Work around
it by post-processing the emitter output to restore escaped non-BMP
unicode sequences back to their original characters.

Fixes lyz-code#300
Fixes lyz-code#227
@david-hong-invitae
david-hong-invitae force-pushed the fix/unicode-emoji-preservation branch from 2cae265 to ad2a051 Compare August 6, 2026 05:43
@lyz-code

lyz-code commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Thank you for your contributions @david-hong-invitae , however, right now i'm unable to take care of the repository so i'm archiving it

@lyz-code

lyz-code commented Aug 6, 2026

Copy link
Copy Markdown
Owner

it looks that i can't archive it and let people interact in issues, so i'll leave it open and unmaintained: #272

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

Successfully merging this pull request may close these issues.

utf-8 characters replaced Unexpected unicode escaping

2 participants