0
# Signature Manipulation
1
2
Utilities for programmatically modifying function signatures by adding or removing parameters. These functions enable dynamic signature construction and are the building blocks used by other makefun utilities for signature modifications.
3
4
```python
5
from typing import Union, Iterable
6
from inspect import Signature, Parameter
7
```
8
9
## Capabilities
10
11
### Adding Parameters to Signatures
12
13
Add parameters to existing signatures at specific positions with automatic parameter kind inference.
14
15
```python { .api }
16
def add_signature_parameters(s: Signature,
17
first: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (),
18
last: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (),
19
custom: Union[Parameter, Iterable[Parameter]] = (),
20
custom_idx: int = -1) -> Signature:
21
"""
22
Adds parameters to an existing signature, returning a new Signature instance.
23
24
Parameters:
25
- s: Signature, original signature to modify
26
- first: Union[str, Parameter, Iterable[Union[str, Parameter]]], default ()
27
Parameters to add at the beginning of the parameter list.
28
Strings are converted to Parameter objects with auto-inferred kinds.
29
- last: Union[str, Parameter, Iterable[Union[str, Parameter]]], default ()
30
Parameters to add at the end of the parameter list.
31
Strings are converted to Parameter objects with auto-inferred kinds.
32
- custom: Union[Parameter, Iterable[Parameter]], default ()
33
Parameter objects to add at a custom position specified by custom_idx
34
- custom_idx: int, default -1
35
Position to insert custom parameters (supports negative indexing)
36
37
Returns:
38
Signature: New signature with added parameters
39
40
Raises:
41
ValueError: If parameter names conflict with existing parameters
42
43
Note:
44
- Parameter kinds are auto-inferred based on context when strings are provided
45
- Maintains proper parameter ordering and kind constraints
46
- Preserves return annotation from original signature
47
"""
48
```
49
50
### Removing Parameters from Signatures
51
52
Remove specified parameters from existing signatures by name.
53
54
```python { .api }
55
def remove_signature_parameters(s: Signature, *param_names: str) -> Signature:
56
"""
57
Removes parameters from an existing signature, returning a new Signature instance.
58
59
Parameters:
60
- s: Signature, original signature to modify
61
- *param_names: str, names of parameters to remove
62
63
Returns:
64
Signature: New signature with specified parameters removed
65
66
Raises:
67
KeyError: If any parameter name is not found in the signature
68
"""
69
```
70
71
### Usage Examples
72
73
#### Basic Parameter Addition
74
75
```python
76
from makefun import add_signature_parameters
77
from inspect import signature, Parameter
78
79
def original_func(x: int, y: str) -> str:
80
return f"{x}: {y}"
81
82
original_sig = signature(original_func)
83
84
# Add parameters at the beginning
85
new_sig = add_signature_parameters(original_sig, first="prefix: str = 'Result'")
86
print(new_sig) # (prefix: str = 'Result', x: int, y: str) -> str
87
88
# Add parameters at the end
89
new_sig2 = add_signature_parameters(original_sig, last=["suffix: str = '!'", "verbose: bool = False"])
90
print(new_sig2) # (x: int, y: str, suffix: str = '!', verbose: bool = False) -> str
91
92
# Add parameters at both ends
93
new_sig3 = add_signature_parameters(original_sig,
94
first="timestamp: float",
95
last="debug: bool = False")
96
print(new_sig3) # (timestamp: float, x: int, y: str, debug: bool = False) -> str
97
```
98
99
#### Using Parameter Objects
100
101
```python
102
from makefun import add_signature_parameters
103
from inspect import signature, Parameter
104
105
def base_func(data: list) -> int:
106
return len(data)
107
108
base_sig = signature(base_func)
109
110
# Create Parameter objects explicitly
111
log_param = Parameter('log_level', Parameter.KEYWORD_ONLY, default='INFO', annotation=str)
112
timeout_param = Parameter('timeout', Parameter.POSITIONAL_OR_KEYWORD, default=30, annotation=int)
113
114
# Add using Parameter objects
115
enhanced_sig = add_signature_parameters(base_sig,
116
first=timeout_param,
117
last=log_param)
118
print(enhanced_sig) # (timeout: int = 30, data: list, *, log_level: str = 'INFO') -> int
119
```
120
121
#### Custom Position Insertion
122
123
```python
124
from makefun import add_signature_parameters
125
from inspect import signature, Parameter
126
127
def func_with_many_params(a: int, b: str, c: float, d: bool = True) -> dict:
128
return {"a": a, "b": b, "c": c, "d": d}
129
130
original_sig = signature(func_with_many_params)
131
132
# Insert parameter at specific position (between b and c)
133
middle_param = Parameter('inserted', Parameter.POSITIONAL_OR_KEYWORD, default="middle", annotation=str)
134
new_sig = add_signature_parameters(original_sig, custom=middle_param, custom_idx=2)
135
print(new_sig) # (a: int, b: str, inserted: str = 'middle', c: float, d: bool = True) -> dict
136
137
# Insert multiple parameters at custom position
138
multi_params = [
139
Parameter('opt1', Parameter.POSITIONAL_OR_KEYWORD, annotation=str),
140
Parameter('opt2', Parameter.POSITIONAL_OR_KEYWORD, default=42, annotation=int)
141
]
142
new_sig2 = add_signature_parameters(original_sig, custom=multi_params, custom_idx=1)
143
print(new_sig2) # (a: int, opt1: str, opt2: int = 42, b: str, c: float, d: bool = True) -> dict
144
```
145
146
#### Automatic Parameter Kind Inference
147
148
```python
149
from makefun import add_signature_parameters
150
from inspect import signature, Parameter
151
152
def base_func(x: int, *, y: str) -> str:
153
"""Function with keyword-only parameter."""
154
return f"{x}: {y}"
155
156
base_sig = signature(base_func)
157
158
# When adding to the beginning, kinds are inferred from first existing parameter
159
new_sig = add_signature_parameters(base_sig, first="prefix: str")
160
print(new_sig) # (prefix: str, x: int, *, y: str) -> str
161
162
# When adding to the end, kinds are inferred from last existing parameter
163
new_sig2 = add_signature_parameters(base_sig, last="suffix: str = '!'")
164
print(new_sig2) # (x: int, *, y: str, suffix: str = '!') -> str
165
166
# Complex example with var-positional
167
def var_func(a: int, *args, **kwargs) -> None:
168
pass
169
170
var_sig = signature(var_func)
171
new_var_sig = add_signature_parameters(var_sig, first="prefix: str")
172
# Results in positional-only for prefix due to *args presence
173
```
174
175
#### Basic Parameter Removal
176
177
```python
178
from makefun import remove_signature_parameters
179
from inspect import signature
180
181
def complex_func(a: int, b: str, c: float = 1.0, d: bool = True, *, e: str = "default") -> dict:
182
return {"a": a, "b": b, "c": c, "d": d, "e": e}
183
184
original_sig = signature(complex_func)
185
186
# Remove single parameter
187
simplified_sig = remove_signature_parameters(original_sig, "c")
188
print(simplified_sig) # (a: int, b: str, d: bool = True, *, e: str = 'default') -> dict
189
190
# Remove multiple parameters
191
minimal_sig = remove_signature_parameters(original_sig, "c", "d", "e")
192
print(minimal_sig) # (a: int, b: str) -> dict
193
```
194
195
#### Combined Operations
196
197
```python
198
from makefun import add_signature_parameters, remove_signature_parameters
199
from inspect import signature
200
201
def original_func(old_param: int, deprecated_arg: str, x: float, y: bool = True) -> str:
202
return f"Result: {old_param}, {deprecated_arg}, {x}, {y}"
203
204
original_sig = signature(original_func)
205
206
# First remove deprecated parameters
207
cleaned_sig = remove_signature_parameters(original_sig, "old_param", "deprecated_arg")
208
print(cleaned_sig) # (x: float, y: bool = True) -> str
209
210
# Then add new parameters
211
modernized_sig = add_signature_parameters(cleaned_sig,
212
first="config: dict",
213
last="verbose: bool = False")
214
print(modernized_sig) # (config: dict, x: float, y: bool = True, verbose: bool = False) -> str
215
```
216
217
#### Working with Complex Signatures
218
219
```python
220
from makefun import add_signature_parameters, remove_signature_parameters
221
from inspect import signature, Parameter
222
223
def complex_original(a: int, b: str = "default", *args, c: float, d: bool = True, **kwargs) -> dict:
224
"""Function with all parameter types."""
225
return {"a": a, "b": b, "args": args, "c": c, "d": d, "kwargs": kwargs}
226
227
original_sig = signature(complex_original)
228
229
# Remove some parameters
230
modified_sig = remove_signature_parameters(original_sig, "b", "d")
231
print(modified_sig) # (a: int, *args, c: float, **kwargs) -> dict
232
233
# Add parameters respecting the existing structure
234
final_sig = add_signature_parameters(modified_sig,
235
first="version: str = '1.0'", # Before positional
236
last="timeout: int = 30") # After keyword-only
237
print(final_sig) # (version: str = '1.0', a: int, *args, c: float, timeout: int = 30, **kwargs) -> dict
238
```
239
240
#### Error Handling
241
242
```python
243
from makefun import add_signature_parameters, remove_signature_parameters
244
from inspect import signature
245
246
def sample_func(x: int, y: str) -> str:
247
return f"{x}: {y}"
248
249
sample_sig = signature(sample_func)
250
251
# Duplicate parameter name error
252
try:
253
add_signature_parameters(sample_sig, first="x: float") # 'x' already exists
254
except ValueError as e:
255
print(f"Duplicate parameter error: {e}")
256
257
# Parameter not found error
258
try:
259
remove_signature_parameters(sample_sig, "nonexistent_param")
260
except KeyError as e:
261
print(f"Parameter not found error: {e}")
262
```
263
264
### Integration with Function Creation
265
266
These utilities are commonly used with `create_function` and other makefun functions:
267
268
```python
269
from makefun import add_signature_parameters, create_function
270
from inspect import signature
271
272
def base_implementation(config, x, y, debug):
273
if debug:
274
print(f"Config: {config}, Processing x={x}, y={y}")
275
return x + y
276
277
def simple_func(x: int, y: int) -> int:
278
"""Simple addition function."""
279
return x + y
280
281
# Get base signature and enhance it
282
base_sig = signature(simple_func)
283
enhanced_sig = add_signature_parameters(base_sig,
284
first="config: dict = {}",
285
last="debug: bool = False")
286
287
# Create new function with enhanced signature
288
enhanced_func = create_function(enhanced_sig, base_implementation,
289
func_name="enhanced_addition")
290
291
print(enhanced_func(5, 3)) # 8 (basic usage)
292
print(enhanced_func(5, 3, debug=True)) # 8 with debug output
293
print(enhanced_func({"mode": "fast"}, 5, 3)) # 8 with config
294
```
295
296
### Practical Applications
297
298
#### API Versioning
299
300
```python
301
from makefun import remove_signature_parameters, add_signature_parameters
302
from inspect import signature
303
304
def api_v1(data: dict, format: str = "json", deprecated_param: bool = True) -> dict:
305
"""Original API version."""
306
return {"version": "v1", "data": data, "format": format}
307
308
# Create v2 API signature by removing deprecated parameter and adding new ones
309
v1_sig = signature(api_v1)
310
v2_base = remove_signature_parameters(v1_sig, "deprecated_param")
311
v2_sig = add_signature_parameters(v2_base, last=["validate: bool = True", "timeout: int = 30"])
312
313
print(v2_sig) # (data: dict, format: str = 'json', validate: bool = True, timeout: int = 30) -> dict
314
```
315
316
#### Configuration Management
317
318
```python
319
from makefun import add_signature_parameters
320
from inspect import signature
321
322
def core_processor(data: list) -> dict:
323
"""Core data processing logic."""
324
return {"processed": len(data), "items": data}
325
326
# Add configuration parameters for different environments
327
base_sig = signature(core_processor)
328
329
# Development environment - add debugging
330
dev_sig = add_signature_parameters(base_sig,
331
first="debug: bool = True",
332
last="log_level: str = 'DEBUG'")
333
334
# Production environment - add performance monitoring
335
prod_sig = add_signature_parameters(base_sig,
336
first="monitor: bool = True",
337
last=["timeout: int = 300", "retries: int = 3"])
338
339
print("Development:", dev_sig)
340
print("Production:", prod_sig)
341
```