2016-09-20 25 views
7

Używam wspaniałej biblioteki Python Click do obsługi opcji wiersza poleceń w moim narzędziu. Oto uproszczona wersja mojego kodu (pełny skrypt here):Python Click: niestandardowy komunikat o błędzie

@click.command(
    context_settings = dict(help_option_names = ['-h', '--help']) 
) 
@click.argument('analysis_dir', 
       type = click.Path(exists=True), 
       nargs = -1, 
       required = True, 
       metavar = "<analysis directory>" 
) 

def mytool(analysis_dir): 
    """ Do stuff """ 

if __name__ == "__main__": 
    mytool() 

Jeśli ktoś uruchamia komendę bez żadnych flag, otrzymują komunikat domyślny błąd kliknięcie:

$ mytool 

Usage: mytool [OPTIONS] <analysis directory> 

Error: Missing argument "analysis_dir". 

To jest ładne, ale "Chciałbym powiedzieć (bardzo) początkującym użytkownikom, że więcej pomocy jest dostępnych przy użyciu flagi pomocy. Innymi słowy, dodaj niestandardowe zdanie do komunikatu o błędzie, gdy polecenie jest nieprawidłowe, mówiąc ludziom, aby wypróbowali mytool --help, aby uzyskać więcej informacji.

Czy istnieje prosty sposób na zrobienie tego? Wiem, że mógłbym usunąć atrybut required i obsłużyć tę logikę w głównej funkcji, ale to wydaje się trochę hackowate dla tak drobnego dodatku.

+0

Mam dokładnie ten sam problem. Chciałbym automatycznie wydrukować pomoc, jeśli wystąpi błąd, lub przynajmniej powiedzieć użytkownikowi, jak wydrukować pomoc. W przeciwnym razie musimy założyć, że wszyscy korzystający z naszego narzędzia znają myślenie oparte na systemie Unix. Podoba mi się do tej pory klikanie, ale jestem zrozpaczony, że na to pytanie nie udzielono odpowiedzi, ponieważ chcę czegoś, co pomoże zbudować narzędzia, które nowicjusze będą mogli z łatwością wykorzystać. – user1677663

+0

Po prostu znalazłem to, co może być rozwiązaniem: http://stackoverflow.com/questions/35642202/python-click-return-the-helper-menu – user1677663

+0

Nie, to nie zadziałało. – user1677663

Odpowiedz

3

Konstrukcja wiadomości dla większości błędów w python-kliknięciu jest obsługiwana przez metodę show klasy UsageError: click.exceptions.UsageError.show.

Po ponownym zdefiniowaniu tej metody można utworzyć własny, dostosowany komunikat o błędzie. Poniżej znajduje się przykład personalizacji, które dołącza menu pomocy do komunikatu o błędzie, który odpowiada na to SO question:

def modify_usage_error(main_command): 
    ''' 
     a method to append the help menu to an usage error 

    :param main_command: top-level group or command object constructed by click wrapper 
    :return: None 
    ''' 

    from click._compat import get_text_stderr 
    from click.utils import echo 
    def show(self, file=None): 
     import sys 
     if file is None: 
      file = get_text_stderr() 
     color = None 
     if self.ctx is not None: 
      color = self.ctx.color 
      echo(self.ctx.get_usage() + '\n', file=file, color=color) 
     echo('Error: %s\n' % self.format_message(), file=file, color=color) 
     sys.argv = [sys.argv[0]] 
     main_command() 

    click.exceptions.UsageError.show = show 

Po zdefiniowaniu głównego polecenia, można wtedy uruchomić skrypt modyfikujący:

import click 
@click.group() 
def cli(): 
    pass 

modify_usage_error(cli) 

Nie zbadałem, czy istnieją wywołania środowiska wykonawczego ClickException inne niż błędy użytkowania. Jeśli tak, to być może trzeba zmodyfikować niestandardową procedurę obsługi błędów, aby najpierw sprawdzić, czy ctx jest atrybutem, zanim dodasz linię click.exceptions.ClickException.show = show, ponieważ nie wydaje się, że wyjątek ClickException jest podawany podczas inicjalizacji ctx.

+0

Fantastyczne, dziękuję RJ! Działa to doskonale z jednym wyjątkiem - musiałem usunąć ostatnie wywołanie funkcji do 'main_command()', ponieważ spowodowało to błąd rekursji. – tallphil

+0

To było dobre! https://github.com/ewels/MultiQC/commit/62cc60 Miałem niski poziom irytacji, że nie mogę tego zrobić przez siedem miesięcy! Dzięki jeszcze raz! – tallphil