Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a4ea603

Browse files
author
Thomas Heller
committed
SF # 595026: support for masks in getargs.c.
New functions: unsigned long PyInt_AsUnsignedLongMask(PyObject *); unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *); unsigned long PyLong_AsUnsignedLongMask(PyObject *); unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); New and changed format codes: b unsigned char 0..UCHAR_MAX B unsigned char none ** h unsigned short 0..USHRT_MAX H unsigned short none ** i int INT_MIN..INT_MAX I * unsigned int 0..UINT_MAX l long LONG_MIN..LONG_MAX k * unsigned long none L long long LLONG_MIN..LLONG_MAX K * unsigned long long none Notes: * New format codes. ** Changed from previous "range-and-a-half" to "none"; the range-and-a-half checking wasn't particularly useful. New test test_getargs2.py, to verify all this.
1 parent e13ddc9 commit a4ea603

7 files changed

Lines changed: 596 additions & 27 deletions

File tree

Include/intobject.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ PyAPI_FUNC(PyObject *) PyInt_FromUnicode(Py_UNICODE*, int, int);
3636
#endif
3737
PyAPI_FUNC(PyObject *) PyInt_FromLong(long);
3838
PyAPI_FUNC(long) PyInt_AsLong(PyObject *);
39+
PyAPI_FUNC(unsigned long) PyInt_AsUnsignedLongMask(PyObject *);
40+
#ifdef HAVE_LONG_LONG
41+
PyAPI_FUNC(unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *);
42+
#endif
43+
3944
PyAPI_FUNC(long) PyInt_GetMax(void);
4045

4146
/* Macro, trading safety for speed */

Include/longobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long);
1919
PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
2020
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
2121
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
22+
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
2223

2324
/* _PyLong_AsScaledDouble returns a double x and an exponent e such that
2425
the true value is approximately equal to x * 2**(SHIFT*e). e is >= 0.
@@ -37,6 +38,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG);
3738
PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG);
3839
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *);
3940
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *);
41+
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
4042
#endif /* HAVE_LONG_LONG */
4143

4244
PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);

