Skip to content

Commit 4eb9011

Browse files
authored
Python 3.13 support in validator.py (#1326)
Fixes #1173 **Why This Broke in Python 3.13** Python ≤ 3.12: When `exec(func)` was called with only globals, the dynamically `generated generate_validate_all` function was accessible in the local scope, and the fallback `locals()['generate_validate_all']` worked. Python 3.13: The scoping behavior changed. When `exec()` is called with only globals, the generated function is no longer accessible via `locals()`, causing the `KeyError: 'generate_validate_all'` encountered in #1173.
1 parent ad5af80 commit 4eb9011

File tree

1 file changed

+8
-11
lines changed

1 file changed

+8
-11
lines changed

python/protoc_gen_validate/validator.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import uuid
77
from functools import lru_cache
88
from ipaddress import IPv4Address, IPv6Address, ip_address
9+
from typing import Any
910
from urllib import parse as urlparse
1011

1112
from google.protobuf.message import Message
@@ -63,11 +64,9 @@ def _validate_inner(proto_message: Message):
6364
func = file_template(proto_message)
6465
global printer
6566
printer += func + "\n"
66-
exec(func)
67-
try:
68-
return generate_validate
69-
except NameError:
70-
return locals()['generate_validate']
67+
local_vars: dict[str, Any] = {}
68+
exec(func, globals(), local_vars)
69+
return local_vars['generate_validate']
7170

7271

7372
class ChangeFuncName(ast.NodeTransformer):
@@ -158,7 +157,7 @@ def _is_embedded_node(node: ast.Assign):
158157
def visit_If(self, node: ast.If):
159158
self.generic_visit(node)
160159
for child in ast.iter_child_nodes(node):
161-
if self._is_embedded_node(child):
160+
if isinstance(child, ast.Assign) and self._is_embedded_node(child):
162161
new_node = ast.AugAssign(
163162
target=ast.Name(id="err", ctx=ast.Store()), op=ast.Add(), value=child.value
164163
) # err += _validate_all(p.{{ name }}
@@ -214,11 +213,9 @@ def _validate_all_inner(proto_message: Message):
214213
func = comment + " All" + "\n" + func
215214
global printer
216215
printer += func + "\n"
217-
exec(func)
218-
try:
219-
return generate_validate_all
220-
except NameError:
221-
return locals()['generate_validate_all']
216+
local_vars: dict[str, Any] = {}
217+
exec(func, globals(), local_vars)
218+
return local_vars['generate_validate_all']
222219

223220

224221
def _validate_all(proto_message: Message) -> str:

0 commit comments

Comments
 (0)