Detect and print if no command line argument is provided - python

This is the program I have:
from sys import argv
script, arg1 = argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if arg1 != "":
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."
I get:
Traceback (most recent call last):
File "filename.py", line 3, in <module>
script, arg1 = argv
ValueError: need more than 1 value to unpack
How can I detect the lack of command line argument and throw an error/exception instead of receiving this error?

I would recommend just checking the program args in the __main__ location of your script, as an entry point to the entire application.
import sys
import os
def program(*args):
# do whatever
pass
if __name__ == "__main__":
try:
arg1 = sys.argv[1]
except IndexError:
print "Usage: " + os.path.basename(__file__) + " <arg1>"
sys.exit(1)
# start the program
program(arg1)

You can handle the exception:
In [6]: def program(argv):
try:
script, argv1 = argv
except ValueError:
print("value error handled")
...:
In [7]: program(argv)
value error handled

try this:
script = argv[0]
try:
arg1 = argv[1]
except:
arg1 = ''

You could use a try statement there:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import sys
class MyError(Exception):
def __init__(self, value):
self.error_string = value
def __str__(self):
return eval(repr(self.error_string))
try:
script, arg1 = sys.argv
except ValueError:
raise MyError, "Not enough arguments"

Seeing that sys.argv is a list you should check the length of the list to make sure it is what you wish it to be. Your script with minor changes to check the length:
from sys import argv
def program(usr_input, arg1):
if(usr_input == arg1):
print "CLI argument and user input are identical"
else:
print "CLI argument and user input aren't identical"
if len(argv)== 2:
arg1 = argv[1]
usr_input = raw_input("enter something: ")
program(usr_input, arg1)
else:
print "You have not entered a CLI argument at all."

Related

How could I make it so that the assertRaise for SystemExit will result as true?

I am trying to create a python CLI tool for monitoring a specific process at a given interval of time.
I am trying to customize the message that gets printed out when a ValueError is caught, while also trying to exit the program by using sys.exit(1), which can be found in the validate function within example.py. If I weren't to use sys.exit(1), the print command within the main function would've been executed.
Having that sorted out, I procceded with performing a unit test (using unittest), by using test_example.py, for the specific program, to check if a SystemExit is raised when a negative value is passed to the time argument.
As such, how could I make it so that the assertRaise for SystemExit will result as true?
I'm using python 3.10.4 and argparse 1.1 .
# example.py
import argparse, sys
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--time", type=float, metavar=" ")
return parser.parse_args(args)
def validate(data):
try:
if data.time < 0:
raise ValueError
except ValueError:
print(f"Time has a negative value: {data.time}. Please use a positive value")
sys.exit(1)
def main():
parsed_data = parse_args(sys.argv[1:])
validate(parsed_data)
print(parsed_data.time)
if __name__ == '__main__':
main()
# test_example.py
import unittest
from example import parse_args, validate
class TestExemplu(unittest.TestCase):
def test_negative_value(self):
with self.assertRaises(SystemExit) as cm:
validate()
the_exception = cm.exception
self.assertEqual(the_exception.code, 1)
if __name__ == '__main__':
unittest.main()
This is the error that I get:
test_negative_value (test_example.TestExemplu) ... ERROR
======================================================================
ERROR: test_negative_value (test_example.TestExemplu)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\tester\Downloads\cli_mon_tool_1\test_example.py", line 16, in test_negative_value
validate()
TypeError: validate() missing 1 required positional argument: 'data'
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (errors=1)
I came up with this solution, according to these 2 links:
Hide traceback unless a debug flag is set
https://gist.github.com/maphew/e3a75c147cca98019cd8/7236687e4161b2c3c5eca0daec500a516cc21055
# example.py
import argparse, sys
debug = False
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--path", type=str, metavar=" ")
parser.add_argument("-t", "--time", type=float, metavar=" ")
return parser.parse_args(args)
def exceptionHandler(exception_type, exception, traceback, debug_hook=sys.excepthook):
'''Print user friendly error messages normally, full traceback if DEBUG on.
Adapted from http://stackoverflow.com/questions/27674602/hide-traceback-unless-a-debug-flag-is-set
'''
if debug:
print('\n*** Error:')
debug_hook(exception_type, exception, traceback)
else:
print("%s: %s" % (exception_type.__name__, exception))
sys.excepthook = exceptionHandler
def validate(data):
try:
if data.time < 0:
raise ValueError
except ValueError:
raise ValueError(f"Time has a negative value: {data.time}. Please use a positive value")
try:
if data.time == 0:
raise ValueError
except ValueError as e:
raise ValueError(f"Time has a value of zero. Please use a positive value")
def main():
parsed_data = parse_args(sys.argv[1:])
validate(parsed_data)
print(parsed_data.path)
print(parsed_data.time)
if __name__ == '__main__':
main()
# test_example.py
import unittest
from example import parse_args, validate
class TestExemplu(unittest.TestCase):
def test_negative_value(self):
parsed_data1 = parse_args(['-t', '-1'])
parsed_data2 = parse_args(['-t', '0'])
parsed_data3 = parse_args(['-t', '-1'])
self.assertRaises(ValueError, validate, parsed_data1)
self.assertRaises(ValueError, validate, parsed_data2)
try:
self.assertRaises(ValueError, validate, parsed_data2)
except:
pass
if __name__ == '__main__':
unittest.main()

Using If statement to call a functions in Python

I am running a code to create cloudformation stack, delete stack, update stack with defined parameter variable using json file using python.
I have defined a 3 different statement under init() function. I need to put a if condition:
if i want to create a stack, it will call "create_products"
else, update a stack, it will call "update_products"
elif, delete a stack, it will update "delete_products"
from __future__ import print_function
import subprocess
import json
import yaml
import sys
import os
import re
import boto3
from glob import glob
def createstack(productName, productId, paramlist):
try:
client = boto3.client('servicecatalog', region_name='us-east-1')
ProvisioningArtifactId = client.list_provisioning_artifacts(ProductId=productId)
ArtifactId = ProvisioningArtifactId['ProvisioningArtifactDetails'][0]['Id']
response = client.provision_product(ProvisionedProductName=productName, ProductId=productId, ProvisioningArtifactId=ArtifactId, ProvisioningParameters=paramlist)
print(response)
except Exception as e:
error = "An error occurred processing this request: " + str(e)
print(error)
def updatestack(productName, productId, paramlist):
try:
client = boto3.client('servicecatalog', region_name='us-east-1')
ProvisioningArtifactId = client.list_provisioning_artifacts(ProductId=productId)
ArtifactId = ProvisioningArtifactId['ProvisioningArtifactDetails'][0]['Id']
response = client.update_provisioned_product(ProvisionedProductName=productName, ProductId=productId, ProvisioningArtifactId=ArtifactId, ProvisioningParameters=paramlist)
print(response)
except Exception as e:
error = "An error occurred processing this request: " + str(e)
print(error)
def deletestack(productName):
try:
client = boto3.client('servicecatalog', region_name='us-east-1')
response = client.terminate_provisioned_product(ProvisionedProductName=productName)
print(response)
return response
except Exception as e:
error = "An error occurred processing this request: " + str(e)
return(error)
def init():
#global args
with open("list_provisional_product.json") as f:
product_list = json.load(f)
with open("testing-pipeline-params.json") as f:
baselist = json.load(f)
for product in product_list["update_products"]:
for provisioned_product_name in product["provisioned_product_names"]:
updatestack(productName=provisioned_product_name, productId=product["product_id"], paramlist=baselist[provisioned_product_name])
for product in product_list["delete_products"]:
for provisioned_product_name in product["provisioned_product_names"]:
deletestack(productName=provisioned_product_name)
for product in product_list["create_products"]:
for provisioned_product_name in product["provisioned_product_names"]:
createstack(productName=provisioned_product_name, productId=product["product_id"], paramlist=baselist[provisioned_product_name])
def main():
init()
if __name__== "__main__":
main()
Yes, You have to get operation name(Create/ Update/ Delete) from user via command line argument or ask user during code execution via input function.
Demo 1: Get Operation name from command line argument by using sys.argv
You have to give operation name when you run your python code. Here Py file name is if_loop.py
import sys
print("arg:", sys.argv)
try:
operation_name = sys.argv[1].lower()
except IndexError:
print("Argument is missing")
exit()
if operation_name == "create":
print("Call Create function")
elif operation_name == "update":
print("Call Update function")
elif operation_name == "delete":
print("Call Dale function")
else:
print("Invalid Operation name")
Output
Invalid Operation name
(env) PS C:\Users\vivek\Documents\Workplace\stackoverflow> python .\if_loop.py Create
arg: ['.\\if_loop.py', 'Create']
Call Create function
Demo 2: Using input function
operation_name = input("Give Operation Name:").lower()
if operation_name == "create":
print("Call Create function")
elif operation_name == "update":
print("Call Update function")
elif operation_name == "delete":
print("Call Dale function")
else:
print("Invalid Operation name")
Output
Give Operation Name:Update
Call Update function
Thank you so much Vivek ! I would rather go with approach 1st ie argv and it actually worked based on my need !! BRAVO

Can I call a function by inputting a string?

