Using Argparse for Dictionary - python

I want to read any one of the items from a list of videos. The video reading and display code is the following. This code is working perfectly fine.
import cv2
def VideoReading(vid):
cap = cv2.VideoCapture(vid)
while True:
ret, frame = cap.read()
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Since I've large number of videos and I'm calling the code through command line, writing the entire video name is cumbersome. So I created a dictionary. Here given the example of 2:
{"Video1.mp4": 1, 'Video2.mp4': 2}
Now I'm using the following code to call the video using value 1 or 2, rather than Video name. The code is the following:
def Main():
VideoFiles= ["Video1.mp4", "Video2.mp4"]
VideoFilesIndicator = [1, 2]
model_list = {}
for i in range(len(VideoFiles)):
model_list[VideoFiles[i]] = VideoFilesIndicator[i]
print(model_list)
def convertvalues(value):
return model_list.get(value, value)
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--video", help = "add video file name of any format", type = convertvalues,\
choices = [1,2], default = 1)
args =parser.parse_args()
return VideoReading(args.video)
if __name__ == "__main__":
Main()
Now when I'm running the code in cmd "python VideoReading.py -v 2", it's throwing me the following error.
error: argument -v/--video: invalid choice: '2' (choose from 1, 2)
I'm not understanding why I'm getting this error. I'm following this post to build my program.

The problem is that convertvalues is returning '2' as a string, because convertvalues returns value as it is (i.e. a string) when it is not found in model_list. Try with:
def convertvalues(value):
return model_list.get(value, int(value))
Also, as it is, your argument parser will always receive an integer in video in the end (either you passed an integer or convertvalues transformed a video file name into an integer). To get the actual file name again you can do something like
args = parser.parse_args()
video_file = VideoFiles[VideoFilesIndicator.index(args.video)]
return VideoReading(video_file)
My suggestion is based on trying to make the minimal amount of changes to the code. However, you may also consider more changes in the program, like flevinkelming suggests, if you don't feel comfortable with the final shape of the code.

Your dictionary is backwards; you want to map a number to a file name, so that when you enter a number, a file name can be returned. There's no need to provide a default value from convertvalues, because you are using choices to limit the allowable inputs to the valid keys of the dict.
def main():
video_files = ["Video1.mp4", "Video2.mp4"]
model_list = dict(enumerate(video_files, start=1))
print(model_list)
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--video",
help="add video file name of any format",
type=lambda str: model_list[int(str)],
choices=model_list.values())
args = parser.parse_args()
return VideoReading(args.video)

An alternative solution, with minimal code, and dynamic help output for users:
import argparse
def main():
model = {
1: "Video1.mp4",
2: "Video2.mp4",
3: "Video3.mp4"
} # Add more if needed
videos = ['{}({})'.format(v, str(k)) for k, v in model.items()]
help_ = "Videos to choose from: {}".format(', '.join(videos))
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--video', help=help_, type=int, default=1)
args = parser.parse_args()
return VideoReading(model[args.video])
if __name__ == '__main__':
main()
python VideoReading.py -h:
usage: VideoReading.py [-h] [-v VIDEO]
optional arguments:
-h, --help show this help message and exit
-v VIDEO, --v VIDEO
Videos to choose from: Video1.mp4(1), Video2.mp4(2),
Video3.mp4(3)
python VideoReading.py:
If you were printing the selection - Video1.mp4
python VideoReading.py -v 3:
If you were printing the selection - Video3.mp4

Related

How to take bulk inputs in python using input function

Code as following:
#enter code here
source_input = input("enter source url: ")
destination_input = input("enter the destination url: ")
new_source = source_input.replace("https://www.domain.com.au","")
new_destination = destination_input.replace("https://www.domain.com.au","")
symbol = "=>"
symbol_space = len(symbol)
center = symbol.center(symbol_space)
source_final = f" '{new_source}' "
destination_final = f" '{new_destination}' "
print(source_final+center+destination_final)
but this code is not taking multiline inputs. I want to provide multiple source and destination inputs like:
Actual source input
https://www.domain.com.au/shop
Actual destination input
https://www.domain.com.au/shopwithus
Actual output
'/shop' => '/shopwithus'
desired source inputs to be taken
https://www.domain.com.au/shop
https://www.domain.com.au/main
https://www.domain.com.au/home
https://www.domain.com.au/contactus
desired destiantion inputs to be taken
https://www.domain.com.au/shopwithus
https://www.domain.com.au/gomain
https://www.domain.com.au/homemain
https://www.domain.com.au/contactus
Desired outputs
'/shop' => '/shopwithus'
'/main' => '/gomain'
'/home' => 'homemain'
'/contactus' => '/contactus'
is there any way to achieve this kind of inputs and outputs?
This may be a lateral move but you could use command line arguments with argparse:
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--source', help='The source.', required=True, type=str)
parser.add_argument('-d', '--destination', help='The desitnation.', required=True, type=str)
cmd_args = parser.parse_args()
def main() -> None:
print("source :", cmd_args.source)
print("destination:", cmd_args.destination)
if __name__ == "__main__":
main()
Then when executing just specify the arguments like follows (to script is called tmp.py)
python3 tmp.py -s "www.source.com" -d "www.destination.com"
# source : www.source.com
# destination: www.destination.com

