Skip to content

Commit b3a6301

Browse files
committed
Support deprecated message and fields
1 parent 3d8c0cb commit b3a6301

File tree

7 files changed

+82
-0
lines changed

7 files changed

+82
-0
lines changed

src/betterproto/plugin/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from dataclasses import dataclass
3434
from dataclasses import field
3535
from typing import (
36+
Iterator,
3637
Union,
3738
Type,
3839
List,
@@ -249,6 +250,13 @@ def input_filenames(self) -> List[str]:
249250
"""
250251
return [f.name for f in self.input_files]
251252

253+
@property
254+
def python_module_imports(self) -> Set[str]:
255+
imports = set()
256+
if any(x for x in self.messages if any(x.deprecated_fields)):
257+
imports.add("warnings")
258+
return imports
259+
252260

253261
@dataclass
254262
class MessageCompiler(ProtoContentBase):
@@ -261,6 +269,7 @@ class MessageCompiler(ProtoContentBase):
261269
fields: List[Union["FieldCompiler", "MessageCompiler"]] = field(
262270
default_factory=list
263271
)
272+
deprecated: bool = field(default=False, init=False)
264273

265274
def __post_init__(self):
266275
# Add message to output file
@@ -269,6 +278,7 @@ def __post_init__(self):
269278
self.output_file.enums.append(self)
270279
else:
271280
self.output_file.messages.append(self)
281+
self.deprecated = self.proto_obj.options.deprecated
272282
super().__post_init__()
273283

274284
@property
@@ -285,6 +295,12 @@ def annotation(self) -> str:
285295
return f"List[{self.py_name}]"
286296
return self.py_name
287297

298+
@property
299+
def deprecated_fields(self) -> Iterator[str]:
300+
for f in self.fields:
301+
if f.deprecated:
302+
yield f.py_name
303+
288304

289305
def is_map(
290306
proto_field_obj: FieldDescriptorProto, parent_message: DescriptorProto

src/betterproto/templates/template.py.j2

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Generated by the protocol buffer compiler. DO NOT EDIT!
22
# sources: {{ ', '.join(description.input_filenames) }}
33
# plugin: python-betterproto
4+
{% for i in description.python_module_imports|sort %}
5+
import {{ i }}
6+
{% endfor %}
47
from dataclasses import dataclass
58
{% if description.datetime_imports %}
69
from datetime import {% for i in description.datetime_imports|sort %}{{ i }}{% if not loop.last %}, {% endif %}{% endfor %}
@@ -50,6 +53,18 @@ class {{ message.py_name }}(betterproto.Message):
5053
pass
5154
{% endif %}
5255

56+
{% if message.deprecated or message.deprecated_fields %}
57+
def __post_init__(self) -> None:
58+
{% if message.deprecated %}
59+
warnings.warn("{{ message.py_name }} is deprecated", DeprecationWarning)
60+
{% endif %}
61+
super().__post_init__()
62+
{% for field in message.deprecated_fields %}
63+
if self.{{ field }}:
64+
warnings.warn("{{ message.py_name }}.{{ field }} is deprecated", DeprecationWarning)
65+
{% endfor %}
66+
{% endif %}
67+
5368

5469
{% endfor %}
5570
{% for service in description.services %}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"v": 10,
3+
"value": 10
4+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
syntax = "proto3";
2+
3+
// Some documentation about the Test message.
4+
message Test {
5+
// Some documentation about the value.
6+
option deprecated = true;
7+
int32 v = 1 [deprecated=true];
8+
int32 value = 2;
9+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"v": 10,
3+
"value": 10
4+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
syntax = "proto3";
2+
3+
// Some documentation about the Test message.
4+
message Test {
5+
// Some documentation about the value.
6+
int32 v = 1 [deprecated=true];
7+
int32 value = 2;
8+
}

tests/test_deprecated.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pytest
2+
3+
from tests.output_betterproto.deprecated import Test as DeprecatedMessageTest
4+
from tests.output_betterproto.deprecated_field import Test as DeprecatedFieldTest
5+
6+
7+
def test_deprecated_message():
8+
with pytest.deprecated_call():
9+
DeprecatedMessageTest(value=10)
10+
11+
12+
def test_deprecated_message_with_deprecated_field():
13+
with pytest.warns(None) as record:
14+
DeprecatedMessageTest(v=10, value=10)
15+
assert len(record) == 2
16+
17+
18+
def test_deprecated_field_warning():
19+
with pytest.deprecated_call():
20+
DeprecatedFieldTest(v=10, value=10)
21+
22+
23+
def test_deprecated_field_no_warning():
24+
with pytest.warns(None) as record:
25+
DeprecatedFieldTest(value=10)
26+
assert not record

0 commit comments

Comments
 (0)