0

So my goal is to enter 80x40 and it enters it in size and return with the format (80, 40).

But if I write 80xdf, it will give an error message and use the default value, then I also want it to give an error when you write one of the arguments < 1.

Also if it's formatted wrong, it should give out an error message.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('width', type=int, help='width of the world')
parser.add_argument('x', type=int, help='x')
parser.add_argument('height', type=int, help='height of the world')
args = parser.parse_args()
if args.width and args.height < 1:
    print("Both width and height needs to have positive values above zero.")
    print("Using default world size: 80x40")
    size = tuple(80, 40)
elif args.format(args.width, args.x, args.height):
    size = tuple("{},{}".format(args.width, args.height))
else:
    print("World size should contain width and height, separated by ‘x’. Ex:'80x40'")
    print("Using default world size: 80x40")
    size = tuple(80, 40)

Error I face when I enter -ws 80x40 -g 0:

usage: main.py [-h] width x height
main.py: error: argument width: invalid int value: '80x40'
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Snapy
  • 9
  • 3
  • 2
    You have "width" and "height" as two separate arguments, but are passing them as a single string "80x40"; try passing them separately or parsing them accordingly. – dsillman2000 Oct 26 '21 at 13:09
  • 1
    You didn't make a single cli argument that takes number x number. You made 3 cli arguments that take 3 separate integers. So You can give `80 0 40` to it (the 0 is what you will save in `x`) – h4z3 Oct 26 '21 at 13:10
  • 1
    Does this answer your question? [Why does "a == x or y or z" always evaluate to True?](https://stackoverflow.com/questions/20002503/why-does-a-x-or-y-or-z-always-evaluate-to-true) – BoarGules Oct 26 '21 at 13:13
  • @dsillman2000 so if i want to enter 80x40, should i use split() first so that they become 3 separate strings? – Snapy Oct 26 '21 at 13:30
  • @BoarGules How is that a duplicate? While it is indeed a valid problem with the code, it is not what the question is about. The code didn't even reach that part yet. The problem is with how the OP defined and passes the arguments. That link should be recommended, not a duplicate target... – Tomerikoo Oct 26 '21 at 13:33

2 Answers2

2

In your snippet, you didn't make a single cli argument that takes NxM. You made 3 cli arguments that take 3 separate (spaces!) integers.

So you can enter e.g. 80 0 40 and it will parse (with middle number being saved as x).


The easiest, out-of-the-box solution, is to require exactly 2 integers for size.

parser = argparse.ArgumentParser()
parser.add_argument('size', nargs=2)
args = parser.parse_args()

size = args.size

Or two positional arguments like you did... but without that x "argument" and without writing x when executing.

parser = argparse.ArgumentParser()
parser.add_argument('width')
parser.add_argument('height')
args = parser.parse_args()

size = args.width, args.height

Both of those will require you to pass arguments as just 80 40, no x, space is needed.

Afterwards, you can go with your ifs. As BoarGules linked, you messed up how and works.

Your if args.width and args.height < 1: means if args.width and (args.height < 1): and any non-empty non-zero value is truthy.

It should be if args.width<0 or args.height<0 - two conditions and you want either of them to be true, hence or

h4z3
  • 5,265
  • 1
  • 15
  • 29
  • Thanks for the answer, but is there any possible way for me to do it by entering 80x40, as the task is that the data should be entered as numberxnumber? – Snapy Oct 26 '21 at 13:34
  • Get a string, split is manually using .split('x'). Check if result has exactly 2 parts and if both of those parse as ints – h4z3 Oct 26 '21 at 13:52
0

If for some reason you really want to pass the argument as 80x40 you can define a single argument with a custom type:

import argparse

def parse_world_size_arg(arg: str) -> tuple:
    """ Parse width and height from command argument. """
    return tuple(map(int, arg.split('x')))

parser = argparse.ArgumentParser()
parser.add_argument('size', type=parse_world_size_arg, help='widthxheight of the world')

args = parser.parse_args()
print(args.size)

And if the above code will be run as python main.py 80x40 the output will be:

(80, 40)

Then you can add some input validation if necessary:

def parse_world_size_arg(arg: str) -> tuple:
    """ Parse width and height from command argument. """
    try:
        return tuple(map(int, arg.split('x')))
    except ValueError:
        return tuple()

...
args = parser.parse_args()
size = (80, 40)
if len(args.size) != 2:
    print("World size should contain width and height, separated by ‘x’. Ex:'80x40'")
    print("Using default world size: 80x40")
elif any(dim < 1 for dim in args.size):
    print("Both width and height need to have positive values above zero.")
    print("Using default world size: 80x40")
else:
    size = args.size
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
  • unfortunately i still get : usage: gol.py [-h] [-g GENERATIONS] [-s SEED] [-ws WORLDSIZE] [-f FILE] gol.py: error: unrecognized arguments: 80x40 – Snapy Oct 26 '21 at 14:06
  • 1
    Because that's a completely different parser definition than what you gave in the question... Apparently you need `python main.py -ws 80x40` – Tomerikoo Oct 26 '21 at 14:07
  • @Snapy Did you manage to make it work? – Tomerikoo Oct 27 '21 at 15:49
  • no, but im going trying with "while try except" but im focused on other things atm :) – Snapy Nov 01 '21 at 11:55