mguijarr
mguijarr

Reputation: 7930

Complex variable arguments checking at runtime

Let's consider a function like this:

def f(*args, **kwargs):
   ...

*args are a variable number of arguments that must be: (an object, a float, a float), possibly repeated N times, followed by 0 to N' objects.

For example this is a valid call:

f(my_obj, 0, 1, other_obj, 2, 3, obj3, obj4)

but this is invalid:

f(my_obj, other_obj, 2, 3)

This function is exposed to users through a Python shell. So, there is value in checking user input -- I am using the typeguard library that works with type annotations (like mypy).

I am trying to use typing module to write the proper annotations... I thought I could at least express the constraint on the groups of 3 args like this:

@typeguard.typechecked
f(*args:Tuple[Any,float,float])

But it does not work. And in anyways I have no idea how to add the constraint on the following objects.

Of course I can craft myself some code to check arguments, but I am sure something better exists for cases of complex variable arguments sequences (either a clever use of the typing module or another Python lib ?)

Upvotes: 1

Views: 77

Answers (1)

Nf4r
Nf4r

Reputation: 1410

What I meant by making the validation:

def _validate(a, b, c):
    assert isinstance(b, float), f"{b} is not a float!"
    assert isinstance(c, float), f"{c} is not a float"

def _validate_args(args):
  if (len(args) % 3 != 0): # wrong number of args
    raise ValueError("Arguments must be passed in pack of 3")
  for idx in range(0, len(args), 3):
      a, b, c = args[idx: idx + 3]
      _validate(a, b, c)

def func(*args, **kwargs):
  _validate_args(args)

func(1, 2.0, 3, 1, 2, 3)

AssertionError: 3 is not a float

You can make any message you want.

Upvotes: 1

Related Questions