[pypy-commit] pypy py3.6: Use same logic as CPython in int.__new__ and fix yet another corner case
rlamy
pypy.commits at gmail.com
Thu Aug 22 11:49:40 EDT 2019
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.6
Changeset: r97244:1a1112535b61
Date: 2019-08-22 16:47 +0100
http://bitbucket.org/pypy/pypy/changeset/1a1112535b61/
Log: Use same logic as CPython in int.__new__ and fix yet another corner
case
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -296,7 +296,6 @@
"expected %s, got %T object", expected, self)
def int(self, space):
- from pypy.objspace.std.intobject import _new_int
w_impl = space.lookup(self, '__int__')
if w_impl is None:
self._typed_unwrap_error(space, "integer")
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -9,7 +9,7 @@
import sys
from rpython.rlib import jit
-from rpython.rlib.objectmodel import instantiate
+from rpython.rlib.objectmodel import instantiate, enforceargs
from rpython.rlib.rarithmetic import (
LONG_BIT, intmask, is_valid_int, ovfcheck, r_longlong, r_uint,
string_to_int)
@@ -851,80 +851,49 @@
sys.maxint == 2147483647)
-def _string_to_int_or_long(space, w_inttype, w_source, string, base=10):
+def _string_to_int_or_long(space, w_source, string, base=10):
try:
- value = string_to_int(string, base, allow_underscores=True, no_implicit_octal=True)
+ value = string_to_int(
+ string, base, allow_underscores=True, no_implicit_octal=True)
+ return wrapint(space, value)
except ParseStringError as e:
raise wrap_parsestringerror(space, e, w_source)
except ParseStringOverflowError as e:
- return _retry_to_w_long(space, e.parser, w_inttype, w_source)
+ return _retry_to_w_long(space, e.parser, w_source)
- if space.is_w(w_inttype, space.w_int):
- w_result = wrapint(space, value)
- else:
- w_result = space.allocate_instance(W_IntObject, w_inttype)
- W_IntObject.__init__(w_result, value)
- return w_result
-
-def _retry_to_w_long(space, parser, w_inttype, w_source):
+def _retry_to_w_long(space, parser, w_source):
from pypy.objspace.std.longobject import newbigint
parser.rewind()
try:
bigint = rbigint._from_numberstring_parser(parser)
except ParseStringError as e:
raise wrap_parsestringerror(space, e, w_source)
- return newbigint(space, w_inttype, bigint)
+ return newbigint(space, space.w_int, bigint)
def _new_int(space, w_inttype, w_x, w_base=None):
- from pypy.objspace.std.longobject import (
- W_AbstractLongObject, W_LongObject, newlong, newbigint)
- if space.config.objspace.std.withsmalllong:
- from pypy.objspace.std.smalllongobject import W_SmallLongObject
+ w_value = w_x # 'x' is the keyword argument name in CPython
+ if w_inttype is space.w_int:
+ return _new_baseint(space, w_x, w_base)
else:
- W_SmallLongObject = None
+ w_tmp = _new_baseint(space, w_x, w_base)
+ return _as_subint(space, w_inttype, w_tmp)
- w_longval = None
- w_value = w_x # 'x' is the keyword argument name in CPython
- value = 0
+def _new_baseint(space, w_value, w_base=None):
if w_base is None:
- #import pdb; pdb.set_trace()
- # check for easy cases
- if type(w_value) is W_IntObject:
- if space.is_w(w_inttype, space.w_int):
- return w_value
- value = w_value.intval
- w_obj = space.allocate_instance(W_IntObject, w_inttype)
- W_IntObject.__init__(w_obj, value)
- return w_obj
- elif type(w_value) is W_LongObject:
- if space.is_w(w_inttype, space.w_int):
- return w_value
- return newbigint(space, w_inttype, w_value.num)
- elif W_SmallLongObject and type(w_value) is W_SmallLongObject:
- if space.is_w(w_inttype, space.w_int):
- return w_value
- return newbigint(space, w_inttype, space.bigint_w(w_value))
+ if space.is_w(space.type(w_value), space.w_int):
+ assert isinstance(w_value, W_AbstractIntObject)
+ return w_value
elif space.lookup(w_value, '__int__') is not None:
w_intvalue = space.int(w_value)
- if isinstance(w_intvalue, W_IntObject):
- if type(w_intvalue) is not W_IntObject:
- w_intvalue = wrapint(space, w_intvalue.intval)
- return _new_int(space, w_inttype, w_intvalue)
- elif isinstance(w_intvalue, W_AbstractLongObject):
- if type(w_intvalue) is not W_LongObject:
- w_intvalue = newlong(space, w_intvalue.asbigint())
- return _new_int(space, w_inttype, w_intvalue)
- else:
- # shouldn't happen
- raise oefmt(space.w_RuntimeError,
- "internal error in int.__new__()")
+ return _ensure_baseint(space, w_intvalue)
elif space.lookup(w_value, '__trunc__') is not None:
w_obj = space.trunc(w_value)
- if not space.is_w(space.type(w_obj), space.w_int):
+ if not space.isinstance_w(w_obj, space.w_int):
w_obj = space.int(w_obj)
- return _from_intlike(space, w_inttype, w_obj)
+ assert isinstance(w_obj, W_AbstractIntObject)
+ return _ensure_baseint(space, w_obj)
elif space.isinstance_w(w_value, space.w_unicode):
from pypy.objspace.std.unicodeobject import unicode_to_decimal_w
try:
@@ -933,10 +902,10 @@
raise oefmt(space.w_ValueError,
'invalid literal for int() with base 10: %R',
w_value)
- return _string_to_int_or_long(space, w_inttype, w_value, b)
+ return _string_to_int_or_long(space, w_value, b)
elif (space.isinstance_w(w_value, space.w_bytearray) or
space.isinstance_w(w_value, space.w_bytes)):
- return _string_to_int_or_long(space, w_inttype, w_value,
+ return _string_to_int_or_long(space, w_value,
space.charbuf_w(w_value))
else:
# If object supports the buffer interface
@@ -949,7 +918,7 @@
"int() argument must be a string, a bytes-like "
"object or a number, not '%T'", w_value)
else:
- return _string_to_int_or_long(space, w_inttype, w_value, buf)
+ return _string_to_int_or_long(space, w_value, buf)
else:
try:
base = space.getindex_w(w_base, None)
@@ -973,14 +942,40 @@
raise oefmt(space.w_TypeError,
"int() can't convert non-string with explicit base")
- return _string_to_int_or_long(space, w_inttype, w_value, s, base)
+ return _string_to_int_or_long(space, w_value, s, base)
+ at enforceargs(None, None, W_AbstractIntObject, typecheck=False)
+def _as_subint(space, w_inttype, w_value):
+ from pypy.objspace.std.longobject import W_LongObject, newbigint
+ if space.config.objspace.std.withsmalllong:
+ from pypy.objspace.std.smalllongobject import W_SmallLongObject
+ else:
+ W_SmallLongObject = None
+ if type(w_value) is W_IntObject:
+ w_obj = space.allocate_instance(W_IntObject, w_inttype)
+ W_IntObject.__init__(w_obj, w_value.intval)
+ return w_obj
+ elif type(w_value) is W_LongObject:
+ return newbigint(space, w_inttype, w_value.num)
+ elif W_SmallLongObject and type(w_value) is W_SmallLongObject:
+ return newbigint(space, w_inttype, space.bigint_w(w_value))
-def _from_intlike(space, w_inttype, w_intlike):
- if space.is_w(w_inttype, space.w_int):
- return w_intlike
- from pypy.objspace.std.longobject import newbigint
- return newbigint(space, w_inttype, space.bigint_w(w_intlike))
+#@enforceargs(None, W_AbstractIntObject, typecheck=False)
+def _ensure_baseint(space, w_intvalue):
+ from pypy.objspace.std.longobject import (
+ W_LongObject, W_AbstractLongObject, newlong)
+ if isinstance(w_intvalue, W_IntObject):
+ if type(w_intvalue) is not W_IntObject:
+ w_intvalue = wrapint(space, w_intvalue.intval)
+ return w_intvalue
+ elif isinstance(w_intvalue, W_AbstractLongObject):
+ if type(w_intvalue) is not W_LongObject:
+ w_intvalue = newlong(space, w_intvalue.asbigint())
+ return w_intvalue
+ else:
+ # shouldn't happen
+ raise oefmt(space.w_RuntimeError,
+ "internal error in int.__new__()")
W_AbstractIntObject.typedef = TypeDef("int",
diff --git a/pypy/objspace/std/test/test_intobject.py b/pypy/objspace/std/test/test_intobject.py
--- a/pypy/objspace/std/test/test_intobject.py
+++ b/pypy/objspace/std/test/test_intobject.py
@@ -533,6 +533,19 @@
assert n == 1
assert type(n) is int
+ def test_trunc_returns_int_subclass_2(self):
+ class BadInt:
+ def __int__(self):
+ return True
+
+ class TruncReturnsBadInt:
+ def __trunc__(self):
+ return BadInt()
+ bad_int = TruncReturnsBadInt()
+ n = int(bad_int)
+ assert n == 1
+ assert type(n) is int
+
def test_int_before_string(self):
class Integral(str):
def __int__(self):
More information about the pypy-commit
mailing list