process.getInputStream() is Buffered and blocks print() from Python code

I’m having difficulty getting Runtime.getRuntime().exec(cmd) to return print() calls from a py5 file. The Processing console output should look like the Terminal output, but is instead very scant and I can’t find any other technique to get a more complete input stream from the py5 app. There are several steps involved to run the demo below and demonstrate the problem:

  1. Install py5 on your system if you haven’t already. Instructions are here: https://py5coding.org/content/install.html I used the miniconda technique but you could also use venv. You should then have the py5-run-sketch executable on your system shown below (macOS) and cmdStr should point to it.
  2. The py5 file source code is shown below; save it with the name “Arrows.py”.
  3. Processing source code also follows. You will need to change the cmdStr and filePath to reflect your system.
  4. Run the Processing code and give it a few seconds to launch the py5 app. Click on the up and down arrows a few times and then stop the thread by clicking on the default Processing window.
  5. Compare what you see in your console output with what you should see in Terminal by running ‘cmdStr’ ‘filePath’ at the prompt. Terminal output on my system is also shown below if you want to skip this step.

Thanks in advance for any insight into improving the console output.

Processing source code:

//https://docs.oracle.com/javase/9/docs/api/java/lang/Process.html
//https://py5coding.org/content/install.html

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

Process process;

// *** Change these for your system *** //
String cmdStr = "/opt/miniconda3/bin/py5-run-sketch";
String filePath = "/Users/xxxxx/py5_code/Arrows.py";

void execAction() {
  try {
    String[] cmd = {cmdStr, filePath};
    process = Runtime.getRuntime().exec(cmd);
    BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
    BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    String s = "";
    while ((s = stdIn.readLine()) != null) {
      println(s);
    }
    String s1 = "";
    while ((s1 = stdErr.readLine()) != null) {
      println(s1);
    }
  }
  catch (IOException  e) {
    println("Error: ", e);
  }
}

void setup() {
  size(250, 150);
  surface.setTitle("exec demo");
  thread("execAction");
  fill(0);
  textSize(18);
  text("Click here to stop thread.", 20, 20);
}

void draw() {
}

void mousePressed() {
  println("mouse pressed.");
  process.destroy();
}

py5 source code - save to file named ‘Arrows.py’:

# Uses Imported mode for py5

from controlP5 import ControlP5

this = get_current_sketch()

def drawUpArrow():
  upArrw = create_graphics(20,20)
  upArrw.begin_draw()
  upArrw.background(255)
  upArrw.fill(0,255,0)
  upArrw.triangle(10,2,2,18,18,18)
  upArrw.end_draw()        
  return upArrw

def drawDownArrow():
  dwnArrw = create_graphics(20,20)
  dwnArrw.begin_draw()
  dwnArrw.background(255)
  dwnArrw.fill(0,255,0)
  dwnArrw.triangle(2,2,18,2,10,18)
  dwnArrw.end_draw()        
  return dwnArrw

def settings():
  size(200,150)

def setup():
  global up,dwn,cp5

  print("Hello py5 world!!")
  window_title("Click on Arrows")  
  cp5 = ControlP5(this)
  upArrw = drawUpArrow()
  up = cp5.addButton("up").setId(2).setPosition(90,40).setSize(20,20)
  up.setImage(upArrw)
  dwnArrw = drawDownArrow()
  dwn = cp5.addButton("dwn").setId(1).setPosition(90,60).setSize(20,20)
  dwn.setImage(dwnArrw)
 
def mouse_pressed(e):
  if(up.isPressed()):
    print("up arrow was pressed.")  

  if(dwn.isPressed()):
    print("down arrow was pressed.")

py5-run-sketch exe:

Console output:

Terminal output. Should see this in Processing console output:

1 Like

As AI suggests, we have to add flush = True to the py5 print() calls, eg print("Hello py5 world!", flush = True) then it will work as expected.

Alternate Approach:
Use ProcessBuilder with builder.environment().put("PYTHONUNBUFFERED", "TRUE"); This also works and obviates the need to add flush=True to every print() in py5.

3 Likes

Hi @svan,

I got this working with Windows as well.

Hardest part was finding the executables… but revealed a real mess with multiple installs on my system that I cleaned up. < Topic for another day!

I could not get ControlP5 working and just wrote simple code for detecting keypresses. This sidetracked me and did not need this import in my code.

Some feedback:

  • Change subject of topic since it is adequate
  • Python code could have been simple and proof of concept.
  • Format your code snippets so they are readable.
    It was not easy for me to read.

I asked ChatGPT to clean it up:

As the AI suggests, we need to add flush=True to print() calls in py5 — for example:
print("Hello py5 world!", flush=True)
This ensures the output appears as expected.

Good use of AI in this case to scrutinize your code and provide formatting tips.

Good topic!

Update
Thank your for making the changes!

:)

Backtracking…

This was one of the hurdles that sidetracked me initially and I worked around it.
I am good to go now!

*** How to Use Processing Libraries*** with py5:

I can sort out most things from experience.
New users and experienced users may be challenged with these topics.

KISS Keep It Simple Sometimes

:)

1 Like

Hello @svan ,

This is a good topic! Thanks!

I have always wanted to explore these more with a variety of applications:

Standard streams - Wikipedia

I launched a py5 sketch from a batch file and confirmed that the print() output appears in the command prompt.

This worked on W10 with this very simple batch file:

@echo off
REM Path to py5-run-sketch executable
set PY5_RUN=C:\Users\GLV\AppData\Local\Programs\Python\Python313\Scripts\py5-run-sketch.exe

REM Path to your Python sketch file
set SKETCH_PATH=D:\Users\GLV\Documents\P4\Stdin_java_Pythin_1_0_0\arrows2.py

REM Run py5-run-sketch on the sketch file
"%PY5_RUN%" "%SKETCH_PATH%"

REM Keep window open so you can read output
pause

Note to visitors to topic:
Those are the directories on my system.
Adjust as required.

I am sure it is easier on Linux and I may get back to using that soon!

:)