pythonpython-3.xexceptionraise

what is the idiomatic way to raise an exception within the exception handler in Python?


What is the correct way in Python of catching an exception, and raising another exception? I.e, I want to catch an exception of type 1, manipulate the Exception object and unconditionally raise a second exception of type 2, so that the calling function doesn't see the Exception of type 1 but absolutely sees the exception of type 2 whose construction depends on data accessed from the type-1 Exception.

Here is the code I've tried which doesn't work.

            def d(wrt):
                try:
                    return rt.derivative(wrt).canonicalize()
                except CannotComputeDerivative as e:
                    msg = "\n".join([f"When generating derivatives from {self}",
                                     f"  when computing edges of {rt}",
                                     f"  which canonicalizes to {self.canonicalize()}",
                                     f"  computing derivative of {e.rte}",
                                     f"  wrt={e.wrt}",
                                     f"  derivatives() reported: {e.msg}"])
                    raise CannotComputeDerivatives(msg=msg,
                                                   rte=rt,
                                                   wrt=wrt,
                                                   first_types=fts,
                                                   mdtd=wrts)

The reason I think it doesn't work is because I get the following message as output:

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 95, in d
    return rt.derivative(wrt).canonicalize()
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_singleton.py", line 68, in derivative
    return super().derivative(wrt)
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 72, in derivative
    return self.derivative_down(wrt)
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_singleton.py", line 91, in derivative_down
    raise CannotComputeDerivative(
rte.r_rte.CannotComputeDerivative

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    self.assertTrue(rt.derivatives())
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives

Following the suggestion of MisterMiyagi I added from None after the raise CannotComputeDerivatives(...). This makes progress, but it seems the unittest environment doesn't really like it. The displayed message during unit testing is shown below. It looks like unittest sadly truncates the message.

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    rt.derivatives()
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives

============= To follow up on the solution: The original problem was that the __init__ function for the CannotComputeDerivatives class was calling super().__init__() without passing the message string. I've updated the class definition as follows.

class CannotComputeDerivatives(Exception):
    def __init__(self, msg, rte, wrt, first_types, mdtd):
        self.msg = msg
        self.rte = rte
        self.wrt = wrt
        self.first_types = first_types
        self.mdtd = mdtd
        super().__init__(msg)

The result is that I get beautiful error messages during unit testing:

Error
Traceback (most recent call last):
  File "/Users/jnewton/Repos/python-rte/pyrte/tests/rte_tests.py", line 615, in test_derivatives
    self.assertTrue(rt.derivatives())
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 111, in derivatives
    return trace_graph(self, edges)
  File "/Users/jnewton/Repos/python-rte/pyrte/genus/utils.py", line 199, in trace_graph
    es = edges(v0)  # List[(L,V)]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in edges
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 109, in <listcomp>
    return [(td, d(td)) for td in wrts]
  File "/Users/jnewton/Repos/python-rte/pyrte/rte/r_rte.py", line 103, in d
    raise CannotComputeDerivatives(msg=msg,
rte.r_rte.CannotComputeDerivatives: When generating derivatives from Singleton(SOr(odd?, SAtomic(Test2)))
  when computing edges of Singleton(SOr(odd?, SAtomic(Test2)))
  which canonicalizes to Singleton(SOr(odd?, SAtomic(Test2)))
  computing derivative of Singleton(SOr(odd?, SAtomic(Test2)))
  wrt=SOr(SAtomic(Test2), odd?)
  derivatives() reported: Singleton.derivative_down cannot compute derivative of Singleton(SOr(odd?, SAtomic(Test2)))
  wrt=SOr(SAtomic(Test2), odd?)
  disjoint=False
  subtypep=None

Solution

  • Thanks @MisterMiyagi for the suggestion to add from None after the raise .... This averts the problem that the system complains about exception within exception.