2017-08-13 15 views
11

मैं एक निष्पादन वातावरण/खोल बनाने की कोशिश कर रहा हूं जो एक सर्वर पर दूरस्थ रूप से निष्पादित करेगा, जो ब्राउज़र में प्रस्तुत सॉकेट पर stdout, err को स्ट्रीम करता है। मैंने वर्तमान में PIPE के साथ subprocess.run का उपयोग करने का प्रयास किया है। समस्या यह है कि प्रक्रिया पूरी होने के बाद मुझे stdout मिलता है। मैं जो हासिल करना चाहता हूं वह एक लाइन-बाय-लाइन, छद्म-टर्मिनल प्रकार के कार्यान्वयन को प्राप्त करना है।लाइव कंसोल बनाने के लिए पायथन की पीटीआई का उपयोग करें

मेरे वर्तमान कार्यान्वयन

test.py

def greeter(): 
    for _ in range(10): 
     print('hello world') 

greeter() 

और खोल में

>>> import subprocess 
>>> result = subprocess.run(['python3', 'test.py'], stdout=subprocess.PIPE) 
>>> print(result.stdout.decode('utf-8')) 
hello world 
hello world 
hello world 
hello world 
hello world 
hello world 
hello world 
hello world 
hello world 
hello world 

तो मैं pty साथ भी इस सरल कार्यान्वयन प्रयास करते हैं, कैसे करता है करने के लिए प्रयास एक ऐसा करता है?

+0

चेक इस बाहर: https://stackoverflow.com/questions/1606795/catching-stdout-in-realtime-from-subprocess –

+0

'का उपयोग कर bufsize = 1' पैरामीटर लाइन बफर सेट करने के लिए उपप्रक्रिया करने की कोशिश करो, और प्रयोग' आईटीईआर (result.stdout.readline, b '') ट्रू लूप – Vinny

उत्तर

4

इम यकीन है कि एक शिकार theres कहीं आस-पास, लेकिन मैं जल्दी से

process = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE,bufsize=0) 

for out in iter(process.stdout.readline, b''): 
    print(out) 
+0

के दौरान लिपटे स्टडआउट को पढ़ने के लिए यह अभी भी 'cmd' को समाप्त करने के लिए इंतजार करेगा और फिर लूप शुरू हो जाएगा। मुझे एक एसिंक कार्यान्वयन चाहिए, इसलिए मैं 'pty' –

+0

के बारे में अधिक जानना चाहता हूं, इसे रीयलटाइम में स्ट्रीम करना चाहिए ... यदि आप इसे –

+3

केस नहीं ढूंढ रहे हैं तो आप अपने बफरसाइज को शून्य पर सेट करना चाहेंगे @ इशानखारे> यह ** ** रीयलटाइम में स्ट्रीम करेगा। 'Popen' फ़ंक्शन पृष्ठभूमि में प्रोग्राम शुरू करता है और तुरंत लौटता है। प्रोग्राम आउटपुट को कुछ भी तुरंत पढ़ा जाएगा। ध्यान दें कि पढ़ना बफर किया गया है, इसलिए पढ़ने के बाद बड़े पैमाने पर पर्याप्त खंड पढ़ने के बाद पढ़ा जाएगा (यही कारण है कि यदि आप बहुत सरल उदाहरणों के साथ परीक्षण करते हैं तो आप सोच सकते हैं कि यह इंतजार कर रहा है)। यदि आप वास्तव में प्रदर्शन की कीमत पर पूरी तरह रीयलटाइम पढ़ना चाहते हैं तो आप 'bufsize = 0' के साथ बफरिंग अक्षम कर सकते हैं। – spectras

2

यह पाते हैं कि आप तो आप एक बहुत लंबे समय के लिए एक कठिन लड़ाई लड़ रहे हो जाएगा विंडोज पर हैं सके, और मैं दर्द के लिए माफी चाहता हूँ आप सहन करेंगे (वहां रहे)। यदि आप लिनक्स पर हैं, तो आप pexpect मॉड्यूल का उपयोग कर सकते हैं। Pexpect आपको पृष्ठभूमि बाल प्रक्रिया को जन्म देने की अनुमति देता है जिसे आप बिडरेक्शनल संचार कर सकते हैं। यह सभी प्रकार के सिस्टम स्वचालन के लिए उपयोगी है, लेकिन एक बहुत ही सामान्य उपयोग केस एसएसएच है।

import pexpect 

child = pexpect.spawn('python3 test.py') 
message = 'hello world' 

while True: 
    try: 
     child.expect(message) 
    except pexpect.exceptions.EOF: 
     break 
    input('child sent: "%s"\nHit enter to continue: ' % 
     (message + child.before.decode())) 

print('reached end of file!') 

मैं इसे बहुत उपयोगी एक वर्ग कुछ एक ssh कनेक्शन की तरह जटिल संभाल करने को बनाने के लिए मिल गया है, लेकिन अगर आपके उपयोग के मामले काफी सरल है उचित या आवश्यक नहीं हो सकता है। जिस तरह से pexpect.before प्रकार बाइट्स है और जो पैटर्न आप खोज रहे हैं उसे छोड़कर अजीब हो सकता है, इसलिए यह एक ऐसा फ़ंक्शन बनाने के लिए समझ में आ सकता है जो कम से कम आपके लिए इसे संभालता है।

def get_output(child, message): 
    return(message + child.before.decode()) 

यदि आप बच्चे की प्रक्रिया में संदेश भेजना चाहते हैं, तो आप child.sendline (लाइन) का उपयोग कर सकते हैं। अधिक जानकारी के लिए, मेरे द्वारा लिंक किए गए दस्तावेज़ देखें।

मुझे उम्मीद है कि मैं मदद करने में सक्षम था!

1

मैं अगर आप एक ब्राउज़र में इस प्रदान कर सकते हैं पता नहीं है, लेकिन आप इस तरह stdout तुरंत प्राप्त मॉड्यूल की तरह एक कार्यक्रम चला सकते हैं:

import importlib 
from importlib.machinery import SourceFileLoader 

class Program: 

    def __init__(self, path, name=''): 
     self.path = path 
     self.name = name 
     if self.path: 
      if not self.name: 
       self.get_name() 
      self.loader = importlib.machinery.SourceFileLoader(self.name, self.path) 
      self.spec = importlib.util.spec_from_loader(self.loader.name, self.loader) 
      self.mod = importlib.util.module_from_spec(self.spec) 
     return 

    def get_name(self): 
     extension = '.py' #change this if self.path is not python program with extension .py 
     self.name = self.path.split('\\')[-1].strip('.py') 
     return 

    def load(self): 
     self.check() 
     self.loader.exec_module(self.mod) 
     return 

    def check(self): 
     if not self.path: 
      Error('self.file is NOT defined.'.format(path)).throw() 
     return 

file_path = 'C:\\Users\\RICHGang\\Documents\\projects\\stackoverflow\\ptyconsole\\test.py' 
file_name = 'test' 
prog = Program(file_path, file_name) 
prog.load() 

आप को test.py में नींद जोड़ सकते हैं

from time import sleep 

def greeter(): 
    for i in range(10): 
     sleep(0.3) 
     print('hello world') 

greeter() 
4

आपके आवेदन कई कार्य के साथ अतुल्यकालिक रूप से काम करने के लिए, stdout से डाटा पढ़ने और फिर एक WebSocket करने के लिए इसे तैयार करने जैसा ही रहा है, तो मैं asyncio उपयोग करने का सुझाव: अंतर देखते हैं।

import asyncio.subprocess 
import os 

from aiohttp.web import (Application, Response, WebSocketResponse, WSMsgType, 
         run_app) 


async def on_websocket(request): 
    # Prepare aiohttp's websocket... 
    resp = WebSocketResponse() 
    await resp.prepare(request) 
    # ... and store in a global dictionary so it can be closed on shutdown 
    request.app['sockets'].append(resp) 

    process = await asyncio.create_subprocess_exec(sys.executable, 
                '/tmp/test.py', 
                stdout=asyncio.subprocess.PIPE, 
                stderr=asyncio.subprocess.PIPE, 
                bufsize=0) 
    # Schedule reading from stdout and stderr as asynchronous tasks. 
    stdout_f = asyncio.ensure_future(p.stdout.readline()) 
    stderr_f = asyncio.ensure_future(p.stderr.readline()) 

    # returncode will be set upon process's termination. 
    while p.returncode is None: 
     # Wait for a line in either stdout or stderr. 
     await asyncio.wait((stdout_f, stderr_f), return_when=asyncio.FIRST_COMPLETED) 

     # If task is done, then line is available. 
     if stdout_f.done(): 
      line = stdout_f.result().encode() 
      stdout_f = asyncio.ensure_future(p.stdout.readline()) 
      await ws.send_str(f'stdout: {line}') 

     if stderr_f.done(): 
      line = stderr_f.result().encode() 
      stderr_f = asyncio.ensure_future(p.stderr.readline()) 
      await ws.send_str(f'stderr: {line}') 

    return resp 


async def on_shutdown(app): 
    for ws in app['sockets']: 
     await ws.close()  


async def init(loop): 
    app = Application() 
    app['sockets'] = [] 
    app.router.add_get('/', on_websocket) 
    app.on_shutdown.append(on_shutdown) 
    return app 


loop = asyncio.get_event_loop() 
app = loop.run_until_complete(init()) 
run_app(app) 

यह aiohttp उपयोग करता है और web_ws और subprocess streams उदाहरण पर आधारित है:

यहाँ एक उदाहरण है कि एक प्रक्रिया चलाता है और एक WebSocket में इसके उत्पादन रीडायरेक्ट कर देता है।

संबंधित मुद्दे