16

Apart from the scripts own console (which does nothing) I want to open two consoles and print the variables con1 and con2 in different consoles, How can I achieve this.

con1 = 'This is Console1'
con2 = 'This is Console2'

I've no idea how to achieve this and spent several hours trying to do so with modules such as subprocess but with no luck. I'm on windows by the way.


Edit:

Would the threading module do the job? or is multiprocessing needed?

Eg:

enter image description here

15
  • 1
    there is only one console Commented Oct 20, 2013 at 15:57
  • 2
    it is really possible Commented Oct 20, 2013 at 16:01
  • 1
    You can have one script that starts itself as a new subprocess, or you could get a native lib. But you definitely can do it. Commented Oct 20, 2013 at 16:05
  • 1
    This might be helpful: stackoverflow.com/questions/11621991/open-second-python-console (possible duplicate) Commented Oct 20, 2013 at 16:05
  • 1
    I don't understand your edit. I don't see any reason subprocess doesn't meet your requirements. Commented Nov 5, 2013 at 20:14

7 Answers 7

15
+50

If you don't want to reconsider your problem and use a GUI such as in @Kevin's answer then you could use subprocess module to start two new consoles concurrently and display two given strings in the opened windows:

#!/usr/bin/env python3
import sys
import time
from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE

messages = 'This is Console1', 'This is Console2'

# open new consoles
processes = [Popen([sys.executable, "-c", """import sys
for line in sys.stdin: # poor man's `cat`
    sys.stdout.write(line)
    sys.stdout.flush()
"""],
    stdin=PIPE, bufsize=1, universal_newlines=True,
    # assume the parent script is started from a console itself e.g.,
    # this code is _not_ run as a *.pyw file
    creationflags=CREATE_NEW_CONSOLE)
             for _ in range(len(messages))]

# display messages
for proc, msg in zip(processes, messages):
    proc.stdin.write(msg + "\n")
    proc.stdin.flush()

time.sleep(10) # keep the windows open for a while

# close windows
for proc in processes:
    proc.communicate("bye\n")

Here's a simplified version that doesn't rely on CREATE_NEW_CONSOLE:

#!/usr/bin/env python
"""Show messages in two new console windows simultaneously."""
import sys
import platform
from subprocess import Popen

messages = 'This is Console1', 'This is Console2'

# define a command that starts new terminal
if platform.system() == "Windows":
    new_window_command = "cmd.exe /c start".split()
else:  #XXX this can be made more portable
    new_window_command = "x-terminal-emulator -e".split()

# open new consoles, display messages
echo = [sys.executable, "-c",
        "import sys; print(sys.argv[1]); input('Press Enter..')"]
processes = [Popen(new_window_command + echo + [msg])  for msg in messages]

# wait for the windows to be closed
for proc in processes:
    proc.wait()
Sign up to request clarification or add additional context in comments.

11 Comments

why doesn't it display any text?
@KDawG: I've tested it on Python 3.3 windows 8. It works as written: two consoles pop up with the messages and they are closed in 10 seconds. The code should work without changes on Python 2.7
Windows 7 user here. When I run this, two console windows flash on screen and quickly close. Ten seconds later, I get OSError: [Errno 22] Invalid argument. (see full stack trace here)
@Kevin: How do you run the script? Could you try: 1. Open a console in a directory with the script 2. Run py the_script.py
Yes, the result is the same.
|
6

You can get something like two consoles using two Tkinter Text widgets.

from Tkinter import *
import threading

class FakeConsole(Frame):
    def __init__(self, root, *args, **kargs):
        Frame.__init__(self, root, *args, **kargs)

        #white text on black background,
        #for extra versimilitude
        self.text = Text(self, bg="black", fg="white")
        self.text.pack()

        #list of things not yet printed
        self.printQueue = []

        #one thread will be adding to the print queue, 
        #and another will be iterating through it.
        #better make sure one doesn't interfere with the other.
        self.printQueueLock = threading.Lock()

        self.after(5, self.on_idle)

    #check for new messages every five milliseconds
    def on_idle(self):
        with self.printQueueLock:
            for msg in self.printQueue:
                self.text.insert(END, msg)            
                self.text.see(END)
            self.printQueue = []
        self.after(5, self.on_idle)

    #print msg to the console
    def show(self, msg, sep="\n"):
        with self.printQueueLock:
            self.printQueue.append(str(msg) + sep)

