execute python script with function from command line, Linux - python

I have my python file called convertImage.py and inside the file I have a script that converts an image to my liking, the entire converting script is set inside a function called convertFile(fileName)
Now my problem is I need to execute this python script from the linux command line while passing the convertFile(fileName) function along with it.
example:
linux user$: python convertImage.py convertFile(fileName)
This should execute the python script passing the appropriate function.
example:
def convertFile(fileName):
import os, sys
import Image
import string
splitName = string.split(fileName, "_")
endName = splitName[2]
splitTwo = string.split(endName, ".")
userFolder = splitTwo[0]
imageFile = "/var/www/uploads/tmp/"+fileName
...rest of the script...
return
What is the right way to execute this python script and properly pass the file name to the function from the liunx command line?
Thank in advanced

This
if __name__ == "__main__":
command= " ".join( sys.argv[1:] )
eval( command )
This will work. But it's insanely dangerous.
You really need to think about what your command-line syntax is. And you need to think about why you're breaking the long-established Linux standards for specifying arguments to a program.
For example, you should consider removing the useless ()'s in your example. Make it this, instead.
python convertImage.py convertFile fileName
Then, you can -- with little work -- use argparse to get the command ("convertFile") and the arguments ("fileName") and work within the standard Linux command line syntax.
function_map = {
'convertFile': convertFile,
'conv': convertFile,
}
parser = argparse.ArgumentParser()
parser.add_argument( 'command', nargs=1 )
parser.add_argument( 'fileName', nargs='+' )
args= parser.parse_args()
function = function_map[args.command]
function( args.fileName )

Quick and dirty way:
linux user$: python convertImage.py convertFile fileName
and then in convertImage.py
if __name__ == '__main__':
import sys
function = getattr(sys.modules[__name__], sys.argv[1])
filename = sys.argv[2]
function(filename)
A more sophisticated approach would use argparse (for 2.7 or 3.2+) or optparse.

Create a top-level executable part of your script that parses command-line argument(s) and then pass it to your function in a call, like so:
import os, sys
#import Image
import string
def convertFile(fileName):
splitName = string.split(fileName, "_")
endName = splitName[2]
splitTwo = string.split(endName, ".")
userFolder = splitTwo[0]
imageFile = "/var/www/uploads/tmp/"+fileName
print imageFile # (rest of the script)
return
if __name__ == '__main__':
filename = sys.argv[1]
convertFile(filename)
Then, from a shell,
$ convertImage.py the_image_file.png
/var/www/uploads/tmp/the_image_file.png

Related

Python Command Line Arguments Syntax Error

I am trying to print out the command line arguments, however when I try to have two print statements, I get a syntax error. Is there a reason for that?
This is my terminal input: python3 test.py example_Resume.pdf softwareengineering
Also, how would I deal with a command-line argument that has a space in between?
import sys
def main(argv):
{
print(f"Name of the script : {sys.argv[0]=}")
print(f"Arguments of the script : {sys.argv[1:]=}") // This line errors
}
if __name__ == "__main__":
main(sys.argv[1:])
The best way to deal with command-line arguments is to use argparse package which takes care of shell injection, optional, default arguments.
Documentation: Argpase
Here is a sample I use for projects.
import argparse
# >>>>>>>>>>>>>>>>>>>>>>> ARGUMENT PARSING <<<<<<<<<<<<<<<<<<<<<<<<<<<<
def args():
"""
Used to get the list of arguments paseed to the class
"""
parser = argparse.ArgumentParser()
parser.add_argument('-r','--raw_file',type=str,
help='It is used to get the raw input file for parsing',
required=True)
args = parser.parse_args()
return args.raw_file
def main():
# PARSED RAW FILE
raw_file=self.args()
if __name__ == '__main__':
main()
In addition to what the other commenters pointed out, your issue is with the curly braces.
I tried your code without them:
import sys
def main(argv):
print(f"Name of the script : {sys.argv[0]=}")
print(f"Arguments of the script : {sys.argv[1:]=}")
if __name__ == "__main__":
main(sys.argv[1:])
Curly braces mean something different in Python.
The question about passing the args when you don't use them in main is valid.

How to deal with tab, newline characters and different kinds of slashes in filenames (python)?

I'm trying to read pathnames from the user and joining new directories to it. The problem is that the path string has directories starting with "n" or "t", which gives inconsistencies when parsing.
My OS in Windows 10, and my Python version is 3.7.6.
The supplied argument to argparse is 'C:\\Codes\\timpel\\noiseAnalysis\\Metadata'
import os
from argparse import ArgumentParser
def main(args):
case_name = 'APP001'
file_name = 'APP001.json'
input_path = args.input_dir
output_file = os.path.join(
args.input_dir,
case_name,
file_name
)
print(input_path)
print(output_file)
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument('input_dir', type=str)
main(parser.parse_args())
The printing results are C:\\Codes\\timpel\\noiseAnalysis\\Metadata and C:\\Codes\\timpel\\noiseAnalysis\\Metadata\APP001\APP001.json respectively.
How should I deal with this type of problem consistently? How should I deal with different types of slashes in the pathname given by the user?
This should work. I needed to change some erroneous variable names, but if you call the program on the command line with:
C:\>prog.py C:\Codes\timpel\noiseAnalysis\Metadata it outputs:
C:\Codes\timpel\noiseAnalysis\Metadata
C:\Codes\timpel\noiseAnalysis\Metadata\APP001\APP001.json
At least in my version of Python (3.6). Code:
import os
from argparse import ArgumentParser
def main(args):
input_path = args.input_dir # <--
case_name = 'APP001'
file_name = 'APP001.json'
output_file = os.path.join(
input_path,
case_name,
file_name
)
print(input_path)
print(output_file)
if __name__ == "__main__":
parser = ArgumentParser()
parser.add_argument('input_dir', type=str)
main(parser.parse_args())
I'm not sure if this helps your question or maybe somebody coming here for argparser-ing Windows path problems, but I found a bug in IDLE that strips backslashes entered in "Run... Customized". This DOES NOT happen when running from the command line.
When you enter C:\Codes\timpel\noiseAnalysis\Metadata into Run... Customized in IDLE it becomesC:CodestimpelnoiseAnalysisMetadata, but works just find on the command line (e.g.:python prog.py C:\Codes\timpel\noiseAnalysis\Metadata)
There is a work-around for IDLE. If you entered the path in quotes (e.g.:'C:\Codes\timpel\noiseAnalysis\Metadata') it will be processed fine.
Also note that backslashes \ in IDLE arguments cause the pre-populated textbox to get screwed up even if you use the quotes work-around. The text that was passed to the previous run will now be surrounded in curly braces (e.g.:{C:CodestimpelnoiseAnalysisMetadata}).
I filed an issue on github for this and I'm waiting for a response.

Python: Paging of argparse help text?

For a Python script that uses argparse and has a very long argument list, is it possible to make argparse page what it prints to the terminal when calling the script with the -h option?
I could not find a quick answer, so I wrote a little something:
# hello.py
import argparse
import os
import shlex
import stat
import subprocess as sb
import tempfile
def get_pager():
"""
Get path to your pager of choice, or less, or more
"""
pagers = (os.getenv('PAGER'), 'less', 'more',)
for path in (os.getenv('PATH') or '').split(os.path.pathsep):
for pager in pagers:
if pager is None:
continue
pager = iter(pager.split(' ', 1))
prog = os.path.join(path, next(pager))
args = next(pager, None) or ''
try:
md = os.stat(prog).st_mode
if md & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
return '{p} {a}'.format(p=prog, a=args)
except OSError:
continue
class CustomArgParser(argparse.ArgumentParser):
"""
A custom ArgumentParser class that prints help messages
using either your pager, or less or more, if available.
Otherwise, it does what ArgumentParser would do.
Use the PAGER environment variable to force it to use your pager
of choice.
"""
def print_help(self, file=None):
text = self.format_help()
pager = get_pager()
if pager is None:
return super().print_help(file)
fd, fname = tempfile.mkstemp(prefix='simeon_help_', suffix='.txt')
with open(fd, 'w') as fh:
super().print_help(fh)
cmd = shlex.split('{p} {f}'.format(p=pager, f=fname))
with sb.Popen(cmd) as proc:
rc = proc.wait()
if rc != 0:
super().print_help(file)
try:
os.unlink(fname)
except:
pass
if __name__ == '__main__':
parser = CustomArgParser(description='Some little program')
parser.add_argument('--message', '-m', help='Your message', default='hello world')
args = parser.parse_args()
print(args.message)
This snippet does main things. First, it defines a function to get the absolute path to a pager. If you set the environment variable PAGER, it will try and use it to display the help messages. Second, it defines a custom class that inherits pretty much everything from argparse.ArgumentParser. The only method that gets overridden here is print_help. It implements print_help by defaulting to super().print_help() whenever a valid pager is not found. If a valid is found, then it writes the help message to a temporary file and then opens a child process that invokes the pager with the path to the temporary file. When the pager returns, the temporary file is deleted. That's pretty much it.
You are more than welcome to update get_pager to add as many pager programs as you see fit.
Call the script:
python3 hello.py --help ## Uses less
PAGER='nano --view' python3 hello.py --help ## Uses nano
PAGER=more python3 hello.py --help ## Uses more

Take input from user and execute the python script at the same time

i have a python script name as neural_net.py . It classify the mnist dataset.
What i want to do is to run it via command line by taking input from user.
The following snippet is taking input from user
file=input()
from PIL import Image
im = Image.open(file).convert('L')
imr=np.array(im).T
single_test = imr.reshape(1,400)
plt.figure(figsize=(5,5))
plt.imshow(imr)
print("value is",nn.predict(single_test))
in command prompt i have to run it as following
python neural_net.py
execute the above line and then give the input
pic_0.png
and it return me the output.
What i want is to do the both of above things as a single command such as
python neural_net.py pic_0.png
Use in code
import sys
file = sys.argv[1]
to get it.
Now you can run it as
python neural_net.py pic_0.png
and file will be pic_0.png
If you run with more arguments
python neural_net.py pic_0.png pic_1.png pic_2.png
then you will have sys.argv[2], sys.argv[3], etc. with values pic_1.png, pic_2.png
If you need more complex soluton like
script.py --input pic_0.png --output image.png
then see module argparse
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--input')
parser.add_argument('-o', '--output', default='output.png')
args = parser.parse_args()
file = args.input
output_file = args.output
EDIT:
I think I realized why you are unhappy. You need to provide a path in addition to the file name, you can either do this with args like
python run.py "c:/users/user/desktop/pictures/pngs/file.png"
and use the original answers. Or simply just put a general path in the code and use the arg for the specific file.
IMAGE_FOLDER = "c:/users/user/desktop/pictures/pngs/"
file = IMAGE_FOLDER + sys.argv[1]
Original:
This is pretty much straight from google results:
CML:
python neural_net.py pic_0.png
Code:
import sys
print sys.argv[1]
Result:
"pic_0.png"
Many thanks for Google and
https://www.pythonforbeginners.com/system/python-sys-argv

python argparse file extension checking

can argparse be used to validate filename extensions for a filename cmd line parameter?
e.g. if i have a python script i run from the cmd line:
$ script.py file.csv
$ script.py file.tab
$ script.py file.txt
i would like argparse to accept the 1st two filename cmd line options but reject the 3rd
i know you can do something like this:
parser = argparse.ArgumentParser()
parser.add_argument("fn", choices=["csv","tab"])
args = parser.parse_args()
to specify two valid choices for a cmd line option
what i'd like is this:
parser.add_argument("fn", choices=["*.csv","*.tab"])
to specify two valid file extensions for the cmd line option. Unfortunately this doesn't work - is there a way to achieve this using argparse?
Sure -- you just need to specify an appropriate function as the type.
import argparse
import os.path
parser = argparse.ArgumentParser()
def file_choices(choices,fname):
ext = os.path.splitext(fname)[1][1:]
if ext not in choices:
parser.error("file doesn't end with one of {}".format(choices))
return fname
parser.add_argument('fn',type=lambda s:file_choices(("csv","tab"),s))
parser.parse_args()
demo:
temp $ python test.py test.csv
temp $ python test.py test.foo
usage: test.py [-h] fn
test.py: error: file doesn't end with one of ('csv', 'tab')
Here's a possibly more clean/general way to do it:
import argparse
import os.path
def CheckExt(choices):
class Act(argparse.Action):
def __call__(self,parser,namespace,fname,option_string=None):
ext = os.path.splitext(fname)[1][1:]
if ext not in choices:
option_string = '({})'.format(option_string) if option_string else ''
parser.error("file doesn't end with one of {}{}".format(choices,option_string))
else:
setattr(namespace,self.dest,fname)
return Act
parser = argparse.ArgumentParser()
parser.add_argument('fn',action=CheckExt({'csv','txt'}))
print parser.parse_args()
The downside here is that the code is getting a bit more complicated in some ways -- The upshot is that the interface gets a good bit cleaner when you actually go to format your arguments.
Define a custom function which takes the name as a string - split the extension off for comparison and just return the string if it's okay, otherwise raise the exception that argparse expects:
def valid_file(param):
base, ext = os.path.splitext(param)
if ext.lower() not in ('.csv', '.tab'):
raise argparse.ArgumentTypeError('File must have a csv or tab extension')
return param
And then use that function, such as:
parser = argparse.ArgumentParser()
parser.add_argument('filename', type=valid_file)
No. You can provide a container object to choices argument, or anything that supports the "in" operator. You can read more at pydocs
You can always check it yourself and provide feedback to the user though.

Categories

Resources