Skip to content

rename_arguments creates double-partial when input is functools.partial #77

@hmgaudecker

Description

@hmgaudecker

Bug

rename_arguments creates a double-partial when the input function is a functools.partial, causing the bound positional arguments to be passed twice.

Minimal Reproducible Example

import functools
from dags.signature import rename_arguments

def inner(bound_arg, free_arg):
    return f"bound={bound_arg}, free={free_arg}"

func = functools.partial(inner, "BOUND_VALUE")

renamed = rename_arguments(func, mapper={"free_arg": "renamed_free"})

renamed(renamed_free="hello")
# TypeError: inner() got multiple values for argument 'free_arg'

renamed("hello")
# TypeError: inner() takes 2 positional arguments but 3 were given

Root Cause

In dags/signature.py, rename_arguments lines 274-279:

# Preserve function type
if isinstance(func, functools.partial):
    partial_wrapper = functools.partial(
        wrapper_rename_arguments, *func.args, **func.keywords
    )
    out = cast("Callable[P, R]", partial_wrapper)

wrapper_rename_arguments already captures func (the partial) in its closure and delegates to it via func(*args, **internal_kwargs). The bound args from the partial are already applied when func is called internally.

The "Preserve function type" block then wraps wrapper_rename_arguments in another functools.partial with the same *func.args, so those args get passed twice: once by the outer partial as positional args, and once by the inner func() call (which is the original partial).

Expected Behavior

rename_arguments should work correctly with functools.partial inputs — renaming only the free (unbound) parameters without duplicating the bound arguments.

dags Version

0.5.0 (also affects current main)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions