5

I`m trying to call the lasground module from a python script, using this method:

args=['lasground', '-i *.las', output_file, arg_step, arg_spike, arg_spikedown, arg_offset, arg_bulge, arg_cores]
proc=subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
output,error=proc.communicate() 

The different variables starting with arg_ are strings representing arguments that should be passed to lasground (for example if I want the step size to be 10, arg_step would be equal to '-step 10' and so on. The problem is that instead of working correctly, lasground throws back the following error:

ERROR: cannot understand argument '-i *.las'

I suppose this has to do with the '' around the string, but every other executable file I have called from python in this way worked as expected. Is there another way to do this so as to send the arguments to lasground in an understandable format from python?

I tried setting shell=False but nothing changed so I am out of ideas.

I am using python 3.5., but I am open to solutions applicable to python 2.x.

2
  • 1
    This is more of a Stack Overflow question as it is a problem with subprocess and not LASGround eg: stackoverflow.com/questions/12605498/… try breaking them up args=['lasground', '-i','*.las', output_file.... but also be aware that the subprocess may not be opening in the correct directory so it's better that you give an entire path. In these complicated arguments I find it better to write to a batch file the entire command and then popen the batch file with no args. Commented Apr 25, 2016 at 22:05
  • You are right, this definitely has to do with python and subprocess not the called executable. But I tried your advice of breaking up all the args(not just the input one) and it worked! Please post your suggestion as an answer so I can mark the question as solved. Many thanks! P.S. I was already working with full paths everywhere, only after I started getting the errors I changed the input file to '*.las' thinking that something weird was messing up my paths.
    – Mihnea
    Commented Apr 26, 2016 at 8:19

1 Answer 1

3

I've had the same problem with the subprocess module, attempting to multi-thread a process, and I've found that breaking up the arguments into individual components where spaces exit seems to work... contrary to what I've read; this may not be necessary on Linux or other platforms but on Windows it seems to be the way to go. By changing

args=['lasground', '-i *.las', output_file, ....

to

args=['lasground', '-i','*.las', output_file, ....

presents the arguments to the subprocess in a more digestible format; this seems true for any instance where a space appears in an argument. Another way that this can be done is by writing a temporary batch file and calling it with no arguments:

# give a batch file a random name eg: TempBat93314028.bat to avoid overwriting existing files
BatFile = os.path.join(os.environ.get("TEMP"),"TempBat{0}.bat".format(random.randint(0,sys.maxint)))

# just to be sure the name is clear.. be careful of race conditions! just because it doesn't exist
# -now- doesn't mean it won't be created by a different process -before- the next line!
# for this reason I would use a unique identifier for each process you intend to run, be creative!
# you're not limited to 8.3 filenames and can use spaces and underscores.
while os.path.exists(BatFile):
    BatFile = os.path.join(os.environ.get("TEMP"),"TempBat{0}.bat".format(random.randint(0,sys.maxint)))

with open(BatFile,'w') as BatWrite:
    # write the CMD on a single line, but this can get confusing
    BatWrite.write("lasground -i {0}\\*.las {1} {2} {3} {4} {5} {6} {7}\n".format(PathToFiles, output_file, arg_step,
                                                                                                                                                            arg_spike, arg_spikedown, arg_offset,
                                                                                                                                                            arg_bulge, arg_cores))
    # or bit by bit, a little more tedious but easier to modify
    BatWrite.write("lasground ")
    BatWrite.write("-i {0}\\*.las ".format(PathToFiles))
    BatWrite.write("{0} ".format(output_file))
    BatWrite.write("{0} ".format(arg_step))
    BatWrite.write("{0} ".format(arg_spike))
    BatWrite.write("{0} ".format(arg_spikedown))
    BatWrite.write("{0} ".format(arg_offset))
    BatWrite.write("{0} ".format(arg_bulge))
    BatWrite.write("{0} ".format(arg_cores))
    BatWrite.write("\n ") # end of line... or os.linesep to make this platform independent 

proc=subprocess.Popen(BatFile,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
output,error=proc.communicate()

# then later
os.remove(BatFile) # it's always good to clean up...

then if the process fails you've got the command as text you can run on a new instance to help with debugging.

2
  • 2
    Writing the commands to a text file is indeed a good idea. What I found also works (at least in my case) is concatenating the entire argument list in a single string. So something like: args = ['lasground', '-i *.las -o etc.las -step 5 -etc -etc']
    – Mihnea
    Commented Apr 27, 2016 at 8:31
  • 1
    That's interesting.. you can use the format example to create the single argument from your parameters as you create the list. I've not tried it that way; so it seems that the args are digestible if they are either individual components with no spaces or a single string containing all arguments, so long as they're not mixed. Commented Apr 27, 2016 at 21:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.