File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -148,14 +148,29 @@ def _coerce_json_safe(obj: _typing.Any):
148148 if isinstance (obj , str | int | float | bool | type (None )):
149149 return obj
150150 if isinstance (obj , dict ):
151- return {_coerce_json_safe (key ): _coerce_json_safe (value ) for key , value in obj .items ()}
151+ return {
152+ _coerce_json_safe_dict_key (key ): _coerce_json_safe (value ) for key , value in obj .items ()
153+ }
152154 if isinstance (obj , list ):
153155 return [_coerce_json_safe (item ) for item in obj ]
154156 if isinstance (obj , tuple ):
155157 return tuple (_coerce_json_safe (item ) for item in obj )
156158 return _safe_repr (obj )
157159
158160
161+ def _coerce_json_safe_dict_key (obj : _typing .Any ):
162+ """
163+ Converts dictionary keys into values accepted by JSON object encoding.
164+ """
165+
166+ if isinstance (obj , str | int | float | bool | type (None )):
167+ return obj
168+ coerced = _coerce_json_safe (obj )
169+ if isinstance (coerced , str | int | float | bool | type (None )):
170+ return coerced
171+ return _safe_repr (coerced )
172+
173+
159174def _safe_repr (obj : _typing .Any ) -> str :
160175 """
161176 Returns a repr without propagating repr errors.
Original file line number Diff line number Diff line change @@ -179,6 +179,22 @@ def test_error_should_accept_exception_with_non_json_serializable_dict_key(
179179 assert log_output ["error" ]["type" ] == "ValueError"
180180 assert log_output ["error" ]["args" ] == [{repr (next (iter (payload .keys ()))): "value" }]
181181
182+ def test_error_should_accept_exception_with_tuple_dict_key (
183+ self , capsys : pytest .CaptureFixture [str ]
184+ ):
185+ payload = {(1 , "two" ): "value" }
186+ exception = ValueError (payload )
187+
188+ logger .error ("failed" , error = exception )
189+
190+ raw_log_output = capsys .readouterr ().err
191+ log_output = json .loads (raw_log_output )
192+
193+ assert log_output ["severity" ] == "ERROR"
194+ assert log_output ["message" ] == "failed"
195+ assert log_output ["error" ]["type" ] == "ValueError"
196+ assert log_output ["error" ]["args" ] == [{"(1, 'two')" : "value" }]
197+
182198 def test_log_should_have_message (self , capsys : pytest .CaptureFixture [str ]):
183199 logger .log ("bar" )
184200 raw_log_output = capsys .readouterr ().out
You can’t perform that action at this time.
0 commit comments