Repository: cocotb/cocotb

Issue:
Only use `TriggerException` in `prime` methods
There are two cases where `TriggerException` is used in user-facing code where another type would be better. It's only utility is in `expect_error` clauses for our own testing as the user will never be able to catch it.


Discussion:

Resolving patch:
diff --git a/cocotb/triggers.py b/cocotb/triggers.py
--- a/cocotb/triggers.py
+++ b/cocotb/triggers.py
@@ -61,7 +61,7 @@ def _pointer_str(obj):
     return full_repr.rsplit(" ", 1)[1][:-1]
 
 
-class TriggerException(Exception):
+class _TriggerException(Exception):
     pass
 
 
@@ -223,7 +223,7 @@ def __init__(
             :func:`~cocotb.utils.get_sim_steps`
 
         Raises:
-            TriggerException: If a negative value is passed for Timer setup.
+            ValueError: If a negative value is passed for Timer setup.
 
         .. versionchanged:: 1.5
             Raise an exception when Timer uses a negative value as it is undefined behavior.
@@ -250,7 +250,7 @@ def __init__(
                     stacklevel=2,
                 )
             else:
-                raise TriggerException("Timer value time_ps must not be negative")
+                raise ValueError("Timer argument time must not be negative")
         if round_mode is None:
             round_mode = type(self).round_mode
         self.sim_steps = get_sim_steps(time, units, round_mode=round_mode)
@@ -262,7 +262,7 @@ def _prime(self, callback):
                 self.sim_steps, callback, self
             )
             if self.cbhdl is None:
-                raise TriggerException("Unable set up %s Trigger" % (str(self)))
+                raise _TriggerException("Unable set up %s Trigger" % (str(self)))
         GPITrigger._prime(self, callback)
 
     def __repr__(self):
@@ -301,7 +301,7 @@ def _prime(self, callback):
         if self.cbhdl is None:
             self.cbhdl = simulator.register_readonly_callback(callback, self)
             if self.cbhdl is None:
-                raise TriggerException("Unable set up %s Trigger" % (str(self)))
+                raise _TriggerException("Unable set up %s Trigger" % (str(self)))
         GPITrigger._prime(self, callback)
 
     def __repr__(self):
@@ -324,7 +324,7 @@ def _prime(self, callback):
         if self.cbhdl is None:
             self.cbhdl = simulator.register_rwsynch_callback(callback, self)
             if self.cbhdl is None:
-                raise TriggerException("Unable set up %s Trigger" % (str(self)))
+                raise _TriggerException("Unable set up %s Trigger" % (str(self)))
         GPITrigger._prime(self, callback)
 
     def __repr__(self):
@@ -347,7 +347,7 @@ def _prime(self, callback):
         if self.cbhdl is None:
             self.cbhdl = simulator.register_nextstep_callback(callback, self)
             if self.cbhdl is None:
-                raise TriggerException("Unable set up %s Trigger" % (str(self)))
+                raise _TriggerException("Unable set up %s Trigger" % (str(self)))
         GPITrigger._prime(self, callback)
 
     def __repr__(self):
@@ -380,7 +380,7 @@ def _prime(self, callback):
                 self.signal._handle, callback, type(self)._edge_type, self
             )
             if self.cbhdl is None:
-                raise TriggerException("Unable set up %s Trigger" % (str(self)))
+                raise _TriggerException("Unable set up %s Trigger" % (str(self)))
         super()._prime(callback)
 
     def __repr__(self):
@@ -607,9 +607,7 @@ def acquire(self):
     def release(self):
         """Release the lock."""
         if not self.locked:
-            raise TriggerException(
-                "Attempt to release an unacquired Lock %s" % (str(self))
-            )
+            raise RuntimeError("Attempt to release an unacquired Lock %s" % (str(self)))
 
         self.locked = False
 


Test patch:
diff --git a/tests/test_cases/issue_120/issue_120.py b/tests/test_cases/issue_120/issue_120.py
--- a/tests/test_cases/issue_120/issue_120.py
+++ b/tests/test_cases/issue_120/issue_120.py
@@ -22,7 +22,7 @@ async def monitor(dut):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
diff --git a/tests/test_cases/issue_142/issue_142.py b/tests/test_cases/issue_142/issue_142.py
--- a/tests/test_cases/issue_142/issue_142.py
+++ b/tests/test_cases/issue_142/issue_142.py
@@ -8,7 +8,7 @@
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
diff --git a/tests/test_cases/issue_348/issue_348.py b/tests/test_cases/issue_348/issue_348.py
--- a/tests/test_cases/issue_348/issue_348.py
+++ b/tests/test_cases/issue_348/issue_348.py
@@ -50,7 +50,7 @@ async def start(self):
 
 # Cadence simulators: "Unable set up RisingEdge(ModifiableObject(sample_module.clk)) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -61,7 +61,7 @@ async def issue_348_rising(dut):
 
 # Cadence simulators: "Unable set up FallingEdge(ModifiableObject(sample_module.clk)) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -72,7 +72,7 @@ async def issue_348_falling(dut):
 
 # Cadence simulators: "Unable set up Edge(ModifiableObject(sample_module.clk)) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
diff --git a/tests/test_cases/test_cocotb/test_timing_triggers.py b/tests/test_cases/test_cocotb/test_timing_triggers.py
--- a/tests/test_cases/test_cocotb/test_timing_triggers.py
+++ b/tests/test_cases/test_cocotb/test_timing_triggers.py
@@ -26,8 +26,8 @@
     ReadWrite,
     RisingEdge,
     Timer,
-    TriggerException,
 )
+from cocotb.triggers import _TriggerException as TriggerException
 from cocotb.utils import get_sim_time
 
 
@@ -261,7 +261,7 @@ async def test_singleton_isinstance(dut):
 @cocotb.test()
 async def test_neg_timer(dut):
     """Test negative timer values are forbidden"""
-    with pytest.raises(TriggerException):
+    with pytest.raises(ValueError):
         Timer(-42)  # no need to even `await`, constructing it is an error
     # handle 0 special case
     with warnings.catch_warnings(record=True) as w:
diff --git a/tests/test_cases/test_external/test_external.py b/tests/test_cases/test_external/test_external.py
--- a/tests/test_cases/test_external/test_external.py
+++ b/tests/test_cases/test_external/test_external.py
@@ -89,7 +89,7 @@ async def test_time_in_external(dut):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -122,7 +122,7 @@ def wait_cycles_wrapper(dut, n):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -186,7 +186,7 @@ async def test_function_from_readonly(dut):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -204,7 +204,7 @@ async def test_function_that_awaits(dut):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )
@@ -225,7 +225,7 @@ async def test_await_after_function(dut):
 
 # Cadence simulators: "Unable set up RisingEdge(...) Trigger" with VHDL (see #1076)
 @cocotb.test(
-    expect_error=cocotb.triggers.TriggerException
+    expect_error=cocotb.triggers._TriggerException
     if cocotb.SIM_NAME.startswith(("xmsim", "ncsim")) and cocotb.LANGUAGE in ["vhdl"]
     else ()
 )