Python3 argparse nargs="+" get number of arguments - python-3.x

I'm now googling for quite a while and I just don't find any solution to my problem.
I am using argparse to parse some command line arguments. I want to be able to parse an arbitrary number of arguments > 1 (therefore nargs="+") and I want to know afterwards how many arguments I have parsed. The arguments are all strings. But I get a problem when I just have one argument, because then the length of the list is the number of characters of the word and not 1 as in 1 argument. And I want to know how many arguments were parsed. Does anyone know how I could solve this problem?
examples:
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("--test", type=str, nargs="+", required=False, default="hi")
args = parser.parse_args()
test = args.test
print(test)
print(len(test))
So with python3 example.py --test hello hallo hey the output is:
['hello', 'hallo', 'hey']
3
But with python3 example.py --test servus the output is:
servus
6
What I already know is that I could do print([test]) but I only want to do that if I have 1 argument. Because if I have more than one arguments and use print([test]) I get a double array... So I just want to know the number of parsed arguments for "test".
I cannot imagine that I am the only one with such a problem, but I could not find anything in the internet. Is there a quick and clean solution?

You left off the test=args.test line.
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("--test", type=str, nargs="+", required=False, default="hi")
args = parser.parse_args()
print(args)
print(len(args.test))
test cases
0856:~/mypy$ python3 stack68020846.py --test one two three
Namespace(test=['one', 'two', 'three'])
3
0856:~/mypy$ python3 stack68020846.py --test one
Namespace(test=['one'])
1
0856:~/mypy$ python3 stack68020846.py
Namespace(test='hi')
2
change the default to default=[]
0856:~/mypy$ python3 stack68020846.py
Namespace(test=[])
0

Theres probably a better solution, but try this:
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument("--test", type=str, nargs="+", required=False, default="hi")
args = parser.parse_args()
print("Number of arguments:", len(args._get_kwargs()[-1][-1]))
By the way, i figured this out by checking the content of args with print(dir(args))

Related

Python argparse with possibly empty string value

I would like to use argparse to pass some values throughout my main function. When calling the python file, I would always like to include the flag for the argument, while either including or excluding its string argument. This is because some external code, where the python file is being called, becomes a lot simpler if this would be possible.
When adding the arguments by calling parser.add_argument, I've tried setting the default value to default=None and also setting it to default=''. I can't make this work on my own it seems..
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--projects_to_build', default='')
args = parser.parse_args()
This call works fine:
py .\python_file.py -p proj_1,proj_2,proj_3
This call does not:
py .\python_file.py -p
python_file.py: error: argument -p/--projects_to_build: expected one argument
You need to pass a nargs value of '?' with const=''
parser.add_argument('-p', '--projects_to_build', nargs='?', const='')
You should also consider adding required=True so you don't have to pass default='' as well.

argparse like docker cli

Hello i am writing cmd tool,
i want to have behaviour like docker does:
docker container run --help
print the help for this particular command.
im stucked with code:
parser.add_argument("method", help=getHelp())
but the method can be anything like
add
remove
update
and how to later add a method in add like:
add ram
add cpu
i can add subparser for add but how to add later a subparser for ram ?
How can i achieve that with argparse in python?
Is it even possible?
Can somebody show me example of third deep command with its own arguments ?
import argparse
import pprint
import random
def get_comments(args):
return [{'post_id': args.post_id,
'comment_id': str(random.randrange(1, 1000)),
'comment': "< comment's body >"}
for _ in range(random.randrange(1, 10))]
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command')
list_parser = subparsers.add_parser('list')
list_subparsers = list_parser.add_subparsers(dest='type')
comments_parser = list_subparsers.add_parser('comments')
comments_parser.add_argument('post_id')
comments_parser.set_defaults(func=get_comments)
accounts_parser = list_subparsers.add_parser('accounts')
show_parser = subparsers.add_parser('show')
args = parser.parse_args()
print(args)
print(args.command)
#result = args.func(args)
print(parser)
#pprint.pprint(args)

Nature of optional arguments argparse Python

As I have started to learn argparse module, I try to get my head around optional arguments in Python argparse. I would like to add my own arguments, as I present below:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--sense", help = "What you are seeking")
arg = parser.parse_args()
if arg.sense:
print("42")
However, the help doesn't seem to accept the new argument in output:
"""python3 file.py -h"""
usage: file.py [-h]
optional arguments:
-h, --help show this help message and exit
What surprises me is the fact, that when I copied the code from a tutorial:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--verbose", help="increase output verbosity",
action="store_true")
args = parser.parse_args()
if args.verbose:
print("verbosity turned on")
https://docs.python.org/3/howto/argparse.html
the help changed. Is there a list of possible optional arguments? Am I allowed to create new ones?

