1

Sometimes an error happens but I don't notice because I may be running multiple cells at once.

I'd like errors to play a sound. In other words, play a sound when the execution fails, an Exception is raised, when execution errors are found, etc.

Many people would like long running cells to play a sound when completed.

Rub
  • 2,071
  • 21
  • 37

2 Answers2

3

COLAB

I mixed the solutions I found in some places 1 2 3 4

a) Create a global exception handler that beeps on errors

b) Create a simple function that you place at the end of the long-running cell (some other approaches on links)

You can change the sounds to anything you like.

Note: The sounds inside the Exception Handler and the beep_completed() are very different and with reason. The first is short and non-annoying and the second is long and pleasant (in case you are away from computer so you clearly hear that the task is completed). In any case you can replace them.

Note: There is a line that only applies to Colab. If you can provide the one for Jupyter I will gladly update the answer.

# This line is specific for Colab  (please provide alternative for Jupyter)
from google.colab import output

from IPython.core.ultratb import AutoFormattedTB

# Catch any Exception, play error sound and re-raise the Exception
#-------------------------------------------------
# initialize the formatter for making the tracebacks into strings
itb = AutoFormattedTB(mode = 'Plain', tb_offset = 1)

# this function will be called on exceptions in any cell
def custom_exc(shell, etype, evalue, tb, tb_offset=None):

    # still show the error within the notebook, don't just swallow it
    shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)


    # Play an audio beep. Any audio URL will do.  
    output.eval_js('new Audio("http://soundbible.com/grab.php?id=419&type=wav").play()')

    # # grab the traceback and make it into a list of strings
    # stb = itb.structured_traceback(etype, evalue, tb)
    # sstb = itb.stb2text(stb)

    # print (sstb) # <--- this is the variable with the traceback string
    # print ("sending mail")
    # send_mail_to_myself(sstb)

# this registers a custom exception handler for the whole current notebook
get_ipython().set_custom_exc((Exception,), custom_exc)
#------------------------------------------


# Function to play a sound (to put at the end of a long job)
def beep_completed():
  #url_sound="http://soundbible.com/grab.php?id=1795&type=mp3";
  output.eval_js('new Audio("http://soundbible.com/grab.php?id=1795&type=mp3").play()')

# Just play it with
beep_completed()

Jupyter

Comment out as needed. If you want to use a local file, you have to download it first and maybe adjust the path.

from IPython.display import Audio, display

# ----- error sound --------
def play_sound_error(self, etype, value, tb, tb_offset=None):
    self.showtraceback((etype, value, tb), tb_offset=tb_offset)

    v1="http://soundbible.com/grab.php?id=419&type=wav" # Short Error Beep sound
    v2="https://wav-sounds.com/wp-content/uploads/2017/09/Various-02.wav" # Short Baby cry
    display(Audio(url=v1, autoplay=True))

    v1="../sound_error_beep.wav" # Short Error Beep sound 
    v2="../sound_baby_cry.wav" # Short Baby cry
    display(Audio(filename=v1, autoplay=True))

# ----- atach it to all Exceptions
get_ipython().set_custom_exc((Exception,), play_sound_error)
  
    
# ----- success sound --------
def play_sound_success():
    v1='http://soundbible.com/grab.php?id=1795&type=wav'
    #display(Audio(url=v1, autoplay=True))
    display(Audio(filename='../sound_success.wav', autoplay=True))
Rub
  • 2,071
  • 21
  • 37
1

Since in my use cases, the set_custom_exc solution was not acceptable as it did override the previously established custom exceptions, I have created a small notification package that works for both regular scripts (using sys.excepthook) and jupyter notebooks (using post_run_cell).

Furthermore, since I did not like to have a Jingle Bell situation when the cells crash immediately, I have added a customizable minimum time interval based on either the total execution time (when in scripts) or the cell execution time (when in notebooks).

The package comes both as import oneliners such as:

import ringbell.auto

Which will play a sound if the execution takes more than a minute.

Or for immediate notification:

import ringbell.immediate

Or, for notifications exclusively on exceptions:

import ringbell.all_exceptions

You can also use it to play a sound whenever you like, by importing the RingBell class and going:

from ringbell import RingBell

RingBell(
    sample = "microwave",
    minimum_execution_time = 0,
    verbose = True
)

You can get it from PyPi by running:

pip install ringbell
Luca Cappelletti
  • 2,485
  • 20
  • 35