Terminal confused after restarting script programmatically (Python) #21380

Closed
opened 2026-01-31 07:43:03 +00:00 by claunia · 3 comments
Owner

Originally created by @sushantshah-dev on GitHub (Mar 10, 2024).

Windows Terminal version

1.19.10573.0

Windows build number

10.0.22621.3235

Other Software

Including but but not limited to VSCode terminal

Steps to reproduce

  1. Restart script using:
def check_file_changes(self):
        """
        Checks for file changes and reloads the server if any changes are detected.
        """
        for path, _, files in os.walk("."):
            for file in files:
                if file.endswith(".py") and os.path.getmtime(os.path.join(path, file)) > self.init_time:
                    self.logger.warning("File<%s> changed. Reloading server..." % file)
                    os.execv(sys.executable, [f'"{sys.executable}"'] + [f'"{arg}"' for arg in sys.argv])
  1. Take multiple inputs at start of the script

Screenshot 2024-03-06 170035

Expected Behavior

No response

Actual Behavior

Terminal confused about input

Another thing that happens when I reload is, I see the line for accepting commands (eg. "C:\Users\XXXX>") before my code output appears... Kind of like, the terminal hallucinates that the program is done running.

Originally created by @sushantshah-dev on GitHub (Mar 10, 2024). ### Windows Terminal version 1.19.10573.0 ### Windows build number 10.0.22621.3235 ### Other Software Including but but not limited to VSCode terminal ### Steps to reproduce 1. Restart script using: ``` def check_file_changes(self): """ Checks for file changes and reloads the server if any changes are detected. """ for path, _, files in os.walk("."): for file in files: if file.endswith(".py") and os.path.getmtime(os.path.join(path, file)) > self.init_time: self.logger.warning("File<%s> changed. Reloading server..." % file) os.execv(sys.executable, [f'"{sys.executable}"'] + [f'"{arg}"' for arg in sys.argv]) ``` 2. Take multiple inputs at start of the script ![Screenshot 2024-03-06 170035](https://github.com/microsoft/vscode/assets/103421781/359c153a-ee23-43e7-98e6-41852042460d) ### Expected Behavior _No response_ ### Actual Behavior Terminal confused about input Another thing that happens when I reload is, I see the line for accepting commands (eg. "C:\Users\XXXX>") before my code output appears... Kind of like, the terminal hallucinates that the program is done running.
claunia added the Resolution-By-DesignNeeds-TriageIssue-Bug labels 2026-01-31 07:43:04 +00:00
Author
Owner

@DHowett commented on GitHub (Mar 11, 2024):

So, the problem is that CMD (and PowerShell) only track one process before returning control to the shell. What happens is this...

sequenceDiagram
   create participant cmd
   create participant python as Python PID 1234
   cmd->>python: CreateProcess(python)
   note left of cmd: cmd waits for python to exit
   create participant python2 as Python PID 2345
   python->>python2: CreateProcess(python)
   destroy python
   python-->>cmd: exit()
   note left of cmd: cmd calls ReadInput()
   note right of python2: Python PID 2345 calls ReadInput()
   note left of cmd: cmd calls ReadInput()
   note right of python2: Python PID 2345 calls ReadInput()

When python calls execve on Windows, it spawns another separate python process to run the script. CMD and PowerShell do not know about it, and so they start to take control back.

This is just one of those really annoying Windows-isms. :/

@DHowett commented on GitHub (Mar 11, 2024): So, the problem is that CMD (and PowerShell) only track one process before returning control to the shell. What happens is this... ```mermaid sequenceDiagram create participant cmd create participant python as Python PID 1234 cmd->>python: CreateProcess(python) note left of cmd: cmd waits for python to exit create participant python2 as Python PID 2345 python->>python2: CreateProcess(python) destroy python python-->>cmd: exit() note left of cmd: cmd calls ReadInput() note right of python2: Python PID 2345 calls ReadInput() note left of cmd: cmd calls ReadInput() note right of python2: Python PID 2345 calls ReadInput() ``` When python calls `execve` on Windows, it spawns another separate python process to run the script. CMD and PowerShell do not know about it, and so they start to take control back. This is just one of those really annoying Windows-isms. :/
Author
Owner

@sushantshah-dev commented on GitHub (Mar 11, 2024):

Can you suggest an alternative for my restart function?

@sushantshah-dev commented on GitHub (Mar 11, 2024): Can you suggest an alternative for my restart function?
Author
Owner

@lhecker commented on GitHub (Mar 12, 2024):

I'd recommend splitting the restart logic and the remaining script apart. Something like this (depends on watchdog):

import os
import subprocess
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class Handler(FileSystemEventHandler):
    def __init__(self):
        self.launch()

    def on_modified(self, event):
        if event.src_path.endswith('.py'):
            self.terminate()
            self.launch()

    def launch(self):
        self.process = subprocess.Popen(['python', 'main.py'])

    def terminate(self):
        if self.process:
            self.process.terminate()
            self.process.wait()

if __name__ == "__main__":
    event_handler = Handler()
    observer = Observer()
    observer.schedule(event_handler, path='.', recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1000)
    except:
        pass

    event_handler.terminate()
    observer.stop()
    observer.join()
@lhecker commented on GitHub (Mar 12, 2024): I'd recommend splitting the restart logic and the remaining script apart. Something like this (depends on [watchdog](https://pythonhosted.org/watchdog/index.html)): ```py import os import subprocess import time from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler class Handler(FileSystemEventHandler): def __init__(self): self.launch() def on_modified(self, event): if event.src_path.endswith('.py'): self.terminate() self.launch() def launch(self): self.process = subprocess.Popen(['python', 'main.py']) def terminate(self): if self.process: self.process.terminate() self.process.wait() if __name__ == "__main__": event_handler = Handler() observer = Observer() observer.schedule(event_handler, path='.', recursive=True) observer.start() try: while True: time.sleep(1000) except: pass event_handler.terminate() observer.stop() observer.join() ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#21380