2012-01-06 3 views
2

파이썬 argparse ArgumentParser 클래스에서 파생 된 파서 클래스를 작성하려고합니다. 다음 코드의 개요는 명령 행에서 제대로 작동하지만 오류가 발생하여 모듈의 컨텍스트에서 이해하기가 어려워졌습니다.argparse 하위 클래스 인수 파서

class SansParser(argparse.ArgumentParser): 
"""Argument parser for preparing a SansModel fit or calculation 

""" 

def __init__(self): 
    """Initialisation method for the parser class""" 

    argparse.ArgumentParser.__init__(self) 


    # Subparsers for the two commands 'calc' and 'fit' 
    self.subparsers = self.add_subparsers() 
    self.fit_parser = self.subparsers.add_parser('fit', help="Fit a dataset") 
    self.fit_parser.add_argument('-d', '-data', '-dataset', type = str, 
           dest = 'dataset', 
           help = "The dataset to fit in SasXML format") 
    self.fit_parser.set_defaults(func=fit) 
    self.calc_parser = self.subparsers.add_parser('calc', prog='test') 
    self.calc_parser.set_defaults(func=calculate) 

내가 스크립트와 훌륭한 등이 동등한를 실행할 수 있습니다 : 다음과 같이

(중요하지 않은 물건을 제거 조금 벗었) 코드입니다. 내가 파이썬 명령 줄에 쉘 또는 수입 중 하나에서 실행하고 클래스를 인스턴스화하려고하면 내가 얻을 :

$ python sansmodel.py 
    Traceback (most recent call last): 
    File "sansmodel.py", line 57, in <module> 
     parser = SansParser() 
    File "sansmodel.py", line 41, in __init__ 
     self.fit_parser = self.subparsers.add_parser('fit', help="Fit a dataset") 
    File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", 
    line 1064, in add_parser 
     parser = self._parser_class(**kwargs) 
TypeError: __init__() got an unexpected keyword argument 'prog' 

를 지금까지 내가 1064 명시 적으로 '음식물'키워드를 만들어 줄에서 argparse 자체의 코드를 말할 수있는 이것은 예상 된 행동이므로 예기치 않은 부분에 대해서는 혼란 스럽습니다. 어떻게 든 범위가 거꾸로 된 것 같아요?

답변

3

argparse.ArgumentParser 동작을 덮어 쓰지 않는 한, 파서 개체를 만들고 해당 개체에 인수와 서브 파서를 추가하는 것이 좋습니다.

즉, SansParser 구현에 의해 덮어 쓰여진 __init__ 메서드를 새 파서를 추가 할 때 원래의 ArgumentParser과 같은 인수를 허용하지 않는 것이 문제입니다. add_parser이 대신 SansParser 새로운 (그 때문에 무한 재귀의 실패)를 만드는라고

self.subparsers._parser_class = argparse.ArgumentParser 

이 방법, 새로운 ArgumentParser이 될 것입니다 :

문제에 대한 해결 방법은이 하나 여야합니다 만들어진.

+1

예. 나는 그 문제에 대해 단지 생각하고 있다고 확신했다. 이제는 파서를 객체로 사용하는 app 클래스를 만드는 것이 더 합리적이라고 생각합니다. 왜냐하면 말하자면,이 메서드 중 하나를 덮어 쓸 필요가 없기 때문입니다. –

0

서브 클래임이 아닌 ArgumentParser 오브젝트에 인수를 추가하기 만하면 @ jcollado의 제안에 동의합니다.

그러나 하위 클래스를 사용하는 경우 self.subparsers._parser_class 값을 변경하는 대신 __init__ 메서드의 서명을 변경하는 것이 좋습니다.

class SansParser(argparse.ArgumentParser): 
"""Argument parser for preparing a SansModel fit or calculation 

""" 

    def __init__(self, *args, **kwargs): 
     """Initialisation method for the parser class""" 
     if 'my_keyword' in kwargs: 
      # Do what needs to be done with kwargs['my_keyword'] 
      del kwargs['my_keyword'] # Since ArgumentParser won't recognize it 

     argparse.ArgumentParser.__init__(self, *args, **kwargs) 

이 방법은, 서브 클래스는이 동작을 재정의 경우를 제외하고, ArgumentParser과 같은 방법을 사용할 수 있습니다.

0

오늘 오후에 같은 오류가 발생하여 해결책을 찾을 때 질문을 발견했습니다. 당신이 ArgumentParser의 __init__()을 읽었다면

, 당신은이 '음식물'권리를 포함하는 일련의 인수를 받아 볼 수 있습니다 : 사용자 정의 파서 클래스는 __init__()를 오버라이드 (override) :

class ArgumentParser(_AttributeHolder, _ActionsContainer): 
"""SOME DOC STRING...""" 

    def __init__(self, 
      prog=None, 
      usage=None, 
      description=None, 
      epilog=None, 
      parents=[], 
      formatter_class=HelpFormatter, 
      prefix_chars='-', 
      fromfile_prefix_chars=None, 
      argument_default=None, 
      conflict_handler='error', 
      add_help=True, 
      allow_abbrev=True): 
     ...... # SOME IMPLEMENTATION 

나는 사실 생각 메서드를 호출하고 인수를 허용하지 않습니다. 그러나 다른 방법은 수정되지 않습니다. 이로 인해 메소드의 동작이 상충되었습니다. 하위 파서를 만들 때 add_parser()는 파서의 __init__()을 'prog'를 포함한 인수로 호출합니다. ArgumentParser는 괜찮습니다. 그러나 오버라이드 된 __init__()을 가진 커스텀 파서는 분명히 실패합니다.

물론 @ jcollado의 제안은 잘 동작하지만 하위 파서의 동작을 사용자 정의하지 않을 수도 있습니다.

이 문제에 대한 나의 해결책은 약간 못 생겼지 만 잘 작동합니다. ArgumentParser __init__()을 재정의 할 때 모든 인수와 기본값을 유지하십시오. 좋아요 :

class MyParser(argparse.ArgumentParser): 
    def __init__(
     self, 
     prog=None, 
     usage=None, 
     description=None, 
     epilog=None, 
     parents=[], 
     formatter_class=argparse.HelpFormatter, 
     prefix_chars='-', 
     fromfile_prefix_chars=None, 
     argument_default=None, 
     conflict_handler='error', 
     add_help=True, 
     allow_abbrev=True 
     # and your custom arguments here 
     ): 

     super(MyParser, self).__init__(prog=prog, usage=usage, description=description, epilog=epilog, 
            parents=parents, formatter_class=formatter_class, 
            prefix_chars=prefix_chars, fromfile_prefix_chars=fromfile_prefix_chars, 
            argument_default=argument_default, conflict_handler=conflict_handler, 
            add_help=add_help, allow_abbrev=allow_abbrev 
            ) 
     # and your custom actions here 
관련 문제