I'm new to python and currently playing around with argpase. I'm trying to call a function using a directory path given as a command line argument followed by an argparse option(-name) and a regex that goes through all the files in the directory and spits out all the matches to the regex as so:
./find.py ../seek -name '[a-z]*\.txt'
However, I'm getting a error that looks like
usage: find.py [-h] [--path PATH] [-name] [--regex REGEX]
find.py: error: unrecognized arguments: . . / s e e k / p r o g r a m . c
And without the -name its just printing all the files inside the path.
Here is what I have so far:
#!/usr/bin/python2.7
import os, sys, argparse,re
from stat import *
def parse(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('--path', help='path of directory', action='store')
parser.add_argument('-name', '--name', action='store_true')
parser.add_argument('--regex', default=r"[a-z0-9A-Z]")
args = parser.parse_args(argv)
print(args)
return args
def main(argv=None):
direc = sys.argv[1]
files = []
for f in os.listdir(direc):
pathname = os.path.join(direc, f)
mode = os.stat(pathname).st_mode
if S_ISREG(mode):
args = parse(pathname)
if args.name:
dirls = [re.match(args.regex, pathname)]
print(dirls)
else:
print pathname
if __name__ == '__main__':main()
Any thoughts?
Argument Parser PATH Example : Different type of arguments with custom handlers added. For path here you can pass '-path' followed by path value as argument
import os
import argparse
from datetime import datetime
def parse_arguments():
parser = argparse.ArgumentParser(description='Process command line arguments.')
parser.add_argument('-path', type=dir_path)
parser.add_argument('-e', '--yearly', nargs = '*', help='yearly date', type=date_year)
parser.add_argument('-a', '--monthly', nargs = '*',help='monthly date', type=date_month)
return parser.parse_args()
def dir_path(path):
if os.path.isdir(path):
return path
else:
raise argparse.ArgumentTypeError(f"readable_dir:{path} is not a valid path")
def date_year(date):
if not date:
return
try:
return datetime.strptime(date, '%Y')
except ValueError:
raise argparse.ArgumentTypeError(f"Given Date({date}) not valid")
def date_month(date):
if not date:
return
try:
return datetime.strptime(date, '%Y/%m')
except ValueError:
raise argparse.ArgumentTypeError(f"Given Date({date}) not valid")
def main():
parsed_args = parse_arguments()
if __name__ == "__main__":
main()
In order for your program to operate, you need a path. So, the --path option must take an argument. Modify your parse() function to change the line
parser.add_argument('--path', help='path of directory', action='store')
to
parser.add_argument('--path', help='path of directory', action='store', required=True)
You need to call parse_args() only once. Remove the parse() invocation to the top of the loop.
And you needn't do
direc = sys.argv[1]
if you are using argparse.
re.match() returns a match object, which is probably not what you want to print.
You might want to take a look at match() versus search().
The match() function only checks if the RE matches at the beginning of the string while search() will scan forward through the string for a match.
If you wanted to print the file names matching the regex, you could do
if S_ISREG(mode):
#args = parse(pathname)
if args.name:
#dirls = re.match(args.regex, pathname)
dirls = re.search(args.regex, pathname)
if( dirls ):
print(pathname)
else:
print pathname
So main() should be something like
def main(argv=None):
args = parse(sys.argv[1:])
print(args)
#direc = sys.argv[1]
direc = args.path
files = []
for f in os.listdir(direc):
pathname = os.path.join(direc, f)
mode = os.stat(pathname).st_mode
if S_ISREG(mode):
#args = parse(pathname)
if args.name:
#dirls = re.match(args.regex, pathname)
dirls = re.search(args.regex, pathname)
if( dirls ):
print(pathname)
else:
print pathname
In order to specify the regex matching the file names, you must specify the regex using the --regex option. By default, you've made it to match names having only numbers and (English) letters.
./find.py --path ../seek -name --regex [a-z]\*.txt
or
./find.py --path ../seek -name --regex '[a-z]*.txt'
Related
I am tasked with creating an app using python to sort files in a given directory.
I want the input path to be passed as a command line argument using
cmd_parser.add_argument()
instead of being accepted as normal input after running the code.
The code does what it's supposed to, but I don't want the path to be received as an input.
Any help is greatly appreciated
import os
import shutil
from argparse import ArgumentParser
def main():
cmd_parser = ArgumentParser(description="Application")
cmd_parser.add_argument(
'-v', '--version',
action='version',
version='Application v0.0.1',
help='show version of the application'
)
cmd_parser.add_argument(
'-h', '--help',
action='help',
help='Please enter a valid directory which contains the files to be sorted'
)
cmd_args = cmd_parser.parse_args()
try:
globals()[cmd_args.action](cmd_args.file)
except Exception as ex:
print('[ERROR]', str(ex))
sys.exit(1)
while True:
directory = input("Please input the directory including the files: ")
if not os.path.isdir(directory):
print("Please input a valid directory")
else:
break
path = directory
os.chdir(path)
new_folder = "Sorted Files"
os.makedirs(new_folder)
path_2 = path+"/"+new_folder
os.chdir(path_2)
new_folder_doc = "Documents"
new_folder_texts = "Texts"
new_folder_images = "Images"
new_folder_other = "Other"
os.makedirs(new_folder_doc)
os.makedirs(new_folder_texts)
os.makedirs(new_folder_images)
os.makedirs(new_folder_other)
for file in os.listdir(path):
file_path = os.path.join(path, file)
if os.path.isfile(file_path):
file_name = os.path.basename(file_path)
if file_path.endswith('.png') or file_path.endswith('.gif') or file_path.endswith('.bmp') or\
file_path.endswith('.jpg') or file_path.endswith('.jpeg') is True:
shutil.move(file_path, new_folder_images)
continue
if file_path.endswith('.txt') or file_path.endswith('.ini') or file_path.endswith('.log') is True:
shutil.move(file_path, new_folder_texts)
continue
if file_path.endswith('.pdf') or file_path.endswith('.docx') or file_path.endswith('.doc') or\
file_path.endswith('.xls') or file_path.endswith('.xlsx') or file_path.endswith('.csv') is True:
shutil.move(file_path, new_folder_doc)
continue
if file_path.endswith('.docx') or file_path.endswith('.txt') or file_path.endswith('.bmp') or \
file_path.endswith('.png') is not True:
shutil.move(file_path, new_folder_other)
continue
my_folder = path # your path here
count = 0
for root, dirs, files in os.walk(my_folder):
count += len([fn for fn in files if fn.endswith(".pdf") or fn.endswith(".docx")
or fn.endswith(".doc") or fn.endswith(".xls") or fn.endswith(".xlsx") or fn.endswith(".csv")
or fn.endswith(".jpeg") or fn.endswith(".jpg") or fn.endswith(".bmp") or fn.endswith(".gif")
or fn.endswith(".png") or fn.endswith(".txt") or fn.endswith(".ini") or fn.endswith(".log")])
print(f"Organized {count} files")
Error resulting from fixed code (It's also not doing what it's supposed to anymore)
usage: StackTestSorter.py [-h] [-v] directory
StackTestSorter.py: error: the following arguments are required: directory
Rather than having:
def main():
cmd_parser = ArgumentParser(description="Application")
cmd_parser.add_argument(
'-v', '--version',
action='version',
version='Application v0.0.1',
help='show version of the application'
)
cmd_parser.add_argument(
'-h', '--help',
action='help',
help=''
)
cmd_args = cmd_parser.parse_args()
try:
globals()[cmd_args.action](cmd_args.file)
except Exception as ex:
print('[ERROR]', str(ex))
sys.exit(1)
while True:
directory = input("Please input the directory including the files: ")
if not os.path.isdir(directory):
print("Please input a valid directory")
else:
break
path = directory
have (removing the --help argument as this will be added automatically):
cmd_parser = ArgumentParser(description="Application")
cmd_parser.add_argument(
'-v', '--version',
action='version',
version='Application v0.0.1',
help='show version of the application'
)
cmd_parser.add_argument(
"directory", # this will be a positional argument
help="a valid directory which contains the files to be sorted",
)
cmd_args = cmd_parser.parse_args()
path = cmd_args.directory
if I understood you correctly all you need to do is add one more argument, something like:
cmd_parser.add_argument("-p", "--path", help="", required=True, default=False)
and then after cmd_args you can do:
path = cmd_args.path
My goal is to create a python's script, which will format/modify the xml file.
Path to file & filename are to be given as arguments in command line.
Here is my code below:
import lxml.etree as etree
from argparse import ArgumentParser
import sys
import os
def main():
parser = ArgumentParser()
parser.add_argument('-p', '--path', help="path to file's directory", required=True)
parser.add_argument('-f', '--file', help="file name", required=True)
args = parser.parse_args()
root_dir = sys.argv[1]
file_name = sys.argv[2]
path = sys.argv[1] + sys.argv[2]
for dirpath, dirnames, files in os.walk(root_dir):
for file in files:
if file == file_name:
print(os.path.join(dirpath, file_name))
with open(path, 'r', encoding="utf8") as myfile:
try:
print("DONE")
parser = etree.XMLParser(remove_blank_text = True)
tree = etree.parse(path, parser)
tree.write(path, pretty_print = True)
except IOError:
print("IO Exception Occured")
if __name__ == "__main__":
main()
When I run it from cmd - I have 0 errors, but the file is not formatted, even though I give the filename that doesn't exist - still no errors. So when I run it from cmd - nothing happens.
When I try to debug it in Visual Studio, there is error that 2 arguments need to be given.
Can anybody tell me how to fix my code, I have no idea where I have wrong code?
You're misusing/combining/confusing sys.argv and ArgumentParser. This code actually gives you the unexpected result, because your variables are not what you think they are!
root_dir = sys.argv[1]
file_name = sys.argv[2]
# Add some print statements to examine these variables:
print(f'root_dir:{root_dir}')
print(f'file_name:{file_name}')
Look:
Do this instead:
root_dir = args.path
file_name = args.file
Here is code I used to test:
from argparse import ArgumentParser
import sys
def main():
parser = ArgumentParser()
parser.add_argument('-p', '--path', help="path to file's directory", required=True)
parser.add_argument('-f', '--file', help="file name", required=True)
args = parser.parse_args()
root_dir = args.path
file_name = args.file
print(f'root_dir:{root_dir}')
print(f'file_name:{file_name}')
if __name__ == "__main__":
main()
You are mixing two things!
METHOD 1
Launch with XmlFormat.py -p c:\User\Desktop\test\ -f test.xml
import lxml.etree as etree
from argparse import ArgumentParser
import sys
import os
def main():
parser = ArgumentParser()
parser.add_argument('-p', '--path', help="path to file's directory", required=True)
parser.add_argument('-f', '--file', help="file name", required=True)
args = parser.parse_args()
root_dir = args.path
file_name = args.file
path = root_dir + file_name
for dirpath, dirnames, files in os.walk(root_dir):
for file in files:
if file == file_name:
print(os.path.join(dirpath, file_name))
with open(path, 'r', encoding="utf8") as myfile:
try:
print("DONE")
parser = etree.XMLParser(remove_blank_text = True)
tree = etree.parse(path, parser)
tree.write(path, pretty_print = True)
except IOError:
print("IO Exception Occured")
if __name__ == "__main__":
main()
METHOD 2
Launch with XmlFormat.py c:\User\Desktop\test\ test.xml (do not use -p and -f)
import lxml.etree as etree
from argparse import ArgumentParser
import sys
import os
def main():
root_dir = sys.argv[1]
file_name = sys.argv[2]
path = root_dir + file_name
for dirpath, dirnames, files in os.walk(root_dir):
for file in files:
if file == file_name:
print(os.path.join(dirpath, file_name))
with open(path, 'r', encoding="utf8") as myfile:
try:
print("DONE")
parser = etree.XMLParser(remove_blank_text = True)
tree = etree.parse(path, parser)
tree.write(path, pretty_print = True)
except IOError:
print("IO Exception Occured")
if __name__ == "__main__":
main()
When I specify the -a switch to add to config file for some reason this calls the read_config file also. For example I use ./script.py -a newfile.txt and the file is added correctly but then returns "Config File not found".
parser = argparse.ArgumentParser(description='Copy multiple Files from a specified data file')
parser.add_argument('-c', '--configfile', default="config.dat", help='file to read the config from')
parser.add_argument('-l', '--location', default="/home/admin/Documents/backup/",help='Choose location to store files')
parser.add_argument('-a', '--add', help='add new line to config data')
def read_config(data):
try:
dest = '/home/admin/Documents/backup/'
# Read in date from config.dat
data = open(data)
# Interate through list of files '\n'
filelist = data.read().split('\n')
# Copy through interated list and strip white spaces and empty lines
for file in filelist:
if file:
shutil.copy(file.strip(), dest)
except FileNotFoundError:
logger.error("Config file not found")
print ("Config File not found")
Not quite sure why this section below is working but read_config is called and finding the except error. Where am I going wrong?
def addtofile(add):
f = open('config.dat', "a")
f.write(add + '\n')
f.close()
args = vars(parser.parse_args())
read = read_config(args['configfile'])
add = addtofile(args['add'])
parser = argparse.ArgumentParser()
parser.add_argument('-c', action='store_true')
a = parser.parse_args()
if a.c:
{
print("get custom config")
}
else:
{
print("using default config file")
}
I think your solution will be:
parser = argparse.ArgumentParser()
parser.add_argument('-c', action='store_true')
a = parser.parse_args()
if a.c:
{
print("get custom config")
}
else:
{
print("using default config file")
}
I have been using argparse in a program I am writing however it doesnt seem to create the stated output file.
My code is:
parser.add_argument("-o", "--output", action='store', dest='output', help="Directs the output to a name of your choice")
with open(output, 'w') as output_file:
output_file.write("%s\n" % item)
I have also tried:
parser.add_argument("-o", "--output", action='store', type=argparse.FileType('w'), dest='output', help="Directs the output to a name of your choice")
output_file.write("%s\n" % item)
The error that occurs is :
output_file.write("%s\n" % item)
NameError: name 'output_file' is not defined
Can someone please explain why I am having this error occuring and how I could solve it?
All my code:
from __future__ import print_function
from collections import defaultdict
from itertools import groupby
import argparse #imports the argparse module so it can be used
from itertools import izip
#print = print_function
parser = argparse.ArgumentParser() #simplifys the wording of using argparse as stated in the python tutorial
parser.add_argument("-r1", type=str, action='store', dest='input1', help="input the forward read file") # allows input of the forward read
parser.add_argument("-r2", type=str, action='store', dest='input2', help="input the reverse read file") # allows input of the reverse read
parser.add_argument("-v", "--verbose", action="store_true", help=" Increases the output, only needs to be used to provide feedback to Tom for debugging")
parser.add_argument("-n", action="count", default=0, help="Allows for up to 5 mismatches, however this will reduce accuracy of matching and cause mismatches. Default is 0")
#parser.add_argument("-o", "--output", action='store', type=argparse.FileType('w'), dest='output', help="Directs the output to a name of your choice")
parser.add_argument("-fastq", action="store_true", help=" States your input as fastq format")
parser.add_argument("-fasta", action="store_true", help=" States your input as fasta format")
parser.add_argument("-o", "--output", action='store', dest='output', help="Directs the output to a name of your choice")
args = parser.parse_args()
def class_chars(chrs):
if 'N' in chrs:
return 'unknown'
elif chrs[0] == chrs[1]:
return 'match'
else:
return 'not_match'
with open(output, 'w') as output_file:
s1 = 'aaaaaaaaaaN123bbbbbbbbbbQccc'
s2 = 'aaaaaaaaaaN456bbbbbbbbbbPccc'
n = 0
consec_matches = []
chars = defaultdict(int)
for k, group in groupby(zip(s1, s2), class_chars):
elems = len(list(group))
chars[k] += elems
if k == 'match':
consec_matches.append((n, n+elems-1))
n += elems
print (chars)
print (consec_matches)
print ([x for x in consec_matches if x[1]-x[0] >= 9])
list = [x for x in consec_matches if x[1]-x[0] >= 9]
flatten_list= [x for y in list for x in y]
print (flatten_list)
matching=[y[1] for y in list for x in y if x ==0 ]
print (matching)
magic = lambda matching: int(''.join(str(i) for i in matching)) # Generator exp.
print (magic(matching))
s2_l = s2[magic(matching):]
line3=s1+s2_l
print (line3)
if line3:
output_file.write("%s\n" % item)
You are missing the bit where the arguments are actually parsed:
parser.add_argument("-o", "--output", help="Directs the output to a name of your choice")
args = parser.parse_args()
with open(args.output, 'w') as output_file:
output_file.write("%s\n" % item)
parser.parse_args() will give you an object from which you can access the arguments by name using the long option name bar the dashes.
I think you almost had the most correct answer. The only problem is output_file was not read from the args:
parser.add_argument("-o", "--output", action='store',
type=argparse.FileType('w'), dest='output',
help="Directs the output to a name of your choice")
#output_file is not defined, you want to read args.output to get the output_file
output_file = args.output
#now you can write to it
output_file.write("%s\n" % item)
When I run your script I get:
Traceback (most recent call last):
File "stack23566970.py", line 31, in <module>
with open(output, 'w') as output_file:
NameError: name 'output' is not defined
There's no place in your script that does output = ....
We can correct that with:
with open(args.output, 'w') as output_file:
argparse returns values as attributes of the args object.
Now I get:
Traceback (most recent call last):
File "stack23566970.py", line 62, in <module>
output_file.write("%s\n" % item)
NameError: name 'item' is not defined
Again, there's no item = ... line.
What is item supposed to be?
I'm new to using the arparse module in python and am hoping someone can help me with the following problem.
I am specifying a variable number of files as inputs using:
parser = argparse.ArgumentParser(description='Get Files')
parser.add_argument('-i','--input', help='Input file(s)',required=True, nargs='+')
args = parser.parse_args()
I would like to specify a variable number of file inputs, each with an associated value of 1 or 2 and am not sure how to do this.
I would like the program to work so that my command line entry should be:
MyProgram.py -i myfile.txt 2 secondfile.txt 1 ...
Once I have this working how do I call each file in the program?
Your code is functional. You could use the grouper recipe to loop through args.input two items at a time:
import argparse
parser = argparse.ArgumentParser(description='Get Files')
parser.add_argument('-i','--input', help='Input file(s)',required=True, nargs='+')
args = parser.parse_args()
for filename, num in zip(*[iter(args.input)]*2):
print(filename, num)
# with open(filename) as f:
# ....
yields
('myfile.txt', '2')
('secondfile.txt', '1')
It would be clearer to have -i once for each pair of inputs, like this:
parser.add_argument("-i", "--input", nargs=2, action='append')
Now, args.input would be a list of lists, like so
[ ['myfile.txt', 2], ['secondfile.txt', 1] ]
It does require slightly more typing for the user, since -i needs to be explicitly typed once per file.
Another option is to specify each argument as a single word, then parse the word using the type argument. I would get rid of the -i argument as well and use positional arguments for required "options".
parser.add_argument('input', nargs='+', type=lambda x: x.rsplit(":", 2))
Usage would be
myscript.py myfile.txt:1 secondfile.txt:2 ...
You might be best off using sys.argv as,
import sys, os
variables = list()
filenames = list()
if( len( sys.argv ) > 1 ):
if( sys.argv[1] == '-i' )or( sys.argv[1] == '--input' ):
N = len( sys.argv[1:] )
for i in range( 2, N, 2 ):
variables.append( int( sys.argv[i] ) )
filenames.append( sys.argv[i+1] )
for file in filenames:
# do something here
os.system( 'less '+file )
I haven't tested this, but that should work.
Try this:
parser = argparse.ArgumentParser(description='Get Files')
parser.add_argument('-i','--input', help='Input file(s)',
required=True, nargs='+', action='append')
args = parser.parse_args()