Lib/test/test_getargs2.py

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
import unittest
2+
from test import test_support
3+
import sys
4+
5+
import warnings, re
6+
warnings.filterwarnings("ignore", category=DeprecationWarning, module=__name__)
7+
8+
"""
9+
> How about the following counterproposal. This also changes some of
10+
> the other format codes to be a little more regular.
11+
>
12+
> Code C type Range check
13+
>
14+
> b unsigned char 0..UCHAR_MAX
15+
> h unsigned short 0..USHRT_MAX
16+
> B unsigned char none **
17+
> H unsigned short none **
18+
> k * unsigned long none
19+
> I * unsigned int 0..UINT_MAX
20+
21+
22+
> i int INT_MIN..INT_MAX
23+
> l long LONG_MIN..LONG_MAX
24+
25+
> K * unsigned long long none
26+
> L long long LLONG_MIN..LLONG_MAX
27+
28+
> Notes:
29+
>
30+
> * New format codes.
31+
>
32+
> ** Changed from previous "range-and-a-half" to "none"; the
33+
> range-and-a-half checking wasn't particularly useful.
34+
35+
Plus a C API or two, e.g. PyInt_AsLongMask() ->
36+
unsigned long and PyInt_AsLongLongMask() -> unsigned
37+
long long (if that exists).
38+
"""
39+
40+
LARGE = 0x7FFFFFFF
41+
VERY_LARGE = 0xFF0000121212121212121242L
42+
43+
from _testcapi import UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, INT_MAX, \
44+
INT_MIN, LONG_MIN, LONG_MAX
45+
46+
from _testcapi import getargs_ul as ul_convert
47+
from _testcapi import getargs_l as l_convert
48+
try:
49+
from _testcapi import getargs_ll as ll_convert
50+
from _testcapi import getargs_ull as ull_convert
51+
except ImportError:
52+
pass
53+
54+
# fake, they are not defined in Python's header files
55+
LLONG_MAX = 2**63-1
56+
LLONG_MIN = -2**63
57+
ULLONG_MAX = 2**64-1
58+
59+
class Long:
60+
def __int__(self):
61+
return 99L
62+
63+
class Int:
64+
def __int__(self):
65+
return 99
66+
67+
class Unsigned_TestCase(unittest.TestCase):
68+
def test_b(self):
69+
# b returns 'unsigned char', and does range checking (0 ... UCHAR_MAX)
70+
self.failUnlessEqual(3, ul_convert("b", 3.14))
71+
self.failUnlessEqual(99, ul_convert("b", Long()))
72+
self.failUnlessEqual(99, ul_convert("b", Int()))
73+
74+
self.assertRaises(OverflowError, ul_convert, "b", -1)
75+
self.failUnlessEqual(0, ul_convert("b", 0))
76+
self.failUnlessEqual(UCHAR_MAX, ul_convert("b", UCHAR_MAX))
77+
self.assertRaises(OverflowError, ul_convert, "b", UCHAR_MAX + 1)
78+
79+
self.failUnlessEqual(42, ul_convert("b", 42))
80+
self.failUnlessEqual(42, ul_convert("b", 42L))
81+
self.assertRaises(OverflowError, ul_convert, "b", VERY_LARGE)
82+
83+
def test_h(self):
84+
# h returns 'unsigned short', and does range checking (0 ... USHRT_MAX)
85+
self.failUnlessEqual(3, ul_convert("h", 3.14))
86+
self.failUnlessEqual(99, ul_convert("h", Long()))
87+
self.failUnlessEqual(99, ul_convert("h", Int()))
88+
89+
self.assertRaises(OverflowError, ul_convert, "h", -1)
90+
self.failUnlessEqual(0, ul_convert("h", 0))
91+
self.failUnlessEqual(USHRT_MAX, ul_convert("h", USHRT_MAX))
92+
self.assertRaises(OverflowError, ul_convert, "h", USHRT_MAX+1)
93+
94+
self.failUnlessEqual(42, ul_convert("h", 42))
95+
self.failUnlessEqual(42, ul_convert("h", 42L))
96+
self.assertRaises(OverflowError, ul_convert, "h", VERY_LARGE)
97+
98+
def test_B(self):
99+
# B returns 'unsigned char', no range checking
100+
self.failUnless(3 == ul_convert("B", 3.14))
101+
self.failUnlessEqual(99, ul_convert("B", Long()))
102+
self.failUnlessEqual(99, ul_convert("B", Int()))
103+
104+
self.failUnlessEqual(UCHAR_MAX, ul_convert("B", -1))
105+
self.failUnlessEqual(UCHAR_MAX, ul_convert("B", -1L))
106+
self.failUnlessEqual(0, ul_convert("B", 0))
107+
self.failUnlessEqual(UCHAR_MAX, ul_convert("B", UCHAR_MAX))
108+
self.failUnlessEqual(0, ul_convert("B", UCHAR_MAX+1))
109+
110+
self.failUnlessEqual(42, ul_convert("B", 42))
111+
self.failUnlessEqual(42, ul_convert("B", 42L))
112+
self.failUnlessEqual(UCHAR_MAX & VERY_LARGE, ul_convert("B", VERY_LARGE))
113+
114+
def test_H(self):
115+
# H returns 'unsigned short', no range checking
116+
self.failUnlessEqual(3, ul_convert("H", 3.14))
117+
self.failUnlessEqual(99, ul_convert("H", Long()))
118+
self.failUnlessEqual(99, ul_convert("H", Int()))
119+
120+
self.failUnlessEqual(USHRT_MAX, ul_convert("H", -1))
121+
self.failUnlessEqual(0, ul_convert("H", 0))
122+
self.failUnlessEqual(USHRT_MAX, ul_convert("H", USHRT_MAX))
123+
self.failUnlessEqual(0, ul_convert("H", USHRT_MAX+1))
124+
125+
self.failUnlessEqual(42, ul_convert("H", 42))
126+
self.failUnlessEqual(42, ul_convert("H", 42L))
127+
128+
self.failUnlessEqual(VERY_LARGE & USHRT_MAX, ul_convert("H", VERY_LARGE))
129+
130+
def test_I(self):
131+
# I returns 'unsigned int', no range checking
132+
self.failUnlessEqual(3, ul_convert("I", 3.14))
133+
self.failUnlessEqual(99, ul_convert("I", Long()))
134+
self.failUnlessEqual(99, ul_convert("I", Int()))
135+
136+
self.failUnlessEqual(UINT_MAX, ul_convert("I", -1))
137+
self.failUnlessEqual(0, ul_convert("I", 0))
138+
self.failUnlessEqual(UINT_MAX, ul_convert("I", UINT_MAX))
139+
self.failUnlessEqual(0, ul_convert("I", UINT_MAX+1))
140+
141+
self.failUnlessEqual(42, ul_convert("I", 42))
142+
self.failUnlessEqual(42, ul_convert("I", 42L))
143+
144+
self.failUnlessEqual(VERY_LARGE & UINT_MAX, ul_convert("I", VERY_LARGE))
145+
146+
def test_k(self):
147+
# k returns 'unsigned long', no range checking
148+
# it does not accept float, or instances with __int__
149+
self.assertRaises(TypeError, ul_convert, "k", 3.14)
150+
self.assertRaises(TypeError, ul_convert, "k", Long())
151+
self.assertRaises(TypeError, ul_convert, "k", Int())
152+
153+
self.failUnlessEqual(ULONG_MAX, ul_convert("k", -1))
154+
self.failUnlessEqual(0, ul_convert("k", 0))
155+
self.failUnlessEqual(ULONG_MAX, ul_convert("k", ULONG_MAX))
156+
self.failUnlessEqual(0, ul_convert("k", ULONG_MAX+1))
157+
158+
self.failUnlessEqual(42, ul_convert("k", 42))
159+
self.failUnlessEqual(42, ul_convert("k", 42L))
160+
161+
self.failUnlessEqual(VERY_LARGE & ULONG_MAX, ul_convert("k", VERY_LARGE))
162+
163+
class Signed_TestCase(unittest.TestCase):
164+
def test_i(self):
165+
# i returns 'int', and does range checking (INT_MIN ... INT_MAX)
166+
self.failUnlessEqual(3, l_convert("i", 3.14))
167+
self.failUnlessEqual(99, l_convert("i", Long()))
168+
self.failUnlessEqual(99, l_convert("i", Int()))
169+
170+
self.assertRaises(OverflowError, l_convert, "i", INT_MIN-1)
171+
self.failUnlessEqual(INT_MIN, l_convert("i", INT_MIN))
172+
self.failUnlessEqual(INT_MAX, l_convert("i", INT_MAX))
173+
self.assertRaises(OverflowError, l_convert, "i", INT_MAX+1)
174+
175+
self.failUnlessEqual(42, l_convert("i", 42))
176+
self.failUnlessEqual(42, l_convert("i", 42L))
177+
self.assertRaises(OverflowError, l_convert, "i", VERY_LARGE)
178+
179+
def test_l(self):
180+
# l returns 'long', and does range checking (LONG_MIN ... LONG_MAX)
181+
self.failUnlessEqual(3, l_convert("l", 3.14))
182+
self.failUnlessEqual(99, l_convert("l", Long()))
183+
self.failUnlessEqual(99, l_convert("l", Int()))
184+
185+
self.assertRaises(OverflowError, l_convert, "l", LONG_MIN-1)
186+
self.failUnlessEqual(LONG_MIN, l_convert("l", LONG_MIN))
187+
self.failUnlessEqual(LONG_MAX, l_convert("l", LONG_MAX))
188+
self.assertRaises(OverflowError, l_convert, "l", LONG_MAX+1)
189+
190+
self.failUnlessEqual(42, l_convert("l", 42))
191+
self.failUnlessEqual(42, l_convert("l", 42L))
192+
self.assertRaises(OverflowError, l_convert, "l", VERY_LARGE)
193+
194+
195+
class LongLong_TestCase(unittest.TestCase):
196+
def test_L(self):
197+
# L returns 'long long', and does range checking (LLONG_MIN ... LLONG_MAX)
198+
199+
# XXX There's a bug in getargs.c, format code "L":
200+
# If you pass something else than a Python long, you
201+
# get "Bad argument to internal function".
202+
203+
# So these three tests are commented out:
204+
205+
## self.failUnlessEqual(3, ll_convert("L", 3.14))
206+
## self.failUnlessEqual(99, ll_convert("L", Long()))
207+
## self.failUnlessEqual(99, ll_convert("L", Int()))
208+
209+
self.assertRaises(OverflowError, ll_convert, "L", LLONG_MIN-1)
210+
self.failUnlessEqual(LLONG_MIN, ll_convert("L", LLONG_MIN))
211+
self.failUnlessEqual(LLONG_MAX, ll_convert("L", LLONG_MAX))
212+
self.assertRaises(OverflowError, ll_convert, "L", LLONG_MAX+1)
213+
214+
self.failUnlessEqual(42, ll_convert("L", 42))
215+
self.failUnlessEqual(42, ll_convert("L", 42L))
216+
self.assertRaises(OverflowError, ll_convert, "L", VERY_LARGE)
217+
218+
def test_K(self):
219+
# K return 'unsigned long long', no range checking
220+
self.assertRaises(TypeError, ull_convert, "K", 3.14)
221+
self.assertRaises(TypeError, ull_convert, "K", Long())
222+
self.assertRaises(TypeError, ull_convert, "K", Int())
223+
self.failUnlessEqual(ULLONG_MAX, ull_convert("K", ULLONG_MAX))
224+
self.failUnlessEqual(0, ull_convert("K", 0))
225+
self.failUnlessEqual(0, ull_convert("K", ULLONG_MAX+1))
226+
227+
self.failUnlessEqual(42, ull_convert("K", 42))
228+
self.failUnlessEqual(42, ull_convert("K", 42L))
229+
230+
self.failUnlessEqual(VERY_LARGE & ULLONG_MAX, ull_convert("K", VERY_LARGE))
231+
232+
def test_main():
233+
suite = unittest.TestSuite()
234+
suite.addTest(unittest.makeSuite(Signed_TestCase))
235+
suite.addTest(unittest.makeSuite(Unsigned_TestCase))
236+
try:
237+
ll_convert
238+
except NameError:
239+
pass # PY_LONG_LONG not available
240+
else:
241+
suite.addTest(unittest.makeSuite(LongLong_TestCase))
242+
test_support.run_suite(suite)
243+
244+
if __name__ == "__main__":
245+
test_main()

0 commit comments

Comments
 (0)