mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-46328: Add sys.exception() (GH-30514)
This commit is contained in:
		
							parent
							
								
									9c2ebb906d
								
							
						
					
					
						commit
						c590b581bb
					
				
					 7 changed files with 147 additions and 19 deletions
				
			
		|  | @ -378,26 +378,41 @@ always available. | |||
|    .. versionadded:: 3.8 | ||||
|       __unraisablehook__ | ||||
| 
 | ||||
| .. function:: exc_info() | ||||
| 
 | ||||
|    This function returns a tuple of three values that give information about the | ||||
|    exception that is currently being handled.  The information returned is specific | ||||
|    both to the current thread and to the current stack frame.  If the current stack | ||||
|    frame is not handling an exception, the information is taken from the calling | ||||
|    stack frame, or its caller, and so on until a stack frame is found that is | ||||
|    handling an exception.  Here, "handling an exception" is defined as "executing | ||||
|    an except clause."  For any stack frame, only information about the exception | ||||
|    being currently handled is accessible. | ||||
| .. function:: exception() | ||||
| 
 | ||||
|    This function returns the exception instance that is currently being | ||||
|    handled.  This exception is specific both to the current thread and | ||||
|    to the current stack frame.  If the current stack frame is not handling | ||||
|    an exception, the exception is taken from the calling stack frame, or its | ||||
|    caller, and so on until a stack frame is found that is handling an | ||||
|    exception.  Here, "handling an exception" is defined as "executing an | ||||
|    except clause." For any stack frame, only the exception being currently | ||||
|    handled is accessible. | ||||
| 
 | ||||
|    .. index:: object: traceback | ||||
| 
 | ||||
|    If no exception is being handled anywhere on the stack, a tuple containing | ||||
|    three ``None`` values is returned.  Otherwise, the values returned are | ||||
|    ``(type, value, traceback)``.  Their meaning is: *type* gets the type of the | ||||
|    exception being handled (a subclass of :exc:`BaseException`); *value* gets | ||||
|    the exception instance (an instance of the exception type); *traceback* gets | ||||
|    a :ref:`traceback object <traceback-objects>` which typically encapsulates | ||||
|    the call stack at the point where the exception last occurred. | ||||
|    If no exception is being handled anywhere on the stack, ``None`` is | ||||
|    returned. | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| 
 | ||||
| 
 | ||||
| .. function:: exc_info() | ||||
| 
 | ||||
|    This function returns the old-style representation of the handled | ||||
|    exception. If an exception ``e`` is currently handled (so | ||||
|    :func:`exception` would return ``e``), :func:`exc_info` returns the | ||||
|    tuple ``(type(e), e, e.__traceback__)``. | ||||
|    That is, a tuple containing the type of the exception (a subclass of | ||||
|    :exc:`BaseException`), the exception itself, and a :ref:`traceback | ||||
|    object <traceback-objects>` which typically encapsulates the call | ||||
|    stack at the point where the exception last occurred. | ||||
| 
 | ||||
|    .. index:: object: traceback | ||||
| 
 | ||||
|    If no exception is being handled anywhere on the stack, this function | ||||
|    return a tuple containing three ``None`` values. | ||||
| 
 | ||||
|    .. versionchanged:: 3.11 | ||||
|       The ``type`` and ``traceback`` fields are now derived from the ``value`` | ||||
|  |  | |||
|  | @ -167,7 +167,7 @@ then re-raise the exception (allowing a caller to handle the exception as well): | |||
|        raise | ||||
| 
 | ||||
| Alternatively the last except clause may omit the exception name(s), however the exception | ||||
| value must then be retrieved from ``sys.exc_info()[1]``. | ||||
| value must then be retrieved with ``sys.exception()``. | ||||
| 
 | ||||
| The :keyword:`try` ... :keyword:`except` statement has an optional *else | ||||
| clause*, which, when present, must follow all *except clauses*.  It is useful | ||||
|  |  | |||
|  | @ -305,6 +305,9 @@ sys | |||
|   the results of subsequent calls to :func:`exc_info`. | ||||
|   (Contributed by Irit Katriel in :issue:`45711`.) | ||||
| 
 | ||||
| * Add :func:`sys.exception` which returns the active exception instance | ||||
|   (equivalent to ``sys.exc_info()[1]``). | ||||
|   (Contributed by Irit Katriel in :issue:`46328`.) | ||||
| 
 | ||||
| threading | ||||
| --------- | ||||
|  |  | |||
|  | @ -71,6 +71,69 @@ def baddisplayhook(obj): | |||
|             code = compile("42", "<string>", "single") | ||||
|             self.assertRaises(ValueError, eval, code) | ||||
| 
 | ||||
| class ActiveExceptionTests(unittest.TestCase): | ||||
|     def test_exc_info_no_exception(self): | ||||
|         self.assertEqual(sys.exc_info(), (None, None, None)) | ||||
| 
 | ||||
|     def test_sys_exception_no_exception(self): | ||||
|         self.assertEqual(sys.exception(), None) | ||||
| 
 | ||||
|     def test_exc_info_with_exception_instance(self): | ||||
|         def f(): | ||||
|             raise ValueError(42) | ||||
| 
 | ||||
|         try: | ||||
|             f() | ||||
|         except Exception as e_: | ||||
|             e = e_ | ||||
|             exc_info = sys.exc_info() | ||||
| 
 | ||||
|         self.assertIsInstance(e, ValueError) | ||||
|         self.assertIs(exc_info[0], ValueError) | ||||
|         self.assertIs(exc_info[1], e) | ||||
|         self.assertIs(exc_info[2], e.__traceback__) | ||||
| 
 | ||||
