Skip to content

Commit bdb1542

Browse files
committed
Account for kwdefaults when copying function
1 parent b346f56 commit bdb1542

4 files changed

Lines changed: 12 additions & 11 deletions

File tree

changelog/69901.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed `salt.utils.functools` `namespaced_function`/`alias_function` dropping keyword-only argument defaults in copied function

salt/utils/functools.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ def namespaced_function(function, global_dict, defaults=None, preserve_context=N
6161
closure=function.__closure__,
6262
)
6363
new_namespaced_function.__dict__.update(function.__dict__)
64+
if function.__kwdefaults__ is not None:
65+
# Only Py 3.13+ accept this in FunctionType.__new__
66+
new_namespaced_function.__kwdefaults__ = function.__kwdefaults__.copy()
6467
return new_namespaced_function
6568

6669

@@ -76,6 +79,9 @@ def alias_function(fun, name, doc=None):
7679
fun.__closure__,
7780
)
7881
alias_fun.__dict__.update(fun.__dict__)
82+
if fun.__kwdefaults__ is not None:
83+
# Only Py 3.13+ accept this in FunctionType.__new__
84+
alias_fun.__kwdefaults__ = fun.__kwdefaults__.copy()
7985

8086
if doc and isinstance(doc, str):
8187
alias_fun.__doc__ = doc

tests/pytests/functional/utils/functools/test_alias_function.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ def func(_arg, *, default="foo"):
88
func2 = alias_function(func, "func2")
99

1010
assert func(None) == "foo"
11-
assert func2(None) == "foo"
11+
assert func2(None) == "foo" # pylint: disable=not-callable

tests/pytests/functional/utils/functools/test_namespaced_function.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,14 @@ def main():
6363
import foopkg.mod1
6464
6565
foopkg.mod1.main()
66-
""".format(
67-
CODE_DIR
68-
)
66+
""".format(CODE_DIR)
6967
run2_contents = """
7068
import sys
7169
sys.path.insert(0, '{}')
7270
import foopkg.mod2
7371
7472
foopkg.mod2.main()
75-
""".format(
76-
CODE_DIR
77-
)
73+
""".format(CODE_DIR)
7874
with pytest.helpers.temp_file(
7975
"run1.py", contents=run1_contents, directory=tmp_path
8076
), pytest.helpers.temp_file(
@@ -83,9 +79,7 @@ def main():
8379
"__init__.py", contents="", directory=pkgpath
8480
), pytest.helpers.temp_file(
8581
"mod1.py", mod1_contents, directory=pkgpath
86-
), pytest.helpers.temp_file(
87-
"mod2.py", mod2_contents, directory=pkgpath
88-
):
82+
), pytest.helpers.temp_file("mod2.py", mod2_contents, directory=pkgpath):
8983
ret = shell.run(sys.executable, str(tmp_path / "run1.py"), cwd=str(tmp_path))
9084
log.warning(ret)
9185
assert ret.returncode == 0
@@ -139,4 +133,4 @@ def func(_arg, *, default="foo"):
139133
func2 = namespaced_function(func, globals())
140134

141135
assert func(None) == "foo"
142-
assert func2(None) == "foo"
136+
assert func2(None) == "foo" # pylint: disable=not-callable

0 commit comments

Comments
 (0)