Skip to content

Commit c8fe4f2

Browse files
committed
Merge branch 'main' of https://github.com/bufbuild/protovalidate-python into protobuf-py-only
2 parents b6715f2 + 66757dc commit c8fe4f2

29 files changed

Lines changed: 1267 additions & 613 deletions

protovalidate/__init__.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from .validator import CompilationError, ValidationError, Validator, Violation, Violations
15+
"""The semantic validation library for Protobuf in Python."""
16+
17+
from __future__ import annotations
18+
19+
from protovalidate._validator import (
20+
CompilationError,
21+
ValidationError,
22+
Validator,
23+
Violation,
24+
Violations,
25+
)
1626

1727
_default_validator = Validator()
1828
validate = _default_validator.validate
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
"""Which CEL backend is available."""
1616

17+
from __future__ import annotations
18+
1719

1820
def _detect() -> bool:
1921
try:

protovalidate/internal/cel_field_presence.py renamed to protovalidate/_cel_field_presence.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,22 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from __future__ import annotations
16+
1517
import threading
18+
from typing import TYPE_CHECKING
1619

1720
import celpy
1821
import celpy.celtypes
1922

23+
if TYPE_CHECKING:
24+
from lark import Tree
25+
2026
_has_state = threading.local()
2127

2228

2329
def in_has() -> bool:
24-
"""
25-
Returns true if inside of CEL interpreter `has` macro.
30+
"""Returns true if inside of CEL interpreter `has` macro.
2631
2732
This enables working around an issue in cel-python where it is not possible
2833
to implement protobuf semantics around the `has` macro.
@@ -35,12 +40,11 @@ def in_has() -> bool:
3540
class InterpretedRunner(celpy.InterpretedRunner):
3641
def evaluate(self, context: celpy.Context) -> celpy.celtypes.Value:
3742
class Evaluator(celpy.Evaluator):
38-
def macro_has_eval(self, exprlist) -> celpy.celtypes.BoolType:
43+
def macro_has_eval(self, exprlist: Tree) -> celpy.celtypes.BoolType:
3944
_has_state.in_has = True
4045
result = super().macro_has_eval(exprlist)
4146
_has_state.in_has = False
4247
return result
4348

4449
e = Evaluator(ast=self.ast, activation=self.new_activation())
45-
value = e.evaluate(context)
46-
return value
50+
return e.evaluate(context)

protovalidate/internal/celexpr/__init__.py renamed to protovalidate/_celexpr/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
"""The cel-expr-python (cel-cpp) validation engine."""
1616

17+
from __future__ import annotations
18+
1719
from .bridge import GoogleBridge
1820
from .extra_func import make_extension
1921
from .rules import RuleFactory
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
from __future__ import annotations
15+
1416
from google.protobuf import descriptor as google_descriptor
1517

1618
# protobuf 7+ removed FieldDescriptor.label / LABEL_REPEATED in favour of is_repeated.
Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,32 @@
1616

1717
from __future__ import annotations
1818

19-
import typing
19+
from typing import TYPE_CHECKING
2020

21-
from google.protobuf import descriptor_pb2 as google_descriptor_pb2
22-
from google.protobuf import descriptor_pool as google_descriptor_pool
23-
from google.protobuf import message as google_message
24-
from google.protobuf import message_factory as google_message_factory
25-
from protobuf import DescFile, DescMessage
21+
from google.protobuf import (
22+
descriptor_pb2 as google_descriptor_pb2,
23+
descriptor_pool as google_descriptor_pool,
24+
message as google_message,
25+
message_factory as google_message_factory,
26+
)
2627

27-
if typing.TYPE_CHECKING:
28+
if TYPE_CHECKING:
2829
import protobuf
30+
from protobuf import DescFile, DescMessage
2931

3032

3133
class GoogleBridge:
32-
"""Lazily mirrors protobuf-py descriptors into google's pool and bridges
33-
protobuf-py message values to google dynamic messages."""
34+
"""Bridges from protobuf-py messages to google.protobuf for use with cel-expr-python."""
3435

3536
def __init__(self) -> None:
36-
self._pool: google_descriptor_pool.DescriptorPool = google_descriptor_pool.Default()
37+
self._pool: google_descriptor_pool.DescriptorPool = (
38+
google_descriptor_pool.Default()
39+
)
3740
self._mirrored: set[str] = set()
3841
self._classes: dict[str, type[google_message.Message]] = {}
3942

4043
def _mirror_file(self, desc_file: DescFile) -> None:
41-
"""Registers a protobuf-py DescFile (and its transitive deps) into the
42-
google pool, dependencies first, skipping files already present."""
44+
"""Registers a protobuf-py DescFile and deps into the google pool."""
4345
if desc_file.name in self._mirrored:
4446
return
4547
self._mirrored.add(desc_file.name)
@@ -48,7 +50,9 @@ def _mirror_file(self, desc_file: DescFile) -> None:
4850
try:
4951
self._pool.FindFileByName(desc_file.name)
5052
except KeyError:
51-
proto = google_descriptor_pb2.FileDescriptorProto.FromString(desc_file.proto.to_binary())
53+
proto = google_descriptor_pb2.FileDescriptorProto.FromString(
54+
desc_file.proto.to_binary()
55+
)
5256
self._pool.Add(proto)
5357

5458
def google_class(self, desc: DescMessage) -> type[google_message.Message]:

protovalidate/internal/celexpr/extra_func.py renamed to protovalidate/_celexpr/extra_func.py

Lines changed: 135 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,27 @@
1414

1515
"""cel-expr-python registration for protovalidate's custom CEL functions."""
1616

17+
from __future__ import annotations
18+
1719
from cel_expr_python import cel
18-
from google.protobuf import descriptor as google_descriptor
19-
from google.protobuf import message as google_message
20-
from google.protobuf import wrappers_pb2 as google_wrappers_pb2
20+
from google.protobuf import (
21+
descriptor as google_descriptor,
22+
message as google_message,
23+
wrappers_pb2 as google_wrappers_pb2,
24+
)
2125

22-
from protovalidate.internal import _funcs
26+
from protovalidate import _funcs
2327

2428
from ._utils import is_repeated
2529

2630

2731
def cel_get_field(message: object, field_name: object) -> object:
2832
if not isinstance(message, google_message.Message):
2933
msg = "invalid argument, expected message"
30-
raise ValueError(msg)
34+
raise TypeError(msg)
3135
if not isinstance(field_name, str):
3236
msg = "invalid argument, expected string"
33-
raise ValueError(msg)
37+
raise TypeError(msg)
3438
if field_name not in message.DESCRIPTOR.fields_by_name:
3539
msg = f"no such field: {field_name}"
3640
raise ValueError(msg)
@@ -50,7 +54,7 @@ def cel_get_field(message: object, field_name: object) -> object:
5054
def cel_unique(val: object) -> bool:
5155
if not isinstance(val, list):
5256
msg = "invalid argument, expected list"
53-
raise ValueError(msg)
57+
raise TypeError(msg)
5458
# Track seen values keyed by (type, value) so that distinct CEL types that
5559
# are equal in Python (notably bool vs int: ``True == 1``) are not treated
5660
# as duplicates, and so that bytes are never confused with strings.
@@ -97,59 +101,157 @@ def make_extension() -> cel.CelExtension:
97101
return cel.CelExtension(
98102
"protovalidate",
99103
[
100-
cel.FunctionDecl("getField", [cel.Overload("get_field", _dyn, [_dyn, _s], impl=cel_get_field)]),
101104
cel.FunctionDecl(
102-
"isNan", [cel.Overload("double_is_nan", _b, [_d], is_member=True, impl=_funcs.cel_is_nan)]
105+
"getField",
106+
[cel.Overload("get_field", _dyn, [_dyn, _s], impl=cel_get_field)],
107+
),
108+
cel.FunctionDecl(
109+
"isNan",
110+
[
111+
cel.Overload(
112+
"double_is_nan",
113+
_b,
114+
[_d],
115+
is_member=True,
116+
impl=_funcs.cel_is_nan,
117+
)
118+
],
103119
),
104120
cel.FunctionDecl(
105121
"isInf",
106122
[
107-
cel.Overload("double_is_inf", _b, [_d], is_member=True, impl=_funcs.cel_is_inf),
108-
cel.Overload("double_int_is_inf", _b, [_d, _i], is_member=True, impl=_funcs.cel_is_inf),
123+
cel.Overload(
124+
"double_is_inf",
125+
_b,
126+
[_d],
127+
is_member=True,
128+
impl=_funcs.cel_is_inf,
129+
),
130+
cel.Overload(
131+
"double_int_is_inf",
132+
_b,
133+
[_d, _i],
134+
is_member=True,
135+
impl=_funcs.cel_is_inf,
136+
),
109137
],
110138
),
111139
cel.FunctionDecl(
112140
"isIp",
113141
[
114-
cel.Overload("string_is_ip", _b, [_s], is_member=True, impl=_funcs.cel_is_ip),
115-
cel.Overload("string_int_is_ip", _b, [_s, _i], is_member=True, impl=_funcs.cel_is_ip),
142+
cel.Overload(
143+
"string_is_ip", _b, [_s], is_member=True, impl=_funcs.cel_is_ip
144+
),
145+
cel.Overload(
146+
"string_int_is_ip",
147+
_b,
148+
[_s, _i],
149+
is_member=True,
150+
impl=_funcs.cel_is_ip,
151+
),
116152
],
117153
),
118154
cel.FunctionDecl(
119155
"isIpPrefix",
120156
[
121-
cel.Overload("string_is_ip_prefix", _b, [_s], is_member=True, impl=_funcs.cel_is_ip_prefix),
122-
cel.Overload("string_int_is_ip_prefix", _b, [_s, _i], is_member=True, impl=_funcs.cel_is_ip_prefix),
123157
cel.Overload(
124-
"string_bool_is_ip_prefix", _b, [_s, _b], is_member=True, impl=_funcs.cel_is_ip_prefix
158+
"string_is_ip_prefix",
159+
_b,
160+
[_s],
161+
is_member=True,
162+
impl=_funcs.cel_is_ip_prefix,
125163
),
126164
cel.Overload(
127-
"string_int_bool_is_ip_prefix", _b, [_s, _i, _b], is_member=True, impl=_funcs.cel_is_ip_prefix
165+
"string_int_is_ip_prefix",
166+
_b,
167+
[_s, _i],
168+
is_member=True,
169+
impl=_funcs.cel_is_ip_prefix,
170+
),
171+
cel.Overload(
172+
"string_bool_is_ip_prefix",
173+
_b,
174+
[_s, _b],
175+
is_member=True,
176+
impl=_funcs.cel_is_ip_prefix,
177+
),
178+
cel.Overload(
179+
"string_int_bool_is_ip_prefix",
180+
_b,
181+
[_s, _i, _b],
182+
is_member=True,
183+
impl=_funcs.cel_is_ip_prefix,
128184
),
129185
],
130186
),
131187
cel.FunctionDecl(
132-
"isEmail", [cel.Overload("string_is_email", _b, [_s], is_member=True, impl=_funcs.cel_is_email)]
188+
"isEmail",
189+
[
190+
cel.Overload(
191+
"string_is_email",
192+
_b,
193+
[_s],
194+
is_member=True,
195+
impl=_funcs.cel_is_email,
196+
)
197+
],
133198
),
134199
cel.FunctionDecl(
135-
"isUri", [cel.Overload("string_is_uri", _b, [_s], is_member=True, impl=_funcs.cel_is_uri)]
200+
"isUri",
201+
[
202+
cel.Overload(
203+
"string_is_uri",
204+
_b,
205+
[_s],
206+
is_member=True,
207+
impl=_funcs.cel_is_uri,
208+
)
209+
],
136210
),
137211
cel.FunctionDecl(
138-
"isUriRef", [cel.Overload("string_is_uri_ref", _b, [_s], is_member=True, impl=_funcs.cel_is_uri_ref)]
212+
"isUriRef",
213+
[
214+
cel.Overload(
215+
"string_is_uri_ref",
216+
_b,
217+
[_s],
218+
is_member=True,
219+
impl=_funcs.cel_is_uri_ref,
220+
)
221+
],
139222
),
140223
cel.FunctionDecl(
141224
"isHostname",
142-
[cel.Overload("string_is_hostname", _b, [_s], is_member=True, impl=_funcs.cel_is_hostname)],
225+
[
226+
cel.Overload(
227+
"string_is_hostname",
228+
_b,
229+
[_s],
230+
is_member=True,
231+
impl=_funcs.cel_is_hostname,
232+
)
233+
],
143234
),
144235
cel.FunctionDecl(
145236
"isHostAndPort",
146237
[
147238
cel.Overload(
148-
"string_bool_is_host_and_port", _b, [_s, _b], is_member=True, impl=_funcs.cel_is_host_and_port
239+
"string_bool_is_host_and_port",
240+
_b,
241+
[_s, _b],
242+
is_member=True,
243+
impl=_funcs.cel_is_host_and_port,
244+
)
245+
],
246+
),
247+
cel.FunctionDecl(
248+
"unique",
249+
[
250+
cel.Overload(
251+
"list_unique", _b, [_l], is_member=True, impl=cel_unique
149252
)
150253
],
151254
),
152-
cel.FunctionDecl("unique", [cel.Overload("list_unique", _b, [_l], is_member=True, impl=cel_unique)]),
153255
cel.FunctionDecl(
154256
"startsWith",
155257
[
@@ -166,15 +268,23 @@ def make_extension() -> cel.CelExtension:
166268
"endsWith",
167269
[
168270
cel.Overload(
169-
"bytes_ends_with", _b, [cel.Type.BYTES, cel.Type.BYTES], is_member=True, impl=_bytes_ends_with
271+
"bytes_ends_with",
272+
_b,
273+
[cel.Type.BYTES, cel.Type.BYTES],
274+
is_member=True,
275+
impl=_bytes_ends_with,
170276
)
171277
],
172278
),
173279
cel.FunctionDecl(
174280
"contains",
175281
[
176282
cel.Overload(
177-
"bytes_contains", _b, [cel.Type.BYTES, cel.Type.BYTES], is_member=True, impl=_bytes_contains
283+
"bytes_contains",
284+
_b,
285+
[cel.Type.BYTES, cel.Type.BYTES],
286+
is_member=True,
287+
impl=_bytes_contains,
178288
)
179289
],
180290
),

0 commit comments

Comments
 (0)