How can I run a different py folder that requires arguments using a different py file?

So I found a script from github(Multithreaded Reddit Image Downloader v2.0 (by u/impshum)) that downloads images from subbredits on reddit.com using given input that are arguments -s(subreddit) -i(number of images) -o(order).
class redditImageScraper:
def __init__(self, sub, limit, order):
config = configparser.ConfigParser()
config.read('conf.ini')
self.sub = sub
self.limit = limit
self.order = order
self.path = f'images/{self.sub}/'
self.reddit = praw.Reddit(client_id=config['REDDIT']['client_id'],
client_secret=config['REDDIT']['client_secret'],
user_agent='Multithreaded Reddit Image Downloader v2.0 (by u/impshum)')
def download(self, image):
r = requests.get(image['url'])
with open(image['fname'], 'wb') as f:
f.write(r.content)
def start(self):
images = []
try:
go = 0
if self.order == 'hot':
submissions = self.reddit.subreddit(self.sub).hot(limit=None)
elif self.order == 'top':
submissions = self.reddit.subreddit(self.sub).top(limit=None)
elif self.order == 'new':
submissions = self.reddit.subreddit(self.sub).new(limit=None)
for submission in submissions:
if not submission.stickied and submission.url.endswith(('jpg', 'jpeg', 'png')):
fname = self.path + re.search('(?s:.*)\w/(.*)', submission.url).group(1)
if not os.path.isfile(fname):
images.append({'url': submission.url, 'fname': fname})
go += 1
if go >= self.limit:
break
if len(images):
if not os.path.exists(self.path):
os.makedirs(self.path)
with concurrent.futures.ThreadPoolExecutor() as ptolemy:
ptolemy.map(self.download, images)
except Exception as e:
print(e)
def main():
parser = argparse.ArgumentParser(description='Multithreaded Reddit Image Downloader v2.0 (by u/impshum)')
required_args = parser.add_argument_group('required arguments')
required_args.add_argument('-s', type=str, help="subreddit", required=True)
required_args.add_argument('-i', type=int, help="number of images", required=True)
required_args.add_argument('-o', type=str, help="order (new/top/hot)", required=True)
args = parser.parse_args()
scraper = redditImageScraper(args.s, args.i, args.o)
scraper.start()
if __name__ == '__main__':
main()
In my second file, get_up.py I imported run.py(the file with the code above) but using run.main() no matter what I try to do here it tells me its missing arguments -s -i -o. Is there a way to input these arguments from get_up.py?
Basically, because run.py parser looking for command line arguments, so you can give these arguments to get_up.py when you run it, for example:
$ python3 get_up.py -s (args goes here)
instead of:
$ python3 get_up.py
Please take a look at https://docs.python.org/3/library/argparse.html

Python default parameter if no command line arguments are passed

I'l like to build a program with this behaviour:
usage: sage 4ct.py [-h] (-r R | -i I | -p P) [-o O]
But if you don't give any parameter, I'd like to have "-r 100" as the default.
Is it possible?
parser = argparse.ArgumentParser(description = '4ct args')
group_input = parser.add_mutually_exclusive_group(required = True)
group_input.add_argument("-r", "-random", help = "Random graph: dual of a triangulation of N vertices", nargs = 1, type = int, default = 100)
group_input.add_argument("-i", "-input", help = "Input edgelist filename (networkx)", nargs = 1)
group_input.add_argument("-p", "-planar", help = "Load a planar embedding of the graph G.faces() - Automatically saved at each run: input_planar_file.serialized", nargs = 1)
parser.add_argument("-o", "-output", help="Output edgelist filename (networkx)", nargs = 1, required = False)
args = parser.parse_args()
Just remove the requiredargument of the add_mutually_exclusive_group function call (or set it to False) and you're done:
import argparse
parser = argparse.ArgumentParser(description = '4ct args')
group_input = parser.add_mutually_exclusive_group(required = False)
group_input.add_argument("-r", "--random", help = "Random graph: dual of a triangulation of N vertices", type = int, default = 100)
group_input.add_argument("-i", "--input", help = "Input edgelist filename (networkx)")
group_input.add_argument("-p", "--planar", help = "Load a planar embedding of the graph G.faces() - Automatically saved at each run: input_planar_file.serialized")
parser.add_argument("-o", "--output", help="Output edgelist filename (networkx)", required = False)
print(parser.parse_args())
# Namespace(input=None, output=None, planar=None, random=100)
print(parser.parse_args("-r 77".split()))
# Namespace(input=None, output=None, planar=None, random=77)
print(parser.parse_args("-o some/path".split()))
# Namespace(input=None, output='some/path', planar=None, random=100)
print(parser.parse_args("-i some/path".split()))
# Namespace(input='some/path', output=None, planar=None, random=100)
print(parser.parse_args("-i some/path -o some/other/path".split()))
# Namespace(input='some/path', output='some/other/path', planar=None, random=100)
print(parser.parse_args("-r 42 -o some/other/path".split()))
# Namespace(input=None, output='some/other/path', planar=None, random=42)
As you can see, the random option is defaulted to 100 even if:
the output option is provided, which seems normal
an option from the mutual exclusive group other than random is provided, which can be problematic. you will have to check in your code if random is the only exclusive option which has a value before taking it in account.
This example also includes some tiny improvement to your option parser:
use long option names with two dashes (it is a convention but it also allows argparse to correctly recognise option name).
remove the nargs=1 in your options definitions which makes you retrieve a list of one value. By removing it, you could retrieve directly the value.
Give the following a try:
import argparse
import sys
parser = argparse.ArgumentParser(description='4ct args')
group_input = parser.add_mutually_exclusive_group(required=True)
group_input.add_argument("-r", "-random", help="Random graph: dual of a triangulation of N vertices", nargs=1, type=int, default=100)
group_input.add_argument("-i", "-input", help="Input edgelist filename (networkx)", nargs=1)
group_input.add_argument("-p", "-planar", help="Load a planar embedding of the graph G.faces() - Automatically saved at each run: input_planar_file.serialized",nargs=1)
parser.add_argument("-o", "-output", help="Output edgelist filename (networkx)", nargs=1, required=False)
if not sys.argv[1:]:
sys.argv.extend(['-r', '100'])
args = parser.parse_args(sys.argv[1:])
Essentially you are checking if any commandline parameters are given at all, and if not, you append the desired -r 100

Parsing Variables from console error

I am fairly new to python and need a little guidance. I'm trying to pass some variables from the console and get and error message:
AuctionStrategy_2.0.py: error: argument -s/--sectorStocks: invalid int value: 'tep3'
when I run the console command:
run AuctionStrategy_2.0.py -in10 -out5 -rolls15 -step3 -t.001 -s5 -m100 -v50 -e'01/01/2016'
Could someone let me how to fix this please? My code at the moment does nothing except try and pass the variables from the console. Please see below for my code:
import argparse
import os
import fnmatch
import pandas as pd
from pandas.tseries.offsets import BDay
import lzma
import numpy as np
import math
import datetime
def main():
print('Processing args....')
insampleLength,outsampleLength,rolls,step,threshold,minStocksPerSector,minMarketCap,minVolume,endDate = get_args()
print(insampleLength,outsampleLength,rolls,step,threshold,minStocksPerSector,minMarketCap,minVolume,endDate)
rawDataPath = 'C:/Users/simon/Documents/data/close_unadjusted/close_unadjusted/'
def get_args():
'''This function parses and return arguments passed in'''
insampleLength = 0
outsampleLength = 0
rolls = 0
step = 0
endDate =''
minStocksPerSector = 0
threshold = 0
parser = argparse.ArgumentParser(
description='Args to run VWAP Auction simulation')
''' Command line arguments'''
parser.add_argument('-in', '--inSampleDataLength', type=int, help='Number of historic epochs insample', required=True)
parser.add_argument('-out', '--outSampleDataLength', type=int, help='Number of historic epochs outsample', required=True)
parser.add_argument('-rolls', '--numberRolls', type=int, help='Number of rolls', required=True)
parser.add_argument('-step', '--rollStep', type=int, help='Number of historic epochs', required=True)
parser.add_argument('-t','--threshold', type=float, help='starting value', required=True)
parser.add_argument('-s','--sectorStocks', type=int, help='minimum number', required=True)
parser.add_argument('-m','--marketCapCutOff', type=int,help='market capitalisation', required=True)
parser.add_argument('-v','--volumeCutOff', type=int, help='daily volume', required = True)
parser.add_argument('-e', '--endDate', type=str,help='last day of testing',required = True)
args = parser.parse_args()
''' Assign args to variables'''
insampleLength = args.inSampleDataLength
outsampleLength = args.outSampleDataLength
rolls = args.numberRolls
step = args.rollStep
threshold = args.threshold
minStocksPerSector = args.sectorStocks
minMarketCap = args.marketCapCutOff
minVolume = args.volumeCutOff
endDate = datetime.datetime.strptime(args.endDate, "%d-%b-%Y")
return insampleLength,outsampleLength,rolls,step,threshold,minStocksPerSector,minMarketCap,minVolume,endDate
if __name__ == "__main__":
print ("AuctionStategy_1.0...25/03/16")
try:
main()
except KeyboardInterrupt:
print ("Ctrl+C pressed. Stopping...")
A single dash always identifies a single-character argument. But you are trying to define -step; this is interpreted as -s, which is redefined later by the actual -s argument.
You should either pick a different identifier for "step", or always use the double-dash version --rollStep.
The argument -s expects an integer, you gave a string, this causes the error you get.
BTW, I think it's better to add spaces between the names of the arguments and it's values, e.g.:
run AuctionStrategy_2.0.py -in 10 -out 5 -rolls 15 -step 3 -t .001 -s 5 -m 100 -v 50 -e '01/01/2016'
Hope this helps

Editing text file through command line argument in Python

I want to edit text file by passing integer number via command line argument in Python. However my code is not working, can some one point me where I am wrong.
import sys, argparse
def main(argv=None):
if argv is None:
argv=sys.argv[1:]
p = argparse.ArgumentParser(description="Editing omnetpp.ini")
p.add_argument('arg1', action='store', default= 1, type=int, help="number of clients")
args = p.parse_args(argv)
n = args.arg1
f = open('C:\\Users\Abcd\Desktop\Omnet\omnetpp.ini', 'a')
for i in range(n):
f.write('*.voipClient['+str(i)+'].udpApp['+str(i)+'].destAddresses = "voipGateway"\n')
f.write('*.voipGateway.udpApp['+str(i)+'].destAddresses = "voipClient['+str(i)+']"\n')
f.close()
If integer number 5 is passed via command line argument then it should add following lines in text file, which is not happening
Output
*.voipClient[0].udpApp[0].destAddresses = "voipGateway"
*.voipGateway.udpApp[0].destAddresses = "voipClient[0]"
*.voipClient[1].udpApp[1].destAddresses = "voipGateway"
*.voipGateway.udpApp[1].destAddresses = "voipClient[1]"
*.voipClient[2].udpApp[2].destAddresses = "voipGateway"
*.voipGateway.udpApp[2].destAddresses = "voipClient[2]"
*.voipClient[3].udpApp[3].destAddresses = "voipGateway"
*.voipGateway.udpApp[3].destAddresses = "voipClient[3]"
*.voipClient[4].udpApp[4].destAddresses = "voipGateway"
*.voipGateway.udpApp[4].destAddresses = "voipClient[4]"
I am following these steps:
Code is saved in test.py
From command line C:\Users\Abcd\Desktop>python test.py 5
Don't close the file in the loop, as soon as it is closed you cannot write to it anymore (in fact, an error should be thrown if you try to write to a closed file object).
Instead, close it after the loop.
Also, to put each sentence on a new line, end the string with the newline symbol \n (sort of pressing "ENTER").
f = open('C:\\Users\Abcd\Desktop\Omnet\omnetpp.ini', 'a')
for i in range(n):
f.write('*.voipClient['+str(i)+'].udpApp['+str(i)+'].destAddresses = "voipGateway"\n')
f.write('*.voipGateway.udpApp['+str(i)+'].destAddresses = "voipClient['+str(i)+']"\n')
f.close()
EDIT
By the way, as Rostyslav Dzinko said in the comments, the way you defined your code is not how you define a main function. In fact, try something like this (see also this SO question):
if __name__ == '__main__':
p = argparse.ArgumentParser(description="Editing omnetpp.ini")
p.add_argument('arg1', action='store', default= 1, type=int, help="number of clients")
args = p.parse_args()

Categories

Resources