@@ -820,6 +820,114 @@ def __bytes__(self):
820
820
self .assertEqual (BytesSubclass (A ()), b'abc' )
821
821
self .assertIs (type (BytesSubclass (A ())), BytesSubclass )
822
822
823
+ # Test PyBytes_FromFormat()
824
+ def test_from_format (self ):
825
+ ctypes = test .support .import_module ('ctypes' )
826
+ _testcapi = test .support .import_module ('_testcapi' )
827
+ from ctypes import pythonapi , py_object
828
+ from ctypes import (
829
+ c_int , c_uint ,
830
+ c_long , c_ulong ,
831
+ c_size_t , c_ssize_t ,
832
+ c_char_p )
833
+
834
+ PyBytes_FromFormat = pythonapi .PyBytes_FromFormat
835
+ PyBytes_FromFormat .restype = py_object
836
+
837
+ # basic tests
838
+ self .assertEqual (PyBytes_FromFormat (b'format' ),
839
+ b'format' )
840
+ self .assertEqual (PyBytes_FromFormat (b'Hello %s !' , b'world' ),
841
+ b'Hello world !' )
842
+
843
+ # test formatters
844
+ self .assertEqual (PyBytes_FromFormat (b'c=%c' , c_int (0 )),
845
+ b'c=\0 ' )
846
+ self .assertEqual (PyBytes_FromFormat (b'c=%c' , c_int (ord ('@' ))),
847
+ b'c=@' )
848
+ self .assertEqual (PyBytes_FromFormat (b'c=%c' , c_int (255 )),
849
+ b'c=\xff ' )
850
+ self .assertEqual (PyBytes_FromFormat (b'd=%d ld=%ld zd=%zd' ,
851
+ c_int (1 ), c_long (2 ),
852
+ c_size_t (3 )),
853
+ b'd=1 ld=2 zd=3' )
854
+ self .assertEqual (PyBytes_FromFormat (b'd=%d ld=%ld zd=%zd' ,
855
+ c_int (- 1 ), c_long (- 2 ),
856
+ c_size_t (- 3 )),
857
+ b'd=-1 ld=-2 zd=-3' )
858
+ self .assertEqual (PyBytes_FromFormat (b'u=%u lu=%lu zu=%zu' ,
859
+ c_uint (123 ), c_ulong (456 ),
860
+ c_size_t (789 )),
861
+ b'u=123 lu=456 zu=789' )
862
+ self .assertEqual (PyBytes_FromFormat (b'i=%i' , c_int (123 )),
863
+ b'i=123' )
864
+ self .assertEqual (PyBytes_FromFormat (b'i=%i' , c_int (- 123 )),
865
+ b'i=-123' )
866
+ self .assertEqual (PyBytes_FromFormat (b'x=%x' , c_int (0xabc )),
867
+ b'x=abc' )
868
+
869
+ sizeof_ptr = ctypes .sizeof (c_char_p )
870
+
871
+ if os .name == 'nt' :
872
+ # Windows (MSCRT)
873
+ ptr_format = '0x%0{}X' .format (2 * sizeof_ptr )
874
+ def ptr_formatter (ptr ):
875
+ return (ptr_format % ptr )
876
+ else :
877
+ # UNIX (glibc)
878
+ def ptr_formatter (ptr ):
879
+ return '%#x' % ptr
880
+
881
+ ptr = 0xabcdef
882
+ self .assertEqual (PyBytes_FromFormat (b'ptr=%p' , c_char_p (ptr )),
883
+ ('ptr=' + ptr_formatter (ptr )).encode ('ascii' ))
884
+ self .assertEqual (PyBytes_FromFormat (b's=%s' , c_char_p (b'cstr' )),
885
+ b's=cstr' )
886
+
887
+ # test minimum and maximum integer values
888
+ size_max = c_size_t (- 1 ).value
889
+ for formatstr , ctypes_type , value , py_formatter in (
890
+ (b'%d' , c_int , _testcapi .INT_MIN , str ),
891
+ (b'%d' , c_int , _testcapi .INT_MAX , str ),
892
+ (b'%ld' , c_long , _testcapi .LONG_MIN , str ),
893
+ (b'%ld' , c_long , _testcapi .LONG_MAX , str ),
894
+ (b'%lu' , c_ulong , _testcapi .ULONG_MAX , str ),
895
+ (b'%zd' , c_ssize_t , _testcapi .PY_SSIZE_T_MIN , str ),
896
+ (b'%zd' , c_ssize_t , _testcapi .PY_SSIZE_T_MAX , str ),
897
+ (b'%zu' , c_size_t , size_max , str ),
898
+ (b'%p' , c_char_p , size_max , ptr_formatter ),
899
+ ):
900
+ self .assertEqual (PyBytes_FromFormat (formatstr , ctypes_type (value )),
901
+ py_formatter (value ).encode ('ascii' )),
902
+
903
+ # width and precision (width is currently ignored)
904
+ self .assertEqual (PyBytes_FromFormat (b'%5s' , b'a' ),
905
+ b'a' )
906
+ self .assertEqual (PyBytes_FromFormat (b'%.3s' , b'abcdef' ),
907
+ b'abc' )
908
+
909
+ # '%%' formatter
910
+ self .assertEqual (PyBytes_FromFormat (b'%%' ),
911
+ b'%' )
912
+ self .assertEqual (PyBytes_FromFormat (b'[%%]' ),
913
+ b'[%]' )
914
+ self .assertEqual (PyBytes_FromFormat (b'%%%c' , c_int (ord ('_' ))),
915
+ b'%_' )
916
+ self .assertEqual (PyBytes_FromFormat (b'%%s' ),
917
+ b'%s' )
918
+
919
+ # Invalid formats and partial formatting
920
+ self .assertEqual (PyBytes_FromFormat (b'%' ), b'%' )
921
+ self .assertEqual (PyBytes_FromFormat (b'x=%i y=%' , c_int (2 ), c_int (3 )),
922
+ b'x=2 y=%' )
923
+
924
+ # Issue #19969: %c must raise OverflowError for values
925
+ # not in the range [0; 255]
926
+ self .assertRaises (OverflowError ,
927
+ PyBytes_FromFormat , b'%c' , c_int (- 1 ))
928
+ self .assertRaises (OverflowError ,
929
+ PyBytes_FromFormat , b'%c' , c_int (256 ))
930
+
823
931
def test_bytes_blocking (self ):
824
932
class IterationBlocked (list ):
825
933
__bytes__ = None
0 commit comments