Skip to content

Fix trailing-newline false positive in Regex validation (#307) - #356

Open
apoorvdarshan wants to merge 1 commit into
keleshev:masterfrom
apoorvdarshan:fix-regex-trailing-newline
Open

Fix trailing-newline false positive in Regex validation (#307)#356
apoorvdarshan wants to merge 1 commit into
keleshev:masterfrom
apoorvdarshan:fix-regex-trailing-newline

Conversation

@apoorvdarshan

Copy link
Copy Markdown

Summary

Regex('^a$').validate('a\n') returned 'a' instead of raising SchemaError (issue #307). In Python's non-MULTILINE mode, $ matches not only at the very end of the string but also just before a single trailing newline, so re.search('^a$', 'a\n') is truthy. The bug only affects a single trailing newline; 'a\n\n' and '\na' already failed as expected.

Fix

In Regex.validate (schema/__init__.py), when the data ends with a newline, re-run the search with an extra newline appended. That turns a lone trailing \n into \n\n, which defeats the $-before-newline quirk. If the match disappears, it was a phantom and validation fails; otherwise the value is accepted. Unanchored/substring patterns (e.g. Regex('foo').validate('foo\n')) are unaffected because their match does not rely on that end-anchor position. The appended newline mirrors the data's type (str vs bytes) so byte patterns keep working.

The change is a small, localized guard — it does not switch to fullmatch, preserving the intended substring-match behavior for unanchored patterns.

Tests

Added regression cases to test_regex covering:

  • Anchored patterns now reject a trailing newline: Regex('^a$').validate('a\n'), Regex('^[a-z]+$').validate('letters\n') raise SchemaError.
  • Existing anchored-pass and other-newline-fail behavior stays correct ('a' passes; 'a\n\n' and '\na' still fail).
  • Unanchored patterns keep substring semantics: Regex('foo').validate('foo\n') and Regex('^foo').validate('foo\n') still return the value.

Full suite: 120 passed. ruff check and ruff format --check are clean, and mypy reports no new errors. (One pre-existing README doctest failure is unrelated to this change — it fails identically on pristine master due to a stale expected error message under newer Python.)

Disclosure: prepared with AI assistance; reviewed and verified locally.

In non-MULTILINE mode Python's $ also matches just before a single
trailing newline, so Regex('^a$').validate('a\n') wrongly returned 'a'
instead of raising SchemaError. Re-check the match with an extra newline
appended so that quirk cannot fire, while preserving substring-matching
for unanchored patterns.

Fixes keleshev#307.
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.

1 participant