C# code do not run complete python script in visual studio - c#

First of all I do not know if it is a bad practice to call python script from c# so if this is the case please tell me.My current problem is as follows.
MY c# code only runs the python script partially....
means (python script create only 4 files when it is supposed to create 10 files)
But When I run my script from cmd in windows I see complete functionality....
Another thing I saw is when I stop my Visual Studio(2013) I see the complete functionality
I am calling the python script(main.py) from c# like this...
public JsonResult FetchscrapyDataUrl(String website)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\ProgramData\Anaconda3\python.exe";
start.Arguments = #"C:\Users\PycharmProjects\scraping_web\scrape_info\main.py";
//this is path to .py file from scrapy project
start.CreateNoWindow = false; // We don't need new window
start.UseShellExecute = false; // Do not use OS shell
//start.RedirectStandardOutput = true;// Any output, generated by application will be redirected back
start.RedirectStandardError = true; // Any error in standard output will be redirected back (for example exceptions)
Console.WriteLine("Python Starting");
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd(); // Here are the exceptions from our Python script
string result = reader.ReadToEnd(); // Here is the result of StdOut(for example: print "test")
Console.Write(result);
}
}
}
Why I am getting complete script functionality when I stop in Visual Studio(2013)??

I dont understand you motivation behind this. But why dont you use IronPython which is excellent addition to the .NET Framework, providing Python developers with the power of the .NET framework.

Related

Pass Image object as a parameter from C# to Python

I want to pass an image object from my c# project to my python script however from my understanding whatever there is in the arguments it is considered as string and also when I try type(passedImage) in python it identifies it as a string even if I try to put a number instead of the image variable.
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\Python\Python36\python.exe";
start.Arguments = string.Format("{0} {1}", #"C:\OCRonImage2.py", image );
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.CreateNoWindow = true;
using (Process process = Process.Start(start))
{
}
When executing OCRonImage2.py manually, is it an image file location that you would pass as an argument? I would be surprise if you would pass in a stream from the command line. It is no surprise that attempting to put the entire image's bytes into an argument would create a string too long. But with the error you reported, I would also believe that the python script was expecting a file path to the image. However, if you look at that python code, I wouldn't be surprised if you find it using the filepath argument to open the file, probably using Image.open(filepath,mode=r). Mode is optional, r is the default.
You are in luck however, Image.open also takes a stream. If you are willing to modify the python code there are two options:
Try converting the argument to a stream object, since the argument is a string maybe use io.StringIO()
Use input() instead of the argument passed, then you could redirect the input of the process and stream the file into your python.
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\Python\Python36\python.exe";
start.Arguments = string.Format("{0}", #"C:\OCRonImage2.py");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.RedirectStandardInput = true;
start.CreateNoWindow = true;
using (Process process = Process.Start(start))
{
StreamWriter streamWriter = process.StandardInput;
streamWriter.Write({imageString});
// ...
}
Be sure the way you encode imageString the same as the decoding is performed in the python script.
Hopefully one of these solutions will work for you.
As I work with the Anaconda distribution of Python, in my tests on an isolated conda environment, the OCR is successful with pytesseract through a Python script, on a test image.
Prerequisites to test:
install Anaconda and create an env called py3.7.4: conda create --name py3.7.4
activate the env with conda activate py3.7.4
install pytesseract with conda install -c conda-forge pytesseract
create a folder called Test and place a jpg file called ocr.jpg with the following sample image:
in the same Test folder also place a Python script called ocr_test.py with the following code:
import pytesseract
from PIL import Image
import argparse
parser = argparse.ArgumentParser(
description='perform OCR on image')
parser.add_argument("--path", "-p", help="path for image")
args = parser.parse_args()
print(pytesseract.image_to_string(Image.open(args.path)))
print("done")
The above snippet accepts the image path as a command line argument. The --path flag must be specified in order to pass the image path as an arg.
Now, in the C# code snippet below, we will:
launch the cmd shell
navigate to the workingDirectory Test folder by specifying the WorkingDirectory arg for the process.start() method.
activate Anaconda with the anaconda.bat file(replace the file path as per its location on your computer)
activate the above conda environment
call the Python script passing the imageFileName as an arg.
C# snippet:
using System.Diagnostics;
using System.Threading;
namespace PyTest
{
class Program
{
static void Main(string[] args)
{
string workingDirectory = #"C:\Test";
string imageFileName = "ocr.JPG";
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
UseShellExecute = false,
RedirectStandardOutput = false,
WorkingDirectory = workingDirectory
}
};
process.Start();
using (var sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
// Vital to activate Anaconda
sw.WriteLine(#"C:\Users\xxxxxxx\Anaconda3\Scripts\activate.bat");
Thread.Sleep(500);
// Activate your environment
sw.WriteLine("conda activate py3.7.4");
Thread.Sleep(500);
sw.WriteLine($"python ocr_test.py --path {imageFileName}");
Thread.Sleep(50000);
}
}
}
}
}
If you have followed the above steps, you should receive the following output on executing the C# snippet in Visual Studio:
Output:
Microsoft Windows [Version 10.0.18362.535]
(c) 2019 Microsoft Corporation. All rights reserved.
C:\xxxxxxx\Projects\Scripts>C:\Users\xxxxx\Anaconda3\Scripts\activate.bat
(base) C:\xxxxxx\Projects\Scripts>conda activate py3.7.4
(py3.7.4) C:\xxxxxxx\Projects\Scripts>python ocr_test.py --path ocr.JPG
Introduction
This is a test to see accuracy of Tesseract OCR
Test 1
Test 2
done
Note: I am unable to test with a standalone Python distro but I believe it should work just fine with that too. The key is to pass the image file path as an argument to the Python script too. That way, the image file path passed as argument from C# is treated similarly by Python too. Also, using Image.open() does the following(from the docs):
Opens and identifies the given image file. This is a lazy operation;
this function identifies the file, but the file remains open and the
actual image data is not read from the file until you try to process
the data
You can save the image as a file somewhere on your local machine and give the python program the path to read it.
That's the easiest way I think you can do.
Edited: You can use a temporary file to make sure the file can be deleted in the future
http://www.java2s.com/Tutorial/CSharp/0300__File-Directory-Stream/Createatempfileanddeleteit.htm
http://www.vcskicks.com/temporary-file.php
I think this will be bad to pass IMAGE as Argument.
Good options to go with:
Stdin on your python example, and RedirectStandardInput on your c#.
TCP Communication. Using TCP Services (No Internet Needed)
Sharing Memory. (More Info, ReadyLib)

Execute embedded python file from c#

I have my script written in Python and GUI for it in C#. That is why I'd like to run Python from C# (I have to use the original Python version because of various modules which i.e. IronPython does not support). To secure the script I embedded it into the .exe file. Now, how can I get the script path?
My previous code:
string python = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + #"\python\python.exe";
// NOW it obviously does not work
string scriptPath = #"C:\..\script.py";
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(python);
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.Arguments = scriptPath;
Process myProcess = new Process();
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
Assembly.GetExecutingAssembly().GetManifestResourceStream(...)
won't be useful here because I don't want stream (or do I?), just the path.
If the script is an embedded resource (How to read embedded resource text file), you could read it as string and use the -c parameter of python.exe

Receive output from a batch file and input