#warning! Calling this more than once per program is a bad idea.
#Tkinter throws a fit when two roots each have a mainloop in different threads.
def makeConsoles(amount):
    root = Tk()
    consoles = [FakeConsole(root) for n in range(amount)]
    for c in consoles:
        c.pack()
    threading.Thread(target=root.mainloop).start()
    return consoles

a,b = makeConsoles(2)

a.show("This is Console 1")
b.show("This is Console 2")

a.show("I've got a lovely bunch of cocounts")
a.show("Here they are standing in a row")

b.show("Lorem ipsum dolor sit amet")
b.show("consectetur adipisicing elit")

Result:

enter image description here

Comments

5

I don't know if it suits you, but you can open two Python interpreters using Windows start command:

from subprocess import Popen
p1 = Popen('start c:\python27\python.exe', shell=True)
p2 = Popen('start c:\python27\python.exe', shell=True)

Of course there is problem that now Python runs in interactive mode which is not what u want (you can also pass file as parameter and that file will be executed).

On Linux I would try to make named pipe, pass the name of the file to python.exe and write python commands to that file. 'Maybe' it will work ;)

But I don't have an idea how to create named pipe on Windows. Windows API ... (fill urself).

Comments

1

pymux

pymux gets close to what you want: https://github.com/jonathanslenders/pymux

Unfortunately it is mostly a CLI tool replacement for tmux and does not have a decent programmatic API yet.

But hacking it up to expose that API is likely the most robust option if you are serious about this.

The README says:

Parts of pymux could become a library, so that any prompt_toolkit application can embed a vt100 terminal. (Imagine a terminal emulator embedded in pyvim.)

Comments

1

If you are on windows you can use win32console module to open a second console for your thread or subprocess output. This is the most simple and easiest way that works if you are on windows.

Here is a sample code:

import win32console
import multiprocessing

def subprocess(queue):
    win32console.FreeConsole() #Frees subprocess from using main console
    win32console.AllocConsole() #Creates new console and all input and output of subprocess goes to this new console
    while True:
        print(queue.get())
        #prints any output produced by main script passed to subprocess using queue

queue = multiprocessing.Queue()
multiprocessing.Process(Target=subprocess, args=[queue]).start()
while True:
    print("Hello World")
    #and whatever else you want to do in ur main process

You can also do this with threading. You have to use queue module if you want the queue functionality as threading module doesn't have queue

Here is the win32console module documentation

Comments

0

I used jfs' response. Here is my embellishment/theft of jfs response. This is tailored to run on Win10 and also handles Unicode:

# https://stackoverflow.com/questions/19479504/how-can-i-open-two-consoles-from-a-single-script
import sys, time, os, locale
from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE

class console(Popen)  :
    NumConsoles = 0
    def __init__(self, color=None, title=None):
        console.NumConsoles += 1

        cmd = "import sys, os, locale"
        cmd += "\nos.system(\'color " + color + "\')" if color is not None else ""
        title = title if title is not None else "console #" + str(console.NumConsoles)
        cmd += "\nos.system(\"title " + title + "\")"
        # poor man's `cat`
        cmd += """
print(sys.stdout.encoding, locale.getpreferredencoding() )
endcoding = locale.getpreferredencoding()
for line in sys.stdin:
    sys.stdout.buffer.write(line.encode(endcoding))
    sys.stdout.flush()
"""

        cmd = sys.executable, "-c", cmd
        # print(cmd, end="", flush=True)
        super().__init__(cmd, stdin=PIPE, bufsize=1, universal_newlines=True, creationflags=CREATE_NEW_CONSOLE, encoding='utf-8')


    def write(self, msg):
        self.stdin.write(msg + "\n" )

if __name__ == "__main__":
    myConsole = console(color="c0", title="test error console")
    myConsole.write("Thank you jfs. Cool explanation")
    NoTitle= console()
    NoTitle.write("default color and title! This answer uses Windows 10")
    NoTitle.write(u"♥♥♥♥♥♥♥♥")
    NoTitle.write("♥")
    time.sleep(5)
    myConsole.terminate()
    NoTitle.write("some more text. Run this at the python console.")
    time.sleep(4)
    NoTitle.terminate()
    time.sleep(5)

Comments

-1

Do you know about screen/tmux?

How about tmuxp? For example, you can try to run cat in split panes and use "sendkeys" to send output (but dig the docs, may be there is even easier ways to achieve this).

As a side bonus this will work in the text console or GUI.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.