Get signal names from numbers in Python


Get signal names from numbers in Python



Is there a way to map a signal number (e.g. signal.SIGINT) to its respective name (i.e. "SIGINT")?



I'd like to be able to print the name of a signal in the log when I receive it, however I cannot find a map from signal numbers to names in Python, i.e.:


import signal
def signal_handler(signum, frame):
logging.debug("Received signal (%s)" % sig_names[signum])

signal.signal(signal.SIGINT, signal_handler)



For some dictionary sig_names, so when the process receives SIGINT it prints:


Received signal (SIGINT)




7 Answers
7



There is none, but if you don't mind a little hack, you can generate it like this:


import signal
dict((k, v) for v, k in reversed(sorted(signal.__dict__.items()))
if v.startswith('SIG') and not v.startswith('SIG_'))





Strictly speaking this will map 1 to SIG_IGN and SIGHUP on most platforms, so I suppose the test should be if v.startswith('SIG') and not v.startswith('SIG_').
– Brian M. Hunt
Mar 31 '10 at 12:45



SIG_IGN


SIGHUP


v.startswith('SIG') and not v.startswith('SIG_')





It also double-maps 6 to SIGABRT and SIGIOT on Mac OS X (though they could be used interchangeably, I suppose, unlike SIG_IGN - which isn't a signal).
– Brian M. Hunt
Mar 31 '10 at 12:48


SIGABRT


SIGIOT


SIG_IGN





@Brian: very true... it's not a perfect solution by far. But it's atleast somewhat platform independent.
– Wolph
Mar 31 '10 at 21:15





No need to sort. The dict will store as it sees fit anyway.
– tbc0
Mar 24 '15 at 20:03





@tbc0: the sort is to give a consistent list of signals since there are duplicates in the list, so it's most certainly needed
– Wolph
Mar 24 '15 at 20:05



With the addition of the signal.Signals enum in Python 3.5 this is now as easy as:


signal.Signals


enum


>>> import signal
>>> signal.SIGINT.name
'SIGINT'
>>> signal.SIGINT.value
2
>>> signal.Signals(2).name
'SIGINT'
>>> signal.Signals['SIGINT'].value
2





This is a great answer for Py3 users.
– Brian M. Hunt
Mar 14 '16 at 21:34



The Python Standard Library By Example shows this function in the chapter on signals:


SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n)
for n in dir(signal) if n.startswith('SIG') and '_' not in n )



You can then use it like this:


print "Terminated by signal %s" % SIGNALS_TO_NAMES_DICT[signal_number]





or (perhaps slightly more preferable) SIGNALS_TO_NAMES_DICT.get(signal_number, "Unnamed signal: %d" % signal_number)
– Brian M. Hunt
Dec 15 '11 at 23:45



SIGNALS_TO_NAMES_DICT.get(signal_number, "Unnamed signal: %d" % signal_number)





This is a better answer and should be accepted.
– kevinarpe
Mar 6 '15 at 6:00





As @Wolph points out in his answer, this solution doesn't guarantee a consistent name to duplicate signals.
– tbc0
Mar 24 '15 at 20:24



I found this article when I was in the same situation and figured the handler is only handling one signal at a time, so I don't even need a whole dictionary, just the name of one signal:


sig_name = tuple((v) for v, k in signal.__dict__.iteritems() if k == signum)[0]



there's probably a notation that doesn't need the tuple(...)[0] bit, but I can't seem to figure it out.





signame = [v for v, k in signal.__dict__.iteritems() if k == signum][0] works fine.
– dwelch91
Feb 15 '13 at 21:21





"signame = next(v for v, k in signal.__dict__.iteritems() if k == signum)" stops when it finds it instead of continuing through the rest of the dict (also, it doesn't have the [0] that @ssc didn't like :D).
– CryingCyclops
Oct 30 '13 at 10:18






If v, k are supposed to stand for keys and values, then the names should be reversed, e.g. sig_name = tuple((k) for k, v in signal.__dict__.iteritems() if v == signum)[0] But then there are other values in signal's dict whose value may match v, in which case, depending on the order iteritems() returns items, you may print a nonsense name.
– tbc0
Mar 24 '15 at 19:21




Well, help(signal) says at the bottom:


help(signal)


DATA
NSIG = 23
SIGABRT = 22
SIGBREAK = 21
SIGFPE = 8
SIGILL = 4
SIGINT = 2
SIGSEGV = 11
SIGTERM = 15
SIG_DFL = 0
SIG_IGN = 1



So this should work:


sig_names = {23:"NSIG", 22:"SIGABRT", 21:"SIGBREAK", 8:"SIGFPE", 4:"SIGILL",
2:"SIGINT", 11:"SIGSEGV", 15:"SIGTERM", 0:"SIG_DFL", 1:"SIG_IGN"}





Unfortunately different platforms have different signal numbers, so this isn't portable. Thanks, though.
– Brian M. Hunt
Mar 31 '10 at 12:41






For example, here's the Mac OS X help(signal): SIGABRT = 6 SIGALRM = 14 SIGBUS = 10 SIGCHLD = 20 SIGCONT = 19 SIGEMT = 7 SIGFPE = 8 SIGHUP = 1 SIGILL = 4 SIGINFO = 29 SIGINT = 2 SIGIO = 23 SIGIOT = 6 SIGKILL = 9 SIGPIPE = 13 SIGPROF = 27 SIGQUIT = 3 SIGSEGV = 11 SIGSTOP = 17 SIGSYS = 12 SIGTERM = 15 SIGTRAP = 5 SIGTSTP = 18 SIGTTIN = 21 SIGTTOU = 22 SIGURG = 16 SIGUSR1 = 30 SIGUSR2 = 31 SIGVTALRM = 26 SIGWINCH = 28 SIGXCPU = 24 SIGXFSZ = 25
– Brian M. Hunt
Mar 31 '10 at 12:44


help(signal)





Ah - I really should have realized that, all things considered, especially since I've experienced how much different signals are on Windows and Linux. WoLpH's solution is cleaner anyway :)
– Daniel G
Mar 31 '10 at 16:06





I wouldn't say my solution is cleaner. Yes, it works on every platform but if your solution is an option, than I'd definately use it and use my version as a fallback.
– Wolph
Mar 31 '10 at 23:58



Building on another answer:


import signal

if hasattr(signal, "Signals"):
def _signal_name(signum):
try:
return signal.Signals(signum).name
except ValueError:
pass
else:
def _signal_name(signum):
for n, v in sorted(signal.__dict__.items()):
if v != signum:
continue
if n.startswith("SIG") and not n.startswith("SIG_"):
return n

def signal_name(signum):
if signal.SIGRTMIN <= signum <= signal.SIGRTMAX:
return "SIGRTMIN+{}".format(signum - signal.SIGRTMIN)
x = _signal_name(signum)
if x is None:
# raise ValueError for invalid signals
signal.getsignal(signum)
x = "<signal {}>".format(signum)
return x



for signal_value of positive number (signal number), or negative value (return status from subprocess):


signal_value


import signal

signal_name = {
getattr(signal, _signame): _signame
for _signame in dir(signal)
if _signame.startswith('SIG')
}.get(abs(signal_value), 'Unknown')






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages