@@ -302,7 +302,7 @@ def test_execute(self, http_client, patched_version_and_sys, patched_request):
302302 "Content-type" : "application/json; charset=utf-8" ,
303303 "test" : "header" ,
304304 },
305- data = '{"foo": "bar"}' ,
305+ data = b '{"foo": "bar"}' ,
306306 timeout = 30 ,
307307 )
308308
@@ -336,7 +336,7 @@ def test_execute_override_timeout(
336336 "Content-type" : "application/json; charset=utf-8" ,
337337 "test" : "header" ,
338338 },
339- data = '{"foo": "bar"}' ,
339+ data = b '{"foo": "bar"}' ,
340340 timeout = 60 ,
341341 )
342342
@@ -426,12 +426,12 @@ def test_execute_with_headers(self, http_client, patched_version_and_sys, patche
426426 "Content-type" : "application/json; charset=utf-8" ,
427427 "test" : "header" ,
428428 },
429- data = '{"foo": "bar"}' ,
429+ data = b '{"foo": "bar"}' ,
430430 timeout = 30 ,
431431 )
432432
433433 def test_execute_with_utf8_characters (self , http_client , patched_version_and_sys , patched_request ):
434- """Test that UTF-8 characters are preserved in JSON requests (not escaped) ."""
434+ """Test that UTF-8 characters are safely encoded in JSON requests."""
435435 mock_response = Mock ()
436436 mock_response .json .return_value = {"success" : True }
437437 mock_response .headers = {"X-Test-Header" : "test" }
@@ -452,17 +452,21 @@ def test_execute_with_utf8_characters(self, http_client, patched_version_and_sys
452452 )
453453
454454 assert response_json == {"success" : True }
455- # Verify that the data sent preserves UTF-8 characters (not escaped)
455+ # Verify that the data is sent as UTF-8 encoded bytes
456456 call_kwargs = patched_request .call_args [1 ]
457457 assert "data" in call_kwargs
458458 sent_data = call_kwargs ["data" ]
459459
460- # The JSON should contain actual UTF-8 characters, not escape sequences
461- assert "Réunion d'équipe" in sent_data
462- assert "De l'idée à la post-prod" in sent_data
463- assert "café" in sent_data
460+ # Data should be bytes
461+ assert isinstance (sent_data , bytes )
462+
463+ # The JSON should contain actual UTF-8 characters (not escaped)
464+ decoded = sent_data .decode ('utf-8' )
465+ assert "Réunion d'équipe" in decoded
466+ assert "De l'idée à la post-prod" in decoded
467+ assert "café" in decoded
464468 # Should NOT contain unicode escape sequences
465- assert "\\ u" not in sent_data
469+ assert "\\ u" not in decoded
466470
467471 def test_execute_with_none_request_body (self , http_client , patched_version_and_sys , patched_request ):
468472 """Test that None request_body is handled correctly."""
@@ -485,7 +489,7 @@ def test_execute_with_none_request_body(self, http_client, patched_version_and_s
485489 assert call_kwargs ["data" ] is None
486490
487491 def test_execute_with_emoji_and_international_characters (self , http_client , patched_version_and_sys , patched_request ):
488- """Test that emoji and various international characters are preserved ."""
492+ """Test that emoji and various international characters are safely encoded ."""
489493 mock_response = Mock ()
490494 mock_response .json .return_value = {"success" : True }
491495 mock_response .headers = {"X-Test-Header" : "test" }
@@ -511,13 +515,58 @@ def test_execute_with_emoji_and_international_characters(self, http_client, patc
511515 call_kwargs = patched_request .call_args [1 ]
512516 sent_data = call_kwargs ["data" ]
513517
514- # All characters should be preserved
515- assert "🎉 Party time! 🥳" in sent_data
516- assert "こんにちは" in sent_data
517- assert "你好" in sent_data
518- assert "Привет" in sent_data
519- assert "Größe" in sent_data
520- assert "¿Cómo estás?" in sent_data
518+ # Data should be bytes
519+ assert isinstance (sent_data , bytes )
520+
521+ # All characters should be preserved (not escaped)
522+ decoded = sent_data .decode ('utf-8' )
523+ assert "🎉 Party time! 🥳" in decoded
524+ assert "こんにちは" in decoded
525+ assert "你好" in decoded
526+ assert "Привет" in decoded
527+ assert "Größe" in decoded
528+ assert "¿Cómo estás?" in decoded
529+ # Should NOT contain unicode escape sequences
530+ assert "\\ u" not in decoded
531+
532+ def test_execute_with_right_single_quotation_mark (self , http_client , patched_version_and_sys , patched_request ):
533+ """Test that right single quotation mark (\\ u2019) is handled correctly.
534+
535+ This character caused UnicodeEncodeError: 'latin-1' codec can't encode character '\\ u2019'.
536+ """
537+ mock_response = Mock ()
538+ mock_response .json .return_value = {"success" : True }
539+ mock_response .headers = {"X-Test-Header" : "test" }
540+ mock_response .status_code = 200
541+ patched_request .return_value = mock_response
542+
543+ # The \u2019 character is the right single quotation mark (')
544+ # This was the exact character that caused the original encoding error
545+ request_body = {
546+ "subject" : "It's a test" , # Contains \u2019 (right single quotation mark)
547+ "body" : "Here's another example with curly apostrophe" ,
548+ }
549+
550+ response_json , response_headers = http_client ._execute (
551+ method = "POST" ,
552+ path = "/messages/send" ,
553+ request_body = request_body ,
554+ )
555+
556+ assert response_json == {"success" : True }
557+ call_kwargs = patched_request .call_args [1 ]
558+ sent_data = call_kwargs ["data" ]
559+
560+ # Data should be bytes
561+ assert isinstance (sent_data , bytes )
562+
563+ # The character should be preserved (not escaped)
564+ decoded = sent_data .decode ('utf-8' )
565+ assert "'" in decoded # \u2019 right single quotation mark
566+ assert "It's a test" in decoded
567+ assert "Here's another" in decoded
568+ # Should NOT contain unicode escape sequences
569+ assert "\\ u2019" not in decoded
521570
522571 def test_execute_with_multipart_data_not_affected (self , http_client , patched_version_and_sys , patched_request ):
523572 """Test that multipart/form-data is not affected by the change."""
0 commit comments