@@ -70,6 +70,12 @@ class ParseError(Error):
7070 """Thrown in case of parsing error."""
7171
7272
73+ class EnumStringValueParseError (ParseError ):
74+ """Thrown if unknown string enum value is encountered.
75+ This exception is suppressed if ignore_unknown_fields is set.
76+ """
77+
78+
7379def MessageToJson (
7480 message ,
7581 preserving_proto_field_name = False ,
@@ -658,11 +664,8 @@ def _ConvertFieldValuePair(self, js, message, path):
658664 path , name , index
659665 )
660666 )
661- getattr (message , field .name ).append (
662- _ConvertScalarFieldValue (
663- item , field , '{0}.{1}[{2}]' .format (path , name , index )
664- )
665- )
667+ self ._ConvertAndAppendScalar (
668+ message , field , item , '{0}.{1}[{2}]' .format (path , name , index ))
666669 elif field .cpp_type == descriptor .FieldDescriptor .CPPTYPE_MESSAGE :
667670 if field .is_extension :
668671 sub_message = message .Extensions [field ]
@@ -672,17 +675,9 @@ def _ConvertFieldValuePair(self, js, message, path):
672675 self .ConvertMessage (value , sub_message , '{0}.{1}' .format (path , name ))
673676 else :
674677 if field .is_extension :
675- message .Extensions [field ] = _ConvertScalarFieldValue (
676- value , field , '{0}.{1}' .format (path , name )
677- )
678+ self ._ConvertAndSetScalarExtension (message , field , value , '{0}.{1}' .format (path , name ))
678679 else :
679- setattr (
680- message ,
681- field .name ,
682- _ConvertScalarFieldValue (
683- value , field , '{0}.{1}' .format (path , name )
684- ),
685- )
680+ self ._ConvertAndSetScalar (message , field , value , '{0}.{1}' .format (path , name ))
686681 except ParseError as e :
687682 if field and field .containing_oneof is None :
688683 raise ParseError (
@@ -795,11 +790,7 @@ def _ConvertStructMessage(self, value, message, path):
795790 def _ConvertWrapperMessage (self , value , message , path ):
796791 """Convert a JSON representation into Wrapper message."""
797792 field = message .DESCRIPTOR .fields_by_name ['value' ]
798- setattr (
799- message ,
800- 'value' ,
801- _ConvertScalarFieldValue (value , field , path = '{0}.value' .format (path )),
802- )
793+ self ._ConvertAndSetScalar (message , field , value , path = '{0}.value' .format (path ))
803794
804795 def _ConvertMapFieldValue (self , value , message , field , path ):
805796 """Convert map field value for a message map field.
@@ -832,9 +823,51 @@ def _ConvertMapFieldValue(self, value, message, field, path):
832823 '{0}[{1}]' .format (path , key_value ),
833824 )
834825 else :
835- getattr (message , field .name )[key_value ] = _ConvertScalarFieldValue (
836- value [key ], value_field , path = '{0}[{1}]' .format (path , key_value )
837- )
826+ self ._ConvertAndSetScalarToMapKey (
827+ message ,
828+ field ,
829+ key_value ,
830+ value [key ],
831+ path = '{0}[{1}]' .format (path , key_value ))
832+
833+ def _ConvertAndSetScalarExtension (self , message , extension_field , js_value , path ):
834+ """Convert scalar from js_value and assign it to message.Extensions[extension_field]."""
835+ try :
836+ message .Extensions [extension_field ] = _ConvertScalarFieldValue (
837+ js_value , extension_field , path )
838+ except EnumStringValueParseError :
839+ if not self .ignore_unknown_fields :
840+ raise
841+
842+ def _ConvertAndSetScalar (self , message , field , js_value , path ):
843+ """Convert scalar from js_value and assign it to message.field."""
844+ try :
845+ setattr (
846+ message ,
847+ field .name ,
848+ _ConvertScalarFieldValue (js_value , field , path ))
849+ except EnumStringValueParseError :
850+ if not self .ignore_unknown_fields :
851+ raise
852+
853+ def _ConvertAndAppendScalar (self , message , repeated_field , js_value , path ):
854+ """Convert scalar from js_value and append it to message.repeated_field."""
855+ try :
856+ getattr (message , repeated_field .name ).append (
857+ _ConvertScalarFieldValue (js_value , repeated_field , path ))
858+ except EnumStringValueParseError :
859+ if not self .ignore_unknown_fields :
860+ raise
861+
862+ def _ConvertAndSetScalarToMapKey (self , message , map_field , converted_key , js_value , path ):
863+ """Convert scalar from 'js_value' and add it to message.map_field[converted_key]."""
864+ try :
865+ getattr (message , map_field .name )[converted_key ] = _ConvertScalarFieldValue (
866+ js_value , map_field .message_type .fields_by_name ['value' ], path ,
867+ )
868+ except EnumStringValueParseError :
869+ if not self .ignore_unknown_fields :
870+ raise
838871
839872
840873def _ConvertScalarFieldValue (value , field , path , require_str = False ):
@@ -851,6 +884,7 @@ def _ConvertScalarFieldValue(value, field, path, require_str=False):
851884
852885 Raises:
853886 ParseError: In case of convert problems.
887+ EnumStringValueParseError: In case of unknown enum string value.
854888 """
855889 try :
856890 if field .cpp_type in _INT_TYPES :
@@ -882,7 +916,9 @@ def _ConvertScalarFieldValue(value, field, path, require_str=False):
882916 number = int (value )
883917 enum_value = field .enum_type .values_by_number .get (number , None )
884918 except ValueError as e :
885- raise ParseError (
919+ # Since parsing to integer failed and lookup in values_by_name didn't
920+ # find this name, we have an enum string value which is unknown.
921+ raise EnumStringValueParseError (
886922 'Invalid enum value {0} for enum type {1}' .format (
887923 value , field .enum_type .full_name
888924 )
@@ -897,6 +933,8 @@ def _ConvertScalarFieldValue(value, field, path, require_str=False):
897933 else :
898934 return number
899935 return enum_value .number
936+ except EnumStringValueParseError as e :
937+ raise EnumStringValueParseError ('{0} at {1}' .format (e , path )) from e
900938 except ParseError as e :
901939 raise ParseError ('{0} at {1}' .format (e , path )) from e
902940
0 commit comments