Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
167 views
in Technique[技术] by (71.8m points)

python - Getting TypeError: bad operand type for unary +: 'str' when trying to use subprocess

I'm new to python so forgive me if I make any stupid errors. I've been trying to figure out how to pass a command to cmd.exe for about an hour now and have encountered an error every time. Recently I've gotten this error: TypeError: bad operand type for unary +: 'str'. Any help would be appreciated, thanks.

#defines a function to run BDP command with subprocess
def runcommand(command):
    """Runs command in cmd.exe"""
    import subprocess
    cmd = command
    returned_value = subprocess.call(cmd, shell=True)  
    # returns the exit code in unix
    print('returned value:', returned_value)

#defines a messagebox function to tell user what file to get
def messagebox(displayinfo):
    """Presents a messagebox telling the user to select a file"""
    from tkinter import messagebox
    messagebox.showinfo(message = displayinfo)

#Sets home to users home path eg C:/users/hsun2
from pathlib import Path
home = str(Path.home())
from tkinter import filedialog

#asks user for location of bfc file
messagebox('Select the bfc.nii.gz file')
bfcfile = filedialog.askopenfilename()
print(bfcfile)

#asks user for location of DTI.nii files
messagebox('Select your DTI.nii file')
dtinii = filedialog.askopenfilename()

#asks user for location of bval file
messagebox('Select bval file')
bvalfile = filedialog.askopenfilename()

#asks user for bvec file
messagebox('Select bvec file')
bvecfile = filedialog.askopenfilename()

output = r"'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile 
+ " --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile 
+ " -b " + bvecfile

#print(output)

#runs bdp command with user input
#output = runcommand("'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile +
#" --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile +
#" -b " + bvecfile)

Returns

C:/Users/hsun2/Desktop/localBDP/MTS/testpy/MTS126028/BrainSuite/sagT1MPRAGE_we_normal.bfc.nii.gz
Traceback (most recent call last):
  File "bdpcommandtest.py", line 44, in <module>
    + " --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile
TypeError: bad operand type for unary +: 'str'


------------------
(program exited with code: 1)

Press any key to continue . . .
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your code as originally posted was legal, because the long string concatenation expression was inside parentheses, and parentheses automatically allow you continue an expression onto the next line:

output = runcommand("'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile +
" --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile +
" -b " + bvecfile)

However, when you take the exact same expression outside of parentheses, it's no longer valid:

command = "'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile +
" --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile +
" -b " + bvecfile

… because now it's three separate expressions, one on each line. And the first one raises a SyntaxError, because it ends with a + with no right arguments.

And if you move the hanging + to the next line, as in your final posted code:

command = "'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile
+ " --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile
+ " -b " + bvecfile

… now it's syntactically valid, but nonsensical—the first line is fine, but the second line is trying to apply the unary + operator to a string, so you get a TypeError.


You can fix this by putting the expression back inside parentheses:

command = ("'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile
+ " --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile
+ " -b " + bvecfile)

… or by using backslash continuation:

command = "'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile 
+ " --FRT --FRACT --tensor --nii " + dtinii + " -g " + bvalfile 
+ " -b " + bvecfile

Although really, even though indentation isn't meaningful to Python inside expressions the way it is in statements, it is meaningful to human readers, so you should try to make it more readable, maybe something like this:

command = (
    "'C:Program FilesBrainSuite18adpdp.exe' " + bfcfile
    + " --FRT --FRACT --tensor --nii " + dtinii
    + " -g " + bvalfile
    + " -b " + bvecfile
)

However, the real fix here should be not using string concatenation in the first place. You're not using the shell here, and in fact you're fighting against it, and not entirely successfully. So just use a list of arguments and don't ask for the shell, and now we don't have to worry about quoting or spacing or getting string concatenation right:

command = [
    r"C:Program FilesBrainSuite18adpdp.exe", bfcfile,
    "--FRT", "--FRACT", "--tensor", "-nii", dtinii,
    "-g", bvalfile, "-b", bvecfile
]

And now, call it without shell=True:

returned_value = subprocess.call(command)

As a side note, notice that I added an r before the path to the program. A in a Python string literal doesn't mean a backslash and a letter b, it means a ^H backspace character. When using Windows pathnames with backslashes as literal values in your source code, always either escape them, or use a raw r prefix.

Also, I'm not sure why you added the str(…) calls all over your code to things that are already strings, but… that's never going to help anything, it just makes things harder to read, so I left them out, as in your original version.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...