¿Por qué este código argparse se comporta de manera diferente entre Python 2 y 3?

El siguiente código, usando subparsers de argparse, falla en Python 3 pero se ejecuta como se esperaba en Python 2. Después de comparar los documentos, todavía no puedo decir por qué.

#!/usr/bin/env python from __future__ import print_function from argparse import ArgumentParser def action(args): print(args) if __name__ == '__main__': std = ArgumentParser(add_help=False) std.add_argument('standard') ap = ArgumentParser() sp = ap.add_subparsers() cmd = sp.add_parser('subcommand', parents=[std], description='Do subcommand') cmd.add_argument('arg') cmd.set_defaults(do=action) args = ap.parse_args() args.do(args) 

La salida de Python 2.7.6 es:

 me@computer$ python test.py usage: test.py [-h] {subcommand} ... test.py: error: too few arguments 

En Python 3.3.5, obtengo:

 me@computer$ python3 test.py Traceback (most recent call last): File "test.py", line 21, in  args.do(args) AttributeError: 'Namespace' object has no attribute 'do' 

la última versión de argparse cambió la forma en que probó los argumentos requeridos, y los subparsers cayeron a través de las grietas. Ya no son “requeridos”. http://bugs.python.org/issue9253#msg186387

Cuando obtiene test.py: error: too few arguments , se opone a que usted no le dio un argumento de ‘subcomando’. En 3.3.5 lo hace más allá de ese paso y devuelve args .

Con este cambio, 3.3.5 debería comportarse igual que las versiones anteriores:

 ap = ArgumentParser() sp = ap.add_subparsers(dest='parser') # dest needed for error message sp.required = True # force 'required' testing 

Nota: es required configurar tanto el dest como el required . dest es necesario para dar a este argumento un nombre en el mensaje de error.


Este error:

 AttributeError: 'Namespace' object has no attribute 'do' 

se produjo porque el subparser cmd no se ejecutó, y no puso sus argumentos (por defecto o no) en el espacio de nombres. Puede ver ese efecto definiendo otro subparser y mirando los argumentos resultantes.