Skip to content
Merged
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
16 changes: 8 additions & 8 deletions Lib/test/test_builtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,16 +331,16 @@ def test_compile(self):
try:
assert False
except AssertionError:
return (True, f.__doc__)
return (True, f.__doc__, __debug__)
else:
return (False, f.__doc__)
return (False, f.__doc__, __debug__)
'''
def f(): """doc"""
values = [(-1, __debug__, f.__doc__),
(0, True, 'doc'),
(1, False, 'doc'),
(2, False, None)]
for optval, debugval, docstring in values:
values = [(-1, __debug__, f.__doc__, __debug__),
(0, True, 'doc', True),
(1, False, 'doc', False),
(2, False, None, False)]
for optval, *expected in values:
# test both direct compilation and compilation via AST
codeobjs = []
codeobjs.append(compile(codestr, "<test>", "exec", optimize=optval))
Expand All @@ -350,7 +350,7 @@ def f(): """doc"""
ns = {}
exec(code, ns)
rv = ns['f']()
self.assertEqual(rv, (debugval, docstring))
self.assertEqual(rv, tuple(expected))

def test_delattr(self):
sys.spam = 1
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def test_debug_assignment(self):
import builtins
prev = builtins.__debug__
setattr(builtins, '__debug__', 'sure')
self.assertEqual(__debug__, prev)
setattr(builtins, '__debug__', prev)

def test_argument_handling(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ``__debug__`` constant is now optimized out at compile time. This fixes also
bpo-22091.
45 changes: 15 additions & 30 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1343,13 +1343,15 @@ is_const(expr_ty e)
case Ellipsis_kind:
case NameConstant_kind:
return 1;
case Name_kind:
return _PyUnicode_EqualToASCIIString(e->v.Name.id, "__debug__");
default:
return 0;
}
}

static PyObject *
get_const_value(expr_ty e)
get_const_value(struct compiler *c, expr_ty e)
{
switch (e->kind) {
case Constant_kind:
Expand All @@ -1364,6 +1366,9 @@ get_const_value(expr_ty e)
return Py_Ellipsis;
case NameConstant_kind:
return e->v.NameConstant.value;
case Name_kind:
assert(_PyUnicode_EqualToASCIIString(e->v.Name.id, "__debug__"));
return c->c_optimize ? Py_False : Py_True;
default:
assert(!is_const(e));
return NULL;
Expand Down Expand Up @@ -3035,6 +3040,11 @@ compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx)
!_PyUnicode_EqualToASCIIString(name, "True") &&
!_PyUnicode_EqualToASCIIString(name, "False"));

if (ctx == Load && _PyUnicode_EqualToASCIIString(name, "__debug__")) {
ADDOP_O(c, LOAD_CONST, c->c_optimize ? Py_False : Py_True, consts);
return 1;
}

op = 0;
optype = OP_NAME;
scope = PyST_GetScope(c->u->u_ste, mangled);
Expand Down Expand Up @@ -3298,7 +3308,7 @@ compiler_subdict(struct compiler *c, expr_ty e, Py_ssize_t begin, Py_ssize_t end
return 0;
}
for (i = begin; i < end; i++) {
key = get_const_value((expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
key = get_const_value(c, (expr_ty)asdl_seq_GET(e->v.Dict.keys, i));
Py_INCREF(key);
PyTuple_SET_ITEM(keys, i - begin, key);
}
Expand Down Expand Up @@ -4044,35 +4054,10 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k)
static int
expr_constant(struct compiler *c, expr_ty e)
{
char *id;
switch (e->kind) {
case Ellipsis_kind:
return 1;
case Constant_kind:
return PyObject_IsTrue(e->v.Constant.value);
case Num_kind:
return PyObject_IsTrue(e->v.Num.n);
case Str_kind:
return PyObject_IsTrue(e->v.Str.s);
case Name_kind:
/* optimize away names that can't be reassigned */
id = PyUnicode_AsUTF8(e->v.Name.id);
if (id && strcmp(id, "__debug__") == 0)
return !c->c_optimize;
return -1;
case NameConstant_kind: {
PyObject *o = e->v.NameConstant.value;
if (o == Py_None)
return 0;
else if (o == Py_True)
return 1;
else if (o == Py_False)
return 0;
}
/* fall through */
default:
return -1;
if (is_const(e)) {
return PyObject_IsTrue(get_const_value(c, e));
}
return -1;
}


Expand Down