Skip to content

Commit 3caca23

Browse files
committed
SF bug #488514: -Qnew needs work
Big Hammer to implement -Qnew as PEP 238 says it should work (a global option affecting all instances of "/"). pydebug.h, main.c, pythonrun.c: define a private _Py_QnewFlag flag, true iff -Qnew is passed on the command line. This should go away (as the comments say) when true division becomes The Rule. This is deliberately not exposed to runtime inspection or modification: it's a one-way one-shot switch to pretend you're using Python 3. ceval.c: when _Py_QnewFlag is set, treat BINARY_DIVIDE as BINARY_TRUE_DIVIDE. test_{descr, generators, zipfile}.py: fiddle so these pass under -Qnew too. This was just a matter of s!/!//! in test_generators and test_zipfile. test_descr was trickier, as testbinop() is passed assumptions that "/" is the same as calling a "__div__" method; put a temporary hack there to call "__truediv__" instead when the method name is "__div__" and 1/2 evaluates to 0.5. Three standard tests still fail under -Qnew (on Windows; somebody please try the Linux tests with -Qnew too! Linux runs a whole bunch of tests Windows doesn't): test_augassign test_class test_coercion I can't stay awake longer to stare at this (be my guest). Offhand cures weren't obvious, nor was it even obvious that cures are possible without major hackery. Question: when -Qnew is in effect, should calls to __div__ magically change into calls to __truediv__? See "major hackery" at tail end of last paragraph <wink>.
1 parent e50959a commit 3caca23

8 files changed

Lines changed: 55 additions & 25 deletions

File tree

‎Include/pydebug.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ extern DL_IMPORT(int) Py_TabcheckFlag;
1616
extern DL_IMPORT(int) Py_UnicodeFlag;
1717
extern DL_IMPORT(int) Py_IgnoreEnvironmentFlag;
1818
extern DL_IMPORT(int) Py_DivisionWarningFlag;
19+
/* _XXX Py_QnewFlag should go away in 2.3. It's true iff -Qnew is passed,
20+
on the command line, and is used in 2.2 by ceval.c to make all "/" divisions
21+
true divisions (which they will be in 2.3). */
22+
extern DL_IMPORT(int) _Py_QnewFlag;
1923

2024
/* this is a wrapper around getenv() that pays attention to
2125
Py_IgnoreEnvironmentFlag. It should be used for getting variables like

‎Lib/test/test_descr.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ def testunop(a, res, expr="len(a)", meth="__len__"):
2323
def testbinop(a, b, res, expr="a+b", meth="__add__"):
2424
if verbose: print "checking", expr
2525
dict = {'a': a, 'b': b}
26+
27+
# XXX Hack so this passes before 2.3 when -Qnew is specified.
28+
if meth == "__div__" and 1/2 == 0.5:
29+
meth = "__truediv__"
30+
2631
vereq(eval(expr, dict), res)
2732
t = type(a)
2833
m = getattr(t, meth)

‎Lib/test/test_generators.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@
182182
Specification: Generators and Exception Propagation
183183
184184
>>> def f():
185-
... return 1/0
185+
... return 1//0
186186
>>> def g():
187187
... yield f() # the zero division exception propagates
188188
... yield 42 # and we'll never get here
@@ -206,7 +206,7 @@
206206
... yield 1
207207
... try:
208208
... yield 2
209-
... 1/0
209+
... 1//0
210210
... yield 3 # never get here
211211
... except ZeroDivisionError:
212212
... yield 4
@@ -253,7 +253,7 @@
253253
... n = len(list)
254254
... if n == 0:
255255
... return []
256-
... i = n / 2
256+
... i = n // 2
257257
... return Tree(list[i], tree(list[:i]), tree(list[i+1:]))
258258
259259
>>> # Show it off: create a tree.
@@ -691,7 +691,7 @@
691691
>>> def f():
692692
... try:
693693
... try:
694-
... 1/0
694+
... 1//0
695695
... except ZeroDivisionError:
696696
... yield 666 # bad because *outer* try has finally
697697
... except:
@@ -708,7 +708,7 @@
708708
... try:
709709
... try:
710710
... yield 12
711-
... 1/0
711+
... 1//0
712712
... except ZeroDivisionError:
713713
... yield 666
714714
... except:
@@ -751,7 +751,7 @@
751751
... pass
752752
... elif 0:
753753
... try:
754-
... 1/0
754+
... 1//0
755755
... except SyntaxError:
756756
... pass
757757
... else:

‎Lib/zipfile.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def FileHeader(self):
117117
"""Return the per-file header as a string."""
118118
dt = self.date_time
119119
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
120-
dostime = dt[3] << 11 | dt[4] << 5 | dt[5] / 2
120+
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
121121
if self.flag_bits & 0x08:
122122
# Set these to zero because we write them after the file data
123123
CRC = compress_size = file_size = 0
@@ -468,7 +468,7 @@ def close(self):
468468
count = count + 1
469469
dt = zinfo.date_time
470470
dosdate = (dt[0] - 1980) << 9 | dt[1] << 5 | dt[2]
471-
dostime = dt[3] << 11 | dt[4] << 5 | dt[5] / 2
471+
dostime = dt[3] << 11 | dt[4] << 5 | (dt[5] // 2)
472472
centdir = struct.pack(structCentralDir,
473473
stringCentralDir, zinfo.create_version,
474474
zinfo.create_system, zinfo.extract_version, zinfo.reserved,

‎Misc/NEWS‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Type/class unification and new-style classes
3939

4040
Core and builtins
4141

42+
- -Qnew now works as documented in PEP 238: when -Qnew is passed on
43+
the command line, all occurrences of "/" use true division instead
44+
of classic division. See the PEP for details. Note that "all"
45+
means all instances in library and 3rd-party modules, as well as in
46+
your own code. As the PEP says, -Qnew is intended for use only in
47+
educational environments with control over the libraries in use.
48+
4249
Extension modules
4350

4451
- gc.get_referents was renamed to gc.get_referrers.
@@ -712,11 +719,15 @@ Core
712719
warnings are issued. Using -Qwarn issues a run-time warning about
713720
all uses of classic division for int and long arguments; -Qwarnall
714721
also warns about classic division for float and complex arguments
715-
(for use with fixdiv.py). Using -Qnew is questionable; it turns on
716-
new division by default, but only in the __main__ module. You can
717-
usefully combine -Qwarn or -Qwarnall and -Qnew: this gives the
718-
__main__ module new division, and warns about classic division
719-
everywhere else.
722+
(for use with fixdiv.py).
723+
[Note: the remainder of this paragraph (preserved below) became
724+
obsolete in 2.2c1 -- -Qnew has global effect in 2.2]
725+
<obsolete>
726+
Using -Qnew is questionable; it turns on new division by default, but
727+
only in the __main__ module. You can usefully combine -Qwarn or
728+
-Qwarnall and -Qnew: this gives the __main__ module new division, and
729+
warns about classic division everywhere else.
730+
</obsolete>
720731

721732
- Many built-in types can now be subclassed. This applies to int,
722733
long, float, str, unicode, and tuple. (The types complex, list and

‎Modules/main.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,11 @@ Py_Main(int argc, char **argv)
169169
break;
170170
}
171171
if (strcmp(_PyOS_optarg, "new") == 0) {
172-
/* XXX This only affects __main__ */
172+
/* This only affects __main__ */
173173
cf.cf_flags |= CO_FUTURE_DIVISION;
174+
/* And this tells the eval loop to treat
175+
BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
176+
_Py_QnewFlag = 1;
174177
break;
175178
}
176179
fprintf(stderr,

‎Python/ceval.c‎

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -903,9 +903,22 @@ eval_frame(PyFrameObject *f)
903903
break;
904904

905905
case BINARY_DIVIDE:
906+
if (!_Py_QnewFlag) {
907+
w = POP();
908+
v = POP();
909+
x = PyNumber_Divide(v, w);
910+
Py_DECREF(v);
911+
Py_DECREF(w);
912+
PUSH(x);
913+
if (x != NULL) continue;
914+
break;
915+
}
916+
/* -Qnew is in effect: fall through to
917+
BINARY_TRUE_DIVIDE */
918+
case BINARY_TRUE_DIVIDE:
906919
w = POP();
907920
v = POP();
908-
x = PyNumber_Divide(v, w);
921+
x = PyNumber_TrueDivide(v, w);
909922
Py_DECREF(v);
910923
Py_DECREF(w);
911924
PUSH(x);
@@ -922,16 +935,6 @@ eval_frame(PyFrameObject *f)
922935
if (x != NULL) continue;
923936
break;
924937

925-
case BINARY_TRUE_DIVIDE:
926-
w = POP();
927-
v = POP();
928-
x = PyNumber_TrueDivide(v, w);
929-
Py_DECREF(v);
930-
Py_DECREF(w);
931-
PUSH(x);
932-
if (x != NULL) continue;
933-
break;
934-
935938
case BINARY_MODULO:
936939
w = POP();
937940
v = POP();

‎Python/pythonrun.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */
6464
int Py_FrozenFlag; /* Needed by getpath.c */
6565
int Py_UnicodeFlag = 0; /* Needed by compile.c */
6666
int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
67+
/* _XXX Py_QnewFlag should go away in 2.3. It's true iff -Qnew is passed,
68+
on the command line, and is used in 2.2 by ceval.c to make all "/" divisions
69+
true divisions (which they will be in 2.3). */
70+
int _Py_QnewFlag = 0;
6771

6872
static int initialized = 0;
6973

0 commit comments

Comments
 (0)