简体   繁体   中英

How can I use an python-click argument from within a click option (check if variable exists in file)?

I want to pass a file (netCDF data file) as first argument and an option (-v) to indicate the variable(s) to read from this file to my script.

I figured I'd need a custom callback to evaluate if this or these variable(s) is/are contained in the file. However, I'm stuck figuring out how to access the argument from within my callback method.

import click
import xarray as xr

def validate_variable(ctx, param, value):
    """Check that requested variable(s) are in netCDF file """

    # HOW TO ACCESS ARGUMENT 'tile' ???

    with xr.open_dataset(ctx.tile) as ds:
        for v in value:
            if v not in ds.data_vars:
                raise click.BadParameter('Var %s not in file %s.' % (v, ctx.tile))

EPILOG = 'my script ...'

CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])

@click.command(context_settings=CONTEXT_SETTINGS, epilog=EPILOG)

@click.pass_context
@click.option('--variable', '-v', multiple=True, metavar='VAR', 
                callback=validate_variable,
                help='variable to render')
@click.argument('tile', type=click.File())
def cli(tile, variable):
    main(tile, variable)

You are running into problems trying to do this in the callback, because the order in which the callbacks are invoked does not guarantee that all of the parameters you need, will have been evaluated when your callback is invoked.

One way you can do this is to override click.Command.make_context() , and do your validation after the context construction is complete.

Custom Command Class

This function is passed a validator function and returns a custom click.Command class.

def command_validate(validator):

    class CustomClass(click.Command):

        def make_context(self, *args, **kwargs):
            ctx = super(CustomClass, self).make_context(*args, **kwargs)
            validator(ctx)
            return ctx

    return CustomClass

Validator Function

The validator function is passed a context, and can raise a click.BadParameter exception when the validation fails.

def validate_variables(ctx):
    """Check that requested variable(s) are in netCDF file """

    value = ctx.params['variable']
    tile = ctx.params['tile']
    with xr.open_dataset(tile) as ds:
        for v in value:
            if v not in ds.data_vars:
                raise click.BadParameter(
                    'Var %s not in file %s.' % (v, tile), ctx)

Using Custom Class:

To use the custom class, pass command_validate a validator function, and pass the return value as cls to the command decorator like:

@click.command(cls=command_validate(validate_variables), ...OtherOptions...)
...Other config...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM