diff --git a/Include/cpython/floatobject.h b/Include/cpython/floatobject.h index 7795d9f83f..84c2726bcc 100644 --- a/Include/cpython/floatobject.h +++ b/Include/cpython/floatobject.h @@ -5,12 +5,17 @@ typedef struct { PyObject_HEAD double ob_fval; + unsigned char ob_randomflag; } PyFloatObject; +#define NOT_FROM_RANDOM 0 +#define FROM_RANDOM 1 + // Macro version of PyFloat_AsDouble() trading safety for speed. // It doesn't check if op is a double object. #define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval) +PyAPI_FUNC(PyObject *) _PyFloat_FromDoubleWithFlags(double x, unsigned char flags); PyAPI_FUNC(int) PyFloat_Pack2(double x, char *p, int le); PyAPI_FUNC(int) PyFloat_Pack4(double x, char *p, int le); diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h index 758aaff2d7..4178b90c31 100644 --- a/Include/cpython/unicodeobject.h +++ b/Include/cpython/unicodeobject.h @@ -135,7 +135,8 @@ typedef struct { unsigned int ascii:1; /* Padding to ensure that PyUnicode_DATA() is always aligned to 4 bytes (see issue #19537 on m68k). */ - unsigned int :25; + unsigned int ob_randomflag:1; + unsigned int :24; } state; } PyASCIIObject; @@ -500,6 +501,11 @@ PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII( const char *buffer, Py_ssize_t size); +PyAPI_FUNC(PyObject*) _PyUnicode_FromASCII_withRandomFlag( + const char *buffer, + Py_ssize_t size, + unsigned char flag); + /* Compute the maximum character of the substring unicode[start:end]. Return 127 for an empty string. */ PyAPI_FUNC(Py_UCS4) _PyUnicode_FindMaxChar ( diff --git a/Lib/test/test_py2xwarn.py b/Lib/test/test_py2xwarn.py index 494c1a7234..1e482fcf70 100644 --- a/Lib/test/test_py2xwarn.py +++ b/Lib/test/test_py2xwarn.py @@ -38,6 +38,14 @@ def test_next(self): w.reset() self.assertNoWarning(iterator_marks.__next__(), w) + def test_random(self): + expected = "String repr of random.random() is longer in 3.x, change code accordingly" + import random + with check_py2x_warnings(("", Py2xWarning)) as w: + self.assertWarning(len(str(random.random())), w, expected) + w.reset() + self.assertNoWarning(len(str(0.123456)), w) + def test_truncate0(self): expected = "Calling truncate(0) on text stream without seek(0)" + \ " may produce inconsistent results. Use seek(0) before truncate(0)" diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 630de3c757..0df99859c5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1390,7 +1390,11 @@ class C(object): pass # reverse check(reversed(''), size('nP')) # float - check(float(0), size('d')) + if sys.py2x_warning: + # plus 8 to reflect struct change for unsigned char ob_randomflag + check(float(0), size('d')+8) + else: + check(float(0), size('d')+8) # sys.floatinfo check(sys.float_info, vsize('') + self.P * len(sys.float_info)) # frame diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index d96c0371ec..4fc03aa24a 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -177,7 +177,11 @@ _random_Random_random_impl(RandomObject *self) /*[clinic end generated code: output=117ff99ee53d755c input=afb2a59cbbb00349]*/ { uint32_t a=genrand_uint32(self)>>5, b=genrand_uint32(self)>>6; - return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0)); + double x = (a * 67108864.0 + b) * (1.0 / 9007199254740992.0); + if (Py_Py2xWarningFlag) + return _PyFloat_FromDoubleWithFlags(x, FROM_RANDOM); + else + return PyFloat_FromDouble(x); } /* initializes mt[N] with a seed */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 86861b7e28..9dfd2f92c5 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -153,9 +153,20 @@ PyFloat_FromDouble(double fval) } _PyObject_Init((PyObject*)op, &PyFloat_Type); op->ob_fval = fval; + op->ob_randomflag = NOT_FROM_RANDOM; return (PyObject *) op; } +PyObject * +_PyFloat_FromDoubleWithFlags(double x, unsigned char flag) +{ + PyObject *o = PyFloat_FromDouble(x); + if (o == NULL) + return NULL; + ((PyFloatObject *)o)->ob_randomflag = flag; + return o; +} + static PyObject * float_from_string_inner(const char *s, Py_ssize_t len, void *obj) { @@ -376,14 +387,16 @@ float_repr(PyFloatObject *v) { PyObject *result; char *buf; - buf = PyOS_double_to_string(PyFloat_AS_DOUBLE(v), 'r', 0, Py_DTSF_ADD_DOT_0, NULL); if (!buf) return PyErr_NoMemory(); - result = _PyUnicode_FromASCII(buf, strlen(buf)); + if (Py_Py2xWarningFlag) + result = _PyUnicode_FromASCII_withRandomFlag(buf, strlen(buf), v->ob_randomflag); + else + result = _PyUnicode_FromASCII(buf, strlen(buf)); PyMem_Free(buf); return result; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e935829072..0d8b2dc9be 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1189,6 +1189,7 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) _PyUnicode_STATE(unicode).kind = kind; _PyUnicode_STATE(unicode).compact = 1; _PyUnicode_STATE(unicode).ascii = is_ascii; + _PyUnicode_STATE(unicode).ob_randomflag = NOT_FROM_RANDOM; if (is_ascii) { ((char*)data)[size] = 0; } @@ -1935,6 +1936,16 @@ _PyUnicode_FromASCII(const char *buffer, Py_ssize_t size) return unicode; } +PyObject* +_PyUnicode_FromASCII_withRandomFlag(const char *buffer, Py_ssize_t size, unsigned char flag) +{ + PyObject *o = _PyUnicode_FromASCII(buffer, size); + if (o == NULL) + return NULL; + ((PyASCIIObject *)o)->state.ob_randomflag = flag; + return o; +} + static Py_UCS4 kind_maxchar_limit(int kind) { @@ -11605,7 +11616,12 @@ unicode_join(PyObject *self, PyObject *iterable) static Py_ssize_t unicode_length(PyObject *self) -{ +{ + if(Py_Py2xWarningFlag && PyUnicode_Check(self) && ((PyASCIIObject *)self)->state.ob_randomflag == 1) + PyErr_WarnEx( + PyExc_Py2xWarning, + "String repr of random.random() is longer in 3.x, change code accordingly", + 1); return PyUnicode_GET_LENGTH(self); }