This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author vstinner
Recipients vstinner
Date 2013-07-18.21:01:01
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1374181261.54.0.8148762893.issue18501@psf.upfronthosting.co.za>
In-reply-to
Content
The ElementTree module allows to write a XML parser using Python callbacks. The module relies on the expat library which is implemented in C. Expat calls these Python callbacks, but ElementTree does not check if a Python exception was raised or not.

Example 1:
-------------------
import unittest
from xml.etree import ElementTree as ET

class Target(object):
    def start(self, tag, attrib):
        print("start")
        raise ValueError("raise start")

    def end(self, tag):
        print("end")
        raise ValueError("raise end")

    def close(self):
        print("close")
        raise ValueError("raise close")

parser = ET.XMLParser(target=Target())
parser.feed("<root><test /></root>")
-------------------

Output with Python 3.3:
-------------------
start
startendendTraceback (most recent call last):
  File "x.py", line 18, in <module>
    parser.feed("<root><test /></root>")
  File "x.py", line 10, in end
    print("end")
  File "x.py", line 10, in end
    print("end")
  File "x.py", line 6, in start
    print("start")
  File "x.py", line 7, in start
    raise ValueError("raise start")
ValueError: raise start
-------------------

start() was called twice, as end() method, even if the first start() method raised an exception.

The traceback is strange: it looks like end() was called by start(), which is wrong.


Example 2:
-------------------
import unittest
from xml.etree import ElementTree as ET

class Target(object):
    def start(self, tag, attrib):
        raise ValueError("raise start")

    def end(self, tag):
        raise ValueError("raise end")

    def close(self):
        raise ValueError("raise close")

parser = ET.XMLParser(target=Target())
parser.feed("<root><test /></root>")
-------------------

Output with Python 3.3:
-------------------
Traceback (most recent call last):
  File "x.py", line 15, in <module>
    parser.feed("<root><test /></root>")
  File "x.py", line 9, in end
    raise ValueError("raise end")
ValueError: raise end
-------------------

end() was called even if start() already failed. The exception which was set by start has been replaced by end() exception.

In my opinion, it's not a good thing to call PyEval_EvalFrameEx() and similar functions when a Python exception is set, because it behaves badly (ex: print("end") in Example 1 raises an exception... which is wrong, the traceback is also corrupted) and may replaces the old exception with a new exception (ex: "end" replaces "started").
History
Date User Action Args
2013-07-18 21:01:01vstinnersetrecipients: + vstinner
2013-07-18 21:01:01vstinnersetmessageid: <1374181261.54.0.8148762893.issue18501@psf.upfronthosting.co.za>
2013-07-18 21:01:01vstinnerlinkissue18501 messages
2013-07-18 21:01:01vstinnercreate