Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add deprecation comments for message fields and enums #1738

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 16 additions & 1 deletion gapic/schema/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ def name(self) -> str:
name = self.field_pb.name
return name + "_" if name in utils.RESERVED_NAMES and self.meta.address.is_proto_plus_type else name

@property
def is_deprecated(self) -> bool:
"""Returns true if the field is deprecated, false otherwise."""
return self.field_pb.options.deprecated

@utils.cached_property
def ident(self) -> metadata.FieldIdentifier:
"""Return the identifier to be used in templates."""
Expand Down Expand Up @@ -748,6 +753,11 @@ class EnumValueType:
def __getattr__(self, name):
return getattr(self.enum_value_pb, name)

@property
def is_deprecated(self) -> bool:
"""Returns true if the enum value protobuf is deprecated, false otherwise."""
return self.enum_value_pb.options.deprecated


@dataclasses.dataclass(frozen=True)
class EnumType:
Expand All @@ -765,6 +775,11 @@ def __hash__(self):
def __getattr__(self, name):
return getattr(self.enum_pb, name)

@property
def is_deprecated(self) -> bool:
"""Returns true if the enum is deprecated, false otherwise."""
return self.enum_pb.options.deprecated

@property
def resource_path(self) -> Optional[str]:
# This is a minor duck-typing workaround for the resource_messages
Expand Down Expand Up @@ -1265,7 +1280,7 @@ def operation_service(self) -> Optional[str]:
@property
def is_deprecated(self) -> bool:
"""Returns true if the method is deprecated, false otherwise."""
return descriptor_pb2.MethodOptions.HasField(self.options, 'deprecated')
return self.options.deprecated

# TODO(yon-mg): remove or rewrite: don't think it performs as intended
# e.g. doesn't work with basic case of gRPC transcoding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class {{ enum.name }}({{ p }}.Enum):
Values:
{% for enum_value in enum.values %}
{{ enum_value.name }} ({{ enum_value.number }}):
{% if enum_value.is_deprecated and 'deprecated' not in enum_value.meta.doc|lower %}
parthea marked this conversation as resolved.
Show resolved Hide resolved
Deprecated.
{% endif %}
{% if enum_value.meta.doc|length > 0 %}
{{ enum_value.meta.doc|rst(width=72, indent=12, nl=False) }}
{% else %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class {{ message.name }}({{ p }}.Message):
Attributes:
{% for field in message.fields.values() %}
{{ field.name }} ({{ field.ident.sphinx }}):
{% if field.is_deprecated and 'deprecated' not in field.meta.doc|lower %}
Deprecated.
{% endif %}
{{ field.meta.doc|rst(indent=12, nl=False) }}
{% if field.oneof %}

Expand Down
18 changes: 17 additions & 1 deletion test_utils/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ def make_field(
enum: wrappers.EnumType = None,
meta: metadata.Metadata = None,
oneof: str = None,
is_deprecated: bool = False,
**kwargs
) -> wrappers.Field:
T = desc.FieldDescriptorProto.Type
Expand All @@ -244,6 +245,9 @@ def make_field(
**kwargs
)

if is_deprecated:
field_pb.options.deprecated = True

return wrappers.Field(
field_pb=field_pb,
enum=enum,
Expand Down Expand Up @@ -297,19 +301,31 @@ def make_enum(
name: str,
package: str = 'foo.bar.v1',
module: str = 'baz',
values: typing.Sequence[typing.Tuple[str, int]] = (),
values: typing.Sequence[typing.Tuple[str, int, bool]] = (),
meta: metadata.Metadata = None,
options: desc.EnumOptions = None,
is_deprecated: bool = False,
) -> wrappers.EnumType:
enum_value_pbs = [
desc.EnumValueDescriptorProto(name=i[0], number=i[1])
for i in values
]

enum_index = 0
for enum_value in enum_value_pbs:
if len(values[enum_index]) > 2:
enum_value.options.deprecated = values[enum_index][2]
parthea marked this conversation as resolved.
Show resolved Hide resolved
enum_index = enum_index + 1

enum_pb = desc.EnumDescriptorProto(
name=name,
value=enum_value_pbs,
options=options,
)

if is_deprecated:
enum_pb.options.deprecated = True

return wrappers.EnumType(
enum_pb=enum_pb,
values=[wrappers.EnumValueType(enum_value_pb=evpb)
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/schema/wrappers/test_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ def test_enum_properties():
assert enum_type.name == 'Color'


def test_enum_deprecated():
enum = make_enum('DeprecatedField', is_deprecated=True)
assert enum.is_deprecated

enum = make_enum('DeprecatedField', is_deprecated=False)
assert not enum.is_deprecated


def test_enum_values_deprecated():
enum_type = make_enum(name='Irrelevant', values=(
('RED', 1, True), ('GREEN', 2, False), ('BLUE', 3, False),
))
for enum_value in enum_type.values:
if enum_value.name == 'RED':
assert enum_value.is_deprecated
else:
assert not enum_value.is_deprecated
assert not enum_type.is_deprecated


def test_enum_value_properties():
enum_type = make_enum(name='Irrelevant', values=(
('RED', 1), ('GREEN', 2), ('BLUE', 3),
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/schema/wrappers/test_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ def test_field_is_primitive():
assert primitive_field.is_primitive


def test_field_deprecated():
field = make_field('DeprecatedField', is_deprecated=True)
assert field.is_deprecated

field = make_field('DeprecatedField', is_deprecated=False)
parthea marked this conversation as resolved.
Show resolved Hide resolved
assert not field.is_deprecated


def test_field_proto_type():
primitive_field = make_field(type='TYPE_INT32')
assert primitive_field.proto_type == 'INT32'
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/schema/wrappers/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def test_message_properties():
assert message.name == 'MyMessage'


def test_message_deprecated():
message = make_field('DeprecatedMessage', is_deprecated=True)
assert message.is_deprecated

message = make_field('DeprecatedMessage', is_deprecated=False)
assert not message.is_deprecated


def test_message_docstring():
L = descriptor_pb2.SourceCodeInfo.Location

Expand Down
3 changes: 3 additions & 0 deletions tests/unit/schema/wrappers/test_method.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ def test_method_deprecated():
method = make_method('DeprecatedMethod', is_deprecated=True)
assert method.is_deprecated

method = make_method('DeprecatedMethod', is_deprecated=False)
assert not method.is_deprecated


def test_method_client_output():
output = make_message(name='Input', module='baz')
Expand Down