I am using python with some external program API in order to automate some stuff.
Have in mind that these "extpro" and "--file" and "--dont-breakaway-from-job" are built in commands that I have to use, my code looks like this:
send = os.system('extpro --file '(os.path.join(base_dir, extpr_path))' --dont-breakaway-from-job')
Error that I am getting is on the --dont-breakaway-from-job, saying Expected ")" pylance.
But when I try this there is no error:
send = os.system('extpro --file "C:/user/program/run.exe" --dont-breakaway-from-job')
Anyone have idea what might be behind this behavior?
Is there a way maybe to split whole command into two or three?
Any advice is welcome, thanks!
os.path.join returns str object, thus your
'extpro --file '(os.path.join(base_dir, extpr_path))' --dont-breakaway-from-job'
expands into:
'extpro --file '"<whatever that path is>"' --dont-breakaway-from-job'
^
In the position marked with ^ the string ends. And, since os.system expects only one single parameter, pylance (and interpreter too) supposes, that this parameter is already passed and throws an error, that closing bracket is expected.
Interpreter doesn't concatenate os.path.join result with string before it, because it doesn't know, that os.path.join is a string. Function call will become string only in runtime.
However, your second variant contains 'some str "inner str" some more'. Python interpreter sees string, starting with ' (single qotation mark) and looks for a matching pair, that will mean end of the string. All " (double quotation marks) between single ones are considered part of the string.
Solution is simple. You can do any of:
# Concatenating strings with +
send = os.system('extpro --file "'+ os.path.join(base_dir, extpr_path) + '" --dont-breakaway-from-job')
# Using format (or f-strings, ifyou're using python 3.6+)
send = os.system('extpro --file "{}" --dont-breakaway-from-job'.format(os.path.join(base_dir, extpr_path)))
# or
send = os.system(f'extpro --file "{os.path.join(base_dir, extpr_path)}" --dont-breakaway-from-job')
In any of 3 variations it's worth wrapping os.path.join results with " (double quotation mark) in case it contains spaces or other undesired symbols, that may e parsed incorrectly
Your line send = os.system('extpro --file '(os.path.join(base_dir, extpr_path))' --dont-breakaway-from-job') doesn't create the string that you expect/need and doesn't concatenate 'extpro --file ' with the filepath (within "!) and the ' --dont-breakaway-from-job').
The easiest solution might be to use a F-string:
send = os.system(f'extpro --file "{os.path.join(base_dir, extpr_path)}" --dont-breakaway-from-job')
Important here is also to add " to the string, since os.path.join(...) doesn't create a string with the ".
If i understood it right, the issue is that you need to concatenate the string with quotation marks? If that is the case, you can use the following
send = os.system("extpro --file \""+os.path.join(base_dir, extpr_path)+"\" --dont-breakaway-from-job")
The os.path.join returns a string which needs to be concatenated using +. Furthermore, you need to include quotation marks around os.path.join. This can be achieved in many ways, but the one i used in this answer is \".
Related
I am working on a new tool to help automate some tedious processes.
it involves ExchangeOnlineManagement, Python, and Powershell.
I have input variables that I am feeding into Powershell commands via Formatted string.
An example that works:
Email = input("Please provide your domain email address ")
sp.run(f"Connect-IPPSSession -UserPrincipalName {Email}", shell=True)
This works with no problem.
However, when I run:
Search_Name = input("What is the name of the Content Search? ")
sp.run(f'Get-ComplianceSearchAction {Search_Name}', shell=True)
I get the following:
+ Get-ComplianceSearchAction #chanroodee.com_purge
+ ~~~~~~~~~~~
The splatting operator '#' cannot be used to reference variables in an expression. '#chanroodee' can be used only as an argument to a command.
To reference variables in an expression use '$chanroodee'.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : SplattingNotPermitted
The original syntax for the command (That works on my machine currently) is
Get-ComplianceSearchAction "#chanroodee.com_purge"
I am assuming that because there are no quotes around the Search_Name var, it is not processing it as an argument. So my goal I guess is to enable quotes to be around every string that passes through the Search_Name input. so that it can be processed as an argument rather than a random string.
A fully robust solution that guarantees that whatever string value you pass to PowerShell is used verbatim requires:
using embedded '...' quoting
which in turn requires that any ' characters contained in the value be escaped as '':
Search_Name = input("What is the name of the Content Search? ")
Search_Name_Escaped = Search_Name.replace("'", "''")
sp.run(f'Get-ComplianceSearchAction \'{Search_Name_Escaped}\'', shell=True)
Note that it is tempting to attempt putting the expression Search_Name.replace("'", "''") directly inside {...} in the -f-string, but that would require \-escaping the ' chars, whereas use of \ isn't supported inside {...}.
A simpler solution is possible if you can assume that your string values never contain ` or $ characters (which would be subject to string interpolation by PowerShell inside "..."), using !r, as suggested by jonrsharpe, which calls the string's __repr__() method in order to automatically return a quoted representation of the value - which uses embedded '...' quoting by default, but switches to embedded "..." quoting if the string itself contains ' (and not also "):
Search_Name = input("What is the name of the Content Search? ")
sp.run(f'Get-ComplianceSearchAction {Search_Name!r}', shell=True)
Something like: f'Get-ComplianceSearchAction "{Search_Name}"'?
I need to transform a string containing single and double quotes and newline characters for use in a system call. Consider the following input string:
"""one'two\nthree"four"""
This should be transformed to the following output string:
"$'one\'two\nthree\"four'"
So that it can be submitted as a message argument in a git commit command:
git commit --message=$'one\'two\nthree\"four'
The odd syntax with the leading $ and surrounding single quotes ' is a bash construct described in the bash manpage in the section on quoting (search for QUOTING). I have tried many python functions including str.replace, re.sub, json.dumps, repr, and str.encode('unicode-escape'). But none have yielded the required transformation. It seems that, in this case, python is too high-level for its own good. Suggestions on how to proceed will be very gratefully received.
The system call itself will be made using code like this (omitting the try block for clarity):
import subprocess
call = ["git", "commit", "--message", "'one\'two\nthree\"four'"]
cpi = subprocess.run(call)
I may also use a git library of some description, but I have not done my homework yet for that.
Note: the unnecessary $ character in the last item in the above call list has been removed.
Your wanted command is erroneous at the moment, it is not a valid Python string since a right " is missing, it should be:
"$'one\'two\nthree\"four'"
This is easily constructed by a simple .format call:
>>> "$'{}'".format("""one'two\nthree"four""") == "$'one\'two\nthree\"four'"
True
I have a command which I can run manually from the windows command prompt, and it works as expected:
> gridcoinresearchd sendmany "Default" {"""x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw""":1.00000000} 2 "Hello World"
So I build my subprocess.call() as follows from a set of variables, some of which are derived from other variables, where;
call_insert = [val for pair in zip(quotes, quotes, quotes, address, quotes, quotes, quotes, colon, call_amount, comma) for val in pair]
call_insert = str("{"+(''.join(call_insert))+"}")
account_label = str('"'+(raw_input("Choose Account Label: "))+'"')
message = str('"'+(raw_input("Enter if you wish to send a message: "))+'"')
then:
subprocess.call(['gridcoinresearchd', 'sendmany', account_label, call_insert, "2", message], shell=True)
when using the subprocess.call I get an error from the target program:
error: Error parsing JSON:{x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw:1.00000000}
if I manually make the variable:
call_insert = str("""{"x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw":1.00000000}""")
then my subprocess.call() works.
So this I think is my confusion with how the windows command prompt is interpreting the quotes I need in my subprocess.call() strings.
I hope that makes sense.
If we inspect the given error message
{x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw:1.00000000}
and compare it to your desired JSON input
{"""x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw""":1.00000000}
we can see that double quotes are missing in the first statement, and it is probably the main reason why JSON is not parsed.
So basically I may suspect that call_insert variable is not formed as you expected, i.e. does not contain double quotes, and is equal to:
str({x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw:1.00000000})
I suggest you to look closer into the first 2 lines of your example and into the code above it to check its output.
OK by trial and error I found that the string must be in this form:
{"x9Bqs6dTm17tsiEyZ9m4j5Yd8N2dpqw":1.00000000}
I am quite new to python and i struck an issue wherein, I am dynamically retrieving a string from a dictionary which looks like this
files="eputilities/epbalancing_alb/referenced assemblies/model/cv6_xmltypemodel_xp2.cs"
I am unable to to perform any actions on this particular file as it is reading the path as 2 different strings
eputilities/epbalancing_alb/referenced and assemblies/model/cv6_xmltypemodel_xp2.cs
as there is a space between referenced and assemblies.
I wanted to know how to convert this to raw_string (ignore the space, but still keep the space between the two and consider it as one string)
I'm not able to figure this out although several comments where there on the web.
Please do help.
Thanks
From the comments to the other answer, I understand that you want to execute some external tool and pass a parameter (a filename) to it. This parameter, however, has spaces in it.
I'd propose to approaches; definitely, I'd use subprocess, not os.system.
import subprocess
# Option 1
subprocess.call([path_to_executable, parameter])
# Option 2
subprocess.call("%s \"%s\"" % (path_to_executable, parameter), shell=True)
For me, both worked, please check if they work yor you as well.
Explanations:
Option 1 takes a list of strings, where the first string has to be the path to the executable and all others are interpreted as command line arguments. As subprocess.call knows about each of these entities, it properly calls the external so that it understand thatparameter` is to be interpreted as one string with spaces - and not as two or more parameters.
Option 2 is different. With the keyword-argument shell=True we tell subprocess.call to execute the call through a shell, i.e., the first positional argument is "interpreted as if it was typed like this in a shell". But now, we have to prepare this string accordingly. So what would you do if you had to type a filename with spaces as a parameter? You'd put it between double quotes. This is what I do here.
Standard string building in python works like this
'%s foo %s'%(str_val_1, str_val_2)
So if I'm understanding you right either have a list of two strings or two different string variables.
For the prior do this:
' '.join(list)
For the latter do this:
'%s %s'%(string_1, string_2)
I am trying to run a program from the command prompt in windows. I am having some issues. The code is below:
commandString = "'C:\Program Files\WebShot\webshotcmd.exe' //url '" + columns[3] + "' //out '"+columns[1]+"~"+columns[2]+".jpg'"
os.system(commandString)
time.sleep(10)
So with the single quotes I get "The filename, directory name, or volume label syntax is incorrect." If I replace the single quotes with \" then it says something to the effect of "'C:\Program' is not a valid executable."
I realize it is a syntax error, but I am not quite sure how to fix this....
column[3] contains a full url copy pasted from a web browser (so it should be url encoded). column[1] will only contain numbers and periods. column[2] contains some text, double quotes and colons are replaced. Mentioning just in case...
Thanks!
Windows requires double quotes in this situation, and you used single quotes.
Use the subprocess module rather than os.system, which is more robust and avoids calling the shell directly, making you not have to worry about confusing escaping issues.
Dont use + to put together long strings. Use string formatting (string %s" % (formatting,)), which is more readable, efficient, and idiomatic.
In this case, don't form a long string as a shell command anyhow, make a list and pass it to subprocess.call.
As best as I can tell you are escaping your forward slash but not your backslashes, which is backwards. A string literal with // has both slashes in the string it makes. In any event, rather than either you should use the os.path module which avoids any confusion from parsing escapes and often makes scripts more portable.
Use the subprocess module for calling system commands. Also ,try removing the single quotes and use double quotes.