Title: DeprecationWarning message applies to wrong context with exec()
Type: enhancement Stage: test needed
Components: None Versions: Python 3.4, Python 3.5, Python 2.7
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Michael.Wu, ghazel, terry.reedy, zach.ware
Priority: normal Keywords:

Created on 2008-07-22 00:40 by ghazel, last changed 2014-06-24 04:38 by terry.reedy.

Messages (8)
msg70129 - (view) Author: Greg Hazel (ghazel) Date: 2008-07-22 00:40
exec()ing a line which causes a DeprecationWarning causes the warning 
to quote the file exec() occurs in instead of the string.

Demonstration of the issue:
msg107441 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2010-06-09 23:42
In 3.1, I get
>>> exec("1/0")
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
  File "<string>", line 1, in <module>
ZeroDivisionError: int division or modulo by zero

In your example, would you really prefer that the warning message start with "<string>1" (or the 2.x equivalent) instead of "t.py1"? If I were running a multi-file app with warnings turned on, I would prefer the latter. The message "DeprecationWarning: raising a string exception is deprecated" is certainly enough to suggest that one search the file for 'raise'.

In any case, this would only be a bug if it disagreed with docs or if this were different from the usual behavior with deprecation warnings. It is too late for new features in 2.x and this does not apply to 3.x.
msg107444 - (view) Author: Greg Hazel (ghazel) Date: 2010-06-10 00:14
Searching the file for "raise" is sort of pointless, since exec() takes a string which might have come from anywhere, and there might be any number of exec() calls in the module. See:

There are at least two reasonable answers:

<string>:1: DeprecationWarning: raising a string exception is deprecated
  raise 'two'

or: DeprecationWarning: raising a string exception is deprecated

Either one would be fine, but randomly choosing the first line of the module where exec() is called is just nonsense.

If you want one that applies to Python 3.x, here you go:
msg109683 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2010-07-09 05:09
New features only in 3.2
msg221294 - (view) Author: Michael Wu (Michael.Wu) Date: 2014-06-22 18:55
I ran the examples in this thread with Python 3.5, and it appears to print out the correct line that exec() occurs on ( It might be time to close this issue.
msg221315 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-06-22 21:33
Zach, your header editing is inconsistent. If you think this is a bug rather than enhancement issue, please say why. Either way, what change you would make?  And even if you think there is a bug, why would you make a change in maintenance releases, given that we do not change exception messages in maintenance releases? Is the change you would make worth breaking doc tests?

Michael, your statement and posted link do not match. Installed 3.4.0 and locally built 3.5.0a0 both produce, for me,
Traceback (most recent call last):
  File "C:\Programs\Python34\", line 10, in <module>
    exec("raise 'two'")
  File "<string>", line 1, in <module>
TypeError: exceptions must derive from BaseException

2.7 produces
Traceback (most recent call last):
  File "C:\Programs\Python34\", line 10, in <module>
    exec("raise 'two'")
  File "<string>", line 1, in <module>
TypeError: exceptions must be old-style classes or derived from BaseException, not str

In other words, the string exception deprecation warning is obsolete and does not occur in any current Python.

The string.maketrans example is also obsolete as maketrans has been removed since 3.1. It now is an AttributeError. In 2.7, it is not deprecated.
msg221333 - (view) Author: Zachary Ware (zach.ware) * (Python committer) Date: 2014-06-23 01:30
Sorry, Terry; I updated the resolution because the issue was not closed, and the versions to match the currently acceptable branches after a discussion at the Bloomberg sprint, but failed to elaborate on what the actual bug here is that came out of that discussion.

The actual problem is with any warning raised by exec'ing a string:

# line 1

import os

os.listdir(b'.') # line 5

exec("os.listdir(b'.')") # line 7
C:\Temp>py -3.4 -Wall DeprecationWarning: The Windows bytes API has been deprecated, use Unicode filenames instead
  os.listdir(b'.') # line 5 DeprecationWarning: The Windows bytes API has been deprecated, use Unicode filenames instead
  # line 1

# line 1

"test" > 3 # line 3

exec("'test' > 3") # line 5

C:\Temp>py -2.7 -3 -Wall DeprecationWarning: comparing unequal types not supported in 3.x
  "test" > 3 # line 3 DeprecationWarning: comparing unequal types not supported in 3.x
  # line 1
msg221396 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-06-24 04:38
Rereading this, I see interlocked behavior (implementation bug) and enhancement (design bug) issues. I have been focused on just the former. 

Consider the exception traceback in msg107441: there are *two* filename, line# pairs. Now consider this warning for
from os import listdir
from warnings import simplefilter
simplefilter('always', DeprecationWarning)
s = "a = 2\nlistdir(b'.')\n"
Warning (from warnings module):
  File "C:\Programs\Python34\", line 2
    from os import listdir
DeprecationWarning: The Windows bytes API has been deprecated, use Unicode filenames instead
There is only *one* filename, line# pair. If we accept that limitation, what should the filename be? An actual filename (if possible) or "<string>"?  Considered in isolation, I think the first (the current choice) is better, because it is essential for fixing the warning (as stated in msg107441). Hence I rejected Greg's first 'solution'.

Similarly, what should the line# be?  The line number of the exec statement or the line number in the string of the statement that caused the warning?  Considered in isolation, the second (the current choice) seems better; the string s could have hundreds of lines and it would be really helpful for eliminating the warning to know which one generated the warning. I presume the author of exec had a reason such as this. Hence I rejected Greg's second solution.

The two isolated answeres make for an inconsistent pair. The could be manageable, but...

The third question is what line, if any, should be printed. If possible, the line in the string that caused the problem seems best. (But note that this line is missing from the exception traceback.)  Second best is the line of the exec call (which *is* in the exception traceback).  The current behavior, resulting from warnings not knowing that the filename and lineno it gets do not form a pair, is worse than nothing and I agree that it is a bug.

I am not sure what to do. The exception/traceback/warning system was not designed for exec.
Date User Action Args
2014-06-24 04:38:25terry.reedysetmessages: + msg221396
stage: test needed
2014-06-23 01:30:00zach.waresetmessages: + msg221333
2014-06-22 21:33:40terry.reedysetnosy: + zach.ware
messages: + msg221315
2014-06-22 18:56:03Michael.Wusetfiles: -
2014-06-22 18:55:50Michael.Wusetfiles: +
nosy: + Michael.Wu
messages: + msg221294

2014-06-22 17:27:36zach.waresetresolution: rejected ->
versions: + Python 2.7, Python 3.4, Python 3.5, - Python 3.2
2010-07-09 05:09:47terry.reedysetmessages: + msg109683
versions: - Python 2.6, Python 2.5, Python 3.1
2010-06-10 00:14:22ghazelsetstatus: closed -> open

messages: + msg107444
versions: + Python 2.6, Python 3.1, Python 3.2
2010-06-09 23:42:37terry.reedysetstatus: open -> closed

nosy: + terry.reedy
messages: + msg107441

type: enhancement
resolution: rejected
2008-07-22 00:40:41ghazelcreate