Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
ab7bf214
Commit
ab7bf214
authored
Feb 26, 2012
by
Nick Coghlan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Close issue #6210: Implement PEP 409
parent
cda6b6d6
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
262 additions
and
41 deletions
+262
-41
Doc/ACKS.txt
Doc/ACKS.txt
+1
-0
Doc/c-api/exceptions.rst
Doc/c-api/exceptions.rst
+13
-6
Doc/library/exceptions.rst
Doc/library/exceptions.rst
+18
-0
Doc/library/stdtypes.rst
Doc/library/stdtypes.rst
+5
-4
Doc/whatsnew/3.3.rst
Doc/whatsnew/3.3.rst
+64
-0
Include/pyerrors.h
Include/pyerrors.h
+1
-0
Lib/test/test_exceptions.py
Lib/test/test_exceptions.py
+23
-6
Lib/test/test_raise.py
Lib/test/test_raise.py
+81
-1
Lib/test/test_traceback.py
Lib/test/test_traceback.py
+15
-0
Lib/traceback.py
Lib/traceback.py
+4
-4
Misc/ACKS
Misc/ACKS
+1
-0
Misc/NEWS
Misc/NEWS
+4
-0
Objects/exceptions.c
Objects/exceptions.c
+18
-11
Python/ceval.c
Python/ceval.c
+9
-8
Python/pythonrun.c
Python/pythonrun.c
+5
-1
No files found.
Doc/ACKS.txt
View file @
ab7bf214
...
@@ -62,6 +62,7 @@ docs@python.org), and we'll be glad to correct the problem.
...
@@ -62,6 +62,7 @@ docs@python.org), and we'll be glad to correct the problem.
* Stefan Franke
* Stefan Franke
* Jim Fulton
* Jim Fulton
* Peter Funk
* Peter Funk
* Ethan Furman
* Lele Gaifax
* Lele Gaifax
* Matthew Gallagher
* Matthew Gallagher
* Gabriel Genellina
* Gabriel Genellina
...
...
Doc/c-api/exceptions.rst
View file @
ab7bf214
...
@@ -421,17 +421,24 @@ Exception Objects
...
@@ -421,17 +421,24 @@ Exception Objects
.. c:function:: PyObject* PyException_GetCause(PyObject *ex)
.. c:function:: PyObject* PyException_GetCause(PyObject *ex)
Return the cause (another exception instance set by ``raise ... from ...``)
Return the cause (either an exception instance, or :const:`None`,
associated with the exception as a new reference, as accessible from Python
set by ``raise ... from ...``) associated with the exception as a new
through :attr:`__cause__`. If there is no cause associated, this returns
reference, as accessible from Python through :attr:`__cause__`.
*NULL*.
If there is no cause associated, this returns *NULL* (from Python
``__cause__ is Ellipsis``). If the cause is :const:`None`, the default
exception display routines stop showing the context chain.
.. c:function:: void PyException_SetCause(PyObject *ex, PyObject *ctx)
.. c:function:: void PyException_SetCause(PyObject *ex, PyObject *ctx)
Set the cause associated with the exception to *ctx*. Use *NULL* to clear
Set the cause associated with the exception to *ctx*. Use *NULL* to clear
it. There is no type check to make sure that *ctx* is an exception instance.
it. There is no type check to make sure that *ctx* is either an exception
This steals a reference to *ctx*.
instance or :const:`None`. This steals a reference to *ctx*.
If the cause is set to :const:`None` the default exception display
routines will not display this exception's context, and will not follow the
chain any further.
.. _unicodeexceptions:
.. _unicodeexceptions:
...
...
Doc/library/exceptions.rst
View file @
ab7bf214
...
@@ -34,6 +34,24 @@ programmers are encouraged to at least derive new exceptions from the
...
@@ -34,6 +34,24 @@ programmers are encouraged to at least derive new exceptions from the
defining exceptions is available in the Python Tutorial under
defining exceptions is available in the Python Tutorial under
:ref:`tut-userexceptions`.
:ref:`tut-userexceptions`.
When raising (or re-raising) an exception in an :keyword:`except` clause
:attr:`__context__` is automatically set to the last exception caught; if the
new exception is not handled the traceback that is eventually displayed will
include the originating exception(s) and the final exception.
This implicit exception chain can be made explicit by using :keyword:`from`
with :keyword:`raise`. The single argument to :keyword:`from` must be an
exception or :const:`None`, and it will bet set as :attr:`__cause__` on the
raised exception. If :attr:`__cause__` is an exception it will be displayed
instead of :attr:`__context__`; if :attr:`__cause__` is None,
:attr:`__context__` will not be displayed by the default exception handling
code. (Note: the default value for :attr:`__context__` is :const:`None`,
while the default value for :attr:`__cause__` is :const:`Ellipsis`.)
In either case, the default exception handling code will not display
any of the remaining links in the :attr:`__context__` chain if
:attr:`__cause__` has been set.
Base classes
Base classes
------------
------------
...
...
Doc/library/stdtypes.rst
View file @
ab7bf214
...
@@ -2985,10 +2985,11 @@ It is written as ``None``.
...
@@ -2985,10 +2985,11 @@ It is written as ``None``.
The Ellipsis Object
The Ellipsis Object
-------------------
-------------------
This object is commonly used by slicing (see :ref:`slicings`). It supports no
This object is commonly used by slicing (see :ref:`slicings`), but may also
special operations. There is exactly one ellipsis object, named
be used in other situations where a sentinel value other than :const:`None`
:const:`Ellipsis` (a built-in name). ``type(Ellipsis)()`` produces the
is needed. It supports no special operations. There is exactly one ellipsis
:const:`Ellipsis` singleton.
object, named :const:`Ellipsis` (a built-in name). ``type(Ellipsis)()``
produces the :const:`Ellipsis` singleton.
It is written as ``Ellipsis`` or ``...``.
It is written as ``Ellipsis`` or ``...``.
...
...
Doc/whatsnew/3.3.rst
View file @
ab7bf214
...
@@ -254,6 +254,9 @@ inspection of exception attributes::
...
@@ -254,6 +254,9 @@ inspection of exception attributes::
PEP 380: Syntax for Delegating to a Subgenerator
PEP 380: Syntax for Delegating to a Subgenerator
================================================
================================================
:pep:`380` - Syntax for Delegating to a Subgenerator
PEP written by Greg Ewing.
PEP 380 adds the ``yield from`` expression, allowing a generator to delegate
PEP 380 adds the ``yield from`` expression, allowing a generator to delegate
part of its operations to another generator. This allows a section of code
part of its operations to another generator. This allows a section of code
containing 'yield' to be factored out and placed in another generator.
containing 'yield' to be factored out and placed in another generator.
...
@@ -267,6 +270,67 @@ Kelly and Nick Coghlan, documentation by Zbigniew Jędrzejewski-Szmek and
...
@@ -267,6 +270,67 @@ Kelly and Nick Coghlan, documentation by Zbigniew Jędrzejewski-Szmek and
Nick Coghlan)
Nick Coghlan)
PEP 409: Suppressing exception context
======================================
:pep:`409` - Suppressing exception context
PEP written by Ethan Furman, implemented by Ethan Furman and Nick Coghlan.
PEP 409 introduces new syntax that allows the display of the chained
exception context to be disabled. This allows cleaner error messages in
applications that convert between exception types::
>>> class D:
... def __init__(self, extra):
... self._extra_attributes = extra
... def __getattr__(self, attr):
... try:
... return self._extra_attributes[attr]
... except KeyError:
... raise AttributeError(attr) from None
...
>>> D({}).x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: x
Without the ``from None`` suffix to suppress the cause, the original
exception would be displayed by default::
>>> class C:
... def __init__(self, extra):
... self._extra_attributes = extra
... def __getattr__(self, attr):
... try:
... return self._extra_attributes[attr]
... except KeyError:
... raise AttributeError(attr)
...
>>> C({}).x
Traceback (most recent call last):
File "<stdin>", line 6, in __getattr__
KeyError: 'x'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: x
No debugging capability is lost, as the original exception context remains
available if needed (for example, if an intervening library has incorrectly
suppressed valuable underlying details)::
>>> try:
... D({}).x
... except AttributeError as exc:
... print(repr(exc.__context__))
...
KeyError('x',)
PEP 3155: Qualified name for classes and functions
PEP 3155: Qualified name for classes and functions
==================================================
==================================================
...
...
Include/pyerrors.h
View file @
ab7bf214
...
@@ -105,6 +105,7 @@ PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *);
...
@@ -105,6 +105,7 @@ PyAPI_FUNC(PyObject *) PyException_GetTraceback(PyObject *);
/* Cause manipulation (PEP 3134) */
/* Cause manipulation (PEP 3134) */
PyAPI_FUNC
(
PyObject
*
)
PyException_GetCause
(
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
PyException_GetCause
(
PyObject
*
);
PyAPI_FUNC
(
void
)
PyException_SetCause
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
void
)
PyException_SetCause
(
PyObject
*
,
PyObject
*
);
PyAPI_FUNC
(
int
)
_PyException_SetCauseChecked
(
PyObject
*
,
PyObject
*
);
/* Context manipulation (PEP 3134) */
/* Context manipulation (PEP 3134) */
PyAPI_FUNC
(
PyObject
*
)
PyException_GetContext
(
PyObject
*
);
PyAPI_FUNC
(
PyObject
*
)
PyException_GetContext
(
PyObject
*
);
...
...
Lib/test/test_exceptions.py
View file @
ab7bf214
...
@@ -387,19 +387,36 @@ class ExceptionTests(unittest.TestCase):
...
@@ -387,19 +387,36 @@ class ExceptionTests(unittest.TestCase):
def
testChainingAttrs
(
self
):
def
testChainingAttrs
(
self
):
e
=
Exception
()
e
=
Exception
()
self
.
assert
Equal
(
e
.
__context__
,
None
)
self
.
assert
IsNone
(
e
.
__context__
)
self
.
assert
Equal
(
e
.
__cause__
,
None
)
self
.
assert
Is
(
e
.
__cause__
,
Ellipsis
)
e
=
TypeError
()
e
=
TypeError
()
self
.
assert
Equal
(
e
.
__context__
,
None
)
self
.
assert
IsNone
(
e
.
__context__
)
self
.
assert
Equal
(
e
.
__cause__
,
None
)
self
.
assert
Is
(
e
.
__cause__
,
Ellipsis
)
class
MyException
(
EnvironmentError
):
class
MyException
(
EnvironmentError
):
pass
pass
e
=
MyException
()
e
=
MyException
()
self
.
assertEqual
(
e
.
__context__
,
None
)
self
.
assertIsNone
(
e
.
__context__
)
self
.
assertEqual
(
e
.
__cause__
,
None
)
self
.
assertIs
(
e
.
__cause__
,
Ellipsis
)
def
testChainingDescriptors
(
self
):
try
:
raise
Exception
()
except
Exception
as
exc
:
e
=
exc
self
.
assertIsNone
(
e
.
__context__
)
self
.
assertIs
(
e
.
__cause__
,
Ellipsis
)
e
.
__context__
=
NameError
()
e
.
__cause__
=
None
self
.
assertIsInstance
(
e
.
__context__
,
NameError
)
self
.
assertIsNone
(
e
.
__cause__
)
e
.
__cause__
=
Ellipsis
self
.
assertIs
(
e
.
__cause__
,
Ellipsis
)
def
testKeywordArgs
(
self
):
def
testKeywordArgs
(
self
):
# test that builtin exception don't take keyword args,
# test that builtin exception don't take keyword args,
...
...
Lib/test/test_raise.py
View file @
ab7bf214
...
@@ -3,12 +3,27 @@
...
@@ -3,12 +3,27 @@
"""Tests for the raise statement."""
"""Tests for the raise statement."""
from
test
import
support
from
test
import
support
,
script_helper
import
re
import
sys
import
sys
import
types
import
types
import
unittest
import
unittest
try
:
from
resource
import
setrlimit
,
RLIMIT_CORE
,
error
as
resource_error
except
ImportError
:
prepare_subprocess
=
None
else
:
def
prepare_subprocess
():
# don't create core file
try
:
setrlimit
(
RLIMIT_CORE
,
(
0
,
0
))
except
(
ValueError
,
resource_error
):
pass
def
get_tb
():
def
get_tb
():
try
:
try
:
raise
OSError
()
raise
OSError
()
...
@@ -77,6 +92,16 @@ class TestRaise(unittest.TestCase):
...
@@ -77,6 +92,16 @@ class TestRaise(unittest.TestCase):
nested_reraise
()
nested_reraise
()
self
.
assertRaises
(
TypeError
,
reraise
)
self
.
assertRaises
(
TypeError
,
reraise
)
def
test_raise_from_None
(
self
):
try
:
try
:
raise
TypeError
(
"foo"
)
except
:
raise
ValueError
()
from
None
except
ValueError
as
e
:
self
.
assertTrue
(
isinstance
(
e
.
__context__
,
TypeError
))
self
.
assertIsNone
(
e
.
__cause__
)
def
test_with_reraise1
(
self
):
def
test_with_reraise1
(
self
):
def
reraise
():
def
reraise
():
try
:
try
:
...
@@ -139,6 +164,23 @@ class TestRaise(unittest.TestCase):
...
@@ -139,6 +164,23 @@ class TestRaise(unittest.TestCase):
class
TestCause
(
unittest
.
TestCase
):
class
TestCause
(
unittest
.
TestCase
):
def
testCauseSyntax
(
self
):
try
:
try
:
try
:
raise
TypeError
except
Exception
:
raise
ValueError
from
None
except
ValueError
as
exc
:
self
.
assertIsNone
(
exc
.
__cause__
)
raise
exc
from
Ellipsis
except
ValueError
as
exc
:
e
=
exc
self
.
assertIs
(
e
.
__cause__
,
Ellipsis
)
self
.
assertIsInstance
(
e
.
__context__
,
TypeError
)
def
test_invalid_cause
(
self
):
def
test_invalid_cause
(
self
):
try
:
try
:
raise
IndexError
from
5
raise
IndexError
from
5
...
@@ -178,6 +220,44 @@ class TestCause(unittest.TestCase):
...
@@ -178,6 +220,44 @@ class TestCause(unittest.TestCase):
class
TestTraceback
(
unittest
.
TestCase
):
class
TestTraceback
(
unittest
.
TestCase
):
def
get_output
(
self
,
code
,
filename
=
None
):
"""
Run the specified code in Python (in a new child process) and read the
output from the standard error or from a file (if filename is set).
Return the output lines as a list.
"""
options
=
{}
if
prepare_subprocess
:
options
[
'preexec_fn'
]
=
prepare_subprocess
process
=
script_helper
.
spawn_python
(
'-c'
,
code
,
**
options
)
stdout
,
stderr
=
process
.
communicate
()
exitcode
=
process
.
wait
()
output
=
support
.
strip_python_stderr
(
stdout
)
output
=
output
.
decode
(
'ascii'
,
'backslashreplace'
)
if
filename
:
self
.
assertEqual
(
output
,
''
)
with
open
(
filename
,
"rb"
)
as
fp
:
output
=
fp
.
read
()
output
=
output
.
decode
(
'ascii'
,
'backslashreplace'
)
output
=
re
.
sub
(
'Current thread 0x[0-9a-f]+'
,
'Current thread XXX'
,
output
)
return
output
.
splitlines
(),
exitcode
def
test_traceback_verbiage
(
self
):
code
=
"""
try:
raise ValueError
except:
raise NameError from None
"""
text
,
exitcode
=
self
.
get_output
(
code
)
self
.
assertEqual
(
len
(
text
),
3
)
self
.
assertTrue
(
text
[
0
].
startswith
(
'Traceback'
))
self
.
assertTrue
(
text
[
1
].
startswith
(
' File '
))
self
.
assertTrue
(
text
[
2
].
startswith
(
'NameError'
))
def
test_sets_traceback
(
self
):
def
test_sets_traceback
(
self
):
try
:
try
:
raise
IndexError
()
raise
IndexError
()
...
...
Lib/test/test_traceback.py
View file @
ab7bf214
...
@@ -246,6 +246,21 @@ class BaseExceptionReportingTests:
...
@@ -246,6 +246,21 @@ class BaseExceptionReportingTests:
self
.
check_zero_div
(
blocks
[
0
])
self
.
check_zero_div
(
blocks
[
0
])
self
.
assertIn
(
'inner_raise() # Marker'
,
blocks
[
2
])
self
.
assertIn
(
'inner_raise() # Marker'
,
blocks
[
2
])
def
test_context_suppression
(
self
):
try
:
try
:
raise
Exception
except
:
raise
ZeroDivisionError
from
None
except
ZeroDivisionError
as
_
:
e
=
_
lines
=
self
.
get_report
(
e
).
splitlines
()
self
.
assertEqual
(
len
(
lines
),
4
)
self
.
assertTrue
(
lines
[
0
].
startswith
(
'Traceback'
))
self
.
assertTrue
(
lines
[
1
].
startswith
(
' File'
))
self
.
assertIn
(
'ZeroDivisionError from None'
,
lines
[
2
])
self
.
assertTrue
(
lines
[
3
].
startswith
(
'ZeroDivisionError'
))
def
test_cause_and_context
(
self
):
def
test_cause_and_context
(
self
):
# When both a cause and a context are set, only the cause should be
# When both a cause and a context are set, only the cause should be
# displayed and the context should be muted.
# displayed and the context should be muted.
...
...
Lib/traceback.py
View file @
ab7bf214
...
@@ -120,14 +120,14 @@ def _iter_chain(exc, custom_tb=None, seen=None):
...
@@ -120,14 +120,14 @@ def _iter_chain(exc, custom_tb=None, seen=None):
seen
.
add
(
exc
)
seen
.
add
(
exc
)
its
=
[]
its
=
[]
cause
=
exc
.
__cause__
cause
=
exc
.
__cause__
if
cause
is
not
None
and
cause
not
in
seen
:
if
cause
is
Ellipsis
:
its
.
append
(
_iter_chain
(
cause
,
None
,
seen
))
its
.
append
([(
_cause_message
,
None
)])
else
:
context
=
exc
.
__context__
context
=
exc
.
__context__
if
context
is
not
None
and
context
not
in
seen
:
if
context
is
not
None
and
context
not
in
seen
:
its
.
append
(
_iter_chain
(
context
,
None
,
seen
))
its
.
append
(
_iter_chain
(
context
,
None
,
seen
))
its
.
append
([(
_context_message
,
None
)])
its
.
append
([(
_context_message
,
None
)])
elif
cause
is
not
None
and
cause
not
in
seen
:
its
.
append
(
_iter_chain
(
cause
,
False
,
seen
))
its
.
append
([(
_cause_message
,
None
)])
its
.
append
([(
exc
,
custom_tb
or
exc
.
__traceback__
)])
its
.
append
([(
exc
,
custom_tb
or
exc
.
__traceback__
)])
# itertools.chain is in an extension module and may be unavailable
# itertools.chain is in an extension module and may be unavailable
for
it
in
its
:
for
it
in
its
:
...
...
Misc/ACKS
View file @
ab7bf214
...
@@ -338,6 +338,7 @@ Jim Fulton
...
@@ -338,6 +338,7 @@ Jim Fulton
Tadayoshi Funaba
Tadayoshi Funaba
Gyro Funch
Gyro Funch
Peter Funk
Peter Funk
Ethan Furman
Geoff Furnish
Geoff Furnish
Ulisses Furquim
Ulisses Furquim
Hagen Fürstenau
Hagen Fürstenau
...
...
Misc/NEWS
View file @
ab7bf214
...
@@ -10,6 +10,10 @@ What's New in Python 3.3 Alpha 1?
...
@@ -10,6 +10,10 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins
Core and Builtins
-----------------
-----------------
- PEP 409, Issue #6210: "raise X from None" is now supported as a means of
suppressing the display of the chained exception context. The chained
context still remains available as the __context__ attribute.
- Issue #10181: New memoryview implementation fixes multiple ownership
- Issue #10181: New memoryview implementation fixes multiple ownership
and lifetime issues of dynamically allocated Py_buffer members (#9990)
and lifetime issues of dynamically allocated Py_buffer members (#9990)
as well as crashes (#8305, #7433). Many new features have been added
as well as crashes (#8305, #7433). Many new features have been added
...
...
Objects/exceptions.c
View file @
ab7bf214
...
@@ -266,28 +266,35 @@ BaseException_get_cause(PyObject *self) {
...
@@ -266,28 +266,35 @@ BaseException_get_cause(PyObject *self) {
PyObject
*
res
=
PyException_GetCause
(
self
);
PyObject
*
res
=
PyException_GetCause
(
self
);
if
(
res
)
if
(
res
)
return
res
;
/* new reference already returned above */
return
res
;
/* new reference already returned above */
Py_RETURN_NONE
;
Py_INCREF
(
Py_Ellipsis
);
return
Py_Ellipsis
;
}
}
static
int
int
BaseException_set_cause
(
PyObject
*
self
,
PyObject
*
arg
)
{
_PyException_SetCauseChecked
(
PyObject
*
self
,
PyObject
*
arg
)
{
if
(
arg
==
NULL
)
{
if
(
arg
==
Py_Ellipsis
)
{
PyErr_SetString
(
PyExc_TypeError
,
"__cause__ may not be deleted"
);
return
-
1
;
}
else
if
(
arg
==
Py_None
)
{
arg
=
NULL
;
arg
=
NULL
;
}
else
if
(
!
PyExceptionInstance_Check
(
arg
))
{
}
else
if
(
arg
!=
Py_None
&&
!
PyExceptionInstance_Check
(
arg
))
{
PyErr_SetString
(
PyExc_TypeError
,
"exception cause must be None "
PyErr_SetString
(
PyExc_TypeError
,
"exception cause must be None
,
"
"or derive from BaseException"
);
"
Ellipsis
or derive from BaseException"
);
return
-
1
;
return
-
1
;
}
else
{
}
else
{
/* PyException_SetCause steals
this
reference */
/* PyException_SetCause steals
a
reference */
Py_INCREF
(
arg
);
Py_INCREF
(
arg
);
}
}
PyException_SetCause
(
self
,
arg
);
PyException_SetCause
(
self
,
arg
);
return
0
;
return
0
;
}
}
static
int
BaseException_set_cause
(
PyObject
*
self
,
PyObject
*
arg
)
{
if
(
arg
==
NULL
)
{
PyErr_SetString
(
PyExc_TypeError
,
"__cause__ may not be deleted"
);
return
-
1
;
}
return
_PyException_SetCauseChecked
(
self
,
arg
);
}
static
PyGetSetDef
BaseException_getset
[]
=
{
static
PyGetSetDef
BaseException_getset
[]
=
{
{
"__dict__"
,
PyObject_GenericGetDict
,
PyObject_GenericSetDict
},
{
"__dict__"
,
PyObject_GenericGetDict
,
PyObject_GenericSetDict
},
...
...
Python/ceval.c
View file @
ab7bf214
...
@@ -3567,22 +3567,23 @@ do_raise(PyObject *exc, PyObject *cause)
...
@@ -3567,22 +3567,23 @@ do_raise(PyObject *exc, PyObject *cause)
if
(
cause
)
{
if
(
cause
)
{
PyObject
*
fixed_cause
;
PyObject
*
fixed_cause
;
int
result
;
if
(
PyExceptionClass_Check
(
cause
))
{
if
(
PyExceptionClass_Check
(
cause
))
{
fixed_cause
=
PyObject_CallObject
(
cause
,
NULL
);
fixed_cause
=
PyObject_CallObject
(
cause
,
NULL
);
if
(
fixed_cause
==
NULL
)
if
(
fixed_cause
==
NULL
)
goto
raise_error
;
goto
raise_error
;
Py_
DECREF
(
cause
);
Py_
CLEAR
(
cause
);
}
}
else
{
else
if
(
PyExceptionInstance_Check
(
cause
))
{
/* Let "exc.__cause__ = cause" handle all further checks */
fixed_cause
=
cause
;
fixed_cause
=
cause
;
cause
=
NULL
;
/* Steal the reference */
}
}
else
{
/* We retain ownership of the reference to fixed_cause */
PyErr_SetString
(
PyExc_TypeError
,
result
=
_PyException_SetCauseChecked
(
value
,
fixed_cause
);
"exception causes must derive from "
Py_DECREF
(
fixed_cause
);
"BaseException"
);
if
(
result
<
0
)
{
goto
raise_error
;
goto
raise_error
;
}
}
PyException_SetCause
(
value
,
fixed_cause
);
}
}
PyErr_SetObject
(
type
,
value
);
PyErr_SetObject
(
type
,
value
);
...
...
Python/pythonrun.c
View file @
ab7bf214
...
@@ -1698,7 +1698,11 @@ print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen)
...
@@ -1698,7 +1698,11 @@ print_exception_recursive(PyObject *f, PyObject *value, PyObject *seen)
else
if
(
PyExceptionInstance_Check
(
value
))
{
else
if
(
PyExceptionInstance_Check
(
value
))
{
cause
=
PyException_GetCause
(
value
);
cause
=
PyException_GetCause
(
value
);
context
=
PyException_GetContext
(
value
);
context
=
PyException_GetContext
(
value
);
if
(
cause
)
{
if
(
cause
&&
cause
==
Py_None
)
{
/* print neither cause nor context */
;
}
else
if
(
cause
)
{
res
=
PySet_Contains
(
seen
,
cause
);
res
=
PySet_Contains
(
seen
,
cause
);
if
(
res
==
-
1
)
if
(
res
==
-
1
)
PyErr_Clear
();
PyErr_Clear
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment