How can I start a node.js subprocess in python on linux with a readable non-blocking output pipe









up vote
2
down vote

favorite












I am trying to create a subprocess of node.js in python to execute javascript code and read the output.



This code works in Windows 10 but on Ubuntu Linux it gives an error. When node starts it gives a prompt of > on stdout and this code attempts to read that prompt to verify that node has started and that the pipe is readable but it doesn't work correctly on Linux.



import os
import subprocess
import time
import re
import json
import logging

logger = logging.getLogger(__name__)

if "nt" == os.name:
import msvcrt
from ctypes import windll, byref, wintypes, GetLastError, WinError
from ctypes.wintypes import HANDLE, DWORD, BOOL, LPDWORD
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
ERROR_NO_DATA = 232
else:
import fcntl

class NodeEngine:

def __init__(self):
self.stdout_fd = None
self.p_stdout_fd = None
self.stdout = None
self.proc = None
self.__init_pipes()

def __init_pipes(self):
self.stdout_fd, self.p_stdout_fd = os.pipe()
self.pipe_no_wait(self.stdout_fd)
self.stdout = os.fdopen(self.p_stdout_fd,"w")



def pipe_no_wait(self, pipefd):

if "nt" == os.name:
SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
SetNamedPipeHandleState.restype = BOOL
h = msvcrt.get_osfhandle(pipefd)
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
if res == 0:
print(WinError())
return False
return True
else:
fl = fcntl.fcntl(pipefd, fcntl.F_GETFL)
fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

def start(self):
self.proc = subprocess.Popen(
["node","-i"],
stdin=subprocess.PIPE,
stdout=self.stdout,
# stderr=subprocess.PIPE,
shell=True
)
bytes_read = 0
ret = ""
timeout = time.time() + 10

while 0 == bytes_read or 1024 == bytes_read:
try:
data = os.read(self.stdout_fd,1024)
ret = ret + data.decode("utf-8")
bytes_read = len(data)
except Exception as e:
if time.time() >= timeout:
raise e
self.stdout.flush()
bytes_read = 0



def close(self):
try:
self.proc.stdin.close()
except:
pass

self.proc.terminate()
self.proc.wait(timeout=0.2)

if __name__ == '__main__':
engine = NodeEngine()
engine.start()


It seems the flush command isn't working. Is there a way to get this to work properly on Linux and Windows?










share|improve this question

























    up vote
    2
    down vote

    favorite












    I am trying to create a subprocess of node.js in python to execute javascript code and read the output.



    This code works in Windows 10 but on Ubuntu Linux it gives an error. When node starts it gives a prompt of > on stdout and this code attempts to read that prompt to verify that node has started and that the pipe is readable but it doesn't work correctly on Linux.



    import os
    import subprocess
    import time
    import re
    import json
    import logging

    logger = logging.getLogger(__name__)

    if "nt" == os.name:
    import msvcrt
    from ctypes import windll, byref, wintypes, GetLastError, WinError
    from ctypes.wintypes import HANDLE, DWORD, BOOL, LPDWORD
    PIPE_NOWAIT = wintypes.DWORD(0x00000001)
    ERROR_NO_DATA = 232
    else:
    import fcntl

    class NodeEngine:

    def __init__(self):
    self.stdout_fd = None
    self.p_stdout_fd = None
    self.stdout = None
    self.proc = None
    self.__init_pipes()

    def __init_pipes(self):
    self.stdout_fd, self.p_stdout_fd = os.pipe()
    self.pipe_no_wait(self.stdout_fd)
    self.stdout = os.fdopen(self.p_stdout_fd,"w")



    def pipe_no_wait(self, pipefd):

    if "nt" == os.name:
    SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
    SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
    SetNamedPipeHandleState.restype = BOOL
    h = msvcrt.get_osfhandle(pipefd)
    res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
    if res == 0:
    print(WinError())
    return False
    return True
    else:
    fl = fcntl.fcntl(pipefd, fcntl.F_GETFL)
    fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

    def start(self):
    self.proc = subprocess.Popen(
    ["node","-i"],
    stdin=subprocess.PIPE,
    stdout=self.stdout,
    # stderr=subprocess.PIPE,
    shell=True
    )
    bytes_read = 0
    ret = ""
    timeout = time.time() + 10

    while 0 == bytes_read or 1024 == bytes_read:
    try:
    data = os.read(self.stdout_fd,1024)
    ret = ret + data.decode("utf-8")
    bytes_read = len(data)
    except Exception as e:
    if time.time() >= timeout:
    raise e
    self.stdout.flush()
    bytes_read = 0



    def close(self):
    try:
    self.proc.stdin.close()
    except:
    pass

    self.proc.terminate()
    self.proc.wait(timeout=0.2)

    if __name__ == '__main__':
    engine = NodeEngine()
    engine.start()


    It seems the flush command isn't working. Is there a way to get this to work properly on Linux and Windows?










    share|improve this question























      up vote
      2
      down vote

      favorite









      up vote
      2
      down vote

      favorite











      I am trying to create a subprocess of node.js in python to execute javascript code and read the output.



      This code works in Windows 10 but on Ubuntu Linux it gives an error. When node starts it gives a prompt of > on stdout and this code attempts to read that prompt to verify that node has started and that the pipe is readable but it doesn't work correctly on Linux.



      import os
      import subprocess
      import time
      import re
      import json
      import logging

      logger = logging.getLogger(__name__)

      if "nt" == os.name:
      import msvcrt
      from ctypes import windll, byref, wintypes, GetLastError, WinError
      from ctypes.wintypes import HANDLE, DWORD, BOOL, LPDWORD
      PIPE_NOWAIT = wintypes.DWORD(0x00000001)
      ERROR_NO_DATA = 232
      else:
      import fcntl

      class NodeEngine:

      def __init__(self):
      self.stdout_fd = None
      self.p_stdout_fd = None
      self.stdout = None
      self.proc = None
      self.__init_pipes()

      def __init_pipes(self):
      self.stdout_fd, self.p_stdout_fd = os.pipe()
      self.pipe_no_wait(self.stdout_fd)
      self.stdout = os.fdopen(self.p_stdout_fd,"w")



      def pipe_no_wait(self, pipefd):

      if "nt" == os.name:
      SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
      SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
      SetNamedPipeHandleState.restype = BOOL
      h = msvcrt.get_osfhandle(pipefd)
      res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
      if res == 0:
      print(WinError())
      return False
      return True
      else:
      fl = fcntl.fcntl(pipefd, fcntl.F_GETFL)
      fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

      def start(self):
      self.proc = subprocess.Popen(
      ["node","-i"],
      stdin=subprocess.PIPE,
      stdout=self.stdout,
      # stderr=subprocess.PIPE,
      shell=True
      )
      bytes_read = 0
      ret = ""
      timeout = time.time() + 10

      while 0 == bytes_read or 1024 == bytes_read:
      try:
      data = os.read(self.stdout_fd,1024)
      ret = ret + data.decode("utf-8")
      bytes_read = len(data)
      except Exception as e:
      if time.time() >= timeout:
      raise e
      self.stdout.flush()
      bytes_read = 0



      def close(self):
      try:
      self.proc.stdin.close()
      except:
      pass

      self.proc.terminate()
      self.proc.wait(timeout=0.2)

      if __name__ == '__main__':
      engine = NodeEngine()
      engine.start()


      It seems the flush command isn't working. Is there a way to get this to work properly on Linux and Windows?










      share|improve this question













      I am trying to create a subprocess of node.js in python to execute javascript code and read the output.



      This code works in Windows 10 but on Ubuntu Linux it gives an error. When node starts it gives a prompt of > on stdout and this code attempts to read that prompt to verify that node has started and that the pipe is readable but it doesn't work correctly on Linux.



      import os
      import subprocess
      import time
      import re
      import json
      import logging

      logger = logging.getLogger(__name__)

      if "nt" == os.name:
      import msvcrt
      from ctypes import windll, byref, wintypes, GetLastError, WinError
      from ctypes.wintypes import HANDLE, DWORD, BOOL, LPDWORD
      PIPE_NOWAIT = wintypes.DWORD(0x00000001)
      ERROR_NO_DATA = 232
      else:
      import fcntl

      class NodeEngine:

      def __init__(self):
      self.stdout_fd = None
      self.p_stdout_fd = None
      self.stdout = None
      self.proc = None
      self.__init_pipes()

      def __init_pipes(self):
      self.stdout_fd, self.p_stdout_fd = os.pipe()
      self.pipe_no_wait(self.stdout_fd)
      self.stdout = os.fdopen(self.p_stdout_fd,"w")



      def pipe_no_wait(self, pipefd):

      if "nt" == os.name:
      SetNamedPipeHandleState = windll.kernel32.SetNamedPipeHandleState
      SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
      SetNamedPipeHandleState.restype = BOOL
      h = msvcrt.get_osfhandle(pipefd)
      res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
      if res == 0:
      print(WinError())
      return False
      return True
      else:
      fl = fcntl.fcntl(pipefd, fcntl.F_GETFL)
      fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

      def start(self):
      self.proc = subprocess.Popen(
      ["node","-i"],
      stdin=subprocess.PIPE,
      stdout=self.stdout,
      # stderr=subprocess.PIPE,
      shell=True
      )
      bytes_read = 0
      ret = ""
      timeout = time.time() + 10

      while 0 == bytes_read or 1024 == bytes_read:
      try:
      data = os.read(self.stdout_fd,1024)
      ret = ret + data.decode("utf-8")
      bytes_read = len(data)
      except Exception as e:
      if time.time() >= timeout:
      raise e
      self.stdout.flush()
      bytes_read = 0



      def close(self):
      try:
      self.proc.stdin.close()
      except:
      pass

      self.proc.terminate()
      self.proc.wait(timeout=0.2)

      if __name__ == '__main__':
      engine = NodeEngine()
      engine.start()


      It seems the flush command isn't working. Is there a way to get this to work properly on Linux and Windows?







      python node.js linux subprocess nonblocking






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 10 at 15:43









      Ralph Ritoch

      1,8841527




      1,8841527






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          I found the bug and it was very subtle. When using Popen with shell=True the first argument shouldn't be a list.



          I changed



           self.proc = subprocess.Popen(
          ["node","-i"],
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          to



           self.proc = subprocess.Popen(
          "node -i",
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          and now it works on both Linux and Windows.



          Note: I'll leave this question open for better solutions






          share|improve this answer




















          • Good catch Ralph!
            – pygo
            Nov 10 at 17:53










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53240567%2fhow-can-i-start-a-node-js-subprocess-in-python-on-linux-with-a-readable-non-bloc%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          I found the bug and it was very subtle. When using Popen with shell=True the first argument shouldn't be a list.



          I changed



           self.proc = subprocess.Popen(
          ["node","-i"],
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          to



           self.proc = subprocess.Popen(
          "node -i",
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          and now it works on both Linux and Windows.



          Note: I'll leave this question open for better solutions






          share|improve this answer




















          • Good catch Ralph!
            – pygo
            Nov 10 at 17:53














          up vote
          0
          down vote













          I found the bug and it was very subtle. When using Popen with shell=True the first argument shouldn't be a list.



          I changed



           self.proc = subprocess.Popen(
          ["node","-i"],
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          to



           self.proc = subprocess.Popen(
          "node -i",
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          and now it works on both Linux and Windows.



          Note: I'll leave this question open for better solutions






          share|improve this answer




















          • Good catch Ralph!
            – pygo
            Nov 10 at 17:53












          up vote
          0
          down vote










          up vote
          0
          down vote









          I found the bug and it was very subtle. When using Popen with shell=True the first argument shouldn't be a list.



          I changed



           self.proc = subprocess.Popen(
          ["node","-i"],
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          to



           self.proc = subprocess.Popen(
          "node -i",
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          and now it works on both Linux and Windows.



          Note: I'll leave this question open for better solutions






          share|improve this answer












          I found the bug and it was very subtle. When using Popen with shell=True the first argument shouldn't be a list.



          I changed



           self.proc = subprocess.Popen(
          ["node","-i"],
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          to



           self.proc = subprocess.Popen(
          "node -i",
          stdin=subprocess.PIPE,
          stdout=self.stdout,
          # stderr=subprocess.PIPE,
          shell=True
          )


          and now it works on both Linux and Windows.



          Note: I'll leave this question open for better solutions







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 10 at 17:44









          Ralph Ritoch

          1,8841527




          1,8841527











          • Good catch Ralph!
            – pygo
            Nov 10 at 17:53
















          • Good catch Ralph!
            – pygo
            Nov 10 at 17:53















          Good catch Ralph!
          – pygo
          Nov 10 at 17:53




          Good catch Ralph!
          – pygo
          Nov 10 at 17:53

















           

          draft saved


          draft discarded















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53240567%2fhow-can-i-start-a-node-js-subprocess-in-python-on-linux-with-a-readable-non-bloc%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Top Tejano songwriter Luis Silva dead of heart attack at 64

          ReactJS Fetched API data displays live - need Data displayed static

          政党