Normalize decorator

This section discusses the purpose of the @normalize decorator, shows how to use it and provides the reference documentation.

Purpose (discussion)

When sharing code, a large amount of code is usually dedicated to processing the arguments of the functions or methods to check their value and normalize it to a standard format.

The Python language offers the ability to accept a large range of input type on a unique function through duck typing. This leads to better integration of the different objects at stake, for instance using an object such as xarray.Dataset or a pandas.DataFrame or pandas.Serie as input to provide a list of dates.

CliMetLab offers predefined shortcuts to implement this. The short API aims to address 80% of the use cases using the @normalize decorator. The longer form aims to tackle specific needs.

Compare the following codes snippets:

How to use

  • How to ensure that the value in the function belongs to a list?

    from climetlab.decorators import normalize
    
    
    @normalize("param", ["tp", "gh"])
    def f(self, param):
        print(param)
    
  • How to ensure that the value in the function is a date with this format “YYYY-MM-DD”?

    from climetlab.decorators import normalize
    
    
    @normalize("option", "date(%Y-%m-%d)")
    def f(option):
        return option
    
    
    assert f(option="2022-12-31") == "2022-12-31"
    assert f(option="20221231") == "2022-12-31"
    assert f(option=20221231) == "2022-12-31"
    
  • How to ensure that the value in the function is a list?

    Add the keyword argument multiple=True. Not available for bounding-box.

  • How to ensure that the value in the function is a list of int?

    from climetlab.decorators import normalize
    
    
    @normalize("option", "int", multiple=True)
    def f(option):
        return option
    
    
    # Alternative shorter version
    @normalize("option", "int-list")
    def g(option):
        return option
    
    
    assert f(option="2022") == [2022]
    assert g(option="2022") == [2022]
    assert f(option=[48, 72.0, "96"]) == [48, 72, 96]
    assert g(option=[48, 72.0, "96"]) == [48, 72, 96]
    
  • How to ensure that the value in the function is not a list?

    Add the keyword argument multiple=False.

  • How to accept list or non-list as input?

    Add the keyword argument multiple=None. Not available for bounding-box.

  • How to add alias/shortcuts/special values to be replaced by actual predefined values?

    Use the keyword argument alias and provide a dictionary.

    from climetlab.decorators import normalize
    
    
    @normalize("param", ["tp", "gh"])
    def f(param):
        return param
    
    
    assert f(param="tp") == "tp"
    # f(param="t2m") # fails
    
    from climetlab.decorators import normalize
    
    DATES = dict(
        april=["20210401", "20210402", "20210403"],
        june=["20210610", "20210611"],
    )
    
    
    @normalize("x", "date-list(%Y%m%d)", aliases=DATES)
    def f(x):
        return x
    
    
    assert f("2021-06-10") == ["20210610"]
    assert f("june") == ["20210610", "20210611"]
    assert f("1999-01-01") == ["19990101"]
    

Reference

Warning

This API is experimental, things may change.

@normalize(name, values, aliases={}, multiple=None, **kwargs)

The @normalize decorator transforms the arguments provided when calling the decorated function, modifies it if needed, and provides a normalised value to the function. It ensures that the value of the argument is what is expected to be processed by the function.

values

If values is a list, the list provides allowed values for the parameter. If values is a string, it is expected to be a shortcut similar to “type(options)” where type is one of the following: "date", "date-list", "bounding-box". These shorts cut aims at providing an easy way to define many options in a more concise manner.

Example: "date-list(%Y%m%d)"

type

Type of value expected by the function. The type should be one of the following: "str", "int", "float", "date", "date-list", "str-list", "int-list", "float-list".

format

The keyword argument format is available for type =’date’ and ‘date-list’. It provides the expected format according to datetime.strftime. Example: format=’%Y%m%d’

convention

Experimental. To be documented.

aliases

Replace a value with another using a dictionary of aliases.

multiple

The keyword argument multiple is not available for bounding-box.

True: Ensure a list value. Turn input into a list if needed.

False: Ensure a non-list value. Turn a list input as non-list if the list has only one element. Fails with ValueError if the list has more than one element.

None: Accept list and non-list values without transformations.