Make WriteLine() work more like print() in ETO forms

Since Rhino8, it seems better to use WriteLine() instead of print() to write things to the command line while running an ETO form. However, two things make WriteLine() cumbersome to use in comparison to print(): (1) you can’t pass multiple arguments and (2) you have to explicitly cast non-string objects to strings. Below is a little wrapper script that solves those two issues and allows you to use WriteLine more like print. You can call the function almost anything you want (print2, for example). And you can either put it at the beginning of your script or put it in a utility file.

#! python 2
import Rhino
import Rhino.Geometry as rg
import Rhino.RhinoApp as app

def writeln(*args):
    txt = ""
    for i in range(len(args)):
        txt += str(args[i])
        if i < len(args)-1: txt += ', '
    Rhino.RhinoApp.WriteLine(txt)

spheres = [rg.Sphere(rg.Point3d.Origin, 1), rg.Sphere(rg.Point3d.Origin, 2).ToBrep()]
some_value = 8

writeln(1, 2, 4.5)
writeln(spheres)
writeln('some text', some_value)

.

Below is my original post with my original ideas of how to make WriteLine easier to use by making it shorter to write, but they didn’t solve the more important issues of passing multiple arguments and casting to strings.
.
.
.
+++ ORIGINAL POST +++
I miss how the print statement could give feedback in the command window in pre-8 rhino while running an ETO form, and I’m tired of typing out Rhino.RhinoApp.WriteLine() all the time. So here’s a couple of ways I’m playing around with in an effort to make using Rhino.RhinoApp.WriteLine() a little easier. I’m kinda liking method two.

# method 1
import Rhino.RhinoApp as rapp

rapp.WriteLine('hello')
#method 2
from Rhino.RhinoApp import WriteLine as writeln

writeln('hello')

Has anyone else played around with something like this? Is doing this problematic somehow?

@webdunce Which script editor are you using? Python print statements print the message on the Rhino command line as well.

@eirannejad Not while an ETO form is running. Or at least not in my experience. (edit: I use the editor that comes with Rhino, btw)

@webdunce i can cofirm this. Print in an Eto form prints after complete not while. I have this problem also with other scripts (with the new ScriptEditor).

_
c.

1 Like

Hi @eirannejad, please try below example script in the old and new editor.

EtoPrintProblem.py (1.8 KB)

thanks,
c.

@clement

Yesterday, I had to chase down lots of weird errors involving arrays and rhino objects and found two limitations with my previous solutions: (1) I can’t write multiple objects and (2) I have to wrap all non-string objects with str(). It’s okay once in a while, but annoying if you have to do it over and over again. So I came up with a helper function that seems to replicate old print’s functionality pretty good.

#! python 2
import Rhino
import Rhino.Geometry as rg

def writeln(*args):
    txt = ""
    for i in range(len(args)):
        txt += str(args[i])
        if i < len(args)-1: txt += ', '
    Rhino.RhinoApp.WriteLine(txt)

spheres = [rg.Sphere(rg.Point3d.Origin, 1), rg.Sphere(rg.Point3d.Origin, 2).ToBrep()]
some_value = 8

writeln(1, 2, 4.5)
writeln(spheres)
writeln('some text', some_value)


I’m still not sure if I’m happy with the name writeln, my only other ideas though are write and print2 (I’m not very creative). If anyone has a better idea for a name for this function, I’d love to hear it.

1 Like

Okay I see where the problem is now. So here is the challenge:

When a script is running and printing stuff, making those prints immediately available in the Terminal panel and Rhino console slows the script down especially if it is looping over many inputs and printing stuff. The output is collected and dumped all at once when the script ends. (RH-78093 and Here)

So I added this option to toggle on when you are running a script and wanting to see the printed outputs immediately:

Toggle that on and scripts will print outputs immediately.

