2014-04-10 4 views
9

Il seguente codice, che utilizza i subparser di argparse, fallisce su Python 3 ma viene eseguito come previsto in Python 2. Dopo aver confrontato i documenti, non riesco ancora a capire perché.Perché questo codice argparse si comporta in modo diverso tra Python 2 e 3?

#!/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) 

L'uscita da Python 2.7.6 è:

[email protected]$ python test.py 
usage: test.py [-h] {subcommand} ... 
test.py: error: too few arguments 

In Python 3.3.5, ottengo:

[email protected]$ python3 test.py 
Traceback (most recent call last): 
    File "test.py", line 21, in <module> 
    args.do(args) 
AttributeError: 'Namespace' object has no attribute 'do' 
+0

Si noti che se si utilizza un subparatore: 'args = cmd.parse_args()' funzionerebbe. – alecxe

+0

Questo codice sembra dare lo stesso errore per me su Python 2.7.4. Molto probabilmente stai eseguendo la versione del file sbagliata o qualcosa del genere. Non dovrebbe funzionare. Provalo ancora più attentamente. – bosnjak

+0

Quando digito il codice in un interprete Python 2.7.6, ottengo lo stesso errore sulla riga 'args = ap.parse_args()'. –

risposta

12

l'ultima versione argparse cambiato come è testato per argomenti richiesti e i subparser sono caduti attraverso le fessure. Non sono più "richiesti". http://bugs.python.org/issue9253#msg186387

Quando si ottiene test.py: error: too few arguments, si oppone al fatto che non gli si sia dato un argomento di 'sottocomando'. In 3.3.5 supera questo passaggio e restituisce args.

Con questa modifica, 3.3.5 dovrebbe comportarsi allo stesso come le versioni precedenti:

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

Nota - sia bisogno dest e required da impostare. dest è necessario per dare a questo argomento un nome nel messaggio di errore.


Questo errore:

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

è stato prodotto perché il subparser cmd non ha funzionato, e non ha messo i suoi argomenti (di default e non) nel namespace. È possibile vedere questo effetto definendo un altro subparser e guardando il risultante args.

+1

Grazie, l'ha inchiodato. Nel caso ci fosse da meravigliarsi, questa soluzione è retrocompatibile con Python 2.7 – Wedgwood