Communication between node and python - python

I have a node script :
//start.js
var spawn = require('child_process').spawn,
py = spawn('python', ['compute_input.py']),
data = [1,2,3,4,5,6,7,8,9],
dataString = '';
py.stdout.on('data', function(data){
dataString += data.toString();
});
py.stdout.on('end', function(){
console.log('Sum of numbers=',dataString);
});
py.stdin.write(JSON.stringify(data));
py.stdin.end();
and a python script :
## compute_input.py
import sys, json, numpy as np
#Read data from stdin
def read_in():
lines = sys.stdin.readlines()
#Since our input would only be having one line, parse our JSON data from that
return json.loads(lines[0])
def main():
#get our data as an array from read_in()
lines = read_in()
#create a numpy array
np_lines = np.array(lines)
#use numpys sum method to find sum of all elements in the array
lines_sum = np.sum(np_lines)
#return the sum to the output stream
print lines_sum
#start process
if __name__ == '__main__':
main()
These two scripts are in a folder my_folder/
If I'm inside my_folder and run the command node start.js, I get Sum of number=45, the scripts is working.
If I'm outside the folder and run the command node my_folder/start.js, I get Sum of number=, the script is not working.
Why ??

Most obvious reason: you are using a relative path for your python script so it's looked up in the current working directory. If you execute your node.js script from the same directory the python script is found, if you execute it from anywhere else (that doesn't happen to contain a compute_input.py file xD) then the python script is not found and the python call fails.
Use the absolute path instead and you should be fine (how you get the absolute path from your node.js script is left as an exercice)

Related

Execute python script through Java

I'm trying to run a very simple python script that clears and writes to a CSV file, from inside of java but I'm having a lot of trouble doing it.
The scripts don't require any input and the output is all written into a CSV file so all I need to do is get the python scripts to run through my java code.
Below is a bit of code that I've seen all over the internet but doesn't seem to be working for me. It seems like for both of the scripts, using this command does nothing to the csv. No errors are thrown and the java program simply exits presumably without executing the python scripts.
public static void main(String[] args) throws IOException
{
Process p = Runtime.getRuntime().exec("python Refresh.py");
}
here are the scripts I'm trying to run.
Script1:
file = open("products.csv","r+")
file.truncate(0)
file.close()
Script2:
from bs4 import BeautifulSoup as soup
from urllib.request import Request, urlopen
import time
filename = "products.csv"
f = open(filename, "a")
#connects to the page and reads and saves raw HTML
for i in (0,25,50,75):
my_url = 'https://www.adorama.com/l/Computers/Computer-Components/Video-and-Graphics-Cards?startAt='+ str(i) +'&sel=Expansion-Ports_HDMI'
hdr = {'User-Agent': 'Mozilla/5.0'}
client = Request(my_url,headers=hdr)
page = urlopen(client).read()
#parsing the HTML
page_soup = soup(page, "html.parser")
#print (page_soup.h1)
containers = page_soup.findAll("div",{"class":"item"})
#print (len(containers))
containers.pop()
for container in containers:
title_container = container.findAll("div",{"class":"item-details"})
title = title_container[0].h2.a.text.strip()
status_container = container.findAll("div",{"class":"item-actions"})
status = status_container[0].form.button.text.strip()
if (status == "Temporarily not available"):
status = "Out of stock"
else:
status = "In stock"
price = container.find("div","prices").input["value"]
link = container.a["href"]
f.write(title.replace(",", "|") + "," + price.replace(",", "") + "," + status + "," + link + "\n")
time.sleep(0.01)
f.close()
The java file, Python script, and the csv file are all in the same folder.
Use the newer ProcessBuilder class:
ProcessBuilder pb = new ProcessBuilder("python","Refresh.py");
Process p = pb.start();
Hope that works for you!
You are not checking for errors from the python script. You can achieve this simply by merging STDERR to STDOUT and reporting the content of STDOUT to console:
Process p = new ProcessBuilder("python", "Refresh.py")
.redirectErrorStream(true)
.start();
p.getInputStream().transferTo(System.out);
int rc = p.waitFor();
This should print out the error message from python and give you error code back. You may have problems with path to files, so you might need to adjust your arguments to explicit pathnames to "python" and/or "Refresh.py".
I managed to fix the issue by constantly reading the "print" and error outputs of the Python file. Whilst I still don't completely understand how this fixed the issue, my best guess is that with this, the Java code keeps the python script "running" until the script itself is finished doing its thing, instead of just opening the script and instantly moving on.
Here's the code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Test {
public static void main(String... args) throws Exception {
String[] callAndArgs = {"python3", "YourScript.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
//System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
//System.out.println(s);
}
}
}
Another Notable Detail is that this code only seems to work when Compiled and run through the Terminal/Geany. If I run the same thing with IntelliJ it does not work. Once again, I'm not sure why this is but I'm suspecting that IntelliJ compiles and runs in a VM of some sorts.

