Opened 5 years ago

Last modified 3 years ago

#30416 assigned Bug

Runserver's reloading mechanism should restore terminal state completely

Reported by: Daniel Hahler Owned by: Daniel Hahler
Component: Core (Management commands) Version: 2.2
Severity: Normal Keywords:
Cc: Tom Forbes Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Daniel Hahler)

Currently it only ensures that echo is on, but not that e.g. Ctrl-C works etc.

This can be triggered when using pdb++, which uses pyrepl itself: it puts the terminal into raw state.

If the reloader then kicks in while at the prompt this will not be restored (except for echo).

Related issue, which mentions that a better mechanism would be good: https://code.djangoproject.com/ticket/15880

btw: pyrepl has no chance to restore itself: listening to SIGTERM is not possible in threads apparently, and e.g. atexit is also not triggered there.

Change History (9)

comment:1 by Daniel Hahler, 5 years ago

Description: modified (diff)

comment:2 by Carlton Gibson, 5 years ago

Triage Stage: UnreviewedAccepted

Hi Daniel. I'm going to Accept this, because I see where you're coming from, but I would be grateful if you could add a detailed set of reproduce steps and/or an example project so that someone picking it up can get going on it easily.

Thanks.

comment:3 by Carlton Gibson, 4 years ago

Resolution: needsinfo
Status: newclosed

Without more details (after 7 months) this isn't really actionable. Happy to see it taken on, with a concrete action plan in place.

comment:4 by Daniel Hahler, 4 years ago

@Carlton

I would be grateful if you could add a detailed set of reproduce steps and/or an example project so that someone picking it up can get going on it easily.

I think everybody being able to fix this has enough info in the original issue already.

I've mentioned one way to trigger this: use pdb++ (with pyrepl), then have the reloader kick in while in the debugger.
A simpler method would be using termios.tcsetattr directly to put it into e.g. raw state, then have the reloader kick in.

Therefore I suggest re-opening it already - it's an existing issue after all, and was mentioned in another issue (linked above) already.

comment:5 by Daniel Hahler, 4 years ago

Also note that the reloader should not really kick in in the first place when the debugger is used / only when the request finished.
(The use case is having a pdb.set_trace(), the debugger being used, and then saving some file - it should not "kill" the debugger then (resulting in this issue))
Therefore waiting for the request / debugger to be finished before reloading would work around this issues (allowing the debugger (pyrepl in this case) to restore the terminal state itself).

Related: https://github.com/pallets/werkzeug/pull/1525 (for Werkzeug's reloader, which is similar IIRC).

comment:6 by Daniel Hahler, 4 years ago

Resolution: needsinfo
Status: closednew

I've rebased and added a test to https://github.com/django/django/pull/11291.

To reproduce this:

  1. install pdbpp (with pyrepl)
  2. put pdb.set_trace() in a view
  3. manage.py runserver
  4. trigger the reloader or use ctrl-c directly
  5. see that ctrl-c does not work on your shell anymore until you use reset

Alternatively:

  1. add the following code to a view or similar:
            import sys
            import termios
    
            fd = sys.stdin.fileno()
            attr = termios.tcgetattr(fd).copy()
            attr[3] &= ~(
                termios.ICANON | termios.ECHO | termios.IEXTEN | (termios.ISIG * 1)
            )
    
            termios.tcsetattr(fd, termios.TCSANOW, attr)
    
  2. trigger the code
  3. observer that ctrl-c does not work anymore

With the patch/fix it will work again after the reloader gets triggered, and/or when killing the runserver manually.

comment:7 by Jacob Walls, 4 years ago

Has patch: set
Owner: changed from nobody to Daniel Hahler
Status: newassigned

comment:8 by Mariusz Felisiak, 3 years ago

Cc: Tom Forbes added

comment:9 by Carlton Gibson, 3 years ago

Needs tests: set

I've left comments on PR — ultimately I'm not sure we need to resolve this ourselves…

Maybe offering a way to pause the auto-reloader if you're in a debugger (as per comment:5 — but not necessarily with the lock approach in linked PR), but even then, I'm not sure we're committed to the auto-reloader working flawlessly if you save file changes whilst working in the debugger.

Possibly the suggested patch is a marginal improvement, but there are no tests at all. (Indeed some coverage is removed.) I'm not sure if we can come up with decent tests to make sure we don't introduce regressions. (It's on that untestable edge.) If we do merge this I think we need to ask regular contributors to try and break it with their debugging setup just to be sure we didn't break something else unexpectedly.

Current status ≈-0

Note: See TracTickets for help on using tickets.
Back to Top