【问题标题】:How to sequentially execute click.command如何顺序执行click.command
【发布时间】:2020-01-27 06:35:06
【问题描述】:

我正在尝试一个接一个地执行多个@click.command()。没有一个函数期望来自另一个函数的输入。我看到的问题是主程序只执行第一个click.command() 并退出。

我已经尝试将click.command()s 分组,但它仍然做同样的事情。

@click.command('make_and_init_model')    
@click.option('--use_all_gpu', default= "y", prompt='Use all available GPUs? y/n')
def make_and_init_model(use_all_gpu):
    debris_model = make_unet()
    if use_all_gpu == "y":
        print("Identifying available GPUs")
        gpus_to_use = [i for i in mx.test_utils.list_gpus()]
    else:
        gpus_to_use = [int(num) for num in input("Enter space separated GPU ids to use for training").split()]

    print("Using GPUs :",gpus_to_use)
    print("Initializing model")
    model.initialize(ctx = [mx.gpu(i) for i in gpus_to_use], force_reinit=True)
    print("Model initialized")
    return model



@click.command('load_dataset') 
@click.option('--base_dir', default = "./train", prompt ="Enter base path to training dataset")
@click.option('--use_default_dir_names', default="y", prompt= "Use default dataset directory names (img and gt)? y/n")
def load_dataset(base_dir, use_default_dir_names):
    try:
        base_dir_path = os.path.abspath(base_dir)
    except:
        print("Please check the base directory path entered. Exiting script...")
        sys.exit(1)

    if use_default_dir_names == "y":
        image_dir_name="img"
        gt_dir_name="gt"
        img_format = "rgb"
        ext=".tif"
    else:
        image_dir_name = input("Enter image directory name")
        gt_dir_name = input("Enter groundtruth directory name")
        img_format = input("Enter image format (ex: rgb, bgr etc)")
        ext = input("Enter full image extension (ex: .tif, .jpg etc)")
    train = DataSet.get_from_directory(base_dir = base_dir_path, 
                                    feature_dir = image_dir_name, 
                                    gt_dir = gt_dir_name, 
                                    image_format = img_format,
                                    termination=ext)
    print("Number of training images found :", len(train))
    return train



@click.command('weights_path_and_name')    
@click.option('--weights_path', default = "./weights", prompt = "Enter path to where the weights are to be saved")
@click.option('--experiment_name', default = "training_1", prompt = "Enter experiment name")
def weights_path_and_name(weights_path, experiment_name):
    try:
        save_weights_path = os.path.abspath(weights_path)
        if not os.path.exists(save_weights_path):
            os.makedirs(save_weights_path)
    except:
        print('Please check the save weights path entered. Exiting script')
        sys.exit(1)
    return save_weights_path, experiment_name


if __name__ == "__main__":
    model = make_and_init_model()
    train = load_dataset()
    save_weights_path, experiment_name = weights_path_and_name()

但它只运行make_and_init_model 然后退出。每个单独的函数本身都是正确的,但我无法按顺序运行它们。