How to run python script from C# code by using command

I have a script file(run_edr.py) in my local machine and when I run it by using "cmd" and the following command then the script works perfectly. The script takes fewer parameters, the first parameter is an input document folder path and the second parameter is the output folder path to store the output documents.
my python command,
python run_edr.py -input_path "C:\Users\aslamm5165\Downloads\EDRCODE_ArgParser\files\EDR" -output_path "C:\Users\aslamm5165\Downloads\test" -site_name "a" -site_address "b" -site_city "c" -site_county "d" -site_state "e" -site_type "1"
I have tried like below, but not working, where Did I go wrong?
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
ScriptEngine engine = Python.GetEngine(runtime);
ScriptSource source = engine.CreateScriptSourceFromFile(#"C:\Users\aslamm5165\Downloads\EDRCODE_ArgParser\run_edr.py");
ScriptScope scope = engine.CreateScope();
List<String> argv = new List<String>();
//Do some stuff and fill argv
argv.Add("python"+#" C:\Users\aslamm5165\Downloads\EDRCODE_ArgParser\run_edr.py -input_path" + #"C:\Users\aslamm5165\Downloads\EDRCODE_ArgParser\files\EDR");
argv.Add("-output_path"+ #"C:\Users\aslamm5165\Downloads\test");
argv.Add("-site_name 'a' -site_address 'b' -site_city 'c' -site_county 'd' -site_state 'e' -site_type '1'");
engine.GetSysModule().SetVariable("argv", argv);
source.Execute(scope);
I have tried with the system process as well as shown below, no error in the code, but the script is not getting executed. So I don't know what is the correct way of doing this but I want to start my script from my .Net Core application.
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"cmd.exe";
start.Arguments = string.Format("python run_edr.py -input_path {0} -output_path {1} -site_name 'a' -site_address 'b' -site_city 'c' -site_county 'd' -site_state 'e' -site_type '1'", #"C:\Users\aslamm5165\Downloads\EDRCODE_ArgParser\files\EDR", #"C:\Users\aslamm5165\Downloads\test");
start.UseShellExecute = true;
start.RedirectStandardOutput = false;
start.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
Process.Start(start);
I solved a similar running Python scripts in .NET Core 3.1 problem by changing the executable file from cmd.exe or /bin/bash in Linux to a batch script (Windows) or shell script (Linux) file. Here's my approach:
1, for Windows OS, create a run.bat file which include the python.exe and the %* to pass all arguments to it:
C:\YOUR_PYTHON_PATH\python.exe %*
2, for LInux OS, create a run.sh file to execute python with arguments:
#!/bin/bash
/usr/bin/python3 "$#"
3, use Process and ProcessStartInfo (your second approach):
string fileName = null;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
fileName = "path_to_bat/run.bat"
}
else
{
fileName = "path_to_bat/run.sh"
}
ProcessStartInfo start = new ProcessStartInfo
{
FileName = fileName,
Arguments = string.Format("\"{0}\" \"{1}\"", script, args),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using Process process = Process.Start(start);
the .NET code is same to Windows except the FileName should be the shell script's name with path.

Endless loop when importing a variable from another file in Python

I have a file called main.py and based on the user input I want to run the code either from file export.py, either from file import.py. This is how my code from main.py looks:
print("Hi, " + os.getlogin() + "!")
print("Extracting filenames...")
path = input('Tell me the path!\n')
filenames = [x for x in os.listdir(path)]
ID = [f for f in filenames if re.search("(?<=ID)(\d+)", f)]
filestxt = "Files.txt"
idtxt = "ID.txt"
PathFiles = os.path.join(path, filestxt)
PathID = os.path.join(path, idtxt)
file = open(PathFiles, "w+")
file.write('\n'.join(ID))
file.close()
with open(PathID, 'w') as f:
for item in ID:
list = re.findall("(?<=ID)(\d+)", item)
string = ('\n'.join(list))
f.write("%s\n" % string)
key = input("Export or Import(e/i)?:")
if key == 'e':
os.system('python export.py')
When I am hitting the 'e' button Python is running the code from export.py, but when it gets to the line
from main import PathID
instead of importing the variable which I need for the following function
with open(PathID) as f:
for line in f:
...
the code from main.py is running again and again from the beginning and I get the following lines in the console:
"Hi, " + os.getlogin() + "!"
"Extracting filenames..."
'Tell me the path!\n'
"Export or Import(e/i)?:"
All I want in export.py is to tell Python to read the ID.txt file from the path I have specified in the main.py file.
How can I call the function from main.py in export.py without getting this endless loop?
Try to use
if __name__ == '__main__':
before
key = input ("Export or Import (e / i) ?:")
if key == 'e':
os.system ('python export.py')
or before any code that should always be executed at startup.
To expand on Jossnix's answer:
When you execute os.system('python export.py'), you're launching a separate Python interpreter process.
When you execute from main import PathID within export.py, all of the code in main.py is run, and then, once it's finished running, the control flow is returned to export.py and it has access to PathID. The problem is that, as it stands, your main.py asks for user input. So, your main.py is stuck waiting for user input - you have to provide the input again to this new Python interpreter session! Hence, export.py is stuck while trying to import main.
Jossnix's solution works because it ensures that the user input component of main.py does not get run if main.py is being imported from another module, but will be run if main.py is executed as the main script.
I think you should get rid of the os.system('python export.py') line entirely. It's wasteful: you're launching a completely separate Python interpreter session and the print messages in main.py get run again (this is pretty confusing for the end-user!). I'd say you're better off having whatever code you want to run if the user enters the key 'e' wrapped in a function, and then run this function directly from main.py (if the user has indeed entered 'e'). You could do this: Create such a function (f) in export.py, taking a PathID argument. Then, within main.py, from export import f. Finally, if the user entered 'e', run f(PathID, ...).

Python exe not deleting itself

I'm trying to create a python script to convert into exe which just deletes itself. When I run it as .py file it works. The code is this:
import os
os.remove(os.getcwd + "\\test.py")
I'm working in Windows that's why I'm using \\ and the file is obviously named test.py. But when I convert it into an exe file (I've tried both with py2exe and pyinstaller) it gives me access denied error. Does anyone know how to fix this?
PS: Yes, I've changed the name to test.exe if you're asking.
It won't be this simple.
1) When you are running the script actually it is the python.exe executing the statements and the script file (test.py) is free. In this way python.exe can delete the script.
2) When you convert convert your script to exe, it is the exe file itself executing, which means the file is 'busy', or said in other words - used by the process, and it cannot be deleted.
Find a way to start another process, which would delete the file after you exit the current process.
Edit(sample code):
import sys
import ctypes
import platform
import subprocess
def execute(command, async=False):
"""
if async=False Executes a shell command and waits until termination and
returns process exit code
if async=True Executes a shell command without waiting for its
termination and returns subprocess.Popen object
On Windows, does not create a console window.
"""
if async:
call = subprocess.Popen
else:
call = subprocess.call
if platform.system() == 'Windows':
# the following CREATE_NO_WINDOW flag runs the process without
# a console window
# it is ignored if the application is not a console application
return call(command, creationflags=0x08000000)
else:
return call(command)
def main():
ctypes.windll.user32.MessageBoxA(0, __file__, 'Show path', 0)
ctypes.windll.user32.MessageBoxA(0, sys.executable, 'sys.executable', 0)
with open(r'D:\delete_me.py', 'w') as f:
f.write('import os\n')
f.write('import time\n')
f.write('time.sleep(2)\n')
f.write('os.remove(r"{}")'.format(sys.executable))
execute(r'C:\Python27\python.exe D:\delete_me.py', async=True)
if __name__ == '__main__':
main()
And this was compiled with `pyinstaller.exe --onefile --windowed D:\self_delete.py
execute function is something we use to execute calls on both Linux and Windows and I just copied it. This is why the platform check is there.
You can use some .bat file with timeout instead of sleep or whatever else you want if you can't execute delete_me.py
What you can do is to use a VBScript to do this. What I have done is made this:
deleteFile is the location of the exe you want to delete. It doesnt matter if its running or not, If its running then it will first be terminated forcefully then deleted, then the VBScript will delete itself too. All this will happen without the console window opening to make it more convenient for the end user. The Python Code is listed below this code
deleteFile ="Install.exe"
Dim oShell : Set oShell = CreateObject("WScript.Shell")
oShell.Run "taskkill /f /im install.exe", 0, True
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(deleteFile) Then
Set fs = CreateObject("Scripting.Filesystemobject")
fs.DeleteFile(deleteFile)
Else
End If
Set oFso = CreateObject("Scripting.FileSystemObject") : oFso.DeleteFile Wscript.ScriptFullName, True
The Python Code:
Here you will have to change \Filename.extention to \Yourfilename.yourfilextension for ex. \example.exe
import os
fname = "Filename.extention"
path = os.getcwd() + "\\" + fname
delcode = f'''deleteFile ="{path}"
Dim oShell : Set oShell = CreateObject("WScript.Shell")
oShell.Run "taskkill /f /im install.exe", 0, True
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(deleteFile) Then
Set fs = CreateObject("Scripting.Filesystemobject")
fs.DeleteFile(deleteFile)
Else
End If
Set oFso = CreateObject("Scripting.FileSystemObject") : oFso.DeleteFile Wscript.ScriptFullName, True'''
f = open("C:\Windows\Temp\delete.vbs", "w")
f.write(delcode)
os.startfile("C:\Windows\Temp\delete.vbs")
The only think you need to do is to add the python code to a function, then change what I said above and just run the function. I have tested it myself and it worked perfectly so there should be no errors in the code
Edit: I know its very old thread but I just wanted to put my answer too since I felt it was easier than others + I was also finding an answer myself to this question so why not to help others too incase someone comes across the same question!

python or bash script that does something when there is no response(output)

There is an external program A.
I want to write a script that does some action if the called external program A does not bring up any output(stout).
How is this possible in bash or python?
You can use the subprocess module which allows you to execute system calls and store its output in variables which can be used later on.
#!/usr/bin/python
import subprocess as sub
ur_call = '<your system call here>'
p = sub.Popen(ur_call, stdout=sub.PIPE,stderr=sub.PIPE)
output, errors = p.communicate()
if len(output) == 0 and len(errors) == 0:
pass # Do something
In a Bash-script, you could redirect the output to a file, and if the length of the file is zero then there was no output.
If the script that sometimes gives output is no.sh then you can do this in Python:
import os
x = os.popen("./no.sh")
y = x.read()
if y:
print "Got output"

Categories

Resources