2010-04-28 10 views
7

Benim Python komut böyle komut satırından başlatıldığında:Birlikte kullanılamayan seçenekleri nasıl kullanırsınız (OptionParser kullanarak)? (Yapılacaklar listesi için)

todo [options] <command> [command-options] 

Bazı seçenekler birlikte kullanılamaz, örneğin

todo add --pos=3 --end "Ask Stackoverflow" 

hem üçüncü pozisyonunu belirtmek istiyorum ve listenin sonu. Benzer şekilde, kısa veya bilgilendirici olmak üzere programımı karıştırırdım. Oldukça güçlü bir seçenek kontrolüne sahip olmak istediğimden, bu gibi durumlar bir demet olacak ve yeni olanlar kesinlikle gelecekte ortaya çıkacak. Bir kullanıcı kötü bir seçenek kombinasyonunu geçerse, tercihen optisse tarafından sağlanan kullanım yardımı ile birlikte bilgilendirici bir mesaj vermek istiyorum. Şu anda bunu, gerçekten çirkin ve fakir bulduğum bir if-else ifadesiyle hallediyorum. Hayalim benim kodunda böyle bir şey olmasıdır:

parser.set_not_allowed(combination=["--pos", "--end"], 
         message="--pos and --end can not be used together") 

ve seçenekleri ayrıştırılırken OptionParser bu kullanmak.

bu kadar bildiğim kadarıyla yok, ben SO topluluğuna sorma: Bunu nasıl ele? Muhtemelen optparse.OptionParser uzatarak

cevap

6

: Eğer parse_args çağrı nerede

class Conflict(object): 
    __slots__ = ("combination", "message", "parser") 

    def __init__(self, combination, message, parser): 
     self.combination = combination 
     self.message = str(message) 
     self.parser = parser 

    def accepts(self, options): 
     count = sum(1 for option in self.combination if hasattr(options, option)) 
     return count <= 1 

class ConflictError(Exception): 
    def __init__(self, conflict): 
     self.conflict = conflict 

    def __str__(self): 
     return self.conflict.message 

class MyOptionParser(optparse.OptionParser): 
    def __init__(self, *args, **kwds): 
     optparse.OptionParser.__init__(self, *args, **kwds) 
     self.conflicts = [] 

    def set_not_allowed(self, combination, message): 
     self.conflicts.append(Conflict(combination, message, self)) 

    def parse_args(self, *args, **kwds): 
     # Force-ignore the default values and parse the arguments first 
     kwds2 = dict(kwds) 
     kwds2["values"] = optparse.Values() 
     options, _ = optparse.OptionParser.parse_args(self, *args, **kwds2) 

     # Check for conflicts 
     for conflict in self.conflicts: 
      if not conflict.accepts(options): 
       raise ConflictError(conflict) 

     # Parse the arguments once again, now with defaults 
     return optparse.OptionParser.parse_args(self, *args, **kwds) 

Daha sonra ConflictError işleyebilir:

try: 
    options, args = parser.parse_args() 
except ConflictError as err: 
    parser.error(err.message) 
+0

Müthiş çözüm! – Joel

+0

'super()', 'OptionParser' eski stil sınıfı olarak oluşturulduğu için Python 2.X için çalışmaz. Bir çözüm, [Yığın Taşması sorusu 2023940] (http://stackoverflow.com/questions/2023940/using-super-when-subclassing-python-class-that-is-not-derived-from-objectold) adresinde sağlanmıştır. – gotgenes

+0

Teşekkürler, üst sınıfı açık bir şekilde yazarak onu düzelttim. –

3

TAMAS cevabı iyi bir başlangıç, ama çalışmak için alamadım, Başbakan, "parser" bir çatışma olduğunda hep bir hata yükselterek Conflict.__slots__ eksik, süper giden bozuk çağrı dahil hataların numarası (veya vardı) Çünkü Conflicts.accepts() içinde parser.has_option() kullanımı vb Gerçekten bu özelliği gerekli yana

belirtilen, benim kendi çözümünü devirdi ve Python Package IndexConflictsOptionParser olarak gelen kullanılabilir hale getirmiştir. O, optparse.OptionParser'un yerine bir damla olarak işe yarıyor. (Ben argparse hotness ayrıştırma Yeni komut satırı olduğunu biliyorum, ama Python 2.6 kullanılamaz ve aşağıda ve optparse daha halen az benimsenmesini sahiptir. Yukarı kesmek istiyorum veya ek argparse kadar kesmek varsa bana mail gönder tabanlı solüsyonu) tuşuna bir dereceye kadar, iki yeni yöntemler, register_conflict() ve unregister_conflict().

#/usr/bin/env python 

import conflictsparse 
parser = conflictsparse.ConflictsOptionParser("python %prog [OPTIONS] ARG") 
# You can retain the Option instances for flexibility, in case you change 
# option strings later 
verbose_opt = parser.add_option('-v', '--verbose', action='store_true') 
quiet_opt = parser.add_option('-q', '--quiet', action='store_true') 
# Alternatively, you don't need to keep references to the instances; 
# we can re-use the option strings later 
parser.add_option('--no-output', action='store_true') 
# Register the conflict. Specifying an error message is optional; the 
# generic one that is generated will usually do. 
parser.register_conflict((verbose_opt, quiet_opt, '--no-output')) 
# Now we parse the arguments as we would with 
# optparse.OptionParser.parse_args() 
opts, args = parser.parse_args() 

O Tamas tarafından başlamış çözümü üzerinde birkaç avantajı vardır:

  • çalışıyor kutunun dışında ve pip (veya easy_install, aracılığıyla) üzerinden yüklenebilir Mecbursun). Bir çatışma
  • Seçenekler onların seçenek dizelerle veya KURU ilkesi ile yardımcı olur onların optparse.Option durumlarda, yoluyla belirtilebilir; Örnekleri kullanırsanız, gerçek dizeleri çakışma kodunu kırmadan endişelenmeden değiştirebilirsiniz.
  • Normal optparse.OptionParser.parse_args() davranışını izler ve komut satırındaki argümanlarda çelişen seçenekleri algıladığında, hataya doğrudan atmak yerine otomatik olarak optparse.OptionParser.error()'u çağırır. (Bu özellik ve bir hata hem de;. optparse 'ın genel tasarımında bir hata tür, ancak optparse davranışı ile en az tutarlı olduğunu, bu paket için bir özellik)
İlgili konular