Passing arguments to Python script via C#?

1,464 views
Skip to first unread message

Gashan

unread,
Nov 27, 2012, 11:09:43 AM11/27/12
to pym...@googlegroups.com

Top of the morning ladies and gents,

I must apologise to have to trouble you with what might appear a small query, which I seem unable to resolve; let me explain; I am trying to pass arguments to a Python script from a WFP C# based GUI application with the object being setting the path and pattern values in the Python via the searchWrapper in C#; as the code snippets might indicate, the tool works fine with a small exception, where if the path or pattern values are preset in Python, all is well, however, if ones wishes to set the path or pattern values via the searchWrapper, then there arises the glitch, and ergo my seeking your input;

 

C# code snippet:

public class searchWrapper

    {

        public List<string> searchQuery(List<string> results, string pyCmd, string path, string pattern)

        {

            string err = null;

            ProcessStartInfo psi = new ProcessStartInfo(@"python");

           

            psi.UseShellExecute = false;

            psi.RedirectStandardError = true;

            psi.RedirectStandardInput = true;

            psi.RedirectStandardOutput = true;

            psi.CreateNoWindow = true;            

            psi.WindowStyle = ProcessWindowStyle.Normal;

           

            psi.Arguments += pyCmd;

 

            List<string> resultOutput = new List<string>();

            try

            {

                using (Process pr = Process.Start(psi))

                {

                    Thread thread = new Thread(() => pr.WaitForExit());

                    thread.Start();

 

                    using (StreamReader rd = pr.StandardOutput)

                    {

                        string line = rd.ReadToEnd();

                        results.Add(line);                       

                    }

                }

            }

            catch(Exception ex)

            {

                err += ex.Message + "\n" + ex.Source;

            }           

            return results;

        }

    }

 

A simple Python code snippet:

#ep.

path = r" c:\users\[username]\appdata\local\microsoft\windows\temporary internet files"

pattern = "*.exe"

 

def getPatterns(path, patterns):

    try:

        if path != None:

           print path, "\n"

           for root, dirs, files in os.walk(path):

               for fn in fnmatch.filter(files, pattern):

                   print(os.path.join(root, "\t\t", fn))

           print "\n"

        else:

             print "\npath could not be null;"

    except e:

           print"\nOoops ...\t", str(e)

#endp.

 

Put it differently, is it possible to pass the 'path' and 'pattern' arguments to the function via the searchWrapper?


And for disclosure, whilst I like Python, I certainly am not a Pythonian, but do prefer this approach of accessing Python code over IronPython, for which others might opt.

I do thank you, and my apologies should the query is found unclear;


Much obliged,

Cheers,

Gashan,

Andrew Carter

unread,
Nov 27, 2012, 11:57:54 AM11/27/12
to pym...@googlegroups.com
Overall, I think you are just asking how to pass arguments to a python
script or create a command line interface using python. For starters,
you can simply import sys and all args passed to a script are
available in the sys.argv list. Then, you can get fancier using the
builtin optparse or (Python 2.7 or later) argparse modules. There's a
lot online about this -- here are just a few for starters -- you can
google on this until your heart is content:

# This one covers sys.argv
http://www.diveintopython.net/scripts_and_streams/command_line_arguments.html

And here is more on builtin optparse/argparse

http://www.doughellmann.com/PyMOTW/optparse/
http://www.doughellmann.com/PyMOTW/argparse/

In addition to this, there are many packages for even getting fancier
-- one I really want time to check out is:

https://github.com/docopt/docopt

It's so cool -- all you do is write POSIX complaint help messages, and
it writes the parser for you -- how is that for DRY.

Andrew


Andrew

Gashan

unread,
Nov 27, 2012, 12:23:14 PM11/27/12
to pym...@googlegroups.com
Andrew,
I thank you sir,
That was my initial thinking, and I did indeed fiddle with the sys.argv and optparse, but that did not quite produce the desired result; I shall nonetheless revisit for good measure; I shall also explore the other suggestions;

Thanks again mate,
Cheers,
Gashan,

Andrew Carter

unread,
Nov 27, 2012, 12:37:36 PM11/27/12
to pym...@googlegroups.com
I would keep fiddling -- I think you'll get there.

Right now, you are basically sending in pyCmd -- let's say the
contents of that variables are "/path/to/script.py". You are
basically doing:

python /path/to/script.py

On the C# side, you just need to expand this to include the 'path' and
'pattern' variable and create a final result that looks like:

python /path/to/script.py <path> <pattern>

Or even -- if you want to use options (and have a default) use
opt/argparse and do:

python /path/to/script.py --path <path> --pattern <pattern>

