1313# limitations under the License.
1414
1515from copy import deepcopy
16+ from typing import Any , Dict , List , Tuple , Union
17+
18+ from google .protobuf .descriptor import FieldDescriptor
19+ from google .protobuf .message import Message as ProtobufMessage
20+ from proto import Message as ProtoPlusMessage
21+
1622from google .ads .googleads .util import (
1723 set_nested_message_field ,
1824 get_nested_attr ,
2935# 1. They are returned as part of a Search or SearchStream request.
3036# 2. They are returned individually in a Get request.
3137# 3. They are sent to the API as part of a Mutate request.
32- _MESSAGES_WITH_SENSITIVE_FIELDS = {
38+ _MESSAGES_WITH_SENSITIVE_FIELDS : Dict [ str , List [ str ]] = {
3339 "CustomerUserAccess" : ["email_address" , "inviter_user_email_address" ],
3440 "CustomerUserAccessInvitation" : ["email_address" ],
3541 "MutateCustomerUserAccessRequest" : [
5056# This is a list of the names of messages that return search results from the
5157# API. These messages contain other messages that may contain sensitive
5258# information that needs to be masked before being logged.
53- _SEARCH_RESPONSE_MESSAGE_NAMES = [
59+ _SEARCH_RESPONSE_MESSAGE_NAMES : List [ str ] = [
5460 "SearchGoogleAdsResponse" ,
5561 "SearchGoogleAdsStreamResponse" ,
5662]
5763
5864
59- def _copy_message (message ):
65+ def _copy_message (
66+ message : Union [ProtobufMessage , ProtoPlusMessage ]
67+ ) -> Union [ProtobufMessage , ProtoPlusMessage ]:
6068 """Returns a copy of the given message.
6169
6270 Args:
@@ -69,7 +77,11 @@ def _copy_message(message):
6977 return deepcopy (message )
7078
7179
72- def _mask_message_fields (field_list , message , mask ):
80+ def _mask_message_fields (
81+ field_list : List [str ],
82+ message : Union [ProtobufMessage , ProtoPlusMessage ],
83+ mask : str
84+ ) -> Union [ProtobufMessage , ProtoPlusMessage ]:
7385 """Copies the given message and masks sensitive fields.
7486
7587 Sensitive fields are given as a list of strings and are overridden
@@ -87,7 +99,7 @@ def _mask_message_fields(field_list, message, mask):
8799 A new instance of the message object with fields copied and masked
88100 where necessary.
89101 """
90- copy = _copy_message (message )
102+ copy : Union [ ProtobufMessage , ProtoPlusMessage ] = _copy_message (message )
91103
92104 for field_path in field_list :
93105 try :
@@ -103,7 +115,9 @@ def _mask_message_fields(field_list, message, mask):
103115 return copy
104116
105117
106- def _mask_google_ads_search_response (message , mask ):
118+ def _mask_google_ads_search_response (
119+ message : Union [ProtobufMessage , ProtoPlusMessage ], mask : str
120+ ) -> Union [ProtobufMessage , ProtoPlusMessage ]:
107121 """Copies and masks sensitive data in a Search response
108122
109123 Response messages include instances of GoogleAdsSearchResponse and
@@ -118,7 +132,7 @@ def _mask_google_ads_search_response(message, mask):
118132 Returns:
119133 A copy of the message with sensitive fields masked.
120134 """
121- copy = _copy_message (message )
135+ copy : Union [ ProtobufMessage , ProtoPlusMessage ] = _copy_message (message )
122136
123137 for row in copy .results :
124138 # Each row is an instance of GoogleAdsRow. The ListFields method
@@ -127,21 +141,21 @@ def _mask_google_ads_search_response(message, mask):
127141 # then we need to access the native proto to call ListFields. If it's
128142 # not proto_plus we can assume it's protobuf and can access ListFields
129143 # directly.
130- if hasattr (row , "_pb" ):
131- row_fields = convert_proto_plus_to_protobuf (row ).ListFields ()
144+ if hasattr (row , "_pb" ): # proto-plus message
145+ row_fields : List [ Tuple ( FieldDescriptor , Any )] = convert_proto_plus_to_protobuf (row ).ListFields ()
132146 else :
133- row_fields = row .ListFields ()
147+ row_fields : List [ Tuple ( FieldDescriptor , Any )] = row .ListFields ()
134148 for field in row_fields :
135149 field_descriptor = field [0 ]
136150 # field_name is the name of the field on the GoogleAdsRow instance,
137151 # for example "campaign" or "customer_user_access"
138- field_name = field_descriptor .name
152+ field_name : str = field_descriptor .name
139153 # message_name is the name of the message, similar to the class
140154 # name, for example "Campaign" or "CustomerUserAccess"
141- message_name = field_descriptor .message_type .name
155+ message_name : str = field_descriptor .message_type .name
142156 if message_name in _MESSAGES_WITH_SENSITIVE_FIELDS .keys ():
143- nested_message = getattr (row , field_name )
144- masked_message = _mask_message_fields (
157+ nested_message : Union [ ProtobufMessage , ProtoPlusMessage ] = getattr (row , field_name )
158+ masked_message : Union [ ProtobufMessage , ProtoPlusMessage ] = _mask_message_fields (
145159 _MESSAGES_WITH_SENSITIVE_FIELDS [message_name ],
146160 nested_message ,
147161 mask ,
@@ -153,7 +167,7 @@ def _mask_google_ads_search_response(message, mask):
153167 return copy
154168
155169
156- def mask_message (message , mask ) :
170+ def mask_message (message : Union [ ProtobufMessage , ProtoPlusMessage ], mask : str ) -> Union [ ProtobufMessage , ProtoPlusMessage ] :
157171 """Copies and returns a message with sensitive fields masked.
158172
159173 Args:
@@ -165,12 +179,12 @@ def mask_message(message, mask):
165179 Returns:
166180 A copy of the message instance with sensitive fields masked.
167181 """
168- class_name = message .__class__ .__name__
182+ class_name : str = message .__class__ .__name__
169183
170184 if class_name in _SEARCH_RESPONSE_MESSAGE_NAMES :
171185 return _mask_google_ads_search_response (message , mask )
172186 elif class_name in _MESSAGES_WITH_SENSITIVE_FIELDS .keys ():
173- sensitive_fields = _MESSAGES_WITH_SENSITIVE_FIELDS [class_name ]
187+ sensitive_fields : List [ str ] = _MESSAGES_WITH_SENSITIVE_FIELDS [class_name ]
174188 return _mask_message_fields (sensitive_fields , message , mask )
175189 else :
176190 return message
0 commit comments