Python argparse: argumento de línea de comando que puede ser nombrado o posicional

Estoy tratando de hacer un progtwig Python que use el módulo argparse para analizar las opciones de la línea de comandos.

Quiero hacer un argumento opcional que puede ser nombrado o posicional. Por ejemplo, quiero que myScript --username=batman haga lo mismo que myScript batman . También quiero que myScript sin nombre de usuario sea válido. es posible? Si es así, ¿cómo se puede hacer esto?

Probé varias cosas similares al código de abajo sin ningún éxito.

 parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument("-u", "--user-name", default="admin") group.add_argument("user-name", default="admin") args = parser.parse_args() 

EDITAR: el código anterior lanza una excepción que dice ValueError: mutually exclusive arguments must be optional .

Estoy usando Python 2.7.2 en OS X 10.8.4.

EDITAR : Probé la sugerencia de Gabriel Jacobsohn, pero no pude hacer que funcionara correctamente en todos los casos.

Intenté esto:

 parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument("-u", "--user-name", default="admin", nargs="?") group.add_argument("user_name", default="admin", nargs="?") args = parser.parse_args() print(args) 

y ejecutar myScript batman imprimiría el Namespace(user_name='batman') , pero myScript -u batman y myScript --user-name=batman imprimiría el Namespace(user_name='admin') .

Intenté cambiar el nombre de user-name a user_name en la primera línea de add_argument y eso a veces resultó tanto en batman como en admin en el espacio de nombres o en un error, dependiendo de cómo ejecuté el progtwig.

Intenté cambiar el nombre de user-name a user-name en la segunda línea de add_argument pero eso imprimirá el Namespace(user-name='batman', user_name='admin') o el Namespace(user-name='admin', user_name='batman') , dependiendo de cómo ejecuté el progtwig.

La forma en que funciona el ArgumentParser , siempre verifica si hay argumentos posicionales finales después de haber analizado los argumentos opcionales. Por lo tanto, si tiene un argumento posicional con el mismo nombre que un argumento opcional, y no aparece en ninguna parte de la línea de comandos, se garantiza que anulará el argumento opcional (ya sea con su valor predeterminado o Ninguno ).

Francamente, esto me parece un error, al menos cuando se usa en un grupo mutuamente exclusivo, ya que si hubiera especificado el parámetro explícitamente, habría sido un error.

Dicho esto, mi solución sugerida es darle un nombre diferente al argumento de posición.

 parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() group.add_argument('-u','--username') group.add_argument('static_username',nargs='?',default='admin') 

Luego, cuando analiza, usa el nombre de usuario opcional si está presente, de lo contrario recurra al nombre estático posicional.

 results = parser.parse_args() username = results.username or results.static_username 

Me doy cuenta de que esta no es una solución particularmente interesante, pero no creo que ninguna de las respuestas lo sea.

Aquí hay una solución que creo que hace todo lo que quieres:

 import argparse if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-u", "--user-name", default="admin") # Gather all extra args into a list named "args.extra" parser.add_argument("extra", nargs='*') args = parser.parse_args() # Set args.user_name to first extra arg if it is not given and len(args.extra) > 0 if args.user_name == parser.get_default("user_name") and args.extra: args.user_name = args.extra.pop(0) print args 

Si ejecuta myScript -u batman o myScript --user-name=batman , args.user_name se establece en ‘batman’. Si haces myScript batman , args.user_name se establece de nuevo en ‘batman’. Y, por último, si solo haces myScript , args.user_name se establece en ‘admin’.

Además, como bono adicional, ahora tiene todos los argumentos adicionales que se pasaron al script almacenado en args.extra . Espero que esto ayude.

Intente utilizar el parámetro “nargs” del método add_argument. De esta manera funciona para mí. Ahora puede agregar el nombre de usuario dos veces, por lo que debe verificarlo y generar un error, si lo desea.

 import argparse if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-u", "--user-name", default="admin") parser.add_argument("user_name", default="admin", nargs="?") args = parser.parse_args() print(args)