5

I have noticed that the default argument value is not set when the custom namespace object is used:

import argparse

class CliArgs(object):
    foo: str = 'not touched'


parser = argparse.ArgumentParser()
parser.add_argument('--foo', default='bar')

args = CliArgs()
parser.parse_args(namespace=args)
print(args.foo) # 'not touched'

print(parser.parse_args()) # 'bar'

ideone: https://ideone.com/7P7VxI

I expected bar to be set in both cases.

Is it expected? I cannot see it in the documentation though.

And if it's expected, is there then really no way to implement that other than using some custom action?

UPD: I reported it as a documentation bug https://bugs.python.org/issue38843

3
  • 1
    Hmm, it looks to have been that way since forever: github.com/python/cpython/blob/v3.8.0/Lib/… Seems buggy to me. Commented Nov 19, 2019 at 1:51
  • Hum... I cannot find a common way in the source code. The attributes in the namespace object are treated as the default already, so the default from add_argument won't be processed at all. Commented Nov 19, 2019 at 1:52
  • @wim it's just so that it was easier to distinguish between "the value was not set" and "it was set to an empty string". not touched there is purely for that reason Commented Nov 19, 2019 at 1:54

1 Answer 1

3

Yes it's expected. EDIT: But only for argparse developers.

See argparse.py

def parse_known_args(...):
    # add any action defaults that aren't present
    for action in self._actions:
        if action.dest is not SUPPRESS:
            if not hasattr(namespace, action.dest):
                if action.default is not SUPPRESS:
                    setattr(namespace, action.dest, action.default)
        # add any parser defaults that aren't present
        for dest in self._defaults:
            if not hasattr(namespace, dest):
                setattr(namespace, dest, self._defaults[dest])

add any action defaults that aren't present

In your example if you set attribute in default object, effect will be the same:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--foo', default='bar')

args = argparse.Namespace()
args.foo = 'not touched'
parser.parse_args(namespace=args)
print(args.foo) # 'not touched'
Sign up to request clarification or add additional context in comments.

3 Comments

So it's undocumented?
It seems so. I've just finished reading documentation and I can't find any description. But it is no surprised for developers how you see the code. I'm very surprised. It could be side effect.
I have reported a documentation bug bugs.python.org/issue38843

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.