Skip to content

fix(evaluate): serialize and parse RegExp values - #3189

Closed
FadeHack (FadeHack) wants to merge 1 commit into
microsoft:mainfrom
FadeHack:fix-3188
Closed

FadeHack (FadeHack) wants to merge 1 commit into
microsoft:mainfrom
FadeHack:fix-3188

Conversation

@FadeHack

@FadeHack FadeHack (FadeHack) commented Aug 26, 2026 •

Copy link
Copy Markdown

serialize_value() has no branch for re.Pattern, so passing a compiled pattern to evaluate() silently sends undefined. parse_value() has no branch for "r", so a RegExp coming back from the page reaches the caller as the raw wire dict instead of a pattern:

>>> page.evaluate("(v) => String(v)", re.compile(r"a\d+", re.I))
'undefined'
>>> page.evaluate("() => /a\\d+/gi")
{'r': {'p': 'a\\d+', 'f': 'gi'}}

The protocol already carries regexes as {r: {p, f}} and the driver implements both sides, so this just adds the two missing branches on the Python side. playwright-dotnet does the same in EvaluateArgumentValueConverter.cs.

Flags reuse the existing escape_regex_flags() helper. On the way back, the JavaScript-only flags (g, y, d, u, v) have no re equivalent and are dropped.

Fixes #3188

serialize_value() had no branch for re.Pattern, so a compiled pattern
passed to evaluate() was silently sent as undefined. parse_value() had
no branch for "r", so a RegExp coming back from the page surfaced as the
raw wire dict instead of a pattern.

Both directions now use the {r: {p, f}} form the driver already
implements. Flags map through the existing escape_regex_flags() helper;
on the way back the JavaScript-only flags (g, y, d, u, v) have no re
equivalent and are dropped.

Fixes: microsoft#3188
@FadeHack

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks good. Reusing escape_regex_flags and adding parse_regex_flags is the right approach.

One concern on the parse side: re.compile raises for JS regex syntax that Python's re doesn't support. That now fails the whole evaluate() / json_value() call, even when the regex is nested deep inside a larger object. All of these raise re.error with this PR, while on main they return the raw dict:

page.evaluate("() => ({ re: /(?<year>\\d{4})/ })")  # unknown extension ?<y
page.evaluate("() => /[^]/")                          # unterminated character set
page.evaluate("() => /\\u{1F600}/u")                  # incomplete escape \u

Named groups are common in app code, so something like page.evaluate("() => window.appConfig") could start failing. Could you catch re.error in parse_value, fall back to the previous value, and add a test for it?

Minor: re.compile(b"a") fails with a protocol error (arg.value.r.p: expected string, got object). An explicit assert would give a clearer message.

@pavelfeldman

Copy link
Copy Markdown
Member

Thanks for the fix and the investigation! Continuing this in #3225, which builds on your change and also handles regexes Python's re can't compile.

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.

[Bug]: RegExp values are not serialized by evaluate(), and returned RegExps leak internal protocol JSON

2 participants