Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions protovalidate/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from collections.abc import Callable
from dataclasses import dataclass
from typing import Optional


@dataclass
Expand All @@ -23,10 +21,6 @@ class Config:

Attributes:
fail_fast (bool): If true, validation will stop after the first violation. Defaults to False.
regex_matches_func: An optional regex matcher to use. If specified, this will be used to match
on regex expressions instead of this library's `matches` logic.
"""

fail_fast: bool = False

regex_matches_func: Optional[Callable[[str, str], bool]] = None
25 changes: 1 addition & 24 deletions protovalidate/internal/extra_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,12 @@
import math
import re
import typing
from collections.abc import Callable
from urllib import parse as urlparse

import celpy
from celpy import celtypes

from protovalidate.config import Config
from protovalidate.internal import string_format
from protovalidate.internal.matches import matches as protovalidate_matches
from protovalidate.internal.rules import MessageType, field_to_cel

# See https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
Expand Down Expand Up @@ -1556,31 +1553,11 @@ def __peek(self, char: str) -> bool:
return self._index < len(self._string) and self._string[self._index] == char


def get_matches_func(matcher: typing.Optional[Callable[[str, str], bool]]):
if matcher is None:
matcher = protovalidate_matches

def cel_matches(text: celtypes.Value, pattern: celtypes.Value) -> celpy.Result:
if not isinstance(text, celtypes.StringType):
msg = "invalid argument for text, expected string"
raise celpy.CELEvalError(msg)
if not isinstance(pattern, celtypes.StringType):
msg = "invalid argument for pattern, expected string"
raise celpy.CELEvalError(msg)

b = matcher(text, pattern)
return celtypes.BoolType(b)

return cel_matches


def make_extra_funcs(config: Config) -> dict[str, celpy.CELFunction]:
def make_extra_funcs() -> dict[str, celpy.CELFunction]:
string_fmt = string_format.StringFormat()
return {
# Missing standard functions
"format": string_fmt.format,
# Overridden standard functions
"matches": get_matches_func(config.regex_matches_func),
# protovalidate specific functions
"getField": cel_get_field,
"isNan": cel_is_nan,
Expand Down
66 changes: 0 additions & 66 deletions protovalidate/internal/matches.py

This file was deleted.

2 changes: 1 addition & 1 deletion protovalidate/validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Validator:

def __init__(self, config=None):
self._cfg = config if config is not None else Config()
funcs = extra_func.make_extra_funcs(self._cfg)
funcs = extra_func.make_extra_funcs()
self._factory = _rules.RuleFactory(funcs)

def validate(
Expand Down
1 change: 0 additions & 1 deletion test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ class TestConfig(unittest.TestCase):
def test_defaults(self):
cfg = Config()
self.assertFalse(cfg.fail_fast)
self.assertIsNone(cfg.regex_matches_func)
5 changes: 2 additions & 3 deletions test/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

from gen.cel.expr import eval_pb2
from gen.cel.expr.conformance.test import simple_pb2
from protovalidate.config import Config
from protovalidate.internal import extra_func
from protovalidate.internal.cel_field_presence import InterpretedRunner

Expand Down Expand Up @@ -109,7 +108,7 @@ def test_format_successes(self):
if test.name in skipped_tests:
continue
ast = self._env.compile(test.expr)
prog = self._env.program(ast, functions=extra_func.make_extra_funcs(Config()))
prog = self._env.program(ast, functions=extra_func.make_extra_funcs())

bindings = build_variables(test.bindings)
# Ideally we should use pytest parametrize instead of subtests, but
Expand All @@ -133,7 +132,7 @@ def test_format_errors(self):
if test.name in skipped_error_tests:
continue
ast = self._env.compile(test.expr)
prog = self._env.program(ast, functions=extra_func.make_extra_funcs(Config()))
prog = self._env.program(ast, functions=extra_func.make_extra_funcs())

bindings = build_variables(test.bindings)
# Ideally we should use pytest parametrize instead of subtests, but
Expand Down
43 changes: 0 additions & 43 deletions test/test_matches.py

This file was deleted.

38 changes: 0 additions & 38 deletions test/test_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import re
import unittest

import celpy
from google.protobuf import message

import protovalidate
Expand Down Expand Up @@ -211,42 +209,6 @@ def test_fail_fast(self):
violations = validator.collect_violations(msg)
self._compare_violations(violations, [expected_violation])

def test_custom_matcher(self):
r"""Tests usage of the custom regex_matches_func in the config

A bit of a contrived example, but this exercises the code path
for specifying a custom regex matches function when writing regex rules.

Usage of the pattern \z is not supported in Python's re engine, only \Z is supported.
However, the inverse is true with re2 (\Z is _not_ supported and \z is supported).

This test shows using a custom matcher that converts any re2-compliant usage of \z
to \Z so that Python's re engine can execute it.
"""
msg = validations_pb2.InvalidRESyntax()

def matcher(text: str, pattern: str) -> bool:
pattern = pattern.replace("z", "Z")
try:
m = re.search(pattern, text)
except re.error as ex:
msg = "match error"
raise celpy.CELEvalError(msg, ex.__class__, ex.args) from ex
return m is not None

cfg = Config(regex_matches_func=matcher)
validator = protovalidate.Validator(config=cfg)

# Test validate
try:
validator.validate(msg)
except Exception:
self.fail("unexpected validation failure")

# Test collect_violations
violations = validator.collect_violations(msg)
self.assertEqual(len(violations), 0)

def _run_valid_tests(self, msg: message.Message):
"""A helper function for testing successful validation on a given message

Expand Down