Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

argparse action on default values

38 views
Skip to first unread message

Florian Lindner

unread,
Jan 8, 2014, 1:20:24 PM1/8/14
to pytho...@python.org
Hello,

I use argparse from Python 3.3.3 with a custom action that normalizes path arguments:

http://docs.python.org/3/library/argparse.html#action

def norm_path(*parts):
""" Returns the normalized, absolute, expanded and joined path, assembled of all parts. """
parts = [ str(p) for p in parts ]
return os.path.abspath(os.path.expanduser(os.path.join(*parts)))

# Taken from the docs
class NormPath(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
print('%r %r %r' % (namespace, values, option_string))
setattr(namespace, self.dest, norm_path(values))


def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--config", help="Path to config file.",
default = "~/.foobar/config", action=NormPath)

return parser.parse_args()


This works fine when there is actually a --config=path supplied. But it's not being applied on default arguments. Of course, I could use "default = norm_path('~/.foobar/config')" but I expect that custom actions are applied to default values as well. The store action works alike for default and supplied values.

What do you think?

Florian

Peter Otten

unread,
Jan 8, 2014, 1:53:11 PM1/8/14
to pytho...@python.org
Florian Lindner wrote:

> I use argparse from Python 3.3.3 with a custom action that normalizes path
arguments:
>
> http://docs.python.org/3/library/argparse.html#action
>
> def norm_path(*parts):
> """ Returns the normalized, absolute, expanded and joined path,
assembled of all parts. """
> parts = [ str(p) for p in parts ]

This looks odd.

> return os.path.abspath(os.path.expanduser(os.path.join(*parts)))
>
> # Taken from the docs
> class NormPath(argparse.Action):
> def __call__(self, parser, namespace, values, option_string=None):
> print('%r %r %r' % (namespace, values, option_string))
> setattr(namespace, self.dest, norm_path(values))
>
>
> def parse_args():
> parser = argparse.ArgumentParser()
> parser.add_argument("--config", help="Path to config file.",
> default = "~/.foobar/config", action=NormPath)
>
> return parser.parse_args()
>
>
> This works fine when there is actually a --config=path supplied. But it's
not being applied on default arguments. Of course, I could use "default =
norm_path('~/.foobar/config')" but I expect that custom actions are applied
to default values as well. The store action works alike for default and
supplied values.
>
> What do you think?

Maybe you should specify type rather than action?

$ cat tmp.py
import argparse

p = argparse.ArgumentParser()
p.add_argument("--foo", default="42", type=int)
print(p.parse_args())

$ python3.3 tmp.py --foo=123
Namespace(foo=123)

$ python3.3 tmp.py
Namespace(foo=42)


Terry Reedy

unread,
Jan 8, 2014, 6:20:15 PM1/8/14
to pytho...@python.org
On 1/8/2014 1:20 PM, Florian Lindner wrote:

> I use argparse from Python 3.3.3 with a custom action that normalizes
> path arguments:

> This works fine when there is actually a --config=path supplied. But
> it's not being applied on default arguments.

This behavior is how I interpret the doc.
http://docs.python.org/3/library/argparse.html#the-add-argument-method

"action - The basic type of action to be taken when this argument is
encountered at the command line."

"default - The value produced if the argument is absent from the command
line."

> Of course, I could use "default = norm_path('~/.foobar/config')"

Do that.

> but I expect that custom actions are applied to default values as well.

See doc quote.

> The store action works alike for default and supplied values.

It would make no sense to ignore defaults. There may be some
undocumented subtleties in the interaction of defaults and actions.

--
Terry Jan Reedy

Chris Angelico

unread,
Jan 9, 2014, 10:24:11 AM1/9/14
to pytho...@python.org
On Thu, Jan 9, 2014 at 5:20 AM, Florian Lindner <mailin...@xgm.de> wrote:
> def norm_path(*parts):
> """ Returns the normalized, absolute, expanded and joined path, assembled of all parts. """
> parts = [ str(p) for p in parts ]
> return os.path.abspath(os.path.expanduser(os.path.join(*parts)))

Apologies for responding to something that's not the point of your
post, but I see this as a job for map, rather than a list comp:

def norm_path(*parts):
""" Returns the normalized, absolute, expanded and joined path,
assembled of all parts. """
path = os.path.join(*map(str,parts))
return os.path.abspath(os.path.expanduser(path))

(or completely onelinered, since you don't seem to mind longish lines).

ChrisA
0 new messages