I'm currently creating an application in C# that allows you to create a server and manage it easily, to do this it uses batch files to run said servers. It works by creating batch files and using those to run the server. (Java by the way).
So, what I'm wondering is if it's possible to grab the output from the console and rather than dumping it in a textbox and closing the console like the code below does, I need it to continually post any output from the console without closing and without spamming loads of consoles open (tried using a timer).
Process myProcess = new Process();
ProcessStartInfo myProcessStartInfo =
new ProcessStartInfo(batchfilelocation);
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
StreamReader myStreamReader = myProcess.StandardOutput;
// Read the standard output of the spawned process.
string myString = myStreamReader.ReadToEnd();
textBox1.Text = textBox1.Text + myString;
myProcess.Close();
I'm also wondering if it would be possible to allow input from a windows forms control such as a button that would execute a command by entering it in the console and pressing enter for example. Or a textbox that allows you to do the same thing.
Thanks!
You don't need a TextBox control to store a string. Just use a string variable instead.
string concatenatedString = null;
concatenatedString += myStreamReader.ReadToEnd();
Secondly, you can do this without creating a console window. The code below will allow your program to run without seeing a ton of console windows popup.
myProcessStartInfo.CreateNoWindow = true;

C# WinForms Process Encoding problem

I am writing a windows forms application in C#
I have a Process Object which runs a cmd command and returns it's output.
Process Pro = new Process();
Pro.StartInfo.FileName = "cmd.exe";
Pro.StartInfo.Arguments = "<Dos Command here>";
Pro.StartInfo.CreateNoWindow = true;
Pro.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Pro.StartInfo.RedirectStandardOutput = true;
Pro.StartInfo.UseShellExecute = false;
Pro.Start();
Which works fine! However if the output of the command is not ASCII(in my case Greek), the Output are random symbols. Surely an encoding problem.
If i run the same code on a console application everything runs smoothly.
I tried reading the Base stream as UTF-8, but no luck!
System.IO.StreamReader Rdr = new System.IO.StreamReader(Pro.StandardOutput.BaseStream, Encoding.UTF8);
Is there any way to read the output properly in a winform application?
Thnx!
The real solution is base on this:
unicode-characters-in-windows-command-line-how
check here:
Wiki code page
for the code page you need.
you can also do an ugly hack, writing the command to a batch file (f.e foo.bat)
then running it as foo.bat > log.txt
then you can read the output from log.txt.

Using a command line program from within a C# application

I have written a C++ program (which executes from the command line), that works fine. Now I need to use it for my C# application. That is to say, I would like the output from my C++ program to be used in my C# application whenever it is called.
Is it possible? If so, how?
Any links or help would be appreciated.
You can use System.Diagnostics.Process to fire up your C++ program and redirect its output to a stream for use in your C# application. The information in this question details the specifics:
string command = "arg1 arg2 arg3"; // command line args
string exec = "filename.exe"; // executable name
string retMessage = String.Empty;
ProcessStartInfo startInfo = new ProcessStartInfo();
Process p = new Process();
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
startInfo.Arguments = command;
startInfo.FileName = exec;
p.StartInfo = startInfo;
p.Start();
using (StreamReader output = p.StandardOutput)
{
retMessage = output.ReadToEnd();
}
p.WaitForExit();
return retMessage;
Make your C++ code DLL, and use pinvoke to call the C++ functions from C# code.
Read this article: Calling Win32 DLLs in C# with P/Invoke
Another way to do this is to use Process class from .Net. Using Process, you don't need to make your C++ code DLL; you can start your C++ EXE as a process from C# code.
You could have your C++ program write it's output to a file, and have your C# program read from the file.
If your application is very performance sensitive, then this is not the best way.
Here is the C# code to run the C++ program:
try
{
Process p = StartProcess(ExecutableFileName);
p.Start();
p.WaitForExit();
}
catch
{
Log("The program failed to execute.");
}
Now you are left to write to the file from your C++ program, and read from it in your C# program.
This will show you how to write to a file from your C++ program:
http://www.cplusplus.com/doc/tutorial/files/
This will show you how to read from a file in your C# program:
http://msdn.microsoft.com/en-us/library/ezwyzy7b.aspx
Since it seems the OP didn't leave any further comments, I am left wondering, would | not have sufficed? I guess it comes down to the object that is the "it" in "whenever it is called". If "it" refers to the C++ program, then Andy Mikula's answer is best. If "it" refers to the C# program, then I would suggest:
C:\>myCpluplus.exe | myCsharp.exe
and simply read from Console.In within myCsharp.exe.

Categories

Resources