Show More
@@ -1484,13 +1484,42 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
1484 | 1484 | print 'Exception value:',value |
|
1485 | 1485 | print 'Traceback :',tb |
|
1486 | 1486 | #print 'Source code :','\n'.join(self.buffer) |
|
1487 | ||
|
1488 | def validate_stb(stb): | |
|
1489 | """validate structured traceback return type | |
|
1490 | ||
|
1491 | return type of CustomTB *should* be a list of strings, but allow | |
|
1492 | single strings or None, which are harmless. | |
|
1493 | ||
|
1494 | This function will *always* return a list of strings, | |
|
1495 | and will raise a TypeError if stb is inappropriate. | |
|
1496 | """ | |
|
1497 | msg = "CustomTB must return list of strings, not %r" % stb | |
|
1498 | if stb is None: | |
|
1499 | return [] | |
|
1500 | elif isinstance(stb, basestring): | |
|
1501 | return [stb] | |
|
1502 | elif not isinstance(stb, list): | |
|
1503 | raise TypeError(msg) | |
|
1504 | # it's a list | |
|
1505 | for line in stb: | |
|
1506 | # check every element | |
|
1507 | if not isinstance(line, basestring): | |
|
1508 | raise TypeError(msg) | |
|
1509 | return stb | |
|
1487 | 1510 | |
|
1488 | 1511 | if handler is None: |
|
1489 | 1512 | wrapped = dummy_handler |
|
1490 | 1513 | else: |
|
1491 | 1514 | def wrapped(self,etype,value,tb,tb_offset=None): |
|
1515 | """wrap CustomTB handler, to protect IPython from user code | |
|
1516 | ||
|
1517 | This makes it harder (but not impossible) for custom exception | |
|
1518 | handlers to crash IPython. | |
|
1519 | """ | |
|
1492 | 1520 | try: |
|
1493 |
|
|
|
1521 | stb = handler(self,etype,value,tb,tb_offset=tb_offset) | |
|
1522 | return validate_stb(stb) | |
|
1494 | 1523 | except: |
|
1495 | 1524 | # clear custom handler immediately |
|
1496 | 1525 | self.set_custom_exc((), None) |
@@ -1499,7 +1528,10 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
1499 | 1528 | stb = self.InteractiveTB.structured_traceback(*sys.exc_info()) |
|
1500 | 1529 | print >> io.stdout, self.InteractiveTB.stb2text(stb) |
|
1501 | 1530 | print >> io.stdout, "The original exception:" |
|
1502 | self.showtraceback((etype,value,tb), tb_offset=tb_offset) | |
|
1531 | stb = self.InteractiveTB.structured_traceback( | |
|
1532 | (etype,value,tb), tb_offset=tb_offset | |
|
1533 | ) | |
|
1534 | return stb | |
|
1503 | 1535 | |
|
1504 | 1536 | self.CustomTB = types.MethodType(wrapped,self) |
|
1505 | 1537 | self.custom_exceptions = exc_tuple |
@@ -1570,11 +1602,7 b' class InteractiveShell(SingletonConfigurable, Magic):' | |||
|
1570 | 1602 | sys.last_value = value |
|
1571 | 1603 | sys.last_traceback = tb |
|
1572 | 1604 | if etype in self.custom_exceptions: |
|
1573 | # FIXME: Old custom traceback objects may just return a | |
|
1574 | # string, in that case we just put it into a list | |
|
1575 | 1605 | stb = self.CustomTB(etype, value, tb, tb_offset) |
|
1576 | if isinstance(ctb, basestring): | |
|
1577 | stb = [stb] | |
|
1578 | 1606 | else: |
|
1579 | 1607 | if exception_only: |
|
1580 | 1608 | stb = ['An exception has occurred, use %tb to see ' |
@@ -155,7 +155,7 b' class InteractiveShellTestCase(unittest.TestCase):' | |||
|
155 | 155 | try: |
|
156 | 156 | # capture stderr |
|
157 | 157 | io.stderr = StringIO() |
|
158 |
ip.set_custom_exc((IOError,),lambda etype,value,tb: |
|
|
158 | ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0) | |
|
159 | 159 | self.assertEquals(ip.custom_exceptions, (IOError,)) |
|
160 | 160 | ip.run_cell(u'raise IOError("foo")') |
|
161 | 161 | self.assertEquals(ip.custom_exceptions, ()) |
@@ -163,4 +163,20 b' class InteractiveShellTestCase(unittest.TestCase):' | |||
|
163 | 163 | finally: |
|
164 | 164 | io.stderr = save_stderr |
|
165 | 165 | |
|
166 | def test_bad_custom_tb_return(self): | |
|
167 | """Check that InteractiveShell is protected from bad return types in custom exception handlers""" | |
|
168 | ip = get_ipython() | |
|
169 | from IPython.utils import io | |
|
170 | save_stderr = io.stderr | |
|
171 | try: | |
|
172 | # capture stderr | |
|
173 | io.stderr = StringIO() | |
|
174 | ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1) | |
|
175 | self.assertEquals(ip.custom_exceptions, (NameError,)) | |
|
176 | ip.run_cell(u'a=abracadabra') | |
|
177 | self.assertEquals(ip.custom_exceptions, ()) | |
|
178 | self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue()) | |
|
179 | finally: | |
|
180 | io.stderr = save_stderr | |
|
181 | ||
|
166 | 182 |
General Comments 0
You need to be logged in to leave comments.
Login now