Argparse add option strings

That question will be strange in some point...
I'm trying to add the option strings in the parser after adding one argument.
For example
import argparse
p = argparse.ArgumentParser()
p.add_argument(dest = 'myvar')
p._actions[1].option_strings = ['-foo']
p.parse_args('-foo 1')
This example doesn't work, it says:
: error: the following arguments are required: -foo
Even though I'm supplying the argument...
Anyone know why this is occurring?
Is there some way to add the option strings after the add_argument method?
After looking at the source code of argparse, I found you also have to register the action by the option string it has:
import argparse
p = argparse.ArgumentParser()
p.add_argument(dest = 'myvar')
p._actions[1].option_strings = ['-foo']
# You also need to do this
p._option_string_actions['-foo'] = p._actions[1]
args = p.parse_args(['-foo', '100'])
print('myvar is', args.myvar) # myvar is 1
Note the change when calling parse_args.
I hope this help!!

How to use argparse in the actual script

How does argparse work? I was told to 'hide' the password from the psycopg2 connection I am building so to be able to run the script automatically every week and being able to share it between departments. This is the beginning of the psycopg2 script where the password is asked:
#Connect to database
conn_string = "host='my_aws_postgresql_database.rds.amazonaws.com' dbname='my_database_name' user='my_username' password='my_password'"
# print the connection string we will use to connect
print ("\"Connecting to database\n ->%s\"" % (conn_string))
Now, how would I use argparse (and getpass) to hide my password? I found this script about this subject a couple of times (I would delete the print statement after getting it to work):
import argparse
import getpass
class Password(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
if values is None:
values = getpass.getpass()
setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser('Test password parser')
parser.add_argument('-p', action=Password, nargs='?', dest='password',
help='Enter your password')
args = parser.parse_args()
print (args.password)
I tried to add the argparse snippet above the #Connect to database code. And replaced the password part on line 2 with
conn_string =
"host='my_aws_postgresql_database.rds.amazonaws.com'
dbname='my_database_name'
user='my_username'
password='" + args + "'"
Then I tried to run the whole script with the command python3 my_script_file.py my_password -p I get asked for the password which I entered, but this rendered the following error
usage: Test password parser [-h] [-p [PASSWORD]]
Test password parser: error: unrecognized arguments: my_password
If I use python3 my_script_file.py my_password I get the same error, but I did not have to enter the password (again).
Am I close to the solution? Is this the standard way of doing this?
The problem was that I used python3 my_script_file.py my_password -p instead of the correct order python3 my_script_file.py -p my_password, see accepted answer below by #hpaulj and the comments to that answer.
This parser is gives the user 2 ways of entering the password, on the commandline, or with a separate getpass prompt:
import argparse
import getpass
class Password(argparse.Action):
def __call__(self, parser, namespace, values, option_string):
if values is None:
values = getpass.getpass()
setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser('Test password parser')
parser.add_argument('-p', action=Password, nargs='?', dest='password',
help='Enter your password')
args = parser.parse_args()
print (args)
Sample runs:
0911:~/mypy$ python3 stack44571340.py
Namespace(password=None)
0912:~/mypy$ python3 stack44571340.py -p test
Namespace(password='test')
0912:~/mypy$ python3 stack44571340.py -p
Password:
Namespace(password='testing')
0912:~/mypy$ python3 stack44571340.py test
usage: Test password parser [-h] [-p [PASSWORD]]
Test password parser: error: unrecognized arguments: test
I tested without any arguments (got the default None)`; with '-p test' which uses the 'test' string; with just '-p', which asks; and without '-p', which produces the error.
I don't know why python3 my_script_file.py -p my_password produced an error; my best guess there's a typo in your parser definition (something wrong with nargs?).
It's not entirely clear how you merged this parser code into the larger script. Done right it shouldn't have changed the behavior of the parser.
The password argument would be used as:
password='" + args.password + "'"
The echo argument, is a positional one, which requires a string. In contrast the -p with nargs='?', is an optional flagged argument, which allows for the three way input I illustrated.
parser.add_argument("echo")
Thank you #CarlShiles, your answer didn't work with that long argparse/getpass snippet from above, but it made me realise that I could just echo the password in there. So I did a simple
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("echo")
args = parser.parse_args()
and then used your suggestion, password='" + args.echo + "'". And then ran the following command python3 my_script_file.py my_password. This worked just fine.

Resources