Saya telah menggunakan argparse
untuk program Python yang bisa -process
, -upload
atau keduanya:
parser = argparse.ArgumentParser(description='Log archiver arguments.')
parser.add_argument('-process', action='store_true')
parser.add_argument('-upload', action='store_true')
args = parser.parse_args()
Program tidak ada artinya tanpa setidaknya satu parameter. Bagaimana cara saya mengkonfigurasi argparse
untuk memaksa setidaknya satu parameter dipilih?
MEMPERBARUI:
Mengikuti komentar: Apa cara Pythonic untuk membuat parameter program dengan setidaknya satu opsi?
-x
secara universal adalah sebuah bendera dan opsional. Potong-
jika diperlukan.process
perilaku default (tanpa perlu menentukan pilihan ada) dan memungkinkan pengguna untuk perubahan itu ke dalamupload
jika yang opsi disetel? Biasanya, opsi harus opsional, karena itulah namanya. Opsi yang diperlukan harus dihindari (ini juga ada diargparse
dokumen).Jawaban:
if not (args.process or args.upload): parser.error('No action requested, add -process or -upload')
sumber
argparse
tidak memiliki opsi bawaan untuk ini.args = vars(parser.parse_args()) if not any(args.values()): parser.error('No arguments provided.')
sumber
vars()
, yang juga berguna untuk meneruskan opsi yang diberi nama dengan cermat ke konstruktor dengan **.vars
. Saya baru saja melakukannya.__dict__
dan merasa bodoh sebelumnya.Jika bukan bagian 'atau keduanya' (awalnya saya melewatkan ini), Anda dapat menggunakan sesuatu seperti ini:
parser = argparse.ArgumentParser(description='Log archiver arguments.') parser.add_argument('--process', action='store_const', const='process', dest='mode') parser.add_argument('--upload', action='store_const', const='upload', dest='mode') args = parser.parse_args() if not args.mode: parser.error("One of --process or --upload must be given")
Meskipun demikian, mungkin lebih baik menggunakan sub-perintah sebagai gantinya.
sumber
--process
OR--upload
, bukan XOR. Ini mencegah kedua opsi disetel pada waktu yang sama.-x
dan--xxx
biasanya merupakan parameter opsional.Saya tahu ini sudah tua seperti kotoran, tetapi cara untuk meminta satu opsi tetapi melarang lebih dari satu (XOR) adalah seperti ini:
parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args() print args
Keluaran:
>opt.py usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: one of the arguments -process -upload is required >opt.py -upload Namespace(process=False, upload=True) >opt.py -process Namespace(process=True, upload=False) >opt.py -upload -process usage: multiplot.py [-h] (-process | -upload) multiplot.py: error: argument -process: not allowed with argument -upload
sumber
Tinjauan Persyaratan
argparse
(saya akan mengabaikan yang ini)Ada juga beberapa persyaratan implisit saat menggunakan command line:
Solusi sampel menggunakan
docopt
(filemanagelog.py
):"""Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print args
Coba jalankan:
Tunjukkan bantuan:
$ python managelog.py -h Manage logfiles Usage: managelog.py [options] process -- <logfile>... managelog.py [options] upload -- <logfile>... managelog.py [options] process upload -- <logfile>... managelog.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> P managelog.py [options] upload -- <logfile>... Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password>
Dan gunakan itu:
$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log {'--': True, '--pswd': 'secret', '--user': 'user', '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': False, 'upload': True}
Alternatif pendek
short.py
Mungkin ada varian yang lebih pendek:
"""Manage logfiles Usage: short.py [options] (process|upload)... -- <logfile>... short.py -h Options: -V, --verbose Be verbose -U, --user <user> Username -P, --pswd <pswd> Password Manage log file by processing and/or uploading it. If upload requires authentication, you shall specify <user> and <password> """ if __name__ == "__main__": from docopt import docopt args = docopt(__doc__) print args
Penggunaannya terlihat seperti ini:
$ python short.py -V process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 1, 'upload': 1}
Perhatikan, sebagai ganti nilai boolean untuk kunci "proses" dan "unggah" yang ada adalah penghitung.
Ternyata, kami tidak dapat mencegah duplikasi kata-kata ini:
$ python short.py -V process process upload -- alfa.log beta.log {'--': True, '--pswd': None, '--user': None, '--verbose': True, '-h': False, '<logfile>': ['alfa.log', 'beta.log'], 'process': 2, 'upload': 1}
Kesimpulan
Mendesain antarmuka baris perintah yang baik terkadang menjadi tantangan.
Ada beberapa aspek program berbasis baris perintah:
argparse
menawarkan banyak hal, tetapi membatasi kemungkinan skenario dan bisa menjadi sangat kompleks.Dengan
docopt
segala sesuatunya menjadi lebih pendek sambil mempertahankan keterbacaan dan menawarkan tingkat fleksibilitas yang tinggi. Jika Anda mengelola mendapatkan argumen parsing dari kamus dan melakukan beberapa konversi (ke integer, membuka file ..) secara manual (atau dengan pustaka lain yang disebutschema
), Anda mungkin merasadocopt
cocok untuk penguraian baris perintah.sumber
Jika Anda memerlukan program python untuk dijalankan dengan setidaknya satu parameter, tambahkan argumen yang tidak memiliki awalan opsi (- atau - secara default) dan set
nargs=+
(Minimal satu argumen diperlukan). Masalah dengan metode ini yang saya temukan adalah jika Anda tidak menentukan argumennya, argparse akan menghasilkan kesalahan "argumen terlalu sedikit" dan tidak mencetak menu bantuan. Jika Anda tidak membutuhkan fungsionalitas itu, berikut ini cara melakukannya dalam kode:import argparse parser = argparse.ArgumentParser(description='Your program description') parser.add_argument('command', nargs="+", help='describe what a command is') args = parser.parse_args()
Saya pikir ketika Anda menambahkan argumen dengan prefiks opsi, narg mengatur seluruh parser argumen dan bukan hanya opsi. (Yang saya maksud adalah, jika Anda memiliki sebuah
--option
flag dengannargs="+"
, maka--option
flag mengharapkan setidaknya satu argumen. Jika Anda memilikioption
dengannargs="+"
, itu mengharapkan setidaknya satu argumen secara keseluruhan.)sumber
choices=['process','upload']
argumen itu.Untuk http://bugs.python.org/issue11588 saya mencari cara untuk menggeneralisasi
mutually_exclusive_group
konsep untuk menangani kasus seperti ini.Dengan perkembangan ini
argparse.py
, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py Saya bisa menulis:parser = argparse.ArgumentParser(prog='PROG', description='Log archiver arguments.') group = parser.add_usage_group(kind='any', required=True, title='possible actions (at least one is required)') group.add_argument('-p', '--process', action='store_true') group.add_argument('-u', '--upload', action='store_true') args = parser.parse_args() print(args)
yang menghasilkan berikut ini
help
:usage: PROG [-h] (-p | -u) Log archiver arguments. optional arguments: -h, --help show this help message and exit possible actions (at least one is required): -p, --process -u, --upload
Ini menerima input seperti '-u', '-up', '--proc --up' dll.
Itu akhirnya menjalankan tes yang mirip dengan https://stackoverflow.com/a/6723066/901925 , meskipun pesan kesalahan harus lebih jelas:
usage: PROG [-h] (-p | -u) PROG: error: some of the arguments process upload is required
Aku penasaran:
apakah parameternya
kind='any', required=True
cukup jelas (terima salah satu grup; setidaknya satu diperlukan)?apakah penggunaannya
(-p | -u)
jelas? Mutually_exclusive_group yang diperlukan menghasilkan hal yang sama. Apakah ada notasi alternatif?Apakah menggunakan grup seperti ini lebih intuitif daripada
phihag's
tes sederhana?sumber
add_usage_group
di halaman ini: docs.python.org/2/library/argparse.html ; maukah Anda memberikan tautan ke dokumentasi untuk itu?Cara terbaik untuk melakukannya adalah dengan menggunakan modul inbuilt python add_mutually_exclusive_group .
parser = argparse.ArgumentParser(description='Log archiver arguments.') group = parser.add_mutually_exclusive_group() group.add_argument('-process', action='store_true') group.add_argument('-upload', action='store_true') args = parser.parse_args()
Jika Anda ingin hanya satu argumen yang dipilih oleh baris perintah, gunakan saja required = True sebagai argumen untuk grup
group = parser.add_mutually_exclusive_group(required=True)
sumber
Mungkin menggunakan sub-parser?
import argparse parser = argparse.ArgumentParser(description='Log archiver arguments.') subparsers = parser.add_subparsers(dest='subparser_name', help='sub-command help') parser_process = subparsers.add_parser('process', help='Process logs') parser_upload = subparsers.add_parser('upload', help='Upload logs') args = parser.parse_args() print("Subparser: ", args.subparser_name)
Sekarang
--help
menunjukkan:$ python /tmp/aaa.py --help usage: aaa.py [-h] {process,upload} ... Log archiver arguments. positional arguments: {process,upload} sub-command help process Process logs upload Upload logs optional arguments: -h, --help show this help message and exit $ python /tmp/aaa.py usage: aaa.py [-h] {process,upload} ... aaa.py: error: too few arguments $ python3 /tmp/aaa.py upload Subparser: upload
Anda juga dapat menambahkan opsi tambahan ke sub-parser ini. Selain itu,
dest='subparser_name'
Anda juga dapat mengikat fungsi untuk dipanggil secara langsung pada sub-perintah yang diberikan (lihat dokumen).sumber
Ini mencapai tujuan dan ini juga akan direfleksikan dalam
--help
output autogenerated argparse , yang merupakan apa yang diinginkan oleh sebagian besar pemrogram waras (juga bekerja dengan argumen opsional):parser.add_argument( 'commands', nargs='+', # require at least 1 choices=['process', 'upload'], # restrict the choice help='commands to execute' )
Dokumen resmi tentang ini: https://docs.python.org/3/library/argparse.html#choices
sumber
Gunakan append_const ke daftar tindakan dan kemudian periksa apakah daftar tersebut diisi:
parser.add_argument('-process', dest=actions, const="process", action='append_const') parser.add_argument('-upload', dest=actions, const="upload", action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested')
Anda bahkan dapat menentukan metode langsung di dalam konstanta.
def upload: ... parser.add_argument('-upload', dest=actions, const=upload, action='append_const') args = parser.parse_args() if(args.actions == None): parser.error('Error: No actions requested') else: for action in args.actions: action()
sumber