I want to make a function that can be called when the text input is equal to a command.
from os import system
from time import sleep
import ctypes
ctypes.windll.kernel32.SetConsoleTitleW('SimpleChat')
print('Hi, welcome to my basic chat engine!')
sleep(5)
system('cls')
username = input('Enter a username: ')
ctypes.windll.kernel32.SetConsoleTitleW('SimpleChat - ' + username)
system('cls')
def commands (command):
commandlist = ['/help','/clear', '/commands']
commanddict = {'/help' : 'help', '/clear' : 'clear', '/commands' : 'commands'}
for possibility in commandlist:
if command == possibilty:
commanddict[possibility]()
break
def textInput (text):
if text[0] == '/':
commands(text)
Does line 24 work to call a function? The way I am imagining it will work is that it will find the entry for the key 'possibility', and then call that as a function, but I am not sure.
If the previous code does not work, what would?
Suppose there's a function called help, clear,... in your code like this.
def help():
print("help!")
Then, the below commands function will do what you want.
Note that function can be used as value of dictionary in Python.
def commands (command):
command_dict = {'/help' : help, '/clear' : clear, '/commands' : commands}
func = command_dict.get(command)
if func is not None:
func()
else:
print("I don't have such a command: %s" % command)
I guess '/commands''s value(command function) in command_dict should be changed to another function. The program will crash if you type 'commands'.

how to pass arguments to imported script in Python

I have a script (script1.py) of the following form:
#!/bin/python
import sys
def main():
print("number of command line options: {numberOfOptions}".format(numberOfOptions = len(sys.argv)))
print("list object of all command line options: {listOfOptions}".format(listOfOptions = sys.argv))
for i in range(0, len(sys.argv)):
print("option {i}: {option}".format(i = i, option = sys.argv[i]))
if __name__ == '__main__':
main()
I want to import this script in another script (script2.py) and pass to it some arguments. The script script2.py could look something like this:
import script1
listOfOptions = ['option1', 'option2']
#script1.main(listOfOptions) insert magic here
How could I pass the arguments defined in script2.py to the main function of script1.py as though they were command line options?
So, for example, would it be Pythonic to do something such as the following?:
import script1
import sys
sys.argv = ['option1', 'option2']
script1.main()
Separate command line parsing and called function
For reusability of your code, it is practical to keep the acting function separated from command line parsing
scrmodule.py
def fun(a, b):
# possibly do something here
return a + b
def main():
#process command line argumens
a = 1 #will be read from command line
b = 2 #will be read from command line
# call fun()
res = fun(a, b)
print "a", a
print "b", b
print "result is", res
if __name__ == "__main__":
main()
Reusing it from another place
from scrmodule import fun
print "1 + 2 = ", fun(1, 2)
# script1.py
#!/bin/python
import sys
#main function is expecting argument from test_passing_arg_to_module.py code.
def main(my_passing_arg):
print("number of command line options: {numberOfOptions}".format(numberOfOptions = len(sys.argv)))
print("list object of all command line options: {listOfOptions}".format(listOfOptions = my_passing_arg))
print(my_passing_arg)
if __name__ == '__main__':
main()
#test_passing_arg_to_module.py
import script1
my_passing_arg="Hello world"
#calling main() function from script1.py code.
#pass my_passinga_arg variable to main(my_passing_arg) function in scritp1.py.
script1.main(my_passing_arg)
##################
# Execute script
# $python3.7 test_passing_arg_to_module.py
# Results.
# number of command line options: 1
# list object of all command line options: Hello world
# Hello world

Python functions and calling args

I'm creating my first python tool, if you want to call it that. (I work in IT Security, btw)
It was going well until I tried to call a function from the main function. I'm sure it's something simple that I'm missing :(. Could someone point me in the right direction? Then feel free to point and laugh.
#!/usr/bin/python
import sys, getopt, socket
def usage():
print "-h --help: help\n"
print "-f --file: File to read bruteforce domain list from.\n"
print "-p --proxy: Proxy address and port. e.g http://192.168.1.64:8080\n"
print "-d --domain: Domain to bruteforce.\n"
print "-e: Turn debug on.\n"
sys.exit()
def main(argv):
file = None
proxy = None
domain = None
try:
opts, argv =getopt.getopt(argv, "h:f:p:d:e",["help", "file=", "proxy=", "domain="])
except getopt.GetoptError as err:
print str(err)
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt in ("-f", "--file"):
file = arg
elif opt in ("-p", "--proxy"):
proxy = arg
elif opt in ("-d", "--domain"):
domain = arg
elif opt in '-e':
global _debug
_debug = 1
else:
assert Flase, "Unhandled option"
print fread.flist
def fread(file, *args):
flist = open(file).readlines()
return
if __name__ == "__main__":
main(sys.argv[1:])
The issue is with your statement print fread.flist. You can't access variables assigned inside functions this way. Instead, change your fread() function to the following:
def fread(file, *args):
flist = open(file).readlines()
return flist
and change the statement above to
print fread(file)
where file is the file you want to access.

Categories