Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
PyAPI_FUNC(int) PyEval_GetRestricted(void);
PyAPI_FUNC(int) _Py3kWarn_NextOpcode(void);

/* Look at the current frame's (if any) code's co_flags, and turn on
the corresponding compiler flags in cf->cf_flags. Return 1 if any
Expand Down
4 changes: 2 additions & 2 deletions Lib/contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ def __init__(self, gen):

def __enter__(self):
try:
return self.gen.next()
return next(self.gen)
except StopIteration:
raise RuntimeError("generator didn't yield")

def __exit__(self, type, value, traceback):
if type is None:
try:
self.gen.next()
next(self.gen)
except StopIteration:
return
else:
Expand Down
35 changes: 32 additions & 3 deletions Lib/test/test_py3kwarn.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,34 @@ def test_sort_cmp_arg(self):
w.reset()
self.assertWarning(sorted(lst, cmp), w, expected)

def test_next_method(self):
expected = 'iterator.next() is not supported in 3.x; use __next__() instead'
it = iter(range(5))
with check_py3k_warnings() as w:
self.assertWarning(it.next(), w, expected)

def test_intern(self):
expected = 'intern() is not supported in 3.x: use sys.intern() instead'
with check_py3k_warnings() as w:
self.assertWarning(intern('pygrate-next-method'), w, expected)

def test_range_materialization(self):
expected = 'range() may require list materialization in 3.x'
with check_py3k_warnings() as w:
self.assertWarning(range(5) + [5], w, expected)

def test_xrange_materialization(self):
expected = 'xrange() may require list materialization in 3.x'
with check_py3k_warnings() as w:
items = xrange(5)
self.assertWarning(None, w, expected)

def test_dict_listlike_materialization(self):
expected = 'dict.keys() may require list materialization in 3.x'
d = {'a': 1, 'b': 2}
with check_py3k_warnings() as w:
self.assertWarning(d.keys()[0], w, expected)

def test_sys_exc_clear(self):
expected = 'sys.exc_clear() not supported in 3.x; use except clauses'
with check_py3k_warnings() as w:
Expand Down Expand Up @@ -288,9 +316,10 @@ def test_bytesio_truncate(self):
from io import BytesIO
x = BytesIO(b'AAAAAA')
expected = "BytesIO.truncate() does not shift the file pointer: use seek(0) before doing truncate(0)"
self.assertWarning(x.truncate(0), w, expected)
w.reset()
self.assertNoWarning(x.truncate(-1), w)
with check_py3k_warnings() as w:
self.assertWarning(x.truncate(0), w, expected)
w.reset()
self.assertNoWarning(x.truncate(-1), w)

def test_file_open(self):
expected = ("The builtin 'file()'/'open()' function is not supported in 3.x, "
Expand Down
16 changes: 16 additions & 0 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

#include "Python.h"
#include "opcode.h"


/* Set a key error with the specified argument, wrapping it in a
Expand All @@ -27,6 +28,15 @@ set_key_error(PyObject *arg)
/* Define this out if you don't want conversion statistics on exit. */
#undef SHOW_CONVERSION_COUNTS

#define WARN_DICT_LISTLIKE(MSG) \
do { \
int nextop = _Py3kWarn_NextOpcode(); \
if ((nextop == BINARY_SUBSCR || nextop == STORE_SUBSCR || \
nextop == BINARY_ADD || nextop == INPLACE_ADD) && \
PyErr_WarnPy3k((MSG), 1) < 0) \
return NULL; \
} while (0)

/* See large comment block below. This must be >= 1. */
#define PERTURB_SHIFT 5

Expand Down Expand Up @@ -1301,6 +1311,8 @@ dict_keys(register PyDictObject *mp)
PyDictEntry *ep;
Py_ssize_t mask, n;

WARN_DICT_LISTLIKE("dict.keys() may require list materialization in 3.x");

again:
n = mp->ma_used;
v = PyList_New(n);
Expand Down Expand Up @@ -1335,6 +1347,8 @@ dict_values(register PyDictObject *mp)
PyDictEntry *ep;
Py_ssize_t mask, n;

WARN_DICT_LISTLIKE("dict.values() may require list materialization in 3.x");

again:
n = mp->ma_used;
v = PyList_New(n);
Expand Down Expand Up @@ -1370,6 +1384,8 @@ dict_items(register PyDictObject *mp)
PyObject *item, *key, *value;
PyDictEntry *ep;

WARN_DICT_LISTLIKE("dict.items() may require list materialization in 3.x");