Currently the script does not know which is preferred by the script. (I can add a support for an in-script-flag so the script can choose e.g # print: always or something)

I am open to better ideas.

4 Likes

Hi @eirannejad , I’ve seen that little icon, but I never knew what it did. I tried it out and it does print, but it bogs down my script until it is unusable. My little writeln function works fine though.

I was getting frustrated with using WriteLine directly, but putting it inside a function so I can pass in multiple arguments and not have to explicitly cast everything to strings seems to be a good work around…at least for me. I think I’m happy with it.

As for suggestions, I wonder if you could add an API method…like Rhino.RhinoApp.WriteLine2 or something, that basically does what my little writeln function does. Then we could use from Rhino.RhinoApp import WriteLine2 as writeln or similar?

Hi @eirannejad,

thank you for taking care about this important issue! IMHO print should behave by default that prints done during a scriptrun (from the editor) are always shown in the command line (as it has been with the old script editor).

I’ve left out the editor’s terminal panel in above thoughts as it is not visible to the developer while a script runs. The editor is minimized.

EDIT: I’ve removed parts of my previous reply since i’ve found that print statements are NOT supressed when the script is run using _RunPythonScript. It just happens with the new editor in it’s default configuration. (read @eirannejad’s reply above).

_
c.

1 Like

Hi @webdunce,

that’s one of the reasons why i do not prefer WriteLine to circumvent the issue. If you run my example script above with the old editor (_EditPythonScript) it will print to the command line once the dialog has been loaded and it will print if you click the button (while dialog is open).

With the new editor, in it’s default configuration, it will not print once the dialog is opened, and when the button is clicked, it prints nothing. (it supresses by default).

I’ve just found that running the script using _RunPythonScript does print the message immediately once opened and once the button is pressed. Should’t a script which is run with the (new) editor by default behave exactly the same as it does when run using _RunPythonScript ?

Yes, that solves the issue, i’m just trying to explain why i want this to be enabled by default.

_
c.

1 Like

@webdunce

If you prefer .WriteLine you can:

from Rhino import RhinoApp as app
print = app.WriteLine

print("Hello Rhino")

@clement

I agree. Printing to Terminal in editor and Rhino command line was the default, until I got feedback that it is slowing down the scripts. I am okay making this the default option now that we have the toggle in the Terminal panel.

This will also solve the discrepancy with _RunPythonScript and _ScriptEditor _Run commands. I made the ticket below for this fix:

RH-86071 Print-Line-By-Line by default

2 Likes

Thank you @eirannejad.

Please apologise for any inconvinience this may cause you @AndersDeleuran. I think since suppression can be enabled to get more speed by the developer, it is better for the new editor to behave like the old editor in it’s default config. I did not know that this is actually a feature and thought it is a bug.

_
c.

1 Like

We’ll keep working on this until we have the best solution. I am also cleaning up the codebase and improving editor performance for Rhino 9 so this hopefully keeps getting better :smiley:

3 Likes

@eirannejad , I have to do something like print2 = app.WriteLine. I think because print itself is a keyword, but I didn’t know that I could do that, and it is cool.

However, it doesn’t allow me to pass multiple inputs and it still requires me to explicitly cast non-string objects to strings, which are two things that make WriteLine cumbersome in comparison to print.

But my little wrapper script uses WriteLine and solves those issues.

def writeln(*args):
    txt = ""
    for i in range(len(args)):
        txt += str(args[i])
        if i < len(args)-1: txt += ', '
    Rhino.RhinoApp.WriteLine(txt)

And it works in a running ETO script without bogging it down (at least not very noticeably). Print made my script run like molasses.

Do you think it would be feasible and a good idea to add something like Rhino.RhinoApp.WriteLine2() to the rhinocommon API, and it would just be a wrapper for Rhino.RhinoApp.WriteLine() but, like my little function, allow passing multiple arguments and take care of building the string for the regular WriteLine?

If not, that’s cool. I can just throw this function at the top of my scripts or into a utility file.

1 Like

@webdunce That would actually be useful. I will bring that up with the big guys who make the decisions on RhinoCommon :smiley:

1 Like

@eirannejad , cool! I hope it works out and is useful to everyone. Naming it WriteLine2 is just a suggestion. It could be called Print or anything you all deem appropriate. We could use it like so…perhaps.

import Rhino.App as app
app.Print('a number', 2)

I was really hoping to get input from other people who develop ETO forms, too…especially since it might be considered for the API.

Also, in the end, if it can’t be added, I will definitely understand. It just might not be API-worthy.

Btw, I have re-titled this post and re-written my original post as a case for the wrapper function, discussing the issues with WriteLine with respect to using it in ETO forms and how the wrapper function solves those issues. I re-wrote it mainly because my goal shifted from trying to find a shorter way to write Rhino.RhinoApp.WriteLine to making WriteLine work more like print, and going forward, I want that to be the first thing people read who click on this post. But it may also be useful when you bring it up with the “big guys.” :slightly_smiling_face:

1 Like

I pushed a fix for this for the next Rhino SRC.

  • I kept the “Print Line by Line” off by default but minimized its scope. Now it only applies to the text terminal at the bottom of the editor. Not the Rhino command line.
    So after this change print statements always print to the Rhino command line matching the behaviour of _RunPythonScript and _ScriptEditor _Run commands.

  • Editor Terminal dumps the captured output when the script ends. Same behaviour as before.

  • If someone wants to see the prints line by line in Editor Terminal they can turn on the toggle. Same behaviour as before.

  • During debug, Editor Terminal prints line by line. Same behaviour as before.

1 Like

I must admit that I’m also a bit lost. The last time GhPython print output performance regressed, @piac and @Alain added this option that allows the user to switch between the fancy, but slow DataGridView output and simple/fast text. Perhaps some similar option is relevant with the new script editor:

ScriptEditor does not use a fancy DataGridView. It’s a simple text box.

I put a good amount of improvements on print speed in the next 8.x

1 Like

Ah, sorry I wasn’t suggesting that. Just that GhPython lets the user decide which output terminal to use (i.e. fast/simple or slow/fancy). And that maybe something similar was appropriate with the new editor (i.e. based on @clement apologies above). But reading the full topic back, I see that is exactly what you have implemented. Haha, I should have read before posting!

That sounds awesome, looking forward to testing it again soon :slight_smile:

1 Like