Skip to content

Commit c5e6b31

Browse files
authored
Merge pull request #46 from Eddy114514/imporve
Add warning for 5 features.
2 parents 723e0de + b3587e1 commit c5e6b31

8 files changed

Lines changed: 121 additions & 6 deletions

File tree

Include/ceval.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void);
3030
PyAPI_FUNC(PyObject *) PyEval_GetLocals(void);
3131
PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void);
3232
PyAPI_FUNC(int) PyEval_GetRestricted(void);
33+
PyAPI_FUNC(int) _Py3kWarn_NextOpcode(void);
3334

3435
/* Look at the current frame's (if any) code's co_flags, and turn on
3536
the corresponding compiler flags in cf->cf_flags. Return 1 if any

Lib/contextlib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ def __init__(self, gen):
1414

1515
def __enter__(self):
1616
try:
17-
return self.gen.next()
17+
return next(self.gen)
1818
except StopIteration:
1919
raise RuntimeError("generator didn't yield")
2020

2121
def __exit__(self, type, value, traceback):
2222
if type is None:
2323
try:
24-
self.gen.next()
24+
next(self.gen)
2525
except StopIteration:
2626
return
2727
else:

Lib/test/test_py3kwarn.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,34 @@ def test_sort_cmp_arg(self):
221221
w.reset()
222222
self.assertWarning(sorted(lst, cmp), w, expected)
223223

224+
def test_next_method(self):
225+
expected = 'iterator.next() is not supported in 3.x; use __next__() instead'
226+
it = iter(range(5))
227+
with check_py3k_warnings() as w:
228+
self.assertWarning(it.next(), w, expected)
229+
230+
def test_intern(self):
231+
expected = 'intern() is not supported in 3.x: use sys.intern() instead'
232+
with check_py3k_warnings() as w:
233+
self.assertWarning(intern('pygrate-next-method'), w, expected)
234+
235+
def test_range_materialization(self):
236+
expected = 'range() may require list materialization in 3.x'
237+
with check_py3k_warnings() as w:
238+
self.assertWarning(range(5) + [5], w, expected)
239+
240+
def test_xrange_materialization(self):
241+
expected = 'xrange() may require list materialization in 3.x'
242+
with check_py3k_warnings() as w:
243+
items = xrange(5)
244+
self.assertWarning(None, w, expected)
245+
246+
def test_dict_listlike_materialization(self):
247+
expected = 'dict.keys() may require list materialization in 3.x'
248+
d = {'a': 1, 'b': 2}
249+
with check_py3k_warnings() as w:
250+
self.assertWarning(d.keys()[0], w, expected)
251+
224252
def test_sys_exc_clear(self):
225253
expected = 'sys.exc_clear() not supported in 3.x; use except clauses'
226254
with check_py3k_warnings() as w:
@@ -288,9 +316,10 @@ def test_bytesio_truncate(self):
288316
from io import BytesIO
289317
x = BytesIO(b'AAAAAA')
290318
expected = "BytesIO.truncate() does not shift the file pointer: use seek(0) before doing truncate(0)"
291-
self.assertWarning(x.truncate(0), w, expected)
292-
w.reset()
293-
self.assertNoWarning(x.truncate(-1), w)
319+
with check_py3k_warnings() as w:
320+
self.assertWarning(x.truncate(0), w, expected)
321+
w.reset()
322+
self.assertNoWarning(x.truncate(-1), w)
294323

295324
def test_file_open(self):
296325
expected = ("The builtin 'file()'/'open()' function is not supported in 3.x, "

Objects/dictobject.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include "Python.h"
11+
#include "opcode.h"
1112

1213

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

31+
#define WARN_DICT_LISTLIKE(MSG) \
32+
do { \
33+
int nextop = _Py3kWarn_NextOpcode(); \
34+
if ((nextop == BINARY_SUBSCR || nextop == STORE_SUBSCR || \
35+
nextop == BINARY_ADD || nextop == INPLACE_ADD) && \
36+
PyErr_WarnPy3k((MSG), 1) < 0) \
37+
return NULL; \
38+
} while (0)
39+
3040
/* See large comment block below. This must be >= 1. */
3141
#define PERTURB_SHIFT 5
3242

@@ -1301,6 +1311,8 @@ dict_keys(register PyDictObject *mp)
13011311
PyDictEntry *ep;
13021312
Py_ssize_t mask, n;
13031313

1314+
WARN_DICT_LISTLIKE("dict.keys() may require list materialization in 3.x");
1315+
13041316
again:
13051317
n = mp->ma_used;
13061318
v = PyList_New(n);
@@ -1335,6 +1347,8 @@ dict_values(register PyDictObject *mp)
13351347
PyDictEntry *ep;
13361348
Py_ssize_t mask, n;
13371349

1350+
WARN_DICT_LISTLIKE("dict.values() may require list materialization in 3.x");
1351+
13381352
again:
13391353
n = mp->ma_used;
13401354
v = PyList_New(n);
@@ -1370,6 +1384,8 @@ dict_items(register PyDictObject *mp)
13701384
PyObject *item, *key, *value;
13711385
PyDictEntry *ep;
13721386