/* Preallocate the list of tuples, to avoid allocations during
* the loop over the items, which could trigger GC, which
* could resize the dict. :-(
Expand Down
10 changes: 9 additions & 1 deletion Objects/rangeobject.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* Range object implementation */

#include "Python.h"
#include "opcode.h"

typedef struct {
PyObject_HEAD
Expand Down Expand Up @@ -67,8 +68,15 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
rangeobject *obj;
long ilow = 0, ihigh = 0, istep = 1;
unsigned long n;
int nextop;

if (PyErr_WarnPy3k_WithFix("xrange() is not supported in 3.x", "use range() instead", 1) < 0)
nextop = _Py3kWarn_NextOpcode();
if (nextop == GET_ITER &&
PyErr_WarnPy3k_WithFix("xrange() is not supported in 3.x",
"use range() instead", 1) < 0)
return NULL;
if (nextop != GET_ITER &&
PyErr_WarnPy3k("xrange() may require list materialization in 3.x", 1) < 0)
return NULL;

if (!_PyArg_NoKeywords("xrange()", kw))
Expand Down
4 changes: 4 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -4857,6 +4857,10 @@ wrap_next(PyObject *self, PyObject *args, void *wrapped)

if (!check_num_args(args, 0))
return NULL;
if (Py_TYPE(self)->tp_iter != NULL &&
PyErr_WarnPy3k("iterator.next() is not supported in 3.x; "
"use __next__() instead", 1) < 0)
return NULL;
res = (*func)(self);
if (res == NULL && !PyErr_Occurred())
PyErr_SetNone(PyExc_StopIteration);
Expand Down
10 changes: 10 additions & 0 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "node.h"
#include "code.h"
#include "eval.h"
#include "opcode.h"

#include <ctype.h>
#include <float.h> /* for DBL_MANT_DIG and friends */
Expand Down Expand Up @@ -1282,6 +1283,9 @@ builtin_intern(PyObject *self, PyObject *args)
"can't intern subclass of string");
return NULL;
}
if (PyErr_WarnPy3k("intern() is not supported in 3.x: use sys.intern() instead",
1) < 0)
return NULL;
Py_INCREF(s);
PyString_InternInPlace(&s);
return s;
Expand Down Expand Up @@ -1970,9 +1974,15 @@ builtin_range(PyObject *self, PyObject *args)
long ilow = 0, ihigh = 0, istep = 1;
long bign;
Py_ssize_t i, n;
int nextop;

PyObject *v;

nextop = _Py3kWarn_NextOpcode();
if ((nextop == BINARY_ADD || nextop == INPLACE_ADD) &&
PyErr_WarnPy3k("range() may require list materialization in 3.x", 1) < 0)
return NULL;

if (PyTuple_Size(args) <= 1) {
if (!PyArg_ParseTuple(args,
"l;range() requires 1-3 int arguments",
Expand Down
47 changes: 47 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,53 @@

#include <ctype.h>

int
_Py3kWarn_NextOpcode(void)
{
PyFrameObject *frame;
char *code;
Py_ssize_t n;
int offset;
int op;
int steps;

frame = PyEval_GetFrame();
if (frame == NULL || frame->f_code == NULL)
return -1;
if (PyString_AsStringAndSize(frame->f_code->co_code, &code, &n) < 0) {
PyErr_Clear();
return -1;
}

offset = frame->f_lasti;
if (offset < 0 || offset >= n)
return -1;

op = (unsigned char)code[offset];
offset += 1;
if (HAS_ARG(op))
offset += 2;

/* These warnings only care about the immediate consumer of the
just-evaluated call result. Looking ahead a handful of opcodes is
enough to skip trivial stack setup before we either find a relevant
consumer or hit a stop opcode showing the value has already been
stored, returned, or discarded. */
for (steps = 0; steps < 8 && offset >= 0 && offset < n; steps++) {
op = (unsigned char)code[offset];
if (op == BINARY_ADD || op == INPLACE_ADD || op == GET_ITER ||
op == BINARY_SUBSCR || op == STORE_SUBSCR)
return op;
if (op == RETURN_VALUE || op == STORE_NAME || op == STORE_FAST ||
op == STORE_GLOBAL || op == STORE_ATTR || op == POP_TOP)
return -1;
offset += 1;
if (HAS_ARG(op))
offset += 2;
}
return -1;
}

#ifndef WITH_TSC

#define READ_TIMESTAMP(var)
Expand Down