【问题讨论】:

    标签: python click command-line-arguments python-click


    【解决方案1】:

    我知道这是一个较老的问题,但这实际上是一个有效的点击用例。这是他们网站上的一个最小示例,他们在其中chain commands together

    @click.group(chain=True)
    def cli():
        pass
    
    
    @cli.command('sdist')
    def sdist():
        click.echo('sdist called')
    
    
    @cli.command('bdist_wheel')
    def bdist_wheel():
        click.echo('bdist_wheel called')
    

    这是来自命令行的调用和输出:

    $ setup.py sdist bdist_wheel
    sdist called
    bdist_wheel called
    

    对于您的实际问题,您可以添加一个组并将命令嵌套在其下,如下所示:

    
    @click.group(chain=True)
    def cli():
        pass
    
    @cli.command('make_and_init_model')
    @click.option('--use_all_gpu', default= "y", prompt='Use all available GPUs? y/n')
    def make_and_init_model(use_all_gpu):
        debris_model = make_unet()
        if use_all_gpu == "y":
            print("Identifying available GPUs")
            gpus_to_use = [i for i in mx.test_utils.list_gpus()]
        else:
            gpus_to_use = [int(num) for num in input("Enter space separated GPU ids to use for training").split()]
    
        print("Using GPUs :",gpus_to_use)
        print("Initializing model")
        model.initialize(ctx = [mx.gpu(i) for i in gpus_to_use], force_reinit=True)
        print("Model initialized")
        return model
    
    
    
    @cli.command('load_dataset')
    @click.option('--base_dir', default = "./train", prompt ="Enter base path to training dataset")
    @click.option('--use_default_dir_names', default="y", prompt= "Use default dataset directory names (img and gt)? y/n")
    def load_dataset(base_dir, use_default_dir_names):
        try:
            base_dir_path = os.path.abspath(base_dir)
        except:
            print("Please check the base directory path entered. Exiting script...")
            sys.exit(1)
    
        if use_default_dir_names == "y":
            image_dir_name="img"
            gt_dir_name="gt"
            img_format = "rgb"
            ext=".tif"
        else:
            image_dir_name = input("Enter image directory name")
            gt_dir_name = input("Enter groundtruth directory name")
            img_format = input("Enter image format (ex: rgb, bgr etc)")
            ext = input("Enter full image extension (ex: .tif, .jpg etc)")
        train = DataSet.get_from_directory(base_dir = base_dir_path,
                                           feature_dir = image_dir_name,
                                           gt_dir = gt_dir_name,
                                           image_format = img_format,
                                           termination=ext)
        print("Number of training images found :", len(train))
        return train
    
    
    
    @cli.command('weights_path_and_name')
    @click.option('--weights_path', default = "./weights", prompt = "Enter path to where the weights are to be saved")
    @click.option('--experiment_name', default = "training_1", prompt = "Enter experiment name")
    def weights_path_and_name(weights_path, experiment_name):
        try:
            save_weights_path = os.path.abspath(weights_path)
            if not os.path.exists(save_weights_path):
                os.makedirs(save_weights_path)
        except:
            print('Please check the save weights path entered. Exiting script')
            sys.exit(1)
        return save_weights_path, experiment_name
    
    
    if __name__ == "__main__":
        cli()
    

    然后您可以通过以下方式调用您的应用程序:

    my_application make_and_init_model load_dataset weights_path_and_name
    

    【讨论】:

      【解决方案2】:

      click.command 并非设计为按顺序运行。尽管可以在命令中使用invoke other commands,但这不会触发 prompt 选项。我相信明确指定选项是click 所做的设计选择。

      在您的使用案例中,我建议通过以下最小示例拆分 API(函数调用)和 CLI(命令行界面)。

      # t.py
      import click
      from click.testing import CliRunner
      
      
      def func1(a):
          print(f'Run func1 with a = {a}')
      
      
      def func2(b):
          print(f'Run func2 with b = {b}')
      
      
      @click.group()
      def cli():
          pass
      
      
      @cli.command()
      @click.option('--a', prompt='a?')
      def cmd1(a):
          func1(a)
      
      
      @cli.command()
      @click.option('--b', prompt='b?')
      def cmd2(b):
          func2(b)
      
      
      @cli.command()
      @click.option('--a', prompt='a?')
      @click.option('--b', prompt='b?')
      def cmd_all(a, b):
          func1(a)
          func2(b)
      
      
      if __name__ == "__main__":
          cli()
      

      那你就可以了

      $ python t.py cmd1
      a?: 5
      Run func1 with a = 5
      $ python t.py cmd2
      b?: 10
      Run func2 with b = 10
      $ python t.py cmd-all
      a?: 5
      b?: 10
      Run func1 with a = 5
      Run func2 with b = 10
      

      替代方案,共享选项签名是可能的,

      # t.py
      import click
      from click.testing import CliRunner
      
      
      def func1(a):
          print(f'Run func1 with a = {a}')
      
      
      def func2(b):
          print(f'Run func2 with b = {b}')
      
      
      @click.group()
      def cli():
          pass
      
      
      opta = click.option('--a', prompt='a?')
      optb = click.option('--b', prompt='b?')
      
      
      @cli.command()
      @opta
      def cmd1(a):
          func1(a)
      
      
      @cli.command()
      @optb
      def cmd2(b):
          func2(b)
      
      
      @cli.command()
      @opta
      @optb
      def cmd_all(a, b):
          func1(a)
          func2(b)
      
      
      if __name__ == "__main__":
          cli()
      

      编辑:这是我第一次在这里提问。对于标签等方面的任何菜鸟错误,请多多包涵

      没关系。下次提问时请尽量举个小例子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-11-12
        • 2021-06-22
        • 1970-01-01
        • 2014-10-19
        • 2021-09-04
        • 2010-12-23
        • 2018-09-03
        • 1970-01-01
        相关资源
        最近更新 更多