discrete1.utils.decorators module
Decorators for stopping for-loops early.
Allow for decorating ml/tune and ml/train and stopping long running jobs while saving the current information with Ctrl+C.
- discrete1.utils.decorators.break_loop(func)[source]
Interrupt-friendly decorator.
The wrapped function receives the wrapper itself as its first argument, allowing it to query
wrapper.stop_event(athreading.Event) to terminate a long‑running loop after the current iteration when the user presses Ctrl+C once. A second Ctrl+C aborts immediately.- Parameters:
func (
callable) –The function to be wrapped. It must accept the wrapper instance as its first positional argument, e.g.:
@break_loop def process(wrapper, data): for i in grange(len(data), stop_event=wrapper.stop_event): # do work ...
- Returns:
The wrapped function. The wrapper has an attribute
stop_event(athreading.Event) that can be inspected insidefunc.- Return type:
callable
Notes
The decorator temporarily replaces the process‑wide
SIGINThandler. The original handler is restored after the function finishes (or raises).wrapper.stop_eventis cleared before each call so that the same decorated function can be invoked repeatedly.
Examples
>>> @break_loop ... def count(wrapper, n): ... for i in grange(n, stop_event=wrapper.stop_event): ... print(i) ... time.sleep(0.5) # simulate work ... >>> count(10) # Press Ctrl+C once to stop after the current ... # iteration; press twice to raise KeyboardInterrupt
- discrete1.utils.decorators.finish_iteration(func)[source]
Interrupt-friendly decorator.
The first
Ctrl+C(SIGINT) request sets a flag; after the wrapped function returns, aKeyboardInterruptis raised if the flag was set. A secondCtrl+CraisesKeyboardInterruptimmediately.- Parameters:
func (
callable) – The function to be wrapped. Its signature is unchanged.- Returns:
The wrapped function that respects the graceful‑interrupt semantics.
- Return type:
callable
Notes
The decorator temporarily replaces the process‑wide
SIGINThandler. The original handler is restored afterfunccompletes.If the wrapped function itself raises
KeyboardInterrupt, the exception propagates unchanged.
Examples
>>> @finish_iteration ... def heavy_task(): ... for i in range(100): ... print(i) ... time.sleep(0.1) ... >>> heavy_task() # Press Ctrl+C once to finish the current loop ... # iteration then raise KeyboardInterrupt.
- discrete1.utils.decorators.grange(*args, stop_event)[source]
Interrupt-friendly generator (
rangetype).- Parameters:
*args (
int) – The same positional arguments accepted by the built‑inrange(). Typical signatures arestop,start, stoporstart, stop, step.stop_event (
threading.Event) – An event object whoseis_setmethod is consulted before each iteration. If the event is set, the generator stops early.
- Yields:
int– Values produced by the underlyingrangecall.- Raises:
TypeError – If
stop_eventis not provided as a keyword argument.
Notes
This helper is intended to be used together with a function wrapped by
break_loop(), which supplies thestop_eventtied to a SIGINT handler.Examples
>>> ev = threading.Event() >>> for i in grange(0, 10, 2, stop_event=ev): ... print(i) 0 2 4 6 8