SF bug #460020: bug or feature: unicode() and subclasses.
Given an immutable type M, and an instance I of a subclass of M, the constructor call M(I) was just returning I as-is; but it should return a new instance of M. This fixes it for M in {int, long}. Strings, floats and tuples remain to be done. Added new macros PyInt_CheckExact and PyLong_CheckExact, to more easily distinguish between "is" and "is a" (i.e., only an int passes PyInt_CheckExact, while any sublass of int passes PyInt_Check). Added private API function _PyLong_Copy.
This commit is contained in:
parent
8b4e43e768
commit
64b5ce3a69
|
@ -28,6 +28,7 @@ typedef struct {
|
|||
extern DL_IMPORT(PyTypeObject) PyInt_Type;
|
||||
|
||||
#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type)
|
||||
#define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type)
|
||||
|
||||
extern DL_IMPORT(PyObject *) PyInt_FromString(char*, char**, int);
|
||||
#ifdef Py_USING_UNICODE
|
||||
|
|
|
@ -46,6 +46,9 @@ struct _longobject {
|
|||
|
||||
DL_IMPORT(PyLongObject *) _PyLong_New(int);
|
||||
|
||||
/* Return a copy of src. */
|
||||
DL_IMPORT(PyObject *) _PyLong_Copy(PyLongObject *src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@ typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */
|
|||
extern DL_IMPORT(PyTypeObject) PyLong_Type;
|
||||
|
||||
#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type)
|
||||
#define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type)
|
||||
|
||||
extern DL_IMPORT(PyObject *) PyLong_FromLong(long);
|
||||
extern DL_IMPORT(PyObject *) PyLong_FromUnsignedLong(unsigned long);
|
||||
|
|
|
@ -1340,6 +1340,9 @@ def inherits():
|
|||
# because the int type gets first dibs.)
|
||||
verify(repr(hexint(7) + 9) == "0x10")
|
||||
verify(repr(hexint(1000) + 7) == "0x3ef")
|
||||
a = hexint(12345)
|
||||
#XXX verify(int(a) == 12345)
|
||||
verify(int(a).__class__ is int)
|
||||
|
||||
class octlong(long):
|
||||
__slots__ = []
|
||||
|
@ -1355,6 +1358,9 @@ def inherits():
|
|||
# (Note that overriding __radd__ here only seems to work
|
||||
# because the example uses a short int left argument.)
|
||||
verify(str(5 + octlong(3000)) == "05675")
|
||||
a = octlong(12345)
|
||||
#XXX verify(long(a) == 12345L)
|
||||
verify(long(a).__class__ is long)
|
||||
|
||||
class precfloat(float):
|
||||
__slots__ = ['prec']
|
||||
|
@ -1364,6 +1370,9 @@ def inherits():
|
|||
def __repr__(self):
|
||||
return "%.*g" % (self.prec, self)
|
||||
verify(repr(precfloat(1.1)) == "1.1")
|
||||
a = precfloat(12345)
|
||||
#XXX verify(float(a) == 12345.0)
|
||||
#XXX verify(float(a).__class__ is float)
|
||||
|
||||
class madtuple(tuple):
|
||||
_rev = None
|
||||
|
@ -1382,6 +1391,12 @@ def inherits():
|
|||
u = t.rev()
|
||||
v = u.rev()
|
||||
verify(v == t)
|
||||
a = madtuple((1,2,3,4,5))
|
||||
verify(tuple(a) == (1,2,3,4,5))
|
||||
#XXX verify(tuple(a).__class__ is tuple)
|
||||
a = madtuple(())
|
||||
verify(tuple(a) == ())
|
||||
#XXX verify(tuple(a).__class__ is tuple)
|
||||
|
||||
class madstring(str):
|
||||
_rev = None
|
||||
|
@ -1400,6 +1415,9 @@ def inherits():
|
|||
t = s.rev()
|
||||
u = t.rev()
|
||||
verify(u == s)
|
||||
s = madstring("12345")
|
||||
#XXX verify(str(s) == "12345")
|
||||
#XXX verify(str(s).__class__ is str)
|
||||
|
||||
class madunicode(unicode):
|
||||
_rev = None
|
||||
|
@ -1413,6 +1431,9 @@ def inherits():
|
|||
u = madunicode("ABCDEF")
|
||||
verify(u.rev() == madunicode(u"FEDCBA"))
|
||||
verify(u.rev().rev() == madunicode(u"ABCDEF"))
|
||||
u = madunicode(u"12345")
|
||||
verify(unicode(u) == u"12345")
|
||||
#XXX verify(unicode(u).__class__ is unicode)
|
||||
|
||||
def all():
|
||||
lists()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Python.h"
|
||||
#include <ctype.h>
|
||||
#include "structmember.h" /* we need the offsetof() macro from there */
|
||||
#include "longintrepr.h"
|
||||
|
||||
#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
|
||||
Py_TPFLAGS_CHECKTYPES)
|
||||
|
@ -818,10 +819,14 @@ PyNumber_Int(PyObject *o)
|
|||
|
||||
if (o == NULL)
|
||||
return null_error();
|
||||
if (PyInt_Check(o)) {
|
||||
if (PyInt_CheckExact(o)) {
|
||||
Py_INCREF(o);
|
||||
return o;
|
||||
}
|
||||
if (PyInt_Check(o)) {
|
||||
PyIntObject *io = (PyIntObject*)o;
|
||||
return PyInt_FromLong(io->ob_ival);
|
||||
}
|
||||
if (PyString_Check(o))
|
||||
return int_from_string(PyString_AS_STRING(o),
|
||||
PyString_GET_SIZE(o));
|
||||
|
@ -868,10 +873,12 @@ PyNumber_Long(PyObject *o)
|
|||
|
||||
if (o == NULL)
|
||||
return null_error();
|
||||
if (PyLong_Check(o)) {
|
||||
if (PyLong_CheckExact(o)) {
|
||||
Py_INCREF(o);
|
||||
return o;
|
||||
}
|
||||
if (PyLong_Check(o))
|
||||
return _PyLong_Copy((PyLongObject *)o);
|
||||
if (PyString_Check(o))
|
||||
/* need to do extra error checking that PyLong_FromString()
|
||||
* doesn't do. In particular long('9.5') must raise an
|
||||
|
|
|
@ -51,6 +51,25 @@ _PyLong_New(int size)
|
|||
return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyLong_Copy(PyLongObject *src)
|
||||
{
|
||||
PyLongObject *result;
|
||||
int i;
|
||||
|
||||
assert(src != NULL);
|
||||
i = src->ob_size;
|
||||
if (i < 0)
|
||||
i = -(i);
|
||||
result = _PyLong_New(i);
|
||||
if (result != NULL) {
|
||||
result->ob_size = i;
|
||||
while (--i >= 0)
|
||||
result->ob_digit[i] = src->ob_digit[i];
|
||||
}
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
/* Create a new long int object from a C long int */
|
||||
|
||||
PyObject *
|
||||
|
@ -2205,7 +2224,7 @@ long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds);
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
assert(PyLong_Check(tmp));
|
||||
assert(PyLong_CheckExact(tmp));
|
||||
n = tmp->ob_size;
|
||||
if (n < 0)
|
||||
n = -n;
|
||||
|
|
Loading…
Reference in New Issue