Reserved Names¶
Proto field names can clash with Python builtins, keywords, and Pydantic BaseModel
attributes. protoc-gen-pydantic handles these automatically using a PEP 8 trailing
underscore alias.
How it works¶
When a proto field name is a reserved word in Python, the generator:
- Appends
_to the Python attribute name (e.g.bool→bool_) - Sets
alias="<original_name>"on the field so JSON / dict serialization still uses the original proto name - Adds
populate_by_name=Truetomodel_configso you can pass either the alias or the Python name when constructing the model
class BuiltinNames(_ProtoModel):
model_config = _ConfigDict(populate_by_name=True, protected_namespaces=())
bool_: bool = _Field(
default=False,
alias="bool",
)
float_: float = _Field(
default=0.0,
alias="float",
)
bytes_: bytes = _Field(
default=b"",
alias="bytes",
)
int_: int = _Field(
default=0,
alias="int",
)
Reserved name categories¶
The following categories of names trigger the trailing-underscore rename:
Python builtins: bool, bytes, complex, dict, float, frozenset, int,
list, map, object, set, str, tuple, type, …
Python keywords: and, as, assert, async, await, break, class,
continue, def, del, elif, else, except, finally, for, from,
global, if, import, in, is, lambda, nonlocal, not, or, pass,
raise, return, try, while, with, yield, False, None, True
Pydantic BaseModel attributes: model_config, model_fields, model_dump,
model_validate, model_json_schema, and other model_* names that would shadow
Pydantic internals
class ReservedFieldNames(_ProtoModel):
model_config = _ConfigDict(populate_by_name=True, protected_namespaces=())
model_config_: str = _Field(
default="",
alias="model_config",
)
model_fields_: str = _Field(
default="",
alias="model_fields",
)
model_dump_: str = _Field(
default="",
alias="model_dump",
)
Using the aliased fields¶
Because populate_by_name=True is set, you can use either the Python name or the proto alias:
# Using the Python name (trailing underscore)
b = BuiltinNames(bool_=True, float_=3.14)
# Using the original proto alias
b = BuiltinNames(**{"bool": True, "float": 3.14})
# Serialization always uses the proto name (no trailing underscore)
print(b.model_dump())
# {"bool": True, "float": 3.14}
buf.validate + reserved names¶
When a reserved field also carries buf.validate constraints, both the alias= and the
constraint kwargs are emitted in a single _Field() call: