Skip to content

Constructors for one-of's allow multiple fields to be set #170

@busunkim96

Description

@busunkim96

dlp.Action is an one-of. Only one 'action' can be set
https://github.com/googleapis/python-dlp/blob/4f3148e93ec3dfc9395aa38a3afc62498500a055/google/cloud/dlp_v2/types/dlp.py#L3740

However, proto-plus doesn't raise if you attempt to set multiple fields when initializing the message. It looks like the last one 'wins'.

from google.cloud import dlp

# Install DLP first: pip install google-cloud-dlp

# dictionary
action = dlp.Action(
    {
        "pub_sub": {"topic": "projects/my-project/topics/1"},
        "job_notification_emails": {},
        "publish_findings_to_cloud_data_catalog": {},
    }
)

# message types
action = dlp.Action(
    pub_sub=dlp.Action.PublishToPubSub(topic="projects/my-project/topics/1"),
    job_notification_emails=dlp.Action.JobNotificationEmails(),
    publish_findings_to_cloud_data_catalog=dlp.Action.PublishFindingsToCloudDataCatalog(),
)
>>> action
publish_findings_to_cloud_data_catalog {
}

That seems to line up with the behavior described in the proto-plus and protobuf docs:

Setting a oneof field will automatically clear all other members of the oneof. So if you set several oneof fields, only the last field you set will still have a value.

Is it possible to raise if someone attempts to set multiple fields when instantiating the message? Or would that not make sense given protobuf also just takes the last field?


Another example with the Song/Composer protos in the docs:

import proto

class Composer(proto.Message):
    given_name = proto.Field(proto.STRING, number=1)
    family_name = proto.Field(proto.STRING, number=2)

class Song(proto.Message):
    composer = proto.Field(Composer, number=1)
    title = proto.Field(proto.STRING, number=2)
    lyrics = proto.Field(proto.STRING, number=3)
    year = proto.Field(proto.INT32, number=4)

class Album(proto.Message):
    track_list = proto.MapField(proto.UINT32, Song, number=1)
    publisher = proto.Field(proto.STRING, number=2)

class AlbumPurchase(proto.Message):
    album = proto.Field(Album, number=1)
    postal_address = proto.Field(proto.STRING, number=2, oneof='delivery')
    download_uri = proto.Field(proto.STRING, number=3, oneof='delivery')

# This does not raise
purchase = AlbumPurchase(postal_address="1600 Amphitheatre Parkway", download_uri="https://example.com")

# Neither does this
purchase_from_dict = AlbumPurchase({"download_uri": "https://example.com", "postal_address": "1600 Amphitheatre Parkway", })

# Using underlying PB
purchase_from_pb = AlbumPurchase.pb()(download_uri="https://example.com", postal_address="1600 Amphitheatre Parkway")

print(purchase)
print(purchase_from_dict)
print(purchase_from_pb)

Output:

download_uri: "https://example.com"

postal_address: "1600 Amphitheatre Parkway"

postal_address: "1600 Amphitheatre Parkway"

Metadata

Metadata

Assignees

Labels

triage meI really want to be triaged.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions