diff --git a/src/testing/exceptiontest.cs b/src/testing/exceptiontest.cs index 45acaa2cc..0b72e0014 100644 --- a/src/testing/exceptiontest.cs +++ b/src/testing/exceptiontest.cs @@ -1,3 +1,4 @@ +using Python.Runtime; using System; using System.Collections; using System.Collections.Generic; @@ -81,6 +82,40 @@ public static void ThrowChainedExceptions() throw new Exception("Outer exception", exc2); } } + + public static IntPtr DoThrowSimple() + { + using (Py.GIL()) + { + dynamic builtins = Py.Import("builtins"); + var typeErrorType = new PyType(builtins.TypeError); + var pyerr = new PythonException(typeErrorType, value:null, traceback:null, "Type error, the first", innerException:null); + throw new ArgumentException("Bogus bad parameter", pyerr); + + } + } + + public static void DoThrowWithInner() + { + using(Py.GIL()) + { + // create a TypeError + dynamic builtins = Py.Import("builtins"); + var pyerrFirst = new PythonException(new PyType(builtins.TypeError), value:null, traceback:null, "Type error, the first", innerException:null); + + // Create an ArgumentException, but as a python exception, with the previous type error as the inner exception + var argExc = new ArgumentException("Bogus bad parameter", pyerrFirst); + var argExcPyObj = argExc.ToPython(); + var pyArgExc = new PythonException(argExcPyObj.GetPythonType(), value:null, traceback:null, argExc.Message, innerException:argExc.InnerException); + // This object must be disposed explicitly or else we get a false-positive leak. + argExcPyObj.Dispose(); + + // Then throw a TypeError with the ArgumentException-as-python-error exception as inner. + var pyerrSecond = new PythonException(new PyType(builtins.TypeError), value:null, traceback:null, "Type error, the second", innerException:pyArgExc); + throw pyerrSecond; + + } + } } diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 7fafeebcb..469934fe5 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -8,6 +8,51 @@ import pytest import pickle +# begin code from https://utcc.utoronto.ca/~cks/space/blog/python/GetAllObjects +import gc +# Recursively expand slist's objects +# into olist, using seen to track +# already processed objects. + +def _getr(slist, olist, seen): + for e in slist: + if id(e) in seen: + continue + seen[id(e)] = None + olist.append(e) + tl = gc.get_referents(e) + if tl: + _getr(tl, olist, seen) + +# The public function. +def get_all_objects(): + gcl = gc.get_objects() + olist = [] + seen = {} + # Just in case: + seen[id(gcl)] = None + seen[id(olist)] = None + seen[id(seen)] = None + # _getr does the real work. + _getr(gcl, olist, seen) + return olist +# end code from https://utcc.utoronto.ca/~cks/space/blog/python/GetAllObjects + +def leak_check(func): + def do_leak_check(): + func() + gc.collect() + exc = {x for x in get_all_objects() if isinstance(x, Exception) and not isinstance(x, pytest.PytestDeprecationWarning)} + print(len(exc)) + if len(exc): + for x in exc: + print('-------') + print(repr(x)) + print(gc.get_referrers(x)) + print(len(gc.get_referrers(x))) + assert False + gc.collect() + return do_leak_check def test_unified_exception_semantics(): """Test unified exception semantics.""" @@ -375,3 +420,33 @@ def test_iteration_innerexception(): # after exception is thrown iterator is no longer valid with pytest.raises(StopIteration): next(val) + +def leak_test(func): + def do_test_leak(): + # PyTest leaks things, gather the current state + orig_exc = {x for x in get_all_objects() if isinstance(x, Exception)} + func() + exc = {x for x in get_all_objects() if isinstance(x, Exception)} + possibly_leaked = exc - orig_exc + assert not possibly_leaked + + return do_test_leak + +@leak_test +def test_dont_leak_exceptions_simple(): + from Python.Test import ExceptionTest + + try: + ExceptionTest.DoThrowSimple() + except System.ArgumentException: + print('type error, as expected') + +@leak_test +def test_dont_leak_exceptions_inner(): + from Python.Test import ExceptionTest + try: + ExceptionTest.DoThrowWithInner() + except TypeError: + print('type error, as expected') + except System.ArgumentException: + print('type error, also expected') \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy