| 1 | import inspect |
| 2 | |
| 3 | def safe_call(func, *args, **kwargs): |
| 4 | sig = inspect.signature(func) |
| 5 | |
| 6 | bound_args = [] |
| 7 | bound_kwargs = {} |
| 8 | |
| 9 | params = sig.parameters |
| 10 | |
| 11 | # Check if function accepts *args / **kwargs |
| 12 | accepts_var_args = any(p.kind == p.VAR_POSITIONAL for p in params.values()) |
| 13 | accepts_var_kwargs = any(p.kind == p.VAR_KEYWORD for p in params.values()) |
| 14 | |
| 15 | # Handle positional args |
| 16 | if accepts_var_args: |
| 17 | bound_args = args |
| 18 | else: |
| 19 | max_positional = sum( |
| 20 | 1 |
| 21 | for p in params.values() |
| 22 | if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD) |
| 23 | ) |
| 24 | bound_args = args[:max_positional] |
| 25 | |
| 26 | # Handle kwargs |
| 27 | if accepts_var_kwargs: |
| 28 | bound_kwargs = kwargs |
| 29 | else: |
| 30 | bound_kwargs = {k: v for k, v in kwargs.items() if k in params} |
| 31 | |
| 32 | return func(*bound_args, **bound_kwargs) |