Something like that should work.

Andrew

Gashan

unread,
Nov 27, 2012, 12:42:49 PM11/27/12
to pym...@googlegroups.com
Thanks again mate,
I shall indeed soldier on, as it were;

On the C# side, in the searchWrapper those values are being provided and passed herein ---
public List<string> searchQuery(List<string> results, string pyCmd, string path, string pattern); it is on the Python side with which I am encountering the glitch; and as you quite rightly noted, I shall need something along these lines ---

python /path/to/script.py --path <path> --pattern <pattern>

Much obliged,
Cheers,
Gashan,

Gashan

unread,
Nov 27, 2012, 1:36:14 PM11/27/12
to pym...@googlegroups.com
Addendum:
On the C# side, this is what is being passed with values:
pyCmd = /python.py + path + pattern;

But on the Python side, only '/python.py' is being processed, and not the 'path' + 'pattern'; simple, one would have thought, but not quite so.

Cheers,
Gashan,

Rohit Patnaik

unread,
Nov 27, 2012, 1:50:51 PM11/27/12
to pymntos
Where do you do that operation? I'm looking at the code you've posted and I see:

    psi.Arguments += pyCmd;

Shouldn't that be more like:

    psy.Arguments += pyCmd;
  psy.Arguments += path;
  psy.Arguments += pattern;

Or are you doing that in some other function? In that case why bother passing path and pattern to this function at all?

Thanks,
Rohit Patnaik

Gashan

unread,
Nov 27, 2012, 1:55:34 PM11/27/12
to pym...@googlegroups.com
Thanks Rohit,
That was actually one of the initial attempts I made, which failed;
Cheers,
Gashan,

Rohit Patnaik

unread,
Nov 27, 2012, 2:22:16 PM11/27/12
to pymntos
Well, I also notice that you're not reading from sys.argv in the initial version of your Python script. What happens when you add something like

    import sys
    pyCmd, path, pattern = sys.argv[1:4]

to your Python script and then call it from C# as I've described above?

Thanks,
Rohit Patnaik

Gashan

unread,
Nov 27, 2012, 2:30:04 PM11/27/12
to pym...@googlegroups.com
Thanks again Rohit,
You are quite right I have done that not earlier --- pyCmd, path, pattern = sys.argv[1:4];
but just tried it, albeit no change;

Cheers,
Gashan,

Mike Hicks

unread,
Nov 27, 2012, 3:32:56 PM11/27/12
to pym...@googlegroups.com
Is psi.Arguments just a string?  You'll need to add spaces in between the arguments in that case:


    psy.Arguments += pyCmd;
  psy.Arguments += " " + path;
  psy.Arguments += " " + pattern;


--
Mike Hicks | mul...@gmail.com

Gashan

unread,
Nov 27, 2012, 4:06:47 PM11/27/12
to pym...@googlegroups.com
Thanks Mike,
Yes, psi.arguments is properties of string type, and indeed I took the 'spaces' 'ween arguments into account;

Much obliged,
Cheers,
Gashan,

Rohit Patnaik

unread,
Nov 28, 2012, 3:11:29 AM11/28/12
to pym...@googlegroups.com

Out of curiosity, what is the value of sys.argv in the Python script when you call it from C#? Is it an empty array? Or are all the arguments pushed together into one value (e.g. sys.argv[1])?

Gashan

unread,
Nov 28, 2012, 10:19:02 AM11/28/12
to pym...@googlegroups.com
Thanks again Rohit,
I trust it to be a single argument; shall be able to confirm it later today, for I am an offsite today;

Cheers,
Gashan,

rskm1

unread,
Nov 28, 2012, 1:29:15 PM11/28/12
to pym...@googlegroups.com
I glanced through the docs for the C# ProcessStartInfo class at http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.71).aspx and it wasn't immediately obvious...

...but one thing (which nobody's mentioned yet) to watch out for when spawning an external command, is whether there's a SHELL that will get involved and "munge" your arguments.  "munge" means that the asterisks in your parm strings will get expanded to match any corresponding filenames in the current working directory.

That's probably not what you want to happen here.  And if that is what is happening, it's not a glitch on the Python end, you need to find a different mechanism to make C# call it (or "quote" those parameters to prevent munging).

Write a simple Python script that just does this:

import sys
if __name__ == '__main__':
..for arg in sys.argv:
....print "Got an arg:", arg

Call it and see what the Python script is actually GETTING from the C#.  The results may surprise you if there happen to be any files in the current working directory that happen to match your 'pattern' parameter.

--Rob
Reply all
Reply to author
Forward
0 new messages