1387+
WARN_DICT_LISTLIKE("dict.items() may require list materialization in 3.x");
1388+
13731389
/* Preallocate the list of tuples, to avoid allocations during
13741390
* the loop over the items, which could trigger GC, which
13751391
* could resize the dict. :-(

Objects/rangeobject.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Range object implementation */
22

33
#include "Python.h"
4+
#include "opcode.h"
45

56
typedef struct {
67
PyObject_HEAD
@@ -67,8 +68,15 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
6768
rangeobject *obj;
6869
long ilow = 0, ihigh = 0, istep = 1;
6970
unsigned long n;
71+
int nextop;
7072

71-
if (PyErr_WarnPy3k_WithFix("xrange() is not supported in 3.x", "use range() instead", 1) < 0)
73+
nextop = _Py3kWarn_NextOpcode();
74+
if (nextop == GET_ITER &&
75+
PyErr_WarnPy3k_WithFix("xrange() is not supported in 3.x",
76+
"use range() instead", 1) < 0)
77+
return NULL;
78+
if (nextop != GET_ITER &&
79+
PyErr_WarnPy3k("xrange() may require list materialization in 3.x", 1) < 0)
7280
return NULL;
7381

7482
if (!_PyArg_NoKeywords("xrange()", kw))

Objects/typeobject.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4857,6 +4857,10 @@ wrap_next(PyObject *self, PyObject *args, void *wrapped)
48574857

48584858
if (!check_num_args(args, 0))
48594859
return NULL;
4860+
if (Py_TYPE(self)->tp_iter != NULL &&
4861+
PyErr_WarnPy3k("iterator.next() is not supported in 3.x; "
4862+
"use __next__() instead", 1) < 0)
4863+
return NULL;
48604864
res = (*func)(self);
48614865
if (res == NULL && !PyErr_Occurred())
48624866
PyErr_SetNone(PyExc_StopIteration);

Python/bltinmodule.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "node.h"
77
#include "code.h"
88
#include "eval.h"
9+
#include "opcode.h"
910

1011
#include <ctype.h>
1112
#include <float.h> /* for DBL_MANT_DIG and friends */
@@ -1282,6 +1283,9 @@ builtin_intern(PyObject *self, PyObject *args)
12821283
"can't intern subclass of string");
12831284
return NULL;
12841285
}
1286+
if (PyErr_WarnPy3k("intern() is not supported in 3.x: use sys.intern() instead",
1287+
1) < 0)
1288+
return NULL;
12851289
Py_INCREF(s);
12861290
PyString_InternInPlace(&s);
12871291
return s;
@@ -1970,9 +1974,15 @@ builtin_range(PyObject *self, PyObject *args)
19701974
long ilow = 0, ihigh = 0, istep = 1;
19711975
long bign;
19721976
Py_ssize_t i, n;
1977+
int nextop;
19731978

19741979
PyObject *v;
19751980

1981+
nextop = _Py3kWarn_NextOpcode();
1982+
if ((nextop == BINARY_ADD || nextop == INPLACE_ADD) &&
1983+
PyErr_WarnPy3k("range() may require list materialization in 3.x", 1) < 0)
1984+
return NULL;
1985+
19761986
if (PyTuple_Size(args) <= 1) {
19771987
if (!PyArg_ParseTuple(args,
19781988
"l;range() requires 1-3 int arguments",

Python/ceval.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,53 @@
1919

2020
#include <ctype.h>
2121

22+
int
23+
_Py3kWarn_NextOpcode(void)
24+
{
25+
PyFrameObject *frame;
26+
char *code;
27+
Py_ssize_t n;
28+
int offset;
29+
int op;
30+
int steps;
31+
32+
frame = PyEval_GetFrame();
33+
if (frame == NULL || frame->f_code == NULL)
34+
return -1;
35+
if (PyString_AsStringAndSize(frame->f_code->co_code, &code, &n) < 0) {
36+
PyErr_Clear();
37+
return -1;
38+
}
39+
40+
offset = frame->f_lasti;
41+
if (offset < 0 || offset >= n)
42+
return -1;
43+
44+
op = (unsigned char)code[offset];
45+
offset += 1;
46+
if (HAS_ARG(op))
47+
offset += 2;
48+
49+
/* These warnings only care about the immediate consumer of the
50+
just-evaluated call result. Looking ahead a handful of opcodes is
51+
enough to skip trivial stack setup before we either find a relevant
52+
consumer or hit a stop opcode showing the value has already been
53+
stored, returned, or discarded. */
54+
for (steps = 0; steps < 8 && offset >= 0 && offset < n; steps++) {
55+
op = (unsigned char)code[offset];
56+
if (op == BINARY_ADD || op == INPLACE_ADD || op == GET_ITER ||
57+
op == BINARY_SUBSCR || op == STORE_SUBSCR)
58+
return op;
59+
if (op == RETURN_VALUE || op == STORE_NAME || op == STORE_FAST ||
60+
op == STORE_GLOBAL || op == STORE_ATTR || op == POP_TOP)
61+
return -1;
62+
offset += 1;
63+
if (HAS_ARG(op))
64+
offset += 2;
65+
}
66+
return -1;
67+
}
68+
2269
#ifndef WITH_TSC
2370

2471
#define READ_TIMESTAMP(var)

0 commit comments

Comments
 (0)