From 8e4918182db3117981cffe0025dca63b786648ab Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Tue, 1 Oct 2019 10:59:10 +1000 Subject: [PATCH] Ensure Matcher.regex raises when passed non-string Matcher.regex is documented as accepting a string, but previously if you passed an already-compiled regex, that would also be accepted by the validator. This happened because re.compile simply returns already-compiled regexes without an error. It would ultimately lead to an error when executing a search, because a compiled regex is not serializable to JSON. Fix it to more strictly typecheck the inputs when creating the matcher, so we fail early and with a meaningful message. --- CHANGELOG.md | 3 ++- pubtools/pulplib/_impl/criteria.py | 7 +++++++ tests/criteria/test_matcher.py | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a5ee72c..d5705e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- n/a +### Changed +- Patterns to `Matcher.regex` are now more strictly typechecked when the matcher is created. ## [2.3.0] - 2019-09-25 diff --git a/pubtools/pulplib/_impl/criteria.py b/pubtools/pulplib/_impl/criteria.py index 5739c4a2..bf7b0e07 100644 --- a/pubtools/pulplib/_impl/criteria.py +++ b/pubtools/pulplib/_impl/criteria.py @@ -256,6 +256,13 @@ class RegexMatcher(Matcher): @_pattern.validator def _check_pattern(self, _, pattern): + # It must be a string. + # Need an explicit check here because re.compile also succeeds + # on already-compiled regex objects. + if not isinstance(pattern, six.string_types): + raise TypeError("Regex matcher expected string, got: %s" % repr(pattern)) + + # Verify that the given value can really be compiled as a regex. re.compile(pattern) # Note: regex matcher does not implement _map since regex is defined only diff --git a/tests/criteria/test_matcher.py b/tests/criteria/test_matcher.py index 3cf2a985..1206cd1e 100644 --- a/tests/criteria/test_matcher.py +++ b/tests/criteria/test_matcher.py @@ -10,3 +10,10 @@ def test_matcher_regex_invalid(): with pytest.raises(re.error): Matcher.regex("foo [bar") + + +def test_matcher_regex_compiled(): + """Matcher.regex raises if passed value is a compiled regex.""" + + with pytest.raises(TypeError): + Matcher.regex(re.compile("foobar"))