簡単に言うと、プログラムに2つのコンソールが必要です。アクティブなユーザー入力用。そして、純粋なログ出力用のもう1つ(受け入れられた回答を含む作業コードは、下の質問のテキストの「Edit-3」セクションにあります。 「Edit-1」および「Edit-2」セクションは機能する回避策です。)
このために、メインコマンドラインPythonスクリプトがあります。これは、ログ出力専用の追加コンソールを開くことになっています。このため、メインに出力されるログ出力をリダイレクトします。スクリプトのコンソール、2番目のコンソールの標準入力、サブプロセスとして開始します(2番目のコンソールを開く他の方法が見つからなかったため、サブプロセスを使用します)。
問題は、この2番目のコンソールの標準入力に送信できるように見えることですが、この2番目のコンソールには何も印刷されません。
以下は、実験に使用したコードです(Windows 10のPyDevでPython 3.4を使用)。関数writing(input, pipe, process)
には、生成された文字列がasにコピーされる部分が含まれます。 pipe
は、サブプロセスを介して開かれたコンソールのstdinを渡しました。関数writing(...)は、クラスwritetest(Thread)
を介して実行されます(コードをいくつか残しましたが、コメントアウトしました)。
_import os
import sys
import io
import time
import threading
from cmd import Cmd
from queue import Queue
from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE
REPETITIONS = 3
# Position of "The class" (Edit-2)
# Position of "The class" (Edit-1)
class generatetest(threading.Thread):
def __init__(self, queue):
self.output = queue
threading.Thread.__init__(self)
def run(self):
print('run generatetest')
generating(REPETITIONS, self.output)
print('generatetest done')
def getout(self):
return self.output
class writetest(threading.Thread):
def __init__(self, input=None, pipe=None, process=None):
if (input == None): # just in case
self.input = Queue()
else:
self.input = input
if (pipe == None): # just in case
self.pipe = PIPE
else:
self.pipe = pipe
if (process == None): # just in case
self.process = subprocess.Popen('C:\Windows\System32\cmd.exe', universal_newlines=True, creationflags=CREATE_NEW_CONSOLE)
else:
self.process = proc
threading.Thread.__init__(self)
def run(self):
print('run writetest')
writing(self.input, self.pipe, self.process)
print('writetest done')
# Position of "The function" (Edit-2)
# Position of "The function" (Edit-1)
def generating(maxint, outline):
print('def generating')
for i in range(maxint):
time.sleep(1)
outline.put_nowait(i)
def writing(input, pipe, process):
print('def writing')
while(True):
try:
print('try')
string = str(input.get(True, REPETITIONS)) + "\n"
pipe = io.StringIO(string)
pipe.flush()
time.sleep(1)
# print(pipe.readline())
except:
print('except')
break
finally:
print('finally')
pass
data_queue = Queue()
data_pipe = sys.stdin
# printer = sys.stdout
# data_pipe = os.pipe()[1]
# The code of 'C:\\Users\\Public\\Documents\\test\\test-cmd.py'
# can be found in the question's text further below under "More code"
exe = 'C:\Python34\python.exe'
# exe = 'C:\Windows\System32\cmd.exe'
arg = 'C:\\Users\\Public\\Documents\\test\\test-cmd.py'
arguments = [exe, arg]
# proc = Popen(arguments, universal_newlines=True, creationflags=CREATE_NEW_CONSOLE)
proc = Popen(arguments, stdin=data_pipe, stdout=PIPE, stderr=PIPE,
universal_newlines=True, creationflags=CREATE_NEW_CONSOLE)
# Position of "The call" (Edit-2 & Edit-1) - file init (proxyfile)
# Position of "The call" (Edit-2) - thread = sockettest()
# Position of "The call" (Edit-1) - thread0 = logtest()
thread1 = generatetest(data_queue)
thread2 = writetest(data_queue, data_pipe, proc)
# time.sleep(5)
# Position of "The call" (Edit-2) - thread.start()
# Position of "The call" (Edit-1) - thread0.start()
thread1.start()
thread2.start()
# Position of "The call" (Edit-2) - thread.join()
# Position of "The call" (Edit-1) - thread.join()
thread1.join(REPETITIONS * REPETITIONS)
thread2.join(REPETITIONS * REPETITIONS)
# data_queue.join()
# receiver = proc.communicate(stdin, 5)
# print('OUT:' + receiver[0])
# print('ERR:' + receiver[1])
print("1st part finished")
_
次の追加のコードスニペットは、サブプロセスから標準出力を抽出することに関して機能します。ただし、以前に送信された標準入力はまだ2番目のコンソールに出力されません。また、2番目のコンソールはすぐに閉じられます。
_proc2 = Popen(['C:\Python34\python.exe', '-i'],
stdin=PIPE,
stdout=PIPE,
stderr=PIPE,
creationflags=CREATE_NEW_CONSOLE)
proc2.stdin.write(b'2+2\n')
proc2.stdin.flush()
print(proc2.stdout.readline())
proc2.stdin.write(b'len("foobar")\n')
proc2.stdin.flush()
print(proc2.stdout.readline())
time.sleep(1)
proc2.stdin.close()
proc2.terminate()
proc2.wait(timeout=0.2)
print("Exiting Main Thread")
_
サブプロセスを開始するためにパラメータ_stdin=data_pipe, stdout=PIPE, stderr=PIPE
_の1つを使用するとすぐに、結果の2番目のコンソールはアクティブではなく、キーボード入力を受け入れません(これは望ましくありませんが、ここでは役立つ情報かもしれません)。
サブプロセスメソッドcommunicate()
は、プロセスが終了するまで待機するため、これには使用できません。
最後に、2番目のコンソール用のファイルのコード。
C:\ Users\Public\Documents\test\test-cmd.py
_from cmd import Cmd
from time import sleep
from datetime import datetime
INTRO = 'command line'
Prompt = '> '
class CommandLine(Cmd):
"""Custom console"""
def __init__(self, intro=INTRO, Prompt=PROMPT):
Cmd.__init__(self)
self.intro = intro
self.Prompt = Prompt
self.doc_header = intro
self.running = False
def do_dummy(self, args):
"""Runs a dummy method."""
print("Do the dummy.")
self.running = True
while(self.running == True):
print(datetime.now())
sleep(5)
def do_stop(self, args):
"""Stops the dummy method."""
print("Stop the dummy, if you can.")
self.running = False
def do_exit(self, args):
"""Exits this console."""
print("Do console exit.")
exit()
if __name__ == '__main__':
cl = CommandLine()
cl.Prompt = Prompt
cl.cmdloop(INTRO)
_
これまでのところ、Windowsコマンドラインインターフェイスが、キーボードからの入力以外の入力を受け入れる機能を提供しているかどうかさえわかりません(必要なstdinパイプなどの代わりに)。とはいえ、ある種のパッシブモードがあるので、私はそれを期待しています。
なぜこれが機能しないのですか?
Pythonで複数のコンソールを操作する の答えで示唆されているように、ファイルを表示するための回避策としてファイルを使用すると、一般的に機能します。ただし、ログファイルは数GBに達するため、この場合の実用的な解決策ではありません。少なくともファイルの分割と適切な処理が必要です。
クラス:
_class logtest(threading.Thread):
def __init__(self, file):
self.file = file
threading.Thread.__init__(self)
def run(self):
print('run logtest')
logging(self.file)
print('logtest done')
_
関数:
_def logging(file):
pexe = 'C:\Python34\python.exe '
script = 'C:\\Users\\Public\\Documents\\test\\test-004.py'
filek = '--file'
filev = file
file = open(file, 'a')
file.close()
time.sleep(1)
print('LOG START (outer): ' + script + ' ' + filek + ' ' + filev)
proc = Popen([pexe, script, filek, filev], universal_newlines=True, creationflags=CREATE_NEW_CONSOLE)
print('LOG FINISH (outer): ' + script + ' ' + filek + ' ' + filev)
time.sleep(2)
_
呼び出し:
_# The file tempdata is filled with several strings of "0\n1\n2\n"
# Looking like this:
# 0
# 1
# 2
# 0
# 1
# 2
proxyfile = 'C:\\Users\\Public\\Documents\\test\\tempdata'
f = open(proxyfile, 'a')
f.close()
time.sleep(1)
thread0 = logtest(proxyfile)
thread0.start()
thread0.join(REPETITIONS * REPETITIONS)
_
テールスクリプト( "test-004.py"):
Windowsはtailコマンドを提供していないので、代わりに次のスクリプトを使用しました( tailに相当するPythonの実装方法-F? の答えに基づいています)。追加でありながら不要なclass CommandLine(Cmd)
は、最初は2番目のコンソールを開いたままにする試みでした(スクリプトファイルの引数がないため)。ただし、コンソールが新しいログファイルの内容を流に印刷し続けるのに役立つことも証明されています。それ以外の場合、出力は決定的/予測不可能でした。
_import time
import sys
import os
import threading
from cmd import Cmd
from argparse import ArgumentParser
def main(args):
parser = ArgumentParser(description="Parse arguments.")
parser.add_argument("-f", "--file", type=str, default='', required=False)
arguments = parser.parse_args(args)
if not arguments.file:
print('LOG PRE-START (inner): file argument not found. Creating new default entry.')
arguments.file = 'C:\\Users\\Public\\Documents\\test\\tempdata'
print('LOG START (inner): ' + os.path.abspath(os.path.dirname(__file__)) + ' ' + arguments.file)
f = open(arguments.file, 'a')
f.close()
time.sleep(1)
words = ['Word']
console = CommandLine(arguments.file, words)
console.Prompt = ''
thread = threading.Thread(target=console.cmdloop, args=('', ))
thread.start()
print("\n")
for hit_Word, hit_sentence in console.watch():
print("Found %r in line: %r" % (hit_Word, hit_sentence))
print('LOG FINISH (inner): ' + os.path.abspath(os.path.dirname(__file__)) + ' ' + arguments.file)
class CommandLine(Cmd):
"""Custom console"""
def __init__(self, fn, words):
Cmd.__init__(self)
self.fn = fn
self.words = words
def watch(self):
fp = open(self.fn, 'r')
while True:
time.sleep(0.05)
new = fp.readline()
print(new)
# Once all lines are read this just returns ''
# until the file changes and a new line appears
if new:
for Word in self.words:
if Word in new:
yield (Word, new)
else:
time.sleep(0.5)
if __name__ == '__main__':
print('LOG START (inner - as main).')
main(sys.argv[1:])
_
まだ試していないが動作する可能性のある3つの回避策は、ソケットです(この回答でも提案されています Pythonで複数のコンソールを動作させる )、プロセスIDを介してプロセスオブジェクトを取得して制御し、 WindowsコンソールAPIに直接アクセスするためのctypesライブラリ。スクリーンバッファーを設定できます。コンソールには複数のバッファーを設定できますが、アクティブバッファーは1つだけです( CreateConsoleScreenBuffer function のドキュメントの備考に記載されています) 。
ただし、ソケットを使用するのが最も簡単な方法かもしれません。そして、少なくともログのサイズはこのように関係ありません。ただし、ここでは接続の問題が問題になる場合があります。
Pythonで複数のコンソールを操作する の回答でも提案されているように、ソケットを回避策として使用して新しいログエンティティを表示することも一般的に機能しています。とはいえ、これは何かをするにはあまりにも多くの労力を費やしているようです。これは単に受信コンソールのプロセスに送られるべきです。
クラス:
_class sockettest(threading.Thread):
def __init__(self, Host, port, file):
self.Host = Host
self.port = port
self.file = file
threading.Thread.__init__(self)
def run(self):
print('run sockettest')
socketing(self.Host, self.port, self.file)
print('sockettest done')
_
関数:
_def socketing(Host, port, file):
pexe = 'C:\Python34\python.exe '
script = 'C:\\Users\\Public\\Documents\\test\test-005.py'
hostk = '--address'
hostv = str(Host)
portk = '--port'
portv = str(port)
filek = '--file'
filev = file
file = open(file, 'a')
file.close()
time.sleep(1)
print('Host START (outer): ' + pexe + script + ' ' + hostk + ' ' + hostv + ' ' + portk + ' ' + portv + ' ' + filek + ' ' + filev)
proc = Popen([pexe, script, hostk, hostv, portk, portv, filek, filev], universal_newlines=True, creationflags=CREATE_NEW_CONSOLE)
print('Host FINISH (outer): ' + pexe + script + ' ' + hostk + ' ' + hostv + ' ' + portk + ' ' + portv + ' ' + filek + ' ' + filev)
time.sleep(2)
_
呼び出し:
_# The file tempdata is filled with several strings of "0\n1\n2\n"
# Looking like this:
# 0
# 1
# 2
# 0
# 1
# 2
proxyfile = 'C:\\Users\\Public\\Documents\\test\\tempdata'
f = open(proxyfile, 'a')
f.close()
time.sleep(1)
thread = sockettest('127.0.0.1', 8888, proxyfile)
thread.start()
thread.join(REPETITIONS * REPETITIONS)
_
ソケットスクリプト( "test-005.py"):
次のスクリプトは、 Python:スレッドを使用したサーバー/クライアントアプリケーションのプログラミング に基づいています。ここでは、ログエントリジェネレータとしてclass CommandLine(Cmd)
を保持しています。この時点で、2番目のコンソールを呼び出すメインスクリプトにクライアントを配置し、(新しい)ファイル行の代わりに実際のログエンティティをキューに供給することは問題になりません。 (サーバーはプリンターです。)
_import socket
import sys
import threading
import time
from cmd import Cmd
from argparse import ArgumentParser
from queue import Queue
BUFFER_SIZE = 5120
class CommandLine(Cmd):
"""Custom console"""
def __init__(self, fn, words, queue):
Cmd.__init__(self)
self.fn = fn
self.words = words
self.queue = queue
def watch(self):
fp = open(self.fn, 'r')
while True:
time.sleep(0.05)
new = fp.readline()
# Once all lines are read this just returns ''
# until the file changes and a new line appears
self.queue.put_nowait(new)
def main(args):
parser = ArgumentParser(description="Parse arguments.")
parser.add_argument("-a", "--address", type=str, default='127.0.0.1', required=False)
parser.add_argument("-p", "--port", type=str, default='8888', required=False)
parser.add_argument("-f", "--file", type=str, default='', required=False)
arguments = parser.parse_args(args)
if not arguments.address:
print('Host PRE-START (inner): Host argument not found. Creating new default entry.')
arguments.Host = '127.0.0.1'
if not arguments.port:
print('Host PRE-START (inner): port argument not found. Creating new default entry.')
arguments.port = '8888'
if not arguments.file:
print('Host PRE-START (inner): file argument not found. Creating new default entry.')
arguments.file = 'C:\\Users\\Public\\Documents\\test\\tempdata'
file_queue = Queue()
print('Host START (inner): ' + ' ' + arguments.address + ':' + arguments.port + ' --file ' + arguments.file)
# Start server
thread = threading.Thread(target=start_server, args=(arguments.address, arguments.port, ))
thread.start()
time.sleep(1)
# Start client
thread = threading.Thread(target=start_client, args=(arguments.address, arguments.port, file_queue, ))
thread.start()
# Start file reader
f = open(arguments.file, 'a')
f.close()
time.sleep(1)
words = ['Word']
console = CommandLine(arguments.file, words, file_queue)
console.Prompt = ''
thread = threading.Thread(target=console.cmdloop, args=('', ))
thread.start()
print("\n")
for hit_Word, hit_sentence in console.watch():
print("Found %r in line: %r" % (hit_Word, hit_sentence))
print('Host FINISH (inner): ' + ' ' + arguments.address + ':' + arguments.port)
def start_client(Host, port, queue):
Host = Host
port = int(port) # arbitrary non-privileged port
queue = queue
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
soc.connect((Host, port))
except:
print("Client connection error" + str(sys.exc_info()))
sys.exit()
print("Enter 'quit' to exit")
message = ""
while message != 'quit':
time.sleep(0.05)
if(message != ""):
soc.sendall(message.encode("utf8"))
if soc.recv(BUFFER_SIZE).decode("utf8") == "-":
pass # null operation
string = ""
if (not queue.empty()):
string = str(queue.get_nowait()) + "\n"
if(string == None or string == ""):
message = ""
else:
message = string
soc.send(b'--quit--')
def start_server(Host, port):
Host = Host
port = int(port) # arbitrary non-privileged port
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# SO_REUSEADDR flag tells the kernel to reuse a local socket in TIME_WAIT state, without waiting for its natural timeout to expire
soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print("Socket created")
try:
soc.bind((Host, port))
except:
print("Bind failed. Error : " + str(sys.exc_info()))
sys.exit()
soc.listen(5) # queue up to 5 requests
print("Socket now listening")
# infinite loop- do not reset for every requests
while True:
connection, address = soc.accept()
ip, port = str(address[0]), str(address[1])
print("Connected with " + ip + ":" + port)
try:
threading.Thread(target=client_thread, args=(connection, ip, port)).start()
except:
print("Thread did not start.")
traceback.print_exc()
soc.close()
def client_thread(connection, ip, port, max_buffer_size=BUFFER_SIZE):
is_active = True
while is_active:
client_input = receive_input(connection, max_buffer_size)
if "--QUIT--" in client_input:
print("Client is requesting to quit")
connection.close()
print("Connection " + ip + ":" + port + " closed")
is_active = False
Elif not client_input == "":
print("{}".format(client_input))
connection.sendall("-".encode("utf8"))
else:
connection.sendall("-".encode("utf8"))
def receive_input(connection, max_buffer_size):
client_input = connection.recv(max_buffer_size)
client_input_size = sys.getsizeof(client_input)
if client_input_size > max_buffer_size:
print("The input size is greater than expected {}".format(client_input_size))
decoded_input = client_input.decode("utf8").rstrip() # decode and strip end of line
result = process_input(decoded_input)
return result
def process_input(input_str):
return str(input_str).upper()
if __name__ == '__main__':
print('Host START (inner - as main).')
main(sys.argv[1:])
_
サブプロセスのコンソール入力パイプ/バッファを直接制御することは、この問題の望ましい解決策です。これは500評判の報奨金です。
残念ながら、私は時間を使い果たしています。したがって、これらの回避策のいずれかを今のところ使用し、後で適切なソリューションに置き換える可能性があります。または、核のオプションを使用する必要があります。コンソールは1つだけで、ユーザーのキーボード入力中は継続的なログ出力が一時停止され、その後印刷されます。もちろん、ユーザーが途中で何かを入力することを決めた場合、これはバッファの問題につながる可能性があります。
James Kentからの回答により、Windowsコマンドライン(cmd)またはPowerShellを介してコードを使用してスクリプトを開始したときに、目的の動作が得られます。ただし、「Python run」でEclipse/PyDevを介してこの同じスクリプトを起動すると、出力は常にメインのEclipse/PyDevコンソールに出力されますが、サブプロセスの2番目のコンソールは空のままで非アクティブのままです。ただし、これは別のシステム/環境の専門分野であり、別の問題だと思います。
_from sys import argv, stdin, stdout
from threading import Thread
from cmd import Cmd
from time import sleep
from datetime import datetime
from subprocess import Popen, PIPE, CREATE_NEW_CONSOLE
INTRO = 'command line'
Prompt = '> '
class CommandLine(Cmd):
"""Custom console"""
def __init__(self, subprocess, intro=INTRO, Prompt=PROMPT):
Cmd.__init__(self)
self.subprocess = subprocess
self.intro = intro
self.Prompt = Prompt
self.doc_header = intro
self.running = False
def do_date(self, args):
"""Prints the current date and time."""
print(datetime.now())
sleep(1)
def do_exit(self, args):
"""Exits this command line application."""
print("Exit by user command.")
if self.subprocess is not None:
try:
self.subprocess.terminate()
except:
self.subprocess.kill()
exit()
class Console():
def __init__(self):
if '-r' not in argv:
self.p = Popen(
['python.exe', __file__, '-r'],
stdin=PIPE,
creationflags=CREATE_NEW_CONSOLE
)
else:
while True:
data = stdin.read(1)
if not data:
# break
sleep(1)
continue
stdout.write(data)
def write(self, data):
self.p.stdin.write(data.encode('utf8'))
self.p.stdin.flush()
def getSubprocess(self):
if self.p:
return self.p
else:
return None
class Feeder (Thread):
def __init__(self, console):
self.console = console
Thread.__init__(self)
def run(self):
feeding(self.console)
def feeding(console):
for i in range(0, 100):
console.write('test %i\n' % i)
sleep(1)
if __name__ == '__main__':
p = Console()
if '-r' not in argv:
thread = Feeder(p)
thread.setDaemon(True)
thread.start()
cl = CommandLine(subprocess=p.getSubprocess())
cl.use_rawinput = False
cl.Prompt = Prompt
cl.cmdloop('\nCommand line is waiting for user input (e.g. help).')
_
上記の質問のテキストでは、別の回避策としてWindowsコンソールAPIに直接アクセスするためにctypesライブラリを使用することに言及しています(「Edit-1:More Thoughts」の下)。または、1つのコンソールだけを使用して、入力プロンプトが常にこの問題全体の核となる選択肢として一番下にとどまるようにします。 (「Edit-2:さらに考え」の下)
Ctypesライブラリを使用するために、私は Windowsでコンソールフォントを変更する に対する次の答えに焦点を当てていました。そして、1つのコンソールだけを使用する場合、 コンソールの入力行を出力の下に置く に対して次の回答を試してみました。これらの答えは両方とも、この問題に関して潜在的なメリットを提供する可能性があり、おそらくこの投稿に出くわした他の人に役立つと思います。また、私は時間を見つけたら、彼らが何らかの形で動作するかどうかを試してみます。
あなたが直面している問題は、Windows上のコンソールサブシステムのアーキテクチャであり、通常表示されるコンソールウィンドウはcmd.exeによってホストされず、代わりにconhost.exeによってホストされ、conhostウィンドウの子プロセスは単一のコンホストインスタンスは、プロセスごとに1つのウィンドウに制限されることを意味します。
これにより、各コンソールウィンドウに追加のプロセスが必要になります。そのウィンドウに何かを表示するには、stdinとstdoutが通常どのように処理され、読み書きされるかを調べる必要があります(ホストにプロセスを書き込むことができるように)stdinをパイプに変更する場合を除き、conhostインスタンスによって、conhostからではなく、親プロセスから来るようになります。これは、stdinに書き込まれたものはすべて子プロセスによってのみ読み取られるため、conhostによって表示されないことを意味します。
私の知る限り、そのようなパイプを共有する方法はありません。
副作用として、stdinをパイプにすると、新しいコンソールウィンドウに送信されるすべてのキーボード入力はどこにも行きません。stdinはそのウィンドウに接続されていないからです。
これは、出力のみの関数の場合、パイプを介して標準入力に親と通信し、すべてを標準出力にエコーする新しいプロセスを生成できることを意味します。
試みはここにあります:
#!python3
import sys, subprocess, time
class Console():
def __init__(self):
if '-r' not in sys.argv:
self.p = subprocess.Popen(
['python.exe', __file__, '-r'],
stdin=subprocess.PIPE,
creationflags=subprocess.CREATE_NEW_CONSOLE
)
else:
while True:
data = sys.stdin.read(1)
if not data:
break
sys.stdout.write(data)
def write(self, data):
self.p.stdin.write(data.encode('utf8'))
self.p.stdin.flush()
if (__name__ == '__main__'):
p = Console()
if '-r' not in sys.argv:
for i in range(0, 100):
p.write('test %i\n' % i)
time.sleep(1)
したがって、2つのプロセス間のニースの単純なパイプで、サブプロセスの場合は入力を出力にエコーバックします。インスタンスがプロセスかどうかを示すために-rを使用しましたが、実装方法に応じて他の方法があります。
注意すべき点がいくつかあります。
__file__
__file__
を使用しているため、cx_Freezeなどを使用して凍結する場合、このアプローチを変更する必要があります。cx_Freezeでフリーズできるバージョンの場合:
import sys, subprocess
class Console():
def __init__(self, ischild=True):
if not ischild:
if hasattr(sys, 'frozen'):
args = ['Console.exe']
else:
args = [sys.executable, __file__]
self.p = subprocess.Popen(
args,
stdin=subprocess.PIPE,
creationflags=subprocess.CREATE_NEW_CONSOLE
)
else:
while True:
data = sys.stdin.read(1)
if not data:
break
sys.stdout.write(data)
def write(self, data):
self.p.stdin.write(data.encode('utf8'))
self.p.stdin.flush()
if (__name__ == '__main__'):
p = Console()
from Console import Console
import sys, time
if (__name__ == '__main__'):
p = Console(False)
for i in range(0, 100):
p.write('test %i\n' % i)
time.sleep(1)
from cx_Freeze import setup, Executable
setup(
name = 'Console-test',
executables = [
Executable(
'Console.py',
base=None,
),
Executable(
'test.py',
base=None,
)
]
)
IDLEなどの開発ツールで動作する新しいバージョン
#!python3
import ctypes, sys, subprocess
Kernel32 = ctypes.windll.Kernel32
class Console():
def __init__(self, ischild=True):
if ischild:
# try allocate new console
result = Kernel32.AllocConsole()
if result > 0:
# if we succeed open handle to the console output
sys.stdout = open('CONOUT$', mode='w')
else:
# if frozen we assume its names Console.exe
# note that when frozen 'Win32GUI' must be used as a base
if hasattr(sys, 'frozen'):
args = ['Console.exe']
else:
# otherwise we use the console free version of python
args = ['pythonw.exe', __file__]
self.p = subprocess.Popen(
args,
stdin=subprocess.PIPE
)
return
while True:
data = sys.stdin.read(1)
if not data:
break
sys.stdout.write(data)
def write(self, data):
self.p.stdin.write(data.encode('utf8'))
self.p.stdin.flush()
if (__name__ == '__main__'):
p = Console()
from Console import Console
import sys, time
if (__name__ == '__main__'):
p = Console(False)
for i in range(0, 100):
p.write('test %i\n' % i)
time.sleep(1)
from cx_Freeze import setup, Executable
setup(
name = 'Console-test',
executables = [
Executable(
'Console.py',
base='Win32GUI',
),
Executable(
'test.py',
base=None,
)
]
)
これはより堅牢にすることができます。つまり、新しいコンソールを作成する前に、既存のコンソールを常に確認し、見つかった場合はそれをデタッチし、エラー処理を改善します。