|     def test_exc_info_with_exception_type(self): | ||||
|         def f(): | ||||
|             raise ValueError | ||||
| 
 | ||||
|         try: | ||||
|             f() | ||||
|         except Exception as e_: | ||||
|             e = e_ | ||||
|             exc_info = sys.exc_info() | ||||
| 
 | ||||
|         self.assertIsInstance(e, ValueError) | ||||
|         self.assertIs(exc_info[0], ValueError) | ||||
|         self.assertIs(exc_info[1], e) | ||||
|         self.assertIs(exc_info[2], e.__traceback__) | ||||
| 
 | ||||
|     def test_sys_exception_with_exception_instance(self): | ||||
|         def f(): | ||||
|             raise ValueError(42) | ||||
| 
 | ||||
|         try: | ||||
|             f() | ||||
|         except Exception as e_: | ||||
|             e = e_ | ||||
|             exc = sys.exception() | ||||
| 
 | ||||
|         self.assertIsInstance(e, ValueError) | ||||
|         self.assertIs(exc, e) | ||||
| 
 | ||||
|     def test_sys_exception_with_exception_type(self): | ||||
|         def f(): | ||||
|             raise ValueError | ||||
| 
 | ||||
|         try: | ||||
|             f() | ||||
|         except Exception as e_: | ||||
|             e = e_ | ||||
|             exc = sys.exception() | ||||
| 
 | ||||
|         self.assertIsInstance(e, ValueError) | ||||
|         self.assertIs(exc, e) | ||||
| 
 | ||||
| 
 | ||||
| class ExceptHookTest(unittest.TestCase): | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| Added the :meth:`sys.exception` method which returns the active exception instance. | ||||
							
								
								
									
										24
									
								
								Python/clinic/sysmodule.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								Python/clinic/sysmodule.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -76,6 +76,28 @@ exit: | |||
|     return return_value; | ||||
| } | ||||
| 
 | ||||
| PyDoc_STRVAR(sys_exception__doc__, | ||||
| "exception($module, /)\n" | ||||
| "--\n" | ||||
| "\n" | ||||
| "Return the current exception.\n" | ||||
| "\n" | ||||
| "Return the most recent exception caught by an except clause\n" | ||||
| "in the current stack frame or in an older stack frame, or None\n" | ||||
| "if no such exception exists."); | ||||
| 
 | ||||
| #define SYS_EXCEPTION_METHODDEF    \ | ||||
|     {"exception", (PyCFunction)sys_exception, METH_NOARGS, sys_exception__doc__}, | ||||
| 
 | ||||
| static PyObject * | ||||
| sys_exception_impl(PyObject *module); | ||||
| 
 | ||||
| static PyObject * | ||||
| sys_exception(PyObject *module, PyObject *Py_UNUSED(ignored)) | ||||
| { | ||||
|     return sys_exception_impl(module); | ||||
| } | ||||
| 
 | ||||
| PyDoc_STRVAR(sys_exc_info__doc__, | ||||
| "exc_info($module, /)\n" | ||||
| "--\n" | ||||
|  | @ -992,4 +1014,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) | |||
| #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF | ||||
|     #define SYS_GETANDROIDAPILEVEL_METHODDEF | ||||
| #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ | ||||
| /*[clinic end generated code: output=855fc93b2347710b input=a9049054013a1b77]*/ | ||||
| /*[clinic end generated code: output=60756bc6f683e0c8 input=a9049054013a1b77]*/ | ||||
|  |  | |||
|  | @ -771,6 +771,28 @@ sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*[clinic input]
 | ||||
| sys.exception | ||||
| 
 | ||||
| Return the current exception. | ||||
| 
 | ||||
| Return the most recent exception caught by an except clause | ||||
| in the current stack frame or in an older stack frame, or None | ||||
| if no such exception exists. | ||||
| [clinic start generated code]*/ | ||||
| 
 | ||||
| static PyObject * | ||||
| sys_exception_impl(PyObject *module) | ||||
| /*[clinic end generated code: output=2381ee2f25953e40 input=c88fbb94b6287431]*/ | ||||
| { | ||||
|     _PyErr_StackItem *err_info = _PyErr_GetTopmostException(_PyThreadState_GET()); | ||||
|     if (err_info->exc_value != NULL) { | ||||
|         return Py_NewRef(err_info->exc_value); | ||||
|     } | ||||
|     Py_RETURN_NONE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /*[clinic input]
 | ||||
| sys.exc_info | ||||
| 
 | ||||
|  | @ -1963,6 +1985,7 @@ static PyMethodDef sys_methods[] = { | |||
|     SYS__CURRENT_FRAMES_METHODDEF | ||||
|     SYS__CURRENT_EXCEPTIONS_METHODDEF | ||||
|     SYS_DISPLAYHOOK_METHODDEF | ||||
|     SYS_EXCEPTION_METHODDEF | ||||
|     SYS_EXC_INFO_METHODDEF | ||||
|     SYS_EXCEPTHOOK_METHODDEF | ||||
|     SYS_EXIT_METHODDEF | ||||
|  | @ -2457,7 +2480,8 @@ Functions:\n\ | |||
| \n\ | ||||
| displayhook() -- print an object to the screen, and save it in builtins._\n\ | ||||
| excepthook() -- print an exception and its traceback to sys.stderr\n\ | ||||
| exc_info() -- return thread-safe information about the current exception\n\ | ||||
| exception() -- return the current thread's active exception\n\ | ||||
| exc_info() -- return information about the current thread's active exception\n\ | ||||
| exit() -- exit the interpreter by raising SystemExit\n\ | ||||
| getdlopenflags() -- returns flags to be used for dlopen() calls\n\ | ||||
| getprofile() -- get the global profiling function\n\ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Irit Katriel
						Irit Katriel