code

Python argparse : 최소한 하나의 인수를 필요로합니다.

codestyles 2020. 10. 7. 07:40
반응형

Python argparse : 최소한 하나의 인수를 필요로합니다.


내가 사용하고 argparse파이썬 할 수있는 프로그램 -process, -upload또는 두 가지 모두 :

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()

프로그램은 하나 이상의 매개 변수 없이는 의미가 없습니다. argparse하나 이상의 매개 변수를 강제로 선택 하도록 구성 하려면 어떻게 해야합니까?

최신 정보:

댓글에 따라 : 최소한 하나의 옵션으로 프로그램을 매개 변수화하는 Python 방식은 무엇입니까?


if not (args.process or args.upload):
    parser.error('No action requested, add -process or -upload')

args = vars(parser.parse_args())
if not any(args.values()):
    parser.error('No arguments provided.')

'또는 둘 다'부분이 아니라면 (처음에 이것을 놓쳤습니다) 다음과 같이 사용할 수 있습니다.

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")

그러나 대신 하위 명령 을 사용하는 것이 더 나은 생각 일 것입니다 .


나는 이것이 먼지로 오래되었다는 것을 알고 있지만 하나의 옵션을 요구하지만 둘 이상의 (XOR)를 금지하는 방법은 다음과 같습니다.

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

산출:

>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  

요구 사항 검토

  • 사용 argparse(나는 이것을 무시할 것입니다)
  • 하나 또는 두 개의 작업을 호출 할 수 있습니다 (적어도 하나는 필요함).
  • Pythonic에 의해 시도하십시오 (차라리 "POSIX"와 같은 이름으로 부르고 싶습니다)

명령 줄에서 생활 할 때 몇 가지 암시 적 요구 사항도 있습니다.

  • 이해하기 쉬운 방식으로 사용자에게 사용법을 설명
  • 옵션은 선택 사항입니다.
  • 플래그 및 옵션 지정 허용
  • 다른 매개 변수 (예 : 파일 이름 또는 이름)와 결합 할 수 있습니다.

docopt(파일 managelog.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

그것을 실행하십시오 :

$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

도움말보기 :

$ 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>

그리고 그것을 사용하십시오 :

$ 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}

짧은 대안 short.py

더 짧은 변형이있을 수 있습니다.

"""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

사용법은 다음과 같습니다.

$ 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}

"process"및 "upload"키에 대한 부울 값 대신 카운터가 있습니다.

우리는 다음 단어의 중복을 막을 수 없습니다.

$ 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}

결론

좋은 명령 줄 인터페이스를 디자인하는 것은 때때로 어려울 수 있습니다.

명령 줄 기반 프로그램에는 여러 측면이 있습니다.

  • 명령 줄의 좋은 디자인
  • 적절한 파서 선택 / 사용

argparse 많은 것을 제공하지만 가능한 시나리오를 제한하고 매우 복잡해질 수 있습니다.

docopt가독성을 보존하고 유연성의 높은 수준을 제공하면서 상황이 훨씬 짧은 이동합니다. 사전에서 구문 분석 된 인수를 가져오고 수동으로 (또는라는 다른 라이브러리를 사용하여 schema) 일부 변환 (정수로 변환 ) docopt을 수행하는 경우 명령 줄 구문 분석에 적합 할 수 있습니다 .


이를 수행하는 가장 좋은 방법은 python inbuilt module 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()

명령 줄에서 하나의 인수 만 선택하려면 required = True를 그룹의 인수로 사용하십시오.

group = parser.add_mutually_exclusive_group(required=True)

하나 이상의 매개 변수를 사용하여 Python 프로그램을 실행 해야하는 경우 옵션 접두어 (기본적으로-또는-) 가없는 인수를 추가 하고 설정합니다 nargs=+(최소 하나의 인수 필요). 내가 찾은이 방법의 문제점은 인수를 지정하지 않으면 argparse가 "너무 적은 인수"오류를 생성하고 도움말 메뉴를 인쇄하지 않는다는 것입니다. 해당 기능이 필요하지 않은 경우 코드에서 수행하는 방법은 다음과 같습니다.

import argparse

parser = argparse.ArgumentParser(description='Your program description')
parser.add_argument('command', nargs="+", help='describe what a command is')
args = parser.parse_args()

내가 생각하는 당신이 옵션을 접두사로 인수를 추가 할 때, nargs 전체 인수 파서뿐 아니라 옵션에 적용있다. (내가 평균, 당신이 경우 --option플래그 nargs="+", 다음 --option. 플래그 예상하는 적어도 하나의 인수를 당신이있는 경우 optionnargs="+", 그것은 전체 적어도 하나의 인수를 기대하고있다.)


For http://bugs.python.org/issue11588 I am exploring ways of generalizing the mutually_exclusive_group concept to handle cases like this.

With this development argparse.py, https://github.com/hpaulj/argparse_issues/blob/nested/argparse.py I am able to write:

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)

which produces the following 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

This accepts inputs like '-u', '-up', '--proc --up' etc.

It ends up running a test similar to https://stackoverflow.com/a/6723066/901925, though the error message needs to be clearer:

usage: PROG [-h] (-p | -u)
PROG: error: some of the arguments process upload is required

I wonder:

  • are the parameters kind='any', required=True clear enough (accept any of the group; at least one is required)?

  • is usage (-p | -u) clear? A required mutually_exclusive_group produces the same thing. Is there some alternative notation?

  • is using a group like this more intuitive than phihag's simple test?


Use append_const to a list of actions and then check that the list is populated:

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')

You can even specify the methods directly within the constants.

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()

Maybe use sub-parsers?

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)

Now --help shows:

$ 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

You can add additional options to these sub-parsers as well. Also instead of using that dest='subparser_name' you can also bind functions to be directly called on given sub-command (see docs).


This achieves the purpose and this will also be relfected in the argparse autogenerated --help output, which is imho what most sane programmers want (also works with optional arguments):

parser.add_argument(
    'commands',
    nargs='+',                      # require at least 1
    choices=['process', 'upload'],  # restrict the choice
    help='commands to execute'
)

Official docs on this: https://docs.python.org/3/library/argparse.html#choices

참고URL : https://stackoverflow.com/questions/6722936/python-argparse-make-at-least-one-argument-required

반응형