sksundae.utils#
General-purpose module for shared utilities across the package.
Classes#
Output container with pretty printing. |
|
Timeout context manager. |
|
Timer context manager. |
Package Contents#
- class sksundae.utils.RichResult(**kwargs)[source]#
Output container with pretty printing.
A container class based off the
_RichResultclass in thescipylibrary. It combines a series of formatting functions to make the printed ‘repr’ easy to read. Use this class directly by passing in any number of keyword arguments, or use it as a base class to have custom classes for different result types.Inheriting classes should define the class attribute
_order_keyswhich is a list of strings that defines how output fields are sorted when an instance is printed.- Parameters:
**kwargs (dict, optional) – User-specified keyword arguments. Any number of arguments can be given as input. The class simply stores the key/value pairs, makes them accessible as attributes, and provides pretty printing.
Examples
The example below demonstrates how to define the
_order_keysclass attribute for custom sorting. If arguments are not in the list, they are placed at the end based on the order they were given. Note that_order_keysonly provides sorting support and that no errors are raised if an argument is not present, e.g.,thirdbelow.class CustomResult(RichResult): _order_keys = ['first', 'second', 'third',] result = CustomResult(second=None, last=None, first=None) print(result)
RichResultcan also be used directly, without any custom sorting. Arguments will print based on the order they were input. Instances will still have a fully formatted ‘repr’, including formatted arrays.import numpy as np t = np.linspace(0, 1, 1000) y = np.random.rand(1000, 5) y[0] = np.inf y[-1] = np.nan result = RichResult(message='Example.', status=0, t=t, y=y) print(result)
After initialization, all key/value pairs are accessible as instance attributes.
result = RichResult(a=10, b=20, c=30) print(result.a*(result.b + result.c))
- class sksundae.utils.Timeout(seconds, name='Timeout', raise_exc=True)[source]#
Timeout context manager.
Uses a thread to track the time spent in a context block and forces an exit (and optionally raises a
TimeoutError) if the execution time exceeds a given number of seconds. See the notes for important details on edge cases where this may not work as expected.- Parameters:
seconds (float) – Number of seconds before timing out.
name (str, optional) – Name to identify the block in exit messages, by default ‘Timeout’.
raise_exc (bool, optional) – If True, raise a
TimeoutErroron exit when the given time limit is exceeded. Use False to handle the timeout manually.
Notes
The
KeyboardInterruptthat is used to force the exit of the main thread may not be immediate, depending on the state of the main thread. For example, if you are runningtime.sleep, the interruption will not be raised until the sleep is complete.If you are using extensions that are not written in pure Python, the interruption may not be raised at all, depending on how that extension was written to catch and handle exceptions.
Examples
The
Timeoutclass is used as a context manager, as shown below. Here, we force a timeout by setting the time limit to 1/1000 of the execution time to complete theslow_fibonaccifunction.def slow_fibonacci(n): if n < 2: return n return slow_fibonacci(n-1) + slow_fibonacci(n-2) with Timer() as timer: result = slow_fibonacci(30) exec_time = timer.elapsed_time time_limit = exec_time / 1000 with Timeout(time_limit) as timeout: result = slow_fibonacci(30)
By default, the context manager will raise an exception if the context block exceeds the set time limit. If you want to suppress this behavior, and handle it manually you can do so using
raise_exc=False.with Timeout(time_limit, raise_exc=False) as timeout: result = slow_fibonacci(30) if timeout.expired: raise timeout.exception
Since we use a
KeyboardInterruptto stop the main thread, you may also want to differentiate between user-raised interrupts and timeouts. This also requires settingraise_exc=Falseto prevent an exception on exit.with Timeout(time_limit, raise_exc=False) as timeout: try: result = slow_fibonacci(30) except KeyboardInterrupt: if timeout.expired: print('Timeout expired.') else: print('User interrupt.') # or raise to stop execution
While demonstrated with a standin function for the Fibonacci sequence, this context manager can be used with any block and can help catch and cancel long-running operations. Note that the
TimerandTimeoututilities can also be used in the same context block, as demonstrated below.with Timer() as timer, Timeout(1000*exec_time) as timeout: result = slow_fibonacci(30) print(f"{timeout.expired=}") # should be False since limit is high timer.print_elapsed()
- property exception: TimeoutError#
The exception to raise if the timer expired.
- property expired: bool#
Whether the timer has expired.
- class sksundae.utils.Timer(name='Elapsed time', units='s', display=True)[source]#
Timer context manager.
Records and prints the elapsed time between entering and exiting a context block.
- Parameters:
name (str, optional) – Context block name used in print. The default is ‘Elapsed time’.
units (Literal['s', 'min', 'h'], optional) – Units to use when printing the elapsed time. The default is ‘s’.
display (bool, optional) – If True, print on exit. Otherwise, only stores the elapsed time.
Notes
If you want to print in additional units, you can convert and print the elapsed time using the
elapsed_timeproperty.A timer instance can be reused across multiple context blocks; however, the
elapsed_timeproperty will only store values from the last block.Examples
The
Timerworks as a context manager:import time def function(sleep_time: float) -> None: time.sleep(sleep_time) with Timer(): function(2.)
If you want to silence printing, set
display=False. You can then callprint_elapsedat a later time, or access theelapsed_timeproperty for custom printing:with Timer(display=False) as timer: function(2.) # print in all allowed units for units in ['s', 'min', 'h']: timer.print_elapsed(units) # custom printing, with higher precision print(f"Elapsed time: {timer.elapsed_time:.10f} s")
- print_elapsed(units='s')[source]#
Print the elapsed time.
- Parameters:
units (Literal['s', 'min', 'h'], optional) – Units to use when printing the elapsed time. The default is ‘s’.
- property elapsed_time: float#
The elapsed time in seconds.