0

I am trying to create some argument parameters for my python file. I only want to accept String type as arguments. Below is my code of foo.py -

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    # options to the user 
    parser.add_argument('--source_table', type = str, required = True)

    args = parser.parse_args()
    params = vars(args) # convert arguments to dictionary
    print(type(params['source_table'])) # prints <class 'str'>

When I give string arguments as -

>python foo.py --source_table=abc

It prints

<class 'str'>

whereas, even if I type

>python foo.py --source_table=123

it prints

<class 'str'>

I would like throw an error saying that only String type is accepted.

Regressor
  • 1,843
  • 4
  • 27
  • 67
  • 1
    `123` can be either a string or int though. What if it's `a1`? Is it still a valid string? If you want only alpha characters you might want to manually handle with `str.isalpha()`. – r.ook Mar 07 '18 at 17:47
  • If you are only interested in some sort of a pattern you might need to use a regex to check the validity. – picmate 涅 Mar 07 '18 at 17:51
  • A link in support of what @Idlehands said: https://docs.python.org/3.4/library/stdtypes.html#string-methods – Mr. T Mar 07 '18 at 17:58

2 Answers2

4

"123" is still a string, but it seems you want to use the alpha characters only. You could check the input before you continue the execution:

import argparse
import re # regex 
if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    # options to the user 
    parser.add_argument('--source_table', type = str, required = True)

    args = parser.parse_args()
    params = vars(args) # convert arguments to dictionary
    src_table = params['source_table']
    # check for alpha only
    if re.match(r'^[a-zA-Z]+$', src_table) is None:
        print("bad input, alpha characters only")
        return
    # continue normal execution
    print(type(src_table)) # prints <class 'str'>

or you can make your own argparse type like here: Python argparse regex expression

edit @idlehands points out below that isalpha() will be sufficient enough for letters only. If you want to allow -, _ or other special characters, then regex is still the way to go. Update the regex in the above code to be re.match(r'^[a-zA-Z\-_]+$', src_table) to match - and _.

ryati
  • 360
  • 3
  • 13
  • 1
    `.isalpha()` is sufficient for the test, no need to use regex for this particular use case... – r.ook Mar 07 '18 at 17:55
  • Very good point. I forgot about `isalpha()`. However, if there are cases where something like `test-new` is allowed, then `isalpha()` will be `False`. – ryati Mar 07 '18 at 17:59
  • `test-new` would also fail with your check, but yes, regex will give you more flexibility if you need it. I'd say OP's question is not exactly clear to determine whether `.isalpha()` is sufficient or a variant of regex is required. – r.ook Mar 07 '18 at 18:25
  • This `isalpha` test could be put into a `type` function. – hpaulj Mar 07 '18 at 18:48
0

This requirement could be implemented with a type function:

def stringonly(astr):
    try:
        int(astr)
    except ValueError:
        return astr
    raise argparse.ArgumentTypeError('only a string type accepted')

This is sort of a ~int type. It raises an error only if the string can be interpreted as an integer. Other tests such as isalpha would be fine too. I could have raised aTypeError or ValueError, but ArgumentTypeError lets me customize the error message.

It would be used as:

In [22]: parser = argparse.ArgumentParser()
In [23]: parser.add_argument('-s','--source', type=stringonly);


In [24]: parser.parse_args('-s 123'.split())
usage: ipython3 [-h] [-s SOURCE]
ipython3: error: argument -s/--source: only a string type accepted
An exception has occurred, use %tb to see the full traceback.

SystemExit: 2

In [25]: parser.parse_args('-s foo'.split())
Out[25]: Namespace(source='foo')
hpaulj
  • 221,503
  • 14
  • 230
  • 353