I want to accept a directory path as user input in an add_argument() of ArgumentParser().
So far, I have written this:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('path', option = os.chdir(input("paste here path to biog.txt file:")), help= 'paste path to biog.txt file')
What would be the ideal solution to this problem?
One can ensure the path is a valid directory with something like:
import argparse, os
def dir_path(string):
if os.path.isdir(string):
return string
else:
raise NotADirectoryError(string)
parser = argparse.ArgumentParser()
parser.add_argument('--path', type=dir_path)
# ...
Check is possible for files using os.path.isfile() instead, or any of the two using os.path.exists().
Argument Parser(argparse) Examples : Different type of arguments with custom handlers added. For PATH 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()
You can use something like:
import argparse, os
parser = argparse.ArgumentParser()
parser.add_argument('--path', help= 'paste path to biog.txt file')
args = parser.parse_args()
os.chdir(args.path) # to change directory to argument passed for '--path'
print os.getcwd()
Pass the directory path as an argument to --path while running your script. Also, check the official document for correct usage of argparse: https://docs.python.org/2/howto/argparse.html
Related
i was using a python package (spotify_dl) to genereate some files. i was doing it manually through the command line:
spotify_dl -l spotify_playlist_link -o download_directory
now i want to do it from inside another python script.
i looked at the package code and found the main function, but i can't figure how to run the main function with arguments of my choosing - in python.
for example what i want:
from spotify_dl import spotify_dl as sp_dl
if __name__=='__main__':
destination_dir = r'D:\some\folder\path'
playlists_url = ['url1','url2','url3',....]
for url in playlists_url:
sp_dl.spotify_dl(l=url,o=destination_dir)
for better clarity, here is the actual code of the spotify_dl main function:
#!/usr/bin/env python
import argparse
import json
import os
import sys
from logging import DEBUG
from pathlib import Path, PurePath
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
from spotify_dl.constants import VERSION
from spotify_dl.models import db, Song
from spotify_dl.scaffold import log, check_for_tokens
from spotify_dl.spotify import fetch_tracks, parse_spotify_url, validate_spotify_url, get_item_name
from spotify_dl.youtube import download_songs, default_filename, playlist_num_filename
def spotify_dl():
"""Main entry point of the script."""
parser = argparse.ArgumentParser(prog='spotify_dl')
parser.add_argument('-l', '--url', action="store",
help="Spotify Playlist link URL", type=str, required=True)
parser.add_argument('-o', '--output', type=str, action='store',
help='Specify download directory.', required=True)
parser.add_argument('-d', '--download', action='store_true',
help='Download using youtube-dl', default=True)
parser.add_argument('-f', '--format_str', type=str, action='store',
help='Specify youtube-dl format string.',
default='bestaudio/best')
parser.add_argument('-k', '--keep_playlist_order', default=False,
action='store_true',
help='Whether to keep original playlist ordering or not.')
parser.add_argument('-m', '--skip_mp3', action='store_true',
help='Don\'t convert downloaded songs to mp3')
parser.add_argument('-s', '--scrape', action="store",
help="Use HTML Scraper for YouTube Search", default=True)
parser.add_argument('-V', '--verbose', action='store_true',
help='Show more information on what''s happening.')
parser.add_argument('-v', '--version', action='store_true',
help='Shows current version of the program')
args = parser.parse_args()
if args.version:
print("spotify_dl v{}".format(VERSION))
exit(0)
db.connect()
db.create_tables([Song])
if os.path.isfile(os.path.expanduser('~/.spotify_dl_settings')):
with open(os.path.expanduser('~/.spotify_dl_settings')) as file:
config = json.loads(file.read())
for key, value in config.items():
if value and (value.lower() == 'true' or value.lower() == 't'):
setattr(args, key, True)
else:
setattr(args, key, value)
if args.verbose:
log.setLevel(DEBUG)
log.info('Starting spotify_dl')
log.debug('Setting debug mode on spotify_dl')
if not check_for_tokens():
exit(1)
sp = spotipy.Spotify(auth_manager=SpotifyClientCredentials())
log.debug('Arguments: {}'.format(args))
if args.url:
valid_item = validate_spotify_url(args.url)
if not valid_item:
sys.exit(1)
if args.output:
item_type, item_id = parse_spotify_url(args.url)
directory_name = get_item_name(sp, item_type, item_id)
save_path = Path(PurePath.joinpath(Path(args.output), Path(directory_name)))
save_path.mkdir(parents=True, exist_ok=True)
log.info("Saving songs to: {}".format(directory_name))
songs = fetch_tracks(sp, item_type, args.url)
if args.download is True:
file_name_f = default_filename
if args.keep_playlist_order:
file_name_f = playlist_num_filename
download_songs(songs, save_path, args.format_str, args.skip_mp3, args.keep_playlist_order, file_name_f)
if __name__ == '__main__':
spotify_dl()
so far i could see mentions of sys.argv but also some comments spoke against using that.
what i want is a clear method that i could run in a loop without complications.
spotify_dl is badly designed, I commonly use this:
def parse_args(argv=None):
parser = argparse.ArgumentParser()
...
return parser.parse_args(argv)
def main(args):
# run your code
if __name__ == "__main__":
args = parse_args()
main(args)
Then you can import this first script in another and call the main function:
from my_first_script import main
def a_function():
args = namedtuple("args", ("arg1", ...))("value1")
main(args)
But you can workaround by overriding sys.argv:
if __name__=='__main__':
destination_dir = r'D:\some\folder\path'
playlists_url = ['url1','url2','url3',....]
for url in playlists_url:
sys.argv = [sys.executable, "-o", destination_dir, "-l", url]
sp_dl.spotify_dl()
You can use subprocess here.
I did not try your example because I don't have those libraries installed, but here's a simple example.
First, a simple commandline script called testpy.py has the following:
import sys
import argparse
def check_arg(args=None):
parser = argparse.ArgumentParser(prog='Test',
description='Test',
epilog='Test')
parser.add_argument('-f', '--first',
help='First argument',
required='True')
results = parser.parse_args(args)
return (results.first)
def main():
with open('test.txt', 'a') as file:
file.write('Success, {}\n'.format(f))
if __name__ == '__main__':
f = check_arg(sys.argv[1:])
main()
This takes one argument f and exports a text file (test.txt) with whatever argument was supplied.
This script can be run from a next script as (save this as new script file):
from subprocess import run, PIPE
args = ['python3', 'testpy.py', '-f', 'First input argument text']
res = run(args, stdout=PIPE, stderr=PIPE)
If you run this, you'll see that the file test.txt will be exported and calling the script testpy.py from this script was successful.
I have written a code function.py in python which has input file path and a output file path and some flags . currently I have hardcoded everything.I want to use command line arguments to provide these inputs so that anyone can run my script by providing input to cmd.how can I do it in python?
In CMD
function.py "input file path" "output file path"
A very rudimentary example would be:
import sys
input_file_path = sys.argv[1]
output_file_path = sys.argv[2]
Note that sys.argv[0] would be your filename. You should also do the relevant checks to make sure there are the correct number of arguments, whether they are valid, etc.
As an alternative to sys.argv, I prefer argparse.
As an example:
# Import the argparse module
import argparse
# Define a function to use argparse to parse your command-line arguments
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
"-i",
"--input-file",
dest="input_file",
help="File to use as input",
type=str
)
parser.add_argument(
"-o",
"--output-file",
dest="output_file",
help="File to output to",
type=str
)
return parser.parse_args()
# If calling this module from the command line, this `if` statement will evaluate to True
if __name__ == "__main__":
# Parse your command-line arguments
args = parse_args()
# Get the parsed value of the "-i" argument:
infile = args.input_file
# Get the parsed value of the "-o" argument:
outfile = args.output_file
I'm having issues calling functions from the command line with argparse. I just want it to execute one of the functions defined in the script.
import os
import shutil
import getpass
import argparse
user = getpass.getuser()
copyfolders = ['Favorites']
parser = argparse.ArgumentParser()
parser.add_argument('e', action='store')
parser.add_argument('i', action='store')
args = parser.parse_args()
def exp(args):
for folder in copyfolders:
c_path = os.path.join("C:", "/", "Users", user, folder)
l_path = os.path.join("L:", "/", "backup", folder)
shutil.copytree(c_path, l_path)
def imp(args):
for folder in copyfolders:
l_path = os.path.join("L:", "/", "backup", folder)
c_path = os.path.join("C:", "/", "Users", user, folder)
shutil.copytree(l_path, c_path)
When I try to call it with an argument I get:
error the follow arguments are required: i
No matter what argument is passed.
A couple of problems here:
You can't use action to call a defined function directly. However, you can set it to a boolean variable value using action='store_true' and then define your logic what to do when that variable is true (or false)
Your functions have to be defined before you call them in the script.
This is what ended up working for me:
def exp(arg):
#replace below with your logic
print("in exp for %s" % arg)
def imp(arg):
#replace below with your logic
print("in imp for %s" % arg)
user = getpass.getuser()
copyfolders = ['Favorites']
parser = argparse.ArgumentParser()
#make sure to prefix the abbreviated argument name with - and the full name with --
parser.add_argument('-e', '--exp', action='store_true', required=False)
parser.add_argument('-i', '--imp', action='store_true', required=False)
args = parser.parse_args()
isExp = args.exp
isImp = args.imp
if isExp:
exp("foo")
if isImp:
imp("bar")
Also, make sure to prefix the abbreviated argument name with - and the full name with --.
Can somebody help me, I'm trying to link an optparse with a csv reader, but I have been unable to do so. Below is my code:
import csv
from optparse import OptionParser
parser = OptionParser()
parser.add_option('--i1', action='store', type='string', dest='input1file', help='[REQUIRED] The input .csv file path.')
(options, args) = parser.parse_args()
input1file = options.input1file
data = csv.reader(open('input1file','r'))
temp = open('C:\Practice\output_edited.csv','a')
for column in data:
temp.write(column[0]+','+column[len(column)-1]+'\n')
print column[0]+','+column[len(column)-1]+'\n'
temp.close()
I don't know how to connect the add_option part so that the user can type in the filename path.
Thanks!
I updated my code. Still can't get it working though.
Update1:
import sys
import csv
from optparse import OptionParser
parser = OptionParser()
parser.add_option('--i1', action='store', type='string', dest='input1file', help='[REQUIRED] The input .csv file path.')
(options, args) = parser.parse_args()
input1file = options.input1file
try:
input1file = args[1]
except IndexError:
sys.exit("Input file required, none given")
data = csv.reader(open(sys.args[1],'r'))
temp = open('C:\Practice\output_edited.csv','a')
for column in data:
temp.write(column[0]+','+column[len(column)-1]+'\n')
print column[0]+','+column[len(column)-1]+'\n'
temp.close()
If you don't specify --i1 on the command line, options.input1file is None, since you don't provide a default value.
myscript.py --i1 input.txt
Since --i1 is required, it really shouldn't be an option (since it is not optional). Take the input file from args, instead:
parser = OptionParser()
(options, args) = parser.parse_args()
try:
input1file = args[0]
except IndexError:
sys.exit("Input file required, none given")
Or, as mgilson suggested, use argparse instead. It supports named positional parameters.
data = csv.reader(open('input1file','r'))
should be
data = csv.reader(open(input1file,'r'))
Based on your comment, it looks like you're forgetting to use the --i1 argument. If it is actually required, you should enforce that:
e.g.:
if not input1file:
print "What? you were supposed to give '--i1 filename', but you didn't. Shame on you!"
sys.exit(1)
note that this is easier to do in argparse. You just pass required=True to the add_argument method
How can options/arguments determine which function is chosen during program execution? For the example I have two options depending on the option I would like them to use their respective functions. What am I missing?
import os, sys, glob
from optparse import OptionParser
def fname(arguments):
files = []
for arg in arguments:
if '*' in arg or '?' in arg:
# contains a wildcard character
files.extend(glob.glob(arg))
elif os.path.isdir(arg):
# is a dictionary
files.extend(glob.glob(os.path.join(arg, '*')))
elif os.path.exists(arg):
# is a file
files.append(arg)
else:
# invalid?
print '%s invalid' % arg
return files
# check if file exists locally, if not: download it
def downnload(filename, keyString):
if not os.path.exists(filename+keyString):
l.get_contents_to_filename(filename+keyString)
# List bucket contents
def blist(bucket):
for b in rs:
print b.name
def main():
usage = "usage: %prog [options] -f filename"
parser = OptionParser(usage)
parser.add_option('-d', '--download',
action='store', dest='download',
default=None, help='download files from cloud')
parser.add_option('-l', '--list',
action='store', dest='bucket',
default=None, help='list buckets or contents of specified bucket')
if len(sys.argv) == 1:
parser.print_help()
sys.exit()
(options, args) = parser.parse_args()
# from boto import
bucket_list = bucket.list()
for l in bucket_list:
keyString = str(l.key)
downnload(options.filename, keyString)
blist(options.bucket)
if __name__ == '__main__':
main()
You are missing a lot.
Where is filename given a value?
Where is keyString given a value?
Where is bucket given a value?
You shouldn't name your function list since that it is a primitive type
You probably want to look at the optparse tutorial. I'm assuming that you expecting bucket to receive the value from the --list command line argument. The value gets stored into options.bucket instead. That is just a start.
I think that you want to change the end of main to check the options and call the appropriate function. Something like:
def main():
# much omitted
if options.filename is not None:
downnload(options.filename, keyString)
elif options.bucket is not None:
blist(options.bucket)
else:
print 'Either --download or --list is required.'
parser.print_help()
sys.exit(-1)
I think that this is what you are looking for. It decides which function to call based on the command line arguments passed in. For example, if the user passes --download filename then the downnload function is called with the supplied filename as the argument.