Template node and python

Hi, I need to use python to run a script, and I'm scrambling to solve this two issues. I need to have the script within node-red for several reasons. Actually, I wrote the python script within the template node, then via a write node I write it in a defined directory so that I can run it with the exec node.
At the moment everything works as expected since I hard coded the variables within the script.


Now I have this global context

image

global.set("test",{"Path":{"A": "FolderA","B": "FolderB","length":[350,500],"test1": 70389,"test2": 13546},"testing":{"Refresh": "default","Errors": 5}})

And this is what I would like to achieve:
1) Directly use the global context.
Using the suggested syntax, this script print what expected

#!/usr/bin/env
test = {{{global.test.Path.test2}}}
print (test)
exit()

but this one returns an error

#!/usr/bin/env
test = {{{global.test.testing.Refresh}}}
print (test)
exit()

image
Anyway, what I would like to have is a variabile within the python script so that I can directly use all its properties. Something like:

test = {{{global.test}}}
var1= Path.test2
var2= testing.Refresh
etc

2) To be able to directly pass the script to the exec node without write it on a file.
I followsd this topic, but it doesn't seem to work anymore

As global.test.testing.refresh is a string should it not have quotes around it?

#!/usr/bin/env
test = "{{{global.test.testing.Refresh}}}"
print (test)
exit()

global.test.Path.test2 is a number so not required.

but without quote I get an error when define it as global context

The quotes would be in the template. As shown above.

Oh yes, I got it. I see what you mean, yes thanks. But how can I have all the global context's properties in a variable?

I just redownloaded that example and tried it; it seems to work for me, I'm on a Raspberry Pi with the latest version of RPiOS (so python is v3 only)
Can you show me what problem you get with it?

I do have a slightly updated version of that flow but if you have spotted a bug I need to test it.

ps It never occurred to me to pass an entire javascript object to python as a single parameter.
It does seem to pass something but you'd have to parse it within python, which seems less simple than passing individual values from Node-red.

pps What is your #! /usr/bin/env at the top of your two scripts intended to do? I suspect it does nothing.

Add quote mustache either side and prior to template set msg.quotes depending if global is a string.
e.g.

[{"id":"3ca9710f86c46a79","type":"inject","z":"b9860b4b9de8c8da","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":560,"y":520,"wires":[["99639618049b79b1"]]},{"id":"99639618049b79b1","type":"change","z":"b9860b4b9de8c8da","name":"","rules":[{"t":"set","p":"test","pt":"global","to":"{\"Path\":{\"A\": \"FolderA\",\"B\": \"FolderB\",\"length\":[350,500],\"test1\": 70389,\"test2\": 13546},\"testing\":{\"Refresh\": \"default\",\"Errors\": 5}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":580,"wires":[["07b2e786018c81df","45a4da5325d30a72"]]},{"id":"07b2e786018c81df","type":"change","z":"b9860b4b9de8c8da","name":"","rules":[{"t":"set","p":"quotes","pt":"msg","to":"$type($globalContext(\"test.testing.Refresh\")) = \"string\" ? '\"' : ''","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":560,"wires":[["813a7d96abfecabf"]]},{"id":"45a4da5325d30a72","type":"change","z":"b9860b4b9de8c8da","name":"","rules":[{"t":"set","p":"quotes","pt":"msg","to":"$type($globalContext(\"global.test.Path.test2\")) = \"string\" ? '\"' : ''","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":620,"wires":[["9006aee5fa9b7656"]]},{"id":"813a7d96abfecabf","type":"template","z":"b9860b4b9de8c8da","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"#!/usr/bin/env\ntest = {{{quotes}}}{{{global.test.testing.Refresh}}}{{{quotes}}}\nprint (test)\nexit()\n","output":"str","x":880,"y":560,"wires":[["fd1f321c74387065"]]},{"id":"9006aee5fa9b7656","type":"template","z":"b9860b4b9de8c8da","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"#!/usr/bin/env\ntest = {{{quotes}}}{{{global.test.Path.test2}}}{{{quotes}}}\nprint (test)\nexit()\n","output":"str","x":860,"y":620,"wires":[["540728c240447648"]]},{"id":"fd1f321c74387065","type":"debug","z":"b9860b4b9de8c8da","name":"debug 332","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1090,"y":540,"wires":[]},{"id":"540728c240447648","type":"debug","z":"b9860b4b9de8c8da","name":"debug 333","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1070,"y":600,"wires":[]}]

Probably easier to get option 2 working though.

yes on raspberry it's ok. On windows 11 and python 3.10.5 I get this

I imagine. I have even trying with json library but without success till now

it's just because at the moment I write the script in a file and then call it from the exec node.

Yes thanks. Now the problem is how to read all the properties since I need several of them

Hmm Windows.
On Linux the #! line specifies which interpreter (eg python, awk, bash etc) should be used to process the file - provided that a) the file is executable (ie ls -l filename shows an x in the relevant place[s]) and b) it is executed by being called by name myscriptname not python myscriptname
The #! should be followed text which evaluates as the name of an existing interpreter (eg #! /binbash or #! /usr/bin/env python)
I don't know what a #! line does on Windows.

Sorry, you're right. What I post for help is based on debian (raspberry) that's why you see this line.
But I even tried your code on windows, and here I get this error, not on the pi

I am afraid I neither run Node-red nor python on WIndows so I can't reproduce the problem.
It does look as it is offended by the script arriving as a multi-line string.
As a test it might be worth:
Removing all comments from the script.
Put a caret symbol ^ before each newline in the script.

Is there any way to for exec to insist on powershell rather than command shell? Or even gasp, a Linux shell?

it's ok, it just because I came across it. On raspberry it's ok.
If someone could help with the full global context. I'm trying to solve it using json.load, but nothing

Please post an export of your flow, using an inject node to set the Json to be passed to the script.

I just solved it passing the global context to the template node as

msg.globaltest = JSON.stringify(global.get("test"))

and calling it from within the script as

import json
test = json.loads('{{{globaltest }}}')
print (test['Path']['test2'])
print (test['testing']['Refresh'])
exit()

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.