mirror of
https://github.com/Nuitka/Nuitka.git
synced 2026-02-01 11:33:19 +01:00
634 lines
14 KiB
Python
634 lines
14 KiB
Python
# Copyright 2025, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
|
|
|
|
|
|
import sys
|
|
|
|
print("Raising an exception type in a function:")
|
|
|
|
|
|
def raiseExceptionClass():
|
|
raise ValueError
|
|
|
|
|
|
try:
|
|
raiseExceptionClass()
|
|
except Exception as e:
|
|
print("Caught exception type", e, repr(e), type(e))
|
|
print("Inside handler, sys.exc_info is this", sys.exc_info())
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Raising an exception instance in a function:")
|
|
|
|
|
|
def raiseExceptionInstance():
|
|
raise ValueError("hallo")
|
|
|
|
|
|
try:
|
|
raiseExceptionInstance()
|
|
except Exception as f:
|
|
print("Caught exception instance", f, repr(f), type(f))
|
|
print("Inside handler, sys.exc_info is this", sys.exc_info())
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Raising an exception, then catch it to re-raise it:")
|
|
|
|
|
|
def raiseExceptionAndReraise(arg):
|
|
try:
|
|
return arg / arg
|
|
except:
|
|
raise
|
|
|
|
|
|
try:
|
|
raiseExceptionAndReraise(0)
|
|
except:
|
|
print("Caught re-raised", sys.exc_info())
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Access an undefined global variable in a function:")
|
|
|
|
|
|
def raiseNonGlobalError():
|
|
return undefined_value
|
|
|
|
|
|
try:
|
|
raiseNonGlobalError()
|
|
except:
|
|
print("NameError caught", sys.exc_info())
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Raise a new style class as an exception, should be rejected:")
|
|
|
|
|
|
def raiseIllegalError():
|
|
class X(object):
|
|
pass
|
|
|
|
raise X()
|
|
|
|
|
|
try:
|
|
raiseIllegalError()
|
|
except TypeError as E:
|
|
print("New style class exception correctly rejected:", E)
|
|
except:
|
|
print(sys.exc_info())
|
|
assert False, "Error, new style class exception was not rejected"
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Raise an old-style class, version dependent outcome:")
|
|
|
|
|
|
class ClassicClassException:
|
|
pass
|
|
|
|
|
|
def raiseCustomError():
|
|
raise ClassicClassException()
|
|
|
|
|
|
try:
|
|
try:
|
|
raiseCustomError()
|
|
except ClassicClassException:
|
|
print("Caught classic class exception")
|
|
except:
|
|
print("Default catch", sys.exc_info())
|
|
|
|
assert False, "Error, old style class exception was not caught"
|
|
except TypeError as e:
|
|
print("Python3 hates to even try and catch classic classes", e)
|
|
else:
|
|
print("Classic exception catching was considered fine.")
|
|
|
|
print("After catching, sys.exc_info is this", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Check lazy exception creation:")
|
|
|
|
|
|
def checkExceptionConversion():
|
|
try:
|
|
raise Exception("some string")
|
|
except Exception as err:
|
|
print("Caught raised object", err, type(err))
|
|
|
|
|
|
checkExceptionConversion()
|
|
print("*" * 20)
|
|
|
|
print("Check exc_info scope:")
|
|
|
|
|
|
def checkExcInfoScope():
|
|
try:
|
|
raise ValueError
|
|
except:
|
|
assert sys.exc_info()[0] is not None
|
|
assert sys.exc_info()[1] is not None
|
|
assert sys.exc_info()[2] is not None
|
|
|
|
if sys.version_info[0] < 3:
|
|
print("Exc_info remains visible after exception handler for Python2")
|
|
|
|
assert sys.exc_info()[0] is not None
|
|
assert sys.exc_info()[1] is not None
|
|
assert sys.exc_info()[2] is not None
|
|
else:
|
|
print("Exc_info is clear after exception handler for Python3")
|
|
|
|
assert sys.exc_info()[0] is None
|
|
assert sys.exc_info()[1] is None
|
|
assert sys.exc_info()[2] is None
|
|
|
|
def subFunction():
|
|
print("Entering with exception info", sys.exc_info())
|
|
|
|
assert sys.exc_info()[0] is not None
|
|
assert sys.exc_info()[1] is not None
|
|
assert sys.exc_info()[2] is not None
|
|
|
|
try:
|
|
print("Trying")
|
|
except:
|
|
pass
|
|
|
|
print(
|
|
"After trying something and didn't have an exception, info is",
|
|
sys.exc_info(),
|
|
)
|
|
|
|
print("Call a function inside the exception handler and check there too.")
|
|
|
|
try:
|
|
raise KeyError
|
|
except:
|
|
assert sys.exc_info()[0] is not None
|
|
assert sys.exc_info()[1] is not None
|
|
assert sys.exc_info()[2] is not None
|
|
|
|
subFunction()
|
|
|
|
print("Call it twice and see.")
|
|
|
|
try:
|
|
raise "me"
|
|
except:
|
|
assert sys.exc_info()[0] is not None
|
|
assert sys.exc_info()[1] is not None
|
|
assert sys.exc_info()[2] is not None
|
|
|
|
subFunction()
|
|
subFunction()
|
|
|
|
|
|
if sys.version_info[0] < 3:
|
|
sys.exc_clear()
|
|
|
|
checkExcInfoScope()
|
|
|
|
print("*" * 20)
|
|
|
|
# Check that the sys.exc_info is cleared again, after being set inside the
|
|
# function checkExcInfoScope, it should now be clear again.
|
|
assert sys.exc_info()[0] is None, sys.exc_info()[0]
|
|
assert sys.exc_info()[1] is None
|
|
assert sys.exc_info()[2] is None
|
|
|
|
print("Check catching subclasses")
|
|
|
|
|
|
def checkDerivedCatch():
|
|
class A(BaseException):
|
|
pass
|
|
|
|
class B(A):
|
|
def __init__(self):
|
|
pass
|
|
|
|
a = A()
|
|
b = B()
|
|
|
|
try:
|
|
raise A(b)
|
|
except B as v:
|
|
print("Caught B", v)
|
|
except A as v:
|
|
print("Didn't catch as B, but as A, Python3 does that", v)
|
|
else:
|
|
print("Not caught A class, not allowed to happen.")
|
|
|
|
try:
|
|
raise B(a)
|
|
except TypeError as e:
|
|
print("TypeError with pair form for class not taking args:", e)
|
|
|
|
|
|
checkDerivedCatch()
|
|
|
|
print("*" * 20)
|
|
|
|
|
|
def checkNonCatch1():
|
|
print("Testing if the else branch is executed in the optimizable case:")
|
|
|
|
try:
|
|
0
|
|
except TypeError:
|
|
print("Should not catch")
|
|
else:
|
|
print("Executed else branch correctly")
|
|
|
|
|
|
checkNonCatch1()
|
|
print("*" * 20)
|
|
|
|
|
|
def checkNonCatch2():
|
|
try:
|
|
print("Testing if the else branch is executed in the non-optimizable case:")
|
|
except TypeError:
|
|
print("Should not catch")
|
|
else:
|
|
print("Executed else branch correctly")
|
|
|
|
|
|
checkNonCatch2()
|
|
print("*" * 20)
|
|
|
|
print("Checking raise that with exception arguments that raise error themselves.")
|
|
|
|
|
|
def checkRaisingRaise():
|
|
def make_error():
|
|
return 1 / 0
|
|
|
|
try:
|
|
make_error()
|
|
except Exception as e:
|
|
print("Had exception", e)
|
|
|
|
try:
|
|
raise TypeError(make_error())
|
|
|
|
except Exception as e:
|
|
print("Had exception", e)
|
|
|
|
try:
|
|
raise TypeError(7) from make_error()
|
|
|
|
except Exception as e:
|
|
print("Had exception", e)
|
|
|
|
|
|
checkRaisingRaise()
|
|
print("*" * 20)
|
|
|
|
print("Checking a re-raise that isn't one:")
|
|
|
|
|
|
def checkMisRaise():
|
|
raise
|
|
|
|
|
|
try:
|
|
checkMisRaise()
|
|
except Exception as e:
|
|
print("Without existing exception, re-raise gives:", e)
|
|
|
|
print("*" * 20)
|
|
|
|
print("Raising an exception in an exception handler gives:")
|
|
|
|
|
|
def nestedExceptions(a, b):
|
|
try:
|
|
a / b
|
|
except ZeroDivisionError:
|
|
a / b
|
|
|
|
|
|
try:
|
|
nestedExceptions(1, 0)
|
|
except Exception as e:
|
|
print("Nested exception gives", e)
|
|
|
|
print("*" * 20)
|
|
|
|
|
|
print("Testing exception that escapes __del__ and therefore cannot be raised")
|
|
|
|
|
|
def divide(a, b):
|
|
return a / b
|
|
|
|
|
|
def raiseExceptionInDel():
|
|
class C:
|
|
def __del__(self):
|
|
c = divide(1, 0)
|
|
print(c)
|
|
|
|
def f():
|
|
C()
|
|
|
|
f()
|
|
|
|
|
|
raiseExceptionInDel()
|
|
print("*" * 20)
|
|
|
|
print("Testing exception changes between generator switches:")
|
|
|
|
|
|
def yieldExceptionInteraction():
|
|
def yield_raise():
|
|
print("Yield finds at generator entry", sys.exc_info()[0])
|
|
try:
|
|
raise KeyError("caught")
|
|
except KeyError:
|
|
yield sys.exc_info()[0]
|
|
yield sys.exc_info()[0]
|
|
yield sys.exc_info()[0]
|
|
|
|
g = yield_raise()
|
|
print("Initial yield from catch in generator", next(g))
|
|
print("Checking from outside of generator", sys.exc_info()[0])
|
|
print("Second yield from the catch reentered", next(g))
|
|
print("Checking from outside of generator", sys.exc_info()[0])
|
|
print("After leaving the catch generator yielded", next(g))
|
|
|
|
|
|
yieldExceptionInteraction()
|
|
print("*" * 20)
|
|
|
|
print(
|
|
"Testing exception change between generator switches while handling an own exception"
|
|
)
|
|
|
|
|
|
def yieldExceptionInteraction2():
|
|
def yield_raise():
|
|
print("Yield finds at generator entry", sys.exc_info()[0])
|
|
try:
|
|
raise ValueError("caught")
|
|
except ValueError:
|
|
yield sys.exc_info()[0]
|
|
yield sys.exc_info()[0]
|
|
yield sys.exc_info()[0]
|
|
|
|
try:
|
|
undefined_global
|
|
except Exception:
|
|
print("Checking from outside of generator with", sys.exc_info()[0])
|
|
g = yield_raise()
|
|
v = next(g)
|
|
print("Initial yield from catch in generator:", v)
|
|
print("Checking from outside the generator:", sys.exc_info()[0])
|
|
print("Second yield from the catch reentered:", next(g))
|
|
print("Checking from outside the generation again:", sys.exc_info()[0])
|
|
print("After leaving the catch generator yielded:", next(g))
|
|
|
|
print("After exiting the trying branch:", sys.exc_info()[0])
|
|
|
|
|
|
yieldExceptionInteraction2()
|
|
print("After function exit, no exception", sys.exc_info())
|
|
print("*" * 20)
|
|
|
|
print("Check what happens if a function attempts to clear the exception in a handler")
|
|
|
|
|
|
def clearingException():
|
|
def clear_sys_exc_info():
|
|
try:
|
|
if sys.version_info[0] < 3:
|
|
sys.exc_clear()
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
raise KeyError
|
|
except:
|
|
print("Before clearing, it's", sys.exc_info())
|
|
clear_sys_exc_info()
|
|
|
|
print("After clearing, it's", sys.exc_info())
|
|
|
|
|
|
clearingException()
|
|
print("*" * 20)
|
|
|
|
print("Check that multiple exceptions can be caught in a handler through a variable:")
|
|
|
|
|
|
def multiCatchViaTupleVariable():
|
|
some_exceptions = (KeyError, ValueError)
|
|
|
|
try:
|
|
raise KeyError
|
|
except some_exceptions:
|
|
print("Yes, indeed.")
|
|
|
|
|
|
multiCatchViaTupleVariable()
|
|
|
|
# Make sure the "repr" of exceptions is fine
|
|
|
|
a = IOError
|
|
print("IOError is represented correctly:", repr(a))
|
|
|
|
|
|
def raising():
|
|
raise ValueError
|
|
|
|
|
|
def not_raising():
|
|
pass
|
|
|
|
|
|
def raiseWithFinallyNotCorruptingLineNumber():
|
|
try:
|
|
try:
|
|
raising()
|
|
finally:
|
|
not_raising()
|
|
except ValueError:
|
|
print("Traceback is in tried block line", sys.exc_info()[2].tb_lineno)
|
|
|
|
|
|
raiseWithFinallyNotCorruptingLineNumber()
|
|
|
|
|
|
def wideCatchMustPublishException():
|
|
print("At entry, no exception", sys.exc_info())
|
|
|
|
try:
|
|
undefined_global
|
|
except:
|
|
print("Inside handler:", sys.exc_info())
|
|
|
|
pass
|
|
|
|
print("Outside handler:", sys.exc_info())
|
|
|
|
|
|
print("Check that a unqualified catch properly preserves exception")
|
|
wideCatchMustPublishException()
|
|
|
|
print("Check if a nested exception handler does overwrite re-raised")
|
|
|
|
|
|
def checkReraiseAfterNestedTryExcept():
|
|
def reraise():
|
|
try:
|
|
raise TypeError("outer")
|
|
except Exception:
|
|
try:
|
|
raise KeyError("nested")
|
|
except KeyError:
|
|
print("Current exception inside nested handler", sys.exc_info())
|
|
|
|
pass
|
|
|
|
print("Current exception after nested handler exited", sys.exc_info())
|
|
|
|
# Which one does this pick
|
|
raise
|
|
|
|
try:
|
|
reraise()
|
|
except Exception as e:
|
|
print("Caught", repr(e))
|
|
|
|
|
|
checkReraiseAfterNestedTryExcept()
|
|
|
|
|
|
def checkReraiseByFunction():
|
|
def reraise():
|
|
raise
|
|
|
|
try:
|
|
try:
|
|
raise TypeError("outer")
|
|
except Exception:
|
|
reraise()
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
print("Exception traceback of re-raise:")
|
|
print("-" * 40)
|
|
traceback.print_exc()
|
|
print("-" * 40)
|
|
print("OK.")
|
|
|
|
|
|
# TODO: Enable this, once the actual traceback of a function
|
|
# re-raise isn't wrong (contains itself) anymore.
|
|
if False:
|
|
checkReraiseByFunction()
|
|
|
|
|
|
def checkNoRaiseExceptionDictBuilding(arg):
|
|
a = {(): arg}
|
|
|
|
b = {None: arg}
|
|
|
|
c = {Ellipsis: arg}
|
|
|
|
d = {1.0j: arg}
|
|
|
|
e = {1.0: arg}
|
|
|
|
f = {int(0): arg}
|
|
|
|
g = {0: arg}
|
|
|
|
h = {type: arg}
|
|
|
|
return a, b, c, d, e, f, g, h
|
|
|
|
|
|
checkNoRaiseExceptionDictBuilding(1)
|
|
|
|
|
|
def checkRaiseExceptionDictBuildingRange(arg):
|
|
try:
|
|
i = {range(10): arg}
|
|
except Exception as e:
|
|
print("Raised", repr(e))
|
|
else:
|
|
print("No exception, OK for Python2")
|
|
|
|
return i
|
|
|
|
|
|
print("Check if range as dict key raises:")
|
|
checkRaiseExceptionDictBuildingRange(2)
|
|
|
|
|
|
def checkRaiseExceptionDictBuildingTuple(arg):
|
|
try:
|
|
i = {(2, []): arg}
|
|
except Exception as e:
|
|
print("Raised", repr(e))
|
|
else:
|
|
return i
|
|
|
|
|
|
print("Check if mutable tuple as dict key raises:")
|
|
checkRaiseExceptionDictBuildingTuple(3)
|
|
|
|
|
|
def checkRaiseExceptionDictBuildingList(arg):
|
|
try:
|
|
i = {[2, ()]: arg}
|
|
except Exception as e:
|
|
print("Raised", repr(e))
|
|
else:
|
|
return i
|
|
|
|
|
|
print("Check if list as dict key raises:")
|
|
checkRaiseExceptionDictBuildingList(4)
|
|
|
|
|
|
def raisesValueErrorFromNone():
|
|
raise ValueError() from None
|
|
|
|
|
|
try:
|
|
print("Raising exception in a function 'from None':")
|
|
raisesValueErrorFromNone()
|
|
except (ValueError, TypeError) as e:
|
|
print("Caught as", repr(e))
|
|
|
|
# Python tests originally created or extracted from other peoples work. The
|
|
# parts were too small to be protected.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|