2012-11-12 52 views
11

Tôi đã tự hỏi liệu có thể có đối số vị trí theo một đối số với tham số tùy chọn hay không. Lý tưởng nhất là đối số cuối cùng được nhập vào dòng lệnh sẽ luôn áp dụng cho 'testname'.đối số tùy chọn argparse trước đối số vị trí

import argparse 
parser = argparse.ArgumentParser(description='TAF') 
parser.add_argument('-r','--release',nargs='?',dest='release',default='trunk') 
parser.add_argument('testname',nargs='+') 
args = parser.parse_args() 

Tôi muốn cả hai cuộc gọi này đều có thể áp dụng cho testname, nhưng lần thứ hai dẫn đến lỗi.

>> python TAF.py -r 1.0 smoketest 
>> python TAF.py -r smoketest 
TAF.py: error: too few arguments 

Tôi nhận thấy rằng việc chuyển đối số vị trí sang mặt trước sẽ dẫn đến hành vi đúng của thông số tùy chọn, tuy nhiên đây không phải là định dạng tôi đang tìm kiếm. Cờ lựa chọn trông giống như một sự thay thế hấp dẫn, tuy nhiên nó ném một lỗi thay vì bỏ qua mục chưa từng có.

CHỈNH SỬA: Tôi đã tìm ra cách hacky xung quanh vấn đề này. Nếu bất cứ ai có một giải pháp đẹp hơn, tôi sẽ đánh giá cao nó.

import argparse 
parser = argparse.ArgumentParser(description='TAF') 
parser.add_argument('-r','--release',nargs='?',dest='release',default='trunk') 
parser.add_argument('testname',nargs=argparse.REMAINDER) 
args = parser.parse_args() 

if not args.testname: 
    args.testname = args.release 
    args.release = '' 

Trả lời

3

Như đã nêu trong documentation:

'?'. Một đối số sẽ được tiêu thụ từ dòng lệnh nếu có thể, và được tạo thành một mục duy nhất. Nếu không có đối số dòng lệnh, giá trị mặc định sẽ được tạo. Lưu ý rằng đối với các đối số tùy chọn , có một trường hợp bổ sung - chuỗi tùy chọn có mặt là nhưng không được theo sau bởi một đối số dòng lệnh. Trong trường hợp này, giá trị từ const sẽ được tạo ra.

Vì vậy, hành vi bạn muốn không thể truy cập được bằng cách sử dụng '?'. Có lẽ bạn có thể viết một số hack bằng cách sử dụng argparse.Action và can thiệp vào các kết quả trước đó. (1)

Tôi nghĩ giải pháp tốt hơn là tách chức năng của tùy chọn đó. Làm cho nó trở thành một tùy chọn yêu cầu một đối số (nhưng tùy chọn chính nó là tùy chọn) và thêm một tùy chọn mà không có đối số đặt phát hành thành 'trunk'. Bằng cách này bạn có thể có được kết quả tương tự mà không cần hack. Ngoài ra tôi nghĩ giao diện đơn giản hơn.

Trong ví dụ của bạn:

python TAF.py -r smoketest 

Đó là khá rõ ràng rằng smoketest sẽ được hiểu là một cuộc tranh cãi để -r. Ít nhất là theo quy ước unix. Nếu bạn muốn giữ nargs='?' sau đó người dùng phải sử dụng --:

$ python TAF.py -r -- sometest 
Namespace(release=None, testname=['sometest']) #parsed result 

(1) Một ý tưởng về làm thế nào để làm điều này: kiểm tra xem tùy chọn có một cuộc tranh cãi. Nếu nó có một kiểm tra nếu nó là một tên thử nghiệm hợp lệ. Nếu được đưa vào tay testname và đặt release thành giá trị mặc định. Bạn cũng sẽ phải đặt "cờ" cho bạn biết rằng điều này đã xảy ra.

Bây giờ, trước khi phân tích cú pháp sys.argv bạn phải chuyển hướng sys.stderr.Khi thực hiện phân tích cú pháp, bạn phải bắt số SystemExit, kiểm tra số stderr và xem lỗi có "quá ít đối số" hay không, kiểm tra xem cờ đã được đặt chưa, nếu bỏ qua lỗi và tiếp tục chạy, nếu không bạn nên in lại bản gốc stderr lỗi thông báo và thoát.

Cách tiếp cận này không có vẻ mạnh mẽ và có thể là lỗi.

+0

Cảm ơn bạn đã trả lời. Tôi đồng ý rằng nó có thể được thực hiện một cách rõ ràng thông qua việc thêm tiền tố cho đối số testname, hoặc như tôi đã đề cập chỉ liệt kê chúng trước đối số khác. –

Các vấn đề liên quan