This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Don't display traceback when import site is interrupted by CTRL+c
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.3
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: Jurko.Gospodnetić, abacabadabacaba, barry, eric.araujo, eric.snow, fossilet, neologix, pitrou, poq, r.david.murray, telmich, vstinner
Priority: normal Keywords: patch

Created on 2012-03-08 09:05 by telmich, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
shellpart.sh telmich, 2012-03-08 09:05 shellpart
caller.py telmich, 2012-03-08 09:06
caller.py telmich, 2012-03-08 18:03 caller with try: ... except on outer block
caller.py telmich, 2012-03-22 15:26 Use python3 -S and import site in try:. .. block
init_sigs_after_site_static.diff telmich, 2012-11-08 14:21
init_sigs_after_site_parameter_z.diff telmich, 2012-11-08 14:21 review
Messages (38)
msg155152 - (view) Author: (telmich) Date: 2012-03-08 09:05
Hello,

pressing ctrl-c or having sigint delivered to the python process in its startup phase results in random tracebacks displayed.

This is related to issue3137, but actually happening in Python 3.2.2 on archlinux.

We noticed this during development of the cdist project (http://www.nico.schottelius.org/software/cdist/), where we call a shell via subprocess.check_call() which calls us again (under a different name and thus different behaviour.

So the call chain is like this:

cdist => /bin/sh -e script => cdist_as_different_name (i.e. __file)

A simple test case to reproduce the problem needs the two files caller.py and shellpart.sh in a directory:

% ln -s caller.py __testpython
% chmod a+x *
% ./caller.py                 
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
^Ccaught signint in parent
Traceback (most recent call last):
  File "/usr/lib/python3.2/site.py", line 58, in <module>
    import traceback
  File "/usr/lib/python3.2/traceback.py", line 3, in <module>
    import linecache
  File "/usr/lib/python3.2/linecache.py", line 10, in <module>
    import tokenize
  File "/usr/lib/python3.2/tokenize.py", line 28, in <module>
    import re                                                                                                         
  File "/usr/lib/python3.2/re.py", line 121, in <module>
[10:02] brief:python-traceback-test%     import functools
  File "/usr/lib/python3.2/functools.py", line 2, in <module>
    """
KeyboardInterrupt


Pressing Ctrl-C results in various different tracebacks and I don't see any way to catch the SIGINT reliably currently, as the code executed seems to be *before* my code is being executed.

There is another related bug at debian that references the same problem:
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=652926
msg155153 - (view) Author: (telmich) Date: 2012-03-08 09:06
And here's the actual python code
msg155164 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-08 15:53
Try to enclose the whole code (including the imports) in the try...except block. I'm not sure why this matters, though.
If you want Python to have a different return code when terminated by a KeyboardInterrupt, then I agree it is a valid feature request.
msg155170 - (view) Author: (telmich) Date: 2012-03-08 18:03
This does not change a thing:

Indirect child being called
^CTraceback (most recent call last):
  File "/usr/lib/python3.2/functools.py", line 176, in wrapper
caught signint in parent
    result = cache[key]
KeyError: (<class 'str'>, '[ \\f\\t]*((\\\\\\r?\\n|#[^\\r\\n]*|([bB]?[rR]?\'\'\'|[bB]?[rR]?"""))|(([0-9]+[jJ]|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)[jJ])|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)|(0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:0+|[1-9][0-9]*)))|((\\*\\*=?|>>=?|<<=?|!=|//=?|->|[+\\-*/%&|^=<>]=?|~)|[][(){}]|(\\r?\\n|\\.\\.\\.|[:;.,@]))|([bB]?[rR]?\'[^\\n\'\\\\]*(?:\\\\.[^\\n\'\\\\]*)*(\'|\\\\\\r?\\n)|[bB]?[rR]?"[^\\n"\\\\]*(?:\\\\.[^\\n"\\\\]*)*("|\\\\\\r?\\n))|\\w+)', 32)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.2/site.py", line 58, in <module>
    import traceback
  File "/usr/lib/python3.2/traceback.py", line 3, in <module>
    import linecache
  File "/usr/lib/python3.2/linecache.py", line 10, in <module>
    import tokenize
  File "/usr/lib/python3.2/tokenize.py", line 118, in <module>
[19:02] brief:python-traceback-test%     _compile, (Token, PseudoToken, Single3, Double3))
  File "/usr/lib/python3.2/tokenize.py", line 115, in _compile
    return re.compile(expr, re.UNICODE)
  File "/usr/lib/python3.2/re.py", line 206, in compile
    return _compile(pattern, flags)
  File "/usr/lib/python3.2/re.py", line 255, in _compile
    return _compile_typed(type(pattern), pattern, flags)
  File "/usr/lib/python3.2/functools.py", line 180, in wrapper
    result = user_function(*args, **kwds)
  File "/usr/lib/python3.2/re.py", line 267, in _compile_typed
    return sre_compile.compile(pattern, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 495, in compile
    code = _code(p, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 480, in _code
    _compile(code, p.data, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 101, in _compile
    _compile(code, av[1], flags)
  File "/usr/lib/python3.2/sre_compile.py", line 142, in _compile
    _compile(code, av, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 101, in _compile
    _compile(code, av[1], flags)
  File "/usr/lib/python3.2/sre_compile.py", line 142, in _compile
    _compile(code, av, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 101, in _compile
    _compile(code, av[1], flags)
  File "/usr/lib/python3.2/sre_compile.py", line 142, in _compile
    _compile(code, av, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 57, in _compile
    _compile_charset(av, flags, code, fixup)
  File "/usr/lib/python3.2/sre_compile.py", line 183, in _compile_charset
    for op, av in _optimize_charset(charset, fixup):
  File "/usr/lib/python3.2/sre_compile.py", line 253, in _optimize_charset
    data = _mk_bitmap(charmap)
  File "/usr/lib/python3.2/sre_compile.py", line 270, in _mk_bitmap
    if m > MAXCODE:
KeyboardInterrupt

[19:03] brief:python-trace
msg155171 - (view) Author: (telmich) Date: 2012-03-08 18:10
Regarding "feature request": I think this is a *bug*, not a feature request: For me, it is impossible to handle SIGINT correctly with my code, because it is half-handled (exception raised, but impossible to catch) by python itself.

Imho this behaviour should not be possible. Instead python could do the standard sigint behaviour, before reading python code (= exit).

When starting to read "python shipped code" (i.e. stuff that comes with python and is always loaded), it should either implement a handler for sigint OR have sigint signal handler set to ignore.

As soon as control flow is passed over to user code, raising KeyboardInterrupt is fine and I can catch that by enclosing all parts (including import statements) into a try: ... block that does what I want.
msg155173 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-08 19:06
> Regarding "feature request": I think this is a *bug*, not a feature
> request: For me, it is impossible to handle SIGINT correctly with my
> code, because it is half-handled (exception raised, but impossible to
> catch) by python itself.

In the trace you just posted, I see "caught signint in parent" (at the
beginning), so the exception was indeed caught.

> When starting to read "python shipped code" (i.e. stuff that comes
> with python and is always loaded), it should either implement a
> handler for sigint OR have sigint signal handler set to ignore.

Well, it does implement a SIGINT handler, and that handler raises
KeyboardInterrupt. QED. You can override that behaviour and register
your own handler using the standard "signal" module.
http://docs.python.org/dev/library/signal.html
msg155175 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-08 20:22
Opened issue14229 for the "signal number as exit code" enhancement as mentioned on the Debian issue tracker.
msg155234 - (view) Author: (telmich) Date: 2012-03-09 14:28
The problem is *NOT* in the parent: The problem is in the *CHILD* that is being called from the shell that is throwing a traceback, which I cannot prevent in the python code.

Please run the script yourself and try to get around the problem, you'll notice it's not possible currently in python 3.2.2.
msg155235 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-09 14:33
> The problem is *NOT* in the parent: The problem is in the *CHILD* that
> is being called from the shell that is throwing a traceback, which I
> cannot prevent in the python code.

Python does not (at least, should not) run differently as a child or as
a parent. As a matter of fact, any uncaught exception will indeed print
a traceback (which is very useful for e.g. debug purposes). If you don't
want such tracebacks, you can capture stderr in the calling process.

Also, it would be better if you explained your actual case, rather than
complain about specific behaviour.
msg155237 - (view) Author: (telmich) Date: 2012-03-09 15:05
You are right, there is no different behaviour as parent or child in general.

I used this example python => shell => python, because it is actually being used like this in cdist (first link in the first post).

The problem arises there, because python is called many (some thousand) times, depending on the configuration, thus you see the problem very often.

This is indeed a general problem, but you cannot easily trigger it in one python process, because the race condition is hard to trigger manually.

Thus the provided use case (running python 1000 times from shell scripts) is very realistic in a typical cdist run.

For demonstration, you can run ./shellpart.sh directly, press ctrl-c and see that you'll get a traceback, although all possible code is protected from the exception.

But (in that's the point) it is possible in user code to catch this exception.

I should probably rephrase the title to

"It is impossible to catch sigint on startup in python code"

Hope this makes things more clear.
msg155243 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-09 16:33
Ok, I see. Would an option to disable the default SIGINT handlers (and let the OS kill the process) be an acceptable solution to your use case?

Keep in mind that letting the OS kill the process will bypass any destructors at the Python level, so for example some buffered file data may not be flushed properly, etc.

By the way, if I'm not mistaken, the problem is only with SIGINT, right?
msg156353 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2012-03-19 18:56
I must be missing something, but I fail to see the problem here.
Basically, when SIGINT is received before the user code is run, it's caught by the default handler which prints a traceback and exits. What's wrong with that? Not catching SIGINT would result in an unclean exit, and I don't see how that would be an improvement.
The exit code may be a valid request, but that's another story.
msg156355 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-03-19 19:10
If one could distinguish that python had ended because of a sigint from the error code, then it would be possible for the caller to throw away stderr in that case.  I agree with the OP that that having to deal with the traceback when you know what you want instead is a bit of a pain, but it may be better than an unclean shutdown.  (I don't know if it is, because I don't know the possible failure modes from an unclean shutdown of the Python startup code).
msg156378 - (view) Author: (telmich) Date: 2012-03-20 03:57
Dear Charles-François,

for everybody who is not *programming* python (imagine there is a *real* user) the tracebacks are useless. Even worse, because the error messages are *changing*, because of different library parts not catching the exception.

Thus someone who is not used to python must have the impression that something must be really broken, if random errors appear on pressing the de-facto standard key kombination to exit a program.

The problem here is that the user is confronted with unwanted output, produced by the interpreter, which is not possible to be caught by a programmer to prevent this situation happening.

It is like the Windows 3.11 error message boxes, which never made sense to you, but appeared way too often and made you feel bad (hope this makes the problem more clear).
msg156397 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2012-03-20 11:37
> for everybody who is not *programming* python (imagine there is a *real* user) the tracebacks are useless. Even worse, because the error messages are *changing*, because of different library parts not catching the exception.

Well, I also use it sometimes ;-)

> The problem here is that the user is confronted with unwanted output, produced by the interpreter, which is not possible to be caught by a programmer to prevent this situation happening.

You can start the interpreter with '-S' to avoid importing the site
module, then:

"""
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

import site
site.main()

[...]
"""

or

"""
try:
    import site
    site.main()

    import signal
    signal.signal(signal.SIGINT, signal.SIG_DFL)
except KeyboardInterrupt:
    whatever

[...]
"""

Or we could change Py_InitializeEx() to setup the signal handlers
after having imported the site module:
"""
--- cpython-93769b8ff40b/Python/pythonrun.c     2012-01-19
10:29:48.000000000 +0000
+++ cpython/Python/pythonrun.c  2012-03-20 11:27:37.000000000 +0000
@@ -313,9 +313,6 @@
     if (initfsencoding(interp) < 0)
         Py_FatalError("Py_Initialize: unable to load the file system codec");

-    if (install_sigs)
-        initsigs(); /* Signal handling stuff, including initintr() */
-
     initmain(); /* Module __main__ */
     if (initstdio() < 0)
         Py_FatalError(
@@ -333,6 +330,9 @@

     if (!Py_NoSiteFlag)
         initsite(); /* Module site */
+
+    if (install_sigs)
+        initsigs(); /* Signal handling stuff, including initintr() */
"""

Note, however, that there will always be a race window, if the signal
is delivered after the signal handlers have been setup and the first
line of the user code is executed.
msg156399 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2012-03-20 11:46
> Or we could change Py_InitializeEx() to setup the signal handlers
> after having imported the site module:

Note that I don't really like this solution, because it's better to
setup handlers for fatal signals (SIGPIPE, SIGXF...) before executing
arbitrary Python code (site).
msg156400 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-20 11:50
> > Or we could change Py_InitializeEx() to setup the signal handlers
> > after having imported the site module:
> 
> Note that I don't really like this solution, because it's better to
> setup handlers for fatal signals (SIGPIPE, SIGXF...) before executing
> arbitrary Python code (site).

Agreed. I think we'd better disable SIGINT initialization when a certain
environment variable is set.
(AFAICT, the issue is only about SIGINT since it's the only one where
the default behaviour is overriden)
msg156574 - (view) Author: (telmich) Date: 2012-03-22 15:26
It seems not even using -S fixes the problem:

[16:25] brief:python-traceback-test% head -n 2 caller.py 
#!/usr/bin/python3 -S

[16:25] brief:python-traceback-test% ./caller.py 
Indirect child being called
Indirect child being called
Indirect child being called
^Ccaught signint in parent
Traceback (most recent call last):
  File "/usr/lib/python3.2/functools.py", line 176, in wrapper
    result = cache[key]
KeyError: (<class 'str'>, '[ \\f\\t]*(\\\\\\r?\\n[ \\f\\t]*)*(#[^\\r\\n]*)?((([0-9]+[jJ]|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)[jJ])|(([0-9]+\\.[0-9]*|\\.[0-9]+)([eE][-+]?[0-9]+)?|[0-9]+[eE][-+]?[0-9]+)|(0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:0+|[1-9][0-9]*)))|((\\*\\*=?|>>=?|<<=?|!=|//=?|->|[+\\-*/%&|^=<>]=?|~)|[][(){}]|(\\r?\\n|\\.\\.\\.|[:;.,@]))|([bB]?[rR]?\'[^\\n\'\\\\]*(?:\\\\.[^\\n\'\\\\]*)*\'|[bB]?[rR]?"[^\\n"\\\\]*(?:\\\\.[^\\n"\\\\]*)*")|\\w+)', 32)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./__testpython", line 4, in <module>
    import site
  File "/usr/lib/python3.2/site.py", line 58, in <module>
    import traceback
  File "/usr/lib/python3.2/traceback.py", line 3, in <module>
    import linecache
  File "/usr/lib/python3.2/linecache.py", line 10, in <module>
    import tokenize
  File "/usr/lib/python3.2/tokenize.py", line 118, in <module>
    _compile, (Token, PseudoToken, Single3, Double3))
  File "/usr/lib/python3.2/tokenize.py", line 115, in _compile
    return re.compile(expr, re.UNICODE)
  File "/usr/lib/python3.2/re.py", line 206, in compile
[16:25] brief:python-traceback-test%     return _compile(pattern, flags)
  File "/usr/lib/python3.2/re.py", line 255, in _compile
    return _compile_typed(type(pattern), pattern, flags)
  File "/usr/lib/python3.2/functools.py", line 180, in wrapper
    result = user_function(*args, **kwds)
  File "/usr/lib/python3.2/re.py", line 267, in _compile_typed
    return sre_compile.compile(pattern, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 495, in compile
    code = _code(p, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 477, in _code
    _compile_info(code, p, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 366, in _compile_info
    lo, hi = pattern.getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth
    i, j = av[1].getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth
    l, h = av.getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth
    i, j = av[1].getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth
    l, h = av.getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth
    i, j = av[1].getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth
    l, h = av.getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 163, in getwidth
    i, j = av[1].getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 153, in getwidth
    l, h = av.getwidth()
  File "/usr/lib/python3.2/sre_parse.py", line 147, in getwidth
    REPEATCODES = (MIN_REPEAT, MAX_REPEAT)
KeyboardInterrupt

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "./__testpython", line 26, in <module>
    if re.match("__", os.path.basename(sys.argv[0])):
NameError: name 're' is not defined
msg156575 - (view) Author: (telmich) Date: 2012-03-22 15:31
I think setting up SIGINT after importing site is a good solution: It will kill the program as expected and as soon as the user takes over control, she can decide what todo.

In which stage/part is the python interpreter when
I guess/hope that the race condition between initsigs(); would have been moved downwards?

I'm asking, because if 'import site' is done, the maximum output seen that could occur is

KeyboardInterrupt


if there is no code around there. Which looks way more sane that what I see currently.
msg156580 - (view) Author: (poq) Date: 2012-03-22 15:56
> It seems not even using -S fixes the problem

That's because you try to use re and os in your except block, and the KeyboardInterrupt is raised before they are imported.
msg156583 - (view) Author: (telmich) Date: 2012-03-22 16:09
Oh yes, you are right. Sorry for the confusion.

When modifying caller.py to only print(), everything works.

But then I've a different problem: If I want to exit(1),
in case I get a SIGINT, I'd like to try to import sys. But trying to import sys, will probably fail again, because the user is still pressing ctrl-c:


[17:05] brief:python-traceback-test% ./caller.py 
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
^Ccaught signint in child
[17:05] brief:python-traceback-test% ./caller.py
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
^Ccaught signint in child
Fatal Python error: Py_Initialize: can't initialize sys standard streams
Traceback (most recent call last):
  File "/usr/lib/python3.2/io.py", line 60, in <module>
[17:05] brief:python-traceback-test%     import _io
  File "/usr/lib/python3.2/os.py", line 22, in <module>
    """
KeyboardInterrupt
./shellpart.sh: line 7: 23123 Aborted                 ./__testpython


I'll change my production code to run with -S and restoring SIGINT and report back.

In any case, I'd appreciate, if cpython would be changed to something more sane/less verbose by default.
msg156638 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2012-03-23 08:54
> In any case, I'd appreciate, if cpython would be changed to something more sane/less verbose by default.

By default, certainly not.
msg156656 - (view) Author: (telmich) Date: 2012-03-23 13:16
Hello François,

I'm confused about your statement: You prefer to throw random and useless error messages to users who are using python instead of doing a clean shutdown like every other application by default?

Don't be offended, but this looks like a software coded by a 12 years old, who is proud about it and does not accept an error being an error and insists on doing it right, although it's a common understanding that throwing errors in non error situations.

I would have imagined a more mature understanding and broader view of python developers.

If you're not willing to fix this bug but insist on doing it the wrong way by default, I'd recommened to reject this bug so that the problem, the reason and the reason why it continues to exists are cleanly documented.

Cheers,

Nico
msg156660 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-23 13:32
> Don't be offended, but this looks like a software coded by a 12 years
> old, who is proud about it and does not accept an error being an error
> and insists on doing it right, although it's a common understanding
> that throwing errors in non error situations.

No, the point is that the exception may be caused by a real bug and
having the traceback is tremendously useful to debug such situations.
So the Python runtime by default prints out the whole traceback when an
uncaught exception occurs. KeyboardInterrupt is not different in this
regard from, say, ZeroDivisionError.

As I said, a possible solution is to allow users to alter the default
signal handling (using an env var).

(note that, AFAICT, you're the first to report a problem here, although
this behaviour has existed for ages)
msg156661 - (view) Author: (telmich) Date: 2012-03-23 13:52
Antoine,

let me explain again: I do not say, python should not print uncaught exceptions.

My point here is that an exception is thrown, which is not catchable at all and this results in random and misleading errors.

I really hope you understand that this is the core problem. It's not about printing uncaught exceptions.

And being the first to report is not something I feel is a bad sign.
msg156665 - (view) Author: (poq) Date: 2012-03-23 14:42
> No, the point is that the exception may be caused by a real bug and having the traceback is tremendously useful to debug such situations. [...] KeyboardInterrupt is not different in this regard from, say, ZeroDivisionError.

KeyboardInterrupt *is* different though. It is caused by the user instead of by any bug.

Of course, it can still be useful to know where the program was interrupted, so showing a traceback for KeyboardInterrupt by default makes sense IMO.

> As I said, a possible solution is to allow users to alter the default signal handling (using an env var).

Why an environment variable instead of a command line switch (as suggested by Ian Jackson)? Shouldn't a script be able to decide for itself how it handles signals?
msg156782 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-03-25 23:13
@telmich: I think you will have more success at getting what you want if you work with us rather than being confrontational.  Respect that we have reasons for doing things a certain way (and not because we are stupid), and we will respect your perspective more, and be more likely to do something about the real problem that you face.

Or, you could submit a patch...and again work *with* us to get it accepted.

Emitting a traceback on KeyboardInterrupt has served us well in the past, even in the startup case to which you are pointing.  If someone makes a mistake in site.py or similar and causes python startup to hang, a traceback on keyboard interrupt is exactly what you want.  You may think that this situation is unlikely to occur, but it is far *more* likely to occur than your situation...given, as Antoine said, that you are the first person to report this as a problem.

So, we need a solution that serves both use cases.  An environment flag or command line option seems to fit the bill.

Now we need a patch.

As far as feature request vs bug, fixing this without removing an existing feature (interrupting a hung startup with a traceback) requires a new option or environment variable, and therefore *by our rules* this can only go into 3.3.  That makes it an enhancement by our (project specific) definition, regardless of whether or not it is a bug by the broader definition of bug.
msg156822 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-03-26 13:43
> Why an environment variable instead of a command line switch (as
> suggested by Ian Jackson)? Shouldn't a script be able to decide for
> itself how it handles signals?

Because the available space for command line switches is rather limited, and this isn't an important option.

This issue applies only to POSIX systems AFAIK, and it's easy to force an env var when running an executable ("MYENVVAR=foo python ...").
msg156834 - (view) Author: (poq) Date: 2012-03-26 17:21
> Because the available space for command line switches is rather limited

Limited by what?

> "MYENVVAR=foo python ..."

That does not work with hashbangs (and env is kludgey).
msg156844 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2012-03-26 18:26
> Limited by what?

The alphabet.

I suppose we could use a -- option, but somebody would have to add support for those.
msg175164 - (view) Author: (telmich) Date: 2012-11-08 14:21
I created two diffs to solve the problem:

a) a static late init of the signal handler
b) configurable late init (using python -z)

Both apply against latest mercurial code:

[15:20] brief:cpython% ./python -V
Python 3.4.0a0
[15:20] brief:cpython% ./python -h | grep -- -z
-z     : initialise signals after 'import site'
[15:20] brief:cpython% 


Using shellpart.sh (the original one) and using the newly compiled python binary (with -z), works fine:

[15:18] brief:python-traceback-test% ./shellpart.sh 
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
Indirect child being called
^C

It would be great if you apply either patch:

the static one is fine for me, but changes the behaviour => may not be suited for everyone. Otoh, it feels pretty clean to do a late signal change anyway.

the parameter based one lets the user choose whether to use traceback'd version or the "unix default" version -> choose this, if you want to ensure backwards compatibility.
msg175165 - (view) Author: (telmich) Date: 2012-11-08 14:21
+ parameter -z based change of behaviour
msg175166 - (view) Author: (telmich) Date: 2012-11-08 14:22
And sorry for the long delay...
msg206215 - (view) Author: Jurko Gospodnetić (Jurko.Gospodnetić) * Date: 2013-12-15 03:26
This issue is related to issue #19983 on Windows.

  Also, I do not think the suggested -z option implementation should be accepted 'as is'.

  On Unix it would make Ctrl-C silently terminate the process if it occurs before default Python signal handling is enabled. I do not know what effect this would have on Windows - possibly the signal would simply be ignored & lost.

  It would also still leave a slight window between when Python sets up its default SIGINT handling and when user code has a chance to set up its own.

  My first instinct is to not do that and instead add an option to block SIGINT handling and allow user code to enable its own or default Python handling as it wishes and then unblock SIGINT handling. Note that by 'blocking' a signal I do not mean losing/ignoring it but delaying its handling until signal handling is unblocked.
msg206748 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-21 14:45
Sorry, but I don't understand this issue. Well, I understood the issue as "When I press CTRL+c to interrupt Python, Python does exit". What's wrong with that? Why do you send CTRL+c if you don't want Python to exit?

Using custom signal handler (SIG_IGN), it would be possible to ignore SIGINT during Python initialization. Using pthread_sigmask(), it is possible to defer the handling of the signal until user is able to setup its own custom signal handler (or just use try/except KeyboardInterrupt). But I don't like these options. I would like to be able to kill (stop) Python as early as possible with CTRL+c.

If you are only worried by the long traceback when importing the site module is interrupted, you can use -S. On UNIX, you can then use signal.pthread_sigmask() to defer the handling of SIGINT.

The whole issue remembers me the dummy question: "is the finally block executed even if I unplug the power cable?".

> http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=652926

This issue can be solved using python -S, calling signal.signal(SIGINT, signal.SIG_DFL) and then import the site module manually.
msg206756 - (view) Author: (telmich) Date: 2013-12-21 15:33
Victor, the problem is *not* that python exits. This is fine and virtually every other unix program behaves like that.

The problem is that python throws an ugly-to-read and completly senseless backtrace to the novice (end!) user by default. Backtraces are great for debugging and should be treated as such, but not presented to an end user by default.

But I as a developer, who wants to prevent the user seeing a backtrace while she does the most normal thing, this places a huge burden on me and I need to use undocumented workarounds to try to prevent this - in the case of a try... except block around my whole program even without suceess.

The point is that no programming language should shout its internals to an end user and prevent the developer from cushion it easily.

Think about "ls -lR" that throws debugging symbols at you, because you interrupted it - you would not want to see them, nor what you be happy if you had to cushion and especially not if this was not documented and hard to do.

So in short my request is to make python more user friendly by cushion the unnecessary backtrace of a Ctrl-C printed out.
msg206759 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-21 15:44
"The problem is that python throws an ugly-to-read and completly senseless backtrace to the novice (end!) user by default."

Oh ok, I changed the title of the issue.

"Backtraces are great for debugging and should be treated as such, but not presented to an end user by default."

We may hide the traceback by default or even do not write anything by default, and write the traceback when -v option is used.

We may hide the traceback when -q is used.
msg342545 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2019-05-15 03:02
No activity for 6 years, I close the issue.
History
Date User Action Args
2022-04-11 14:57:27adminsetgithub: 58436
2019-05-15 03:02:34vstinnersetstatus: open -> closed
resolution: out of date
messages: + msg342545

stage: needs patch -> resolved
2015-05-22 00:02:35abacabadabacabasetnosy: + abacabadabacaba
2013-12-21 15:44:17vstinnersetmessages: + msg206759
title: It is impossible to catch sigint on startup in python code -> Don't display traceback when import site is interrupted by CTRL+c
2013-12-21 15:33:16telmichsetmessages: + msg206756
2013-12-21 14:45:04vstinnersetnosy: + vstinner
messages: + msg206748
2013-12-17 13:06:05fossiletsetnosy: + fossilet
2013-12-15 03:26:07Jurko.Gospodnetićsetmessages: + msg206215
2013-12-15 03:20:40r.david.murraysetcomponents: + Interpreter Core, - email
2013-12-15 02:04:38Jurko.Gospodnetićsetnosy: + barry, Jurko.Gospodnetić
components: + email, - Interpreter Core
2012-11-13 02:59:27eric.snowsetnosy: + eric.snow
2012-11-08 14:22:04telmichsetmessages: + msg175166
2012-11-08 14:21:27telmichsetfiles: + init_sigs_after_site_parameter_z.diff

messages: + msg175165
2012-11-08 14:21:03telmichsetfiles: + init_sigs_after_site_static.diff
keywords: + patch
messages: + msg175164
2012-03-26 18:26:09r.david.murraysetmessages: + msg156844
2012-03-26 17:21:21poqsetmessages: + msg156834
2012-03-26 13:43:39pitrousetmessages: + msg156822
2012-03-25 23:13:34r.david.murraysetmessages: + msg156782
stage: needs patch
2012-03-23 14:42:17poqsetmessages: + msg156665
2012-03-23 13:52:24telmichsetmessages: + msg156661
2012-03-23 13:32:29pitrousetmessages: + msg156660
2012-03-23 13:16:02telmichsetmessages: + msg156656
2012-03-23 08:54:27neologixsetmessages: + msg156638
2012-03-22 16:09:25telmichsetmessages: + msg156583
2012-03-22 15:56:12poqsetnosy: + poq
messages: + msg156580
2012-03-22 15:31:34telmichsetmessages: + msg156575
2012-03-22 15:26:06telmichsetfiles: + caller.py

messages: + msg156574
2012-03-20 11:50:19pitrousetmessages: + msg156400
2012-03-20 11:46:33neologixsetmessages: + msg156399
2012-03-20 11:37:55neologixsetmessages: + msg156397
2012-03-20 03:57:44telmichsetmessages: + msg156378
2012-03-19 19:10:07r.david.murraysetnosy: + r.david.murray
messages: + msg156355
2012-03-19 18:56:43neologixsetnosy: + neologix
messages: + msg156353
2012-03-11 10:19:20eric.araujosetnosy: + eric.araujo
2012-03-09 16:33:51pitrousetversions: + Python 3.3, - Python 3.2
title: SIGINT (Ctrl-C) not caught at startup -> It is impossible to catch sigint on startup in python code
messages: + msg155243

components: + Interpreter Core
type: crash -> enhancement
2012-03-09 15:06:00telmichsetmessages: + msg155237
2012-03-09 14:33:37pitrousetmessages: + msg155235
2012-03-09 14:28:52telmichsetmessages: + msg155234
2012-03-08 20:22:10pitrousetmessages: + msg155175
2012-03-08 19:06:15pitrousetmessages: + msg155173
2012-03-08 18:10:48telmichsetmessages: + msg155171
2012-03-08 18:03:59telmichsetfiles: + caller.py

messages: + msg155170
2012-03-08 15:53:08pitrousetnosy: + pitrou
messages: + msg155164
2012-03-08 09:06:26telmichsetfiles: + caller.py

messages: + msg155153
2012-03-08 09:05:36telmichcreate