I'm trying to create a function dynamically. Here is an example:
import ast
import textwrap
from typing import Any, Callable, List, Union
def create_function(
func_name: str,
arg_types: List[Any],
):
union_elts = [ast.Name(id=t.__name__, ctx=ast.Load()) for t in arg_types]
vararg_annotation = ast.Subscript(
value=ast.Name(id='Union', ctx=ast.Load()),
slice=ast.Tuple(elts=union_elts, ctx=ast.Load()),
ctx=ast.Load()
)
args_node = ast.arguments(
posonlyargs=[],
args=[],
vararg=ast.arg(arg='args', annotation=vararg_annotation),
kwonlyargs=[],
kw_defaults=[],
defaults=[]
)
body_code = f"""
return ', '.join([str(t) for t in args])
"""
function_def = ast.FunctionDef(
name=func_name,
args=args_node,
returns=ast.Name(id=str.__name__, ctx=ast.Load()),
body=ast.parse(textwrap.dedent(body_code)).body,
decorator_list=[],
)
module = ast.Module(body=[function_def], type_ignores=[])
ast.fix_missing_locations(module)
code = compile(module, filename="<generated_code>", mode="exec")
exec_scope = {}
exec(code, {'Union': Union, **globals()}, exec_scope)
return exec_scope[func_name]
test: Callable[
[Union[str | int | float], ...],
str
] = create_function(
func_name='test',
arg_types=[str, int, float],
)
print(test('1', 2, 3.0, '4'))
The function works fine and description says test: (str | int | float, Any) -> str. But I see Unexpected argument warning after a second argument (PyCharm Build #PY-251.23774.444, built on April 15, 2025). How can I fix this, or is it an issue with my code editor?
I tried to clear file system cache and VCS log caches / indexes - it didn't help.

arg_types=[str, int, float]says there are only 3 arguments, you're calling it with 4.[Union[str | int | float], ...]and expected it will works likedef test(*args: Union[int, float, str]) -> str:. What am I missing? Looks like the problem withast.Subscriptorarg_typestest: int | dict = 1; test[3] = 'abc'Even though you've declared that it can be a dictionary, the type checker knows that it's an integer.int | dictis still not subscriptable.