11# -*- coding: utf-8 -*-
22#
3- # Util/py3compat.py : Compatibility code for handling Py3k / Python 2.x
4- #
5- # Written in 2010 by Thorsten Behrens
3+ # Util/py3compat.py : Python 3 compatibility helpers
64#
75# ===================================================================
86# The contents of this file are dedicated to the public domain. To
2220# SOFTWARE.
2321# ===================================================================
2422
25- """Compatibility code for handling string/bytes changes from Python 2.x to Py3k
26-
27- In Python 2.x, strings (of type ''str'') contain binary data, including encoded
28- Unicode text (e.g. UTF-8). The separate type ''unicode'' holds Unicode text.
29- Unicode literals are specified via the u'...' prefix. Indexing or slicing
30- either type always produces a string of the same type as the original.
31- Data read from a file is always of '''str'' type.
32-
33- In Python 3.x, strings (type ''str'') may only contain Unicode text. The u'...'
34- prefix and the ''unicode'' type are now redundant. A new type (called
35- ''bytes'') has to be used for binary data (including any particular
36- ''encoding'' of a string). The b'...' prefix allows one to specify a binary
37- literal. Indexing or slicing a string produces another string. Slicing a byte
38- string produces another byte string, but the indexing operation produces an
39- integer. Data read from a file is of '''str'' type if the file was opened in
40- text mode, or of ''bytes'' type otherwise.
41-
42- Since PyCrypto aims at supporting both Python 2.x and 3.x, the following helper
43- functions are used to keep the rest of the library as independent as possible
44- from the actual Python version.
45-
46- In general, the code should always deal with binary strings, and use integers
47- instead of 1-byte character strings.
48-
49- b(s)
50- Take a text string literal (with no prefix or with u'...' prefix) and
51- make a byte string.
52- bchr(c)
53- Take an integer and make a 1-character byte string.
54- bord(c)
55- Take the result of indexing on a byte string and make an integer.
56- tobytes(s)
57- Take a text string, a byte string, or a sequence of character taken from
58- a byte string and make a byte string.
23+ """Python 3 compatibility helpers for bytes/string handling.
24+
25+ This module provides helper functions for consistent handling of bytes and strings.
26+ Requires Python 3.8+.
5927"""
6028
6129import sys
62- import abc
63-
64-
65- if sys .version_info [0 ] == 2 :
66-
67- def b (s ):
68- return s
69-
70- def bchr (s ):
71- return chr (s )
72-
73- def bstr (s ):
74- return str (s )
75-
76- def bord (s ):
77- return ord (s )
78-
79- def tobytes (s , encoding = "latin-1" ):
80- if isinstance (s , unicode ): # noqa: F821 - unicode exists in Python 2
81- return s .encode (encoding )
82- elif isinstance (s , str ):
83- return s
84- elif isinstance (s , bytearray ):
85- return bytes (s )
86- elif isinstance (s , memoryview ):
87- return s .tobytes ()
88- else :
89- return "" .join (s )
30+ from abc import ABC
31+ from io import BytesIO , StringIO
32+ from sys import maxsize as maxint
9033
91- def tostr (bs ):
92- return bs
9334
94- def byte_string (s ):
95- return isinstance (s , str )
35+ def b (s ):
36+ """Convert a text string to bytes."""
37+ return s .encode ("latin-1" )
9638
97- # In Python 2, a memoryview does not support concatenation
98- def concat_buffers (a , b ):
99- if isinstance (a , memoryview ):
100- a = a .tobytes ()
101- if isinstance (b , memoryview ):
102- b = b .tobytes ()
103- return a + b
10439
105- from StringIO import StringIO
40+ def bchr (s ):
41+ """Convert an integer to a single-byte bytes object."""
42+ return bytes ([s ])
10643
107- BytesIO = StringIO
10844
109- from sys import maxint
45+ def bstr (s ):
46+ """Convert string or int to bytes."""
47+ if isinstance (s , str ):
48+ return bytes (s , "latin-1" )
49+ else :
50+ return bytes (s )
11051
111- iter_range = xrange # noqa: F821 - xrange exists in Python 2
11252
113- def is_native_int (x ):
114- return isinstance (x , (int , long )) # noqa: F821 - long exists in Python 2
53+ def bord (s ):
54+ """Return the integer value of a byte (identity function in Python 3)."""
55+ return s
11556
116- def is_string (x ):
117- return isinstance (x , basestring ) # noqa: F821 - basestring exists in Python 2
11857
119- def is_bytes (x ):
120- return (
121- isinstance (x , str ) or isinstance (x , bytearray ) or isinstance (x , memoryview )
122- )
58+ def tobytes (s , encoding = "latin-1" ):
59+ """Convert various types to bytes."""
60+ if isinstance (s , bytes ):
61+ return s
62+ elif isinstance (s , bytearray ):
63+ return bytes (s )
64+ elif isinstance (s , str ):
65+ return s .encode (encoding )
66+ elif isinstance (s , memoryview ):
67+ return s .tobytes ()
68+ else :
69+ return bytes ([s ])
12370
124- ABC = abc .ABCMeta ("ABC" , (object ,), {"__slots__" : ()})
12571
126- FileNotFoundError = IOError
72+ def tostr (bs ):
73+ """Convert bytes to string."""
74+ return bs .decode ("latin-1" )
12775
128- else :
12976
130- def b (s ):
131- return s .encode ("latin-1" ) # utf-8 would cause some side-effects we don't want
77+ def byte_string (s ):
78+ """Check if s is a bytes object."""
79+ return isinstance (s , bytes )
13280
133- def bchr (s ):
134- return bytes ([s ])
13581
136- def bstr (s ):
137- if isinstance (s , str ):
138- return bytes (s , "latin-1" )
139- else :
140- return bytes (s )
82+ def concat_buffers (a , b ):
83+ """Concatenate two buffer-like objects."""
84+ return a + b
14185
142- def bord (s ):
143- return s
144-
145- def tobytes (s , encoding = "latin-1" ):
146- if isinstance (s , bytes ):
147- return s
148- elif isinstance (s , bytearray ):
149- return bytes (s )
150- elif isinstance (s , str ):
151- return s .encode (encoding )
152- elif isinstance (s , memoryview ):
153- return s .tobytes ()
154- else :
155- return bytes ([s ])
15686
157- def tostr (bs ):
158- return bs .decode ("latin-1" )
87+ iter_range = range
15988
160- def byte_string (s ):
161- return isinstance (s , bytes )
16289
163- def concat_buffers (a , b ):
164- return a + b
90+ def is_native_int (x ):
91+ """Check if x is a native integer."""
92+ return isinstance (x , int )
16593
166- from io import BytesIO
167- from io import StringIO
168- from sys import maxsize as maxint
16994
170- iter_range = range
95+ def is_string (x ):
96+ """Check if x is a string."""
97+ return isinstance (x , str )
17198
172- def is_native_int (x ):
173- return isinstance (x , int )
17499
175- def is_string (x ):
176- return isinstance (x , str )
100+ def is_bytes (x ):
101+ """Check if x is bytes-like."""
102+ return isinstance (x , (bytes , bytearray , memoryview ))
177103
178- def is_bytes (x ):
179- return (
180- isinstance (x , bytes )
181- or isinstance (x , bytearray )
182- or isinstance (x , memoryview )
183- )
184104
185- from abc import ABC
105+ FileNotFoundError = FileNotFoundError
186106
187- FileNotFoundError = FileNotFoundError
107+ __all__ = [
108+ "b" ,
109+ "bchr" ,
110+ "bstr" ,
111+ "bord" ,
112+ "tobytes" ,
113+ "tostr" ,
114+ "byte_string" ,
115+ "concat_buffers" ,
116+ "BytesIO" ,
117+ "StringIO" ,
118+ "maxint" ,
119+ "iter_range" ,
120+ "is_native_int" ,
121+ "is_string" ,
122+ "is_bytes" ,
123+ "ABC" ,
124+ "FileNotFoundError" ,
125+ ]
188126
189127
190128def _copy_bytes (start , end , seq ):
@@ -197,7 +135,3 @@ def _copy_bytes(start, end, seq):
197135 return bytes (seq [start :end ])
198136 else :
199137 return seq [start :end ]
200-
201-
202- del sys
203- del abc
0 commit comments