1. configargparse

About 4 min

1. configargparse

1.1. Instal

configargparse 是 argparse的 增强版, configargparse 完全支持所有argparse功能 , 可以取代 argparse 。

pip install configargparse

注意:不是configparser,那是专门用来解析ini的。

可惜不能用 notebook执行,只能用py脚本。

1.2. 头

一样的ArgumentParser

argparse

import argparse
parser = argparse.ArgumentParser()

configargparse

import configargparse
parser = configargparse.ArgumentParser()

configargparse.ArgumentParser()默认解读txt配置。

1.3. unique feature

which argparse don't have.

1.3.1. config file

默认的ArgumentParser() 直接就对 txt, ini, yaml格式都支持。

# python t.py --config 'some.txt'
# python t.py --config 'some.ini'
# python t.py --config 'some.yaml'

import configargparse
parser = configargparse.ArgumentParser()
parser.add_argument('--config', is_config_file=True, help='config file path')
parser.add_argument("--num", type=int)
parser.add_argument("--no_cache", action='store_true')
args = parser.parse_args()
print(args)

# Namespace(config='some.txt', num=1, no_cache=True)
# this is a comment
; this is also a comment (.ini style)
---            # lines that start with --- are ignored (yaml style)
-------------------
[section]      # .ini-style section names are treated as comments

# how to specify a key-value pair (all of these are equivalent):
num 1     # key is case sensitive: "Num" isn't "num"
num = 1   # (.ini style)  (white space is ignored, so num = 1 same as num=1)
num: 1    # (yaml style)
--num 1   # (argparse style)

action="store_true"的特殊效果,原本无论argparse和configargparse都无法对命令行参数下的--no_cache True/False进行解析error: unrecognized arguments: True,而通过config配置文件就可以做到显式赋值。

# 可以 no_cache 表示 True,不写就 False
no_cache
--no_cache
# 此外,区别于命令行传参, 这里可以显示传值,允许 no_cache = True 和 no_cache = False
no_cache = True    # "True" and "true" are the same
no_cache = False   # "False" and "false" are the same
# 但和用命令行的一样,当`default=True`,无论赋值还是不赋值,结果都是True.
parser.add_argument("--no_cache", action='store_true', default=True)

no_cache
--no_cache
no_cache = True
no_cache = False

1.3.2. parse string

import configargparse
parser = configargparse.ArgumentParser()
parser.add_argument('--config', is_config_file=True, help='config file path')
parser.add_argument("--num", default=0, type=int)
parser.add_argument("--no_cache", action='store_true')

cmd = '--no_cache'
# 甚至还能融合config file。cmd = '--config ./some.txt --no_cache'

parser.parse_args(cmd)
print(parser.parse_args(cmd))

'''
Namespace(config=None, no_cache=True, num=0)
'''

1.3.3. format_values

直接想要parser.format_values(),看似不用args = parser.parse_args()的返回值args。但是parser.parse_args()不仅只是返回参数,而且是一个初始化的过程。所以还得写。

import configargparse
parser = configargparse.ArgumentParser()
parser.add_argument('--config', is_config_file=True, help='config file path')
parser.add_argument("--num", default=0, type=int)
parser.add_argument("--no_cache", action='store_true')
parser.add_argument("--default_value", default=0, type=int)
parser.add_argument("--value", type=int)
parser.add_argument("--test", action='store_true')


parser.parse_args()
print(parser.format_values())
$ python t.py --config some.txt --test
Command Line Args:   --config some.txt --test
Config File (some.txt):
  num:               1
  no_cache:          true
Defaults:
  --default_value:   0

会打印来自命令行、配置文件、默认值的参数。然而,不在这三者的value就不会被打印。

1.4. project example

1.4.1. verbosity 分组

当显示帮助消息时,ArgumentParser 将 命令行 参数分组为 “positional arguments” 和 “optional arguments”

# 互斥
group = parser.add_mutually_exclusive_group()
group.add_argument('--verbose', action='store_true')
group.add_argument('--quiet', action='store_true')
args = parser.parse_args()
print('hello', args)

if args.quiet:
    print('quiet form')
elif args.verbose:
    print('long form')
else:
    print('normal form')


'''
(fff) PS E:\CodeProject\Git\rubbish> python a.py --h
usage: a.py [-h] [--verbose | --quiet]

optional arguments:
  -h, --help  show this help message and exit
  --verbose
  --quiet
(fff) PS E:\CodeProject\Git\rubbish> python a.py 
hello Namespace(verbose=False, quiet=False)
normal form
(fff) PS E:\CodeProject\Git\rubbish> python a.py --quiet
hello Namespace(verbose=False, quiet=True)
(fff) PS E:\CodeProject\Git\rubbish> python a.py --verbose
hello Namespace(verbose=True, quiet=False)
long form
'''

1.4.2. 小型项目

import configargparse

def config_parser(cmd=None):
    parser = configargparse.ArgumentParser()
    
    # config file
    parser.add_argument('--config', is_config_file=True, help='config file path')
    parser.add_argument('--with_depth', action='store_true')
    parser.add_argument("--batch_size", type=int, default=4096)
    parser.add_argument("--seed", type=int, default=None, help="random seed for generating consistent images per prompt")
    parser.add_argument("--lr_init", type=float, default=0.02, help='learning rate')    
    parser.add_argument('--model_name', type=str, default='TensorVMSplit', choices=['TensorVMSplit', 'TensorCP'])

    if cmd is not None:
        return parser.parse_args(cmd)
    else:
        return parser.parse_args()

        
def main():
    # cmd = '--config ./config.txt --with_depth'
    # args = config_parser(cmd)
    args = config_parser()
    print(args)

    #### 解系参数
    # 根据是不是None而有不同的处理方案
    if args.seed is None:
        ...
    else:
        ...

    if  args.with_depth:
        ...


    engine()

1.4.3. 大型项目自定义分组

定一个类, __init__()包办,生成实例就直接返回args。args = Arguments().args

https://github.com/derv82/wifite2/blob/master/wifite/args.pyopen in new window

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .util.color import Color

import argparse, sys

class Arguments(object):
    ''' Holds arguments used by the Wifite '''

    def __init__(self, configuration):
        # Hack: Check for -v before parsing args; so we know which commands to display.
        self.verbose = '-v' in sys.argv or '-hv' in sys.argv or '-vh' in sys.argv
        self.config = configuration
        self.args = self.get_arguments()

    def _verbose(self, msg):
        if self.verbose:
            return Color.s(msg)
        else:
            return argparse.SUPPRESS

    def get_arguments(self):
        ''' Returns parser.args() containing all program arguments '''

        parser = argparse.ArgumentParser(usage=argparse.SUPPRESS,
                formatter_class=lambda prog: argparse.HelpFormatter(
                    prog, max_help_position=80, width=130))

        self._add_global_args(parser.add_argument_group(Color.s('{C}SETTINGS{W}')))
        self._add_wep_args(parser.add_argument_group(Color.s('{C}WEP{W}')))
        self._add_wpa_args(parser.add_argument_group(Color.s('{C}WPA{W}')))
        self._add_wps_args(parser.add_argument_group(Color.s('{C}WPS{W}')))
        self._add_pmkid_args(parser.add_argument_group(Color.s('{C}PMKID{W}')))
        self._add_command_args(parser.add_argument_group(Color.s('{C}COMMANDS{W}')))

        return parser.parse_args()


    def _add_global_args(self, glob):
        glob.add_argument('-v',
            '--verbose',
            action='count',
            default=0,
            dest='verbose',
            help=Color.s('Shows more options ({C}-h -v{W}). Prints commands and ' +
                'outputs. (default: {G}quiet{W})'))
        
        # ...

    def _add_wep_args(self, wep):
        # WEP
        wep.add_argument('--wep',
            action='store_true',
            dest='wep_filter',
            help=Color.s('Show only {C}WEP-encrypted networks{W}'))

    def _add_wpa_args(self, wpa):
        wpa.add_argument('--wpa',
            action='store_true',
            dest='wpa_filter',
            help=Color.s('Show only {C}WPA-encrypted networks{W} (includes {C}WPS{W})'))
        wpa.add_argument('-wpa', help=argparse.SUPPRESS, action='store_true',
                dest='wpa_filter')

if __name__ == '__main__':
    from .config import Configuration
    Configuration.initialize(False)
    # 这里调用
    a = Arguments(Configuration)
    args = a.args
    for (key,value) in sorted(args.__dict__.items()):
        Color.pl('{C}%s: {G}%s{W}' % (key.ljust(21),value))