Migrate to a full native extension wrapping protovalidate-cc - #507
Open
anuraaga wants to merge 1 commit into
Open
Migrate to a full native extension wrapping protovalidate-cc#507anuraaga wants to merge 1 commit into
anuraaga wants to merge 1 commit into
Conversation
anuraaga
marked this pull request as draft
August 5, 2026 08:25
anuraaga
force-pushed
the
protovalidate-cc
branch
from
August 5, 2026 12:24
cc0255a to
2f85e4c
Compare
anuraaga
marked this pull request as ready for review
August 5, 2026 12:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Performance matters here and popular validation libraries are largely written in native. We took one step there by replacing our CEL engine with cel-expr-python, but that left several problems. The idea of utilizing protovalidate-cc as a native core came up, but a Python project must not require Bazel to allow smooth sdist builds and to improve contributor experience. At first this seemed like a blocker, but this takes an approach that I think is viable.
Instead of running Bazel on every build, this uses it as a preprocessing step to vendor in C++ sources for us to wrap into a standard PyO3 + cargo build. This relies on certain observations
-syscrates heavily to expose existing native libraries and includes robust support for building them with it'scccrateSo this adds a script, extract_native_sources, which fetches the protovalidate-cc repo and uses Bazel to build it, which fetches in its dependency sources, and we use
bazel aqueryto analyse the build graph for the exact source files used. We vendor the sources and a manifest of the files list to feed to standard cargoccmachinery, to have a simple cargo build for the libraries that sidesteps Bazel completely.This isn't a simple approach by any means but it is systematic and I believe robust - we don't have any shady regex matching, we use bazel's queries to get real info on the build. IMO it's the best way to follow our standing directive of reusing cel-cpp here. And the approach could be used to implement a protovalidate-rust in the future that still uses the cpp CEL engine - if that happened, protovalidate-python and protovalidate-cpp would both wrap that.
Result, every problem we have is eliminated
Improvement, perhaps still a problem though much less of a deal - we only copy once between protobuf-py and protobuf-cpp, no upb copy in between like before.
First bench is from an interim state.
Notice how celpy is just way too slow, so even keeping it as a fallback was somewhat questionable in whether it could actually be used. There are still quite some good wins going from the cel-expr approach to this.
This is the final one after some more optimizations especially when returning errors - didn't even record celpy since doesn't matter much.
The gap to pydantic is much reduced. We will still need to improve further - this will involve implementing native rules in protovalidate-cc as we have done in some of the other languages. Profiling shows most time is spent in CC, not our bindings (which includes the marshaling cost of the protos to C++).
Just for context, I did some highly experimental native rule evaluation in the vendored protovalidate-cc for a good improvement.
Fixes #489