Argparse: Argumen wajib yang tercantum dalam “argumen opsional”?

229

Saya menggunakan kode sederhana berikut untuk mem-parsing beberapa argumen; perhatikan bahwa salah satunya diperlukan. Sayangnya, ketika pengguna menjalankan skrip tanpa memberikan argumen, teks penggunaan / bantuan yang ditampilkan tidak menunjukkan bahwa ada argumen non-opsional, yang menurut saya sangat membingungkan. Bagaimana saya bisa mendapatkan python untuk menunjukkan bahwa argumen tidak opsional?

Ini kodenya:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

Saat menjalankan kode di atas tanpa memberikan argumen yang diperlukan, saya mendapatkan output berikut:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name
mort
sumber
5
Dalam garis penggunaan, -i INPUTbagian tersebut tidak dikelilingi oleh tanda kurung siku, yang menunjukkan kehalusan yang memang diperlukan. Anda juga dapat menjelaskannya secara manual melalui helpparam
Jaime RGP
7
@JaimeRGP Ya, tapi itu tidak cukup, tentu saja, dan itu juga kurang menonjol. Nama grup yang diberikan optional argumentsuntuk argumen yang diperlukan masih menyesatkan.
Acumenus

Jawaban:

316

Parameter yang dimulai dengan -atau --biasanya dianggap opsional. Semua parameter lain adalah parameter posisi dan karena itu diperlukan oleh desain (seperti argumen fungsi posisi). Dimungkinkan untuk memerlukan argumen opsional, tetapi ini sedikit bertentangan dengan desain mereka. Karena mereka masih merupakan bagian dari argumen non-posisional, mereka masih akan terdaftar di bawah header “argumen opsional” yang membingungkan walaupun mereka diharuskan. Namun tanda kurung kotak yang hilang pada bagian penggunaan menunjukkan bahwa mereka memang diperlukan.

Lihat juga dokumentasinya :

Secara umum, modul argparse mengasumsikan bahwa flag seperti -f dan --bar menunjukkan argumen opsional, yang selalu dapat dihilangkan pada baris perintah.

Catatan: Opsi yang diperlukan umumnya dianggap sebagai bentuk yang buruk karena pengguna mengharapkan opsi menjadi opsional, dan karenanya harus dihindari jika memungkinkan.

Karena itu, tajuk “argumen posisional” dan “argumen opsional” dalam bantuan dihasilkan oleh dua kelompok argumen di mana argumen dipisahkan secara otomatis. Sekarang, Anda bisa "meretasnya" dan mengubah nama yang opsional, tetapi solusi yang jauh lebih elegan adalah membuat grup lain untuk "argumen bernama wajib" (atau apa pun yang Anda ingin menyebutnya):

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name
menyodok
sumber
Saya mengalami masalah yang sama. Saya mencoba solusi Anda. Itu memang menambah argumen ke grup baru tetapi kode saya sepertinya tidak berfungsi setelah itu. Solusi apa pun akan dihargai. Tautan ke kode saya - pastebin.com/PvC2aujz
Zarar Mahmud
1
@ZararMahmud: Anda memberikan argumen kosong di baris 24 kode Anda: parser.parse_args([])Sebaliknya, gunakan parser.parse_args()tanpa argumen untuk menangkap konten sys.argv. Per argparse
Devin
@poke: Solusi bagus! Tetapi ini tidak membantu jika Anda membutuhkan kelompok eksklusif satu sama lain, atau apakah saya kehilangan sesuatu?
Hakim
@ Judge saya akan merekomendasikan membaca ini pymotw.com/3/argparse/#mutually-exclusive-options
Peter Moore
79

Karena saya lebih suka mendaftar argumen yang diperlukan sebelum opsional, saya meretasnya melalui:

    parser = argparse.ArgumentParser()
    parser._action_groups.pop()
    required = parser.add_argument_group('required arguments')
    optional = parser.add_argument_group('optional arguments')
    required.add_argument('--required_arg', required=True)
    optional.add_argument('--optional_arg')
    return parser.parse_args()

dan ini menghasilkan:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
               [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

Saya bisa hidup tanpa 'bantuan' muncul di grup argumen opsional.

Karl Rosaen
sumber
3
Apakah ini benar-benar memaksa argparse untuk memperlakukan argumen seperti yang diminta?
Anthony
6
Saya pikir argumen 'wajib' masih perlu diatur saat menambahkan argumen.
Karl Rosaen
Bagus sekali.
Paul Cezanne
7
@Anthony - tidak, Anda perlu 'wajib = Benar' di add_argument untuk itu. Jawaban di atas hanya menggambarkan pengelompokan argumen.
user2275693
47

Membangun dari @Karl Rosaen

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

dan ini menghasilkan:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG
RalphyZ
sumber
1
BTW, apakah ada cara (metode) bagaimana cara mendapatkan akses _action_grouptanpa mengakses anggota yang dilindungi? Dalam kasus saya, saya perlu menambahkan beberapa argumen ke grup (kustom) yang sudah ada.
machin
Ini bagus. Memecahkan item --help yang muncul di daftar opsional kedua.
Jeremy
Catatan : jawaban ini memecah API yang terbuka, periksa jawaban oleh Bryan_D di bawah.
lol
18

Sekali lagi, membangun dari @RalphyZ

Yang ini tidak merusak API yang terbuka.

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

Yang akan menunjukkan hal yang sama seperti di atas dan akan bertahan versi masa depan:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG
Bryan_D
sumber
Bisakah Anda menjelaskan bagaimana jawaban RalphyZ merusak API yang terbuka?
jeremysprofile
5
_action_groupsdimaksudkan hanya untuk penggunaan internal. Oleh karena itu, tidak ada jaminan kompatibilitas lintas versi.
Bryan_D