diff --git a/ibis/common/grounds.py b/ibis/common/grounds.py index d142b3486dd4..3289ac7b6f83 100644 --- a/ibis/common/grounds.py +++ b/ibis/common/grounds.py @@ -103,18 +103,23 @@ def __new__(metacls, clsname, bases, dct): # mandatory fields without default values must preceed the optional # ones in the function signature, the partial ordering will be kept - new_params, inherited_params, optional_inherited_params = [], [], [] + new_args, new_kwargs = [], [] + inherited_args, inherited_kwargs = [], [] + for name, param in params.items(): if name in inherited: if param.default is EMPTY: - inherited_params.append(param) + inherited_args.append(param) else: - optional_inherited_params.append(param) + inherited_kwargs.append(param) else: - new_params.append(param) + if param.default is EMPTY: + new_args.append(param) + else: + new_kwargs.append(param) signature = inspect.Signature( - inherited_params + new_params + optional_inherited_params + inherited_args + new_args + new_kwargs + inherited_kwargs ) attribs["__slots__"] = tuple(slots) diff --git a/ibis/common/tests/test_grounds.py b/ibis/common/tests/test_grounds.py index d6986d692e6f..b0ba38cbddf4 100644 --- a/ibis/common/tests/test_grounds.py +++ b/ibis/common/tests/test_grounds.py @@ -192,6 +192,28 @@ class NoHooves(Farm): assert g1.goats == 0 +def test_keyword_argument_reordering(): + class Alpha(Annotable): + a = IsInt + b = IsInt + + class Beta(Alpha): + c = IsInt + d = Optional(IsInt, default=0) + e = IsInt + + obj = Beta(1, 2, 3, 4) + assert obj.a == 1 + assert obj.b == 2 + assert obj.c == 3 + assert obj.e == 4 + assert obj.d == 0 + + obj = Beta(1, 2, 3, 4, 5) + assert obj.d == 5 + assert obj.e == 4 + + def test_not_copy_default(): default = tuple()