How to create a new console in Python to print message

Question:

I make a python script running in the console, and I want to create another console for printing important messages without running another python script to do that.
I first tried to use win32console.AllocConsole() directly, but it got Access is denied
(Seemingly because one process can attach to at most one console according to the docs).
So I tried creating a new process by using multiprocessing :

import sys, os
import win32api, win32con, win32console
import multiprocessing

def ShowConsole():
    win32console.FreeConsole()
    win32console.AllocConsole()
    sys.stdout = open("CONOUT$", "w")
    sys.stderr = open("CONOUT$", "w")
    print("Test")
    os.system("pause")

if __name__ == '__main__':
    p = multiprocessing.Process(target=ShowConsole)
    p.start()

But when I ran the code in Powershell, it exited directly with no message while no new console is created.
None of the possible solutions I found in stackoverflow works for me. What should I do?

Update: It turns out that it is because multiprocessing.Process fails to call ShowConsole function. I use multiprocessing.dummy.Process as the alternative and it works as expected.
The reason why multiprocessing.Process fails to call target is still unclear.

Asked By: Kulo

||

Answers:

It looks like the issue might be with the way you are trying to open the console using sys.stdout and sys.stderr. Try using the following code instead:

import sys, os
import win32api, win32con, win32console
import multiprocessing

def ShowConsole():
    win32console.FreeConsole()
    win32console.AllocConsole()
    os.dup2(win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE), sys.stdout.fileno())
    os.dup2(win32console.GetStdHandle(win32console.STD_ERROR_HANDLE), sys.stderr.fileno())
    print("Test")
    os.system("pause")

if __name__ == '__main__':
    p = multiprocessing.Process(target=ShowConsole)
    p.start()
Answered By: Kelli

There’s nothing wrong with your example above, it pops the console as shown below. I added a "hello" in the main section to differentiate.
enter image description here

But since you want to values from the first console to the second,
here’s a better example. Utilize put/get to pass the information from the first console to the second console.

import win32console
import multiprocessing
import time

def secondconsole(output):
    win32console.FreeConsole()
    win32console.AllocConsole()
    while True:
        print(output.get())

if __name__ == "__main__":
    output = multiprocessing.Queue()
    multiprocessing.Process(target=secondconsole, args=[output]).start()
    while True:
        print("Hello World")
        output.put("Hello to second console")  #here you will provide the data to the second console
        time.sleep(3)   #sleep for 3 seconds just for testing
Answered By: Sin Han Jinn
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.