Small library to dynamically create python functions.
npx @tessl/cli install tessl/pypi-makefun@1.16.00
# Makefun
1
2
A comprehensive Python library for dynamically creating functions at runtime, enabling developers to programmatically generate functions with custom signatures, parameters, and behavior. Makefun provides advanced capabilities for function introspection, signature manipulation, and dynamic code generation, making it particularly useful for creating decorators, proxies, and meta-programming utilities.
3
4
## Package Information
5
6
- **Package Name**: makefun
7
- **Language**: Python
8
- **Installation**: `pip install makefun`
9
10
## Core Imports
11
12
```python
13
import makefun
14
```
15
16
Common import pattern for main functionality:
17
18
```python
19
from makefun import create_function, with_signature, wraps, partial
20
```
21
22
For signature manipulation utilities:
23
24
```python
25
from makefun import add_signature_parameters, remove_signature_parameters
26
```
27
28
For exception handling:
29
30
```python
31
from makefun import UndefinedSymbolError, UnsupportedForCompilation, SourceUnavailable
32
```
33
34
For version information:
35
36
```python
37
from makefun import __version__
38
```
39
40
## Basic Usage
41
42
```python
43
from makefun import create_function, with_signature, wraps
44
from inspect import signature
45
46
# Create a function from a signature string
47
def my_impl(a, b, c=None):
48
return f"Called with a={a}, b={b}, c={c}"
49
50
# Generate a function with specific signature
51
dynamic_func = create_function("foo(x: int, y: str, z=42)", my_impl)
52
print(dynamic_func(1, "hello")) # "Called with a=1, b=hello, c=42"
53
54
# Use as decorator to change function signature
55
@with_signature("(name: str, age: int = 0)")
56
def greet(name, age):
57
return f"Hello {name}, you are {age} years old"
58
59
print(greet("Alice", 30)) # "Hello Alice, you are 30 years old"
60
61
# Enhanced wrapper with signature preservation
62
@wraps(greet, new_sig="(person_name: str, person_age: int = 25)")
63
def enhanced_greet(person_name, person_age):
64
return greet(person_name, person_age)
65
66
print(enhanced_greet("Bob")) # "Hello Bob, you are 25 years old"
67
```
68
69
## Architecture
70
71
Makefun's design centers around three core concepts:
72
73
- **Dynamic Function Creation**: Functions are generated at runtime from signature specifications, either as strings or Signature objects
74
- **Signature Preservation**: All generated functions maintain proper introspection capabilities, working seamlessly with `inspect.signature()` and `help()`
75
- **Enhanced Wrappers**: Improved alternatives to `functools.wraps` and `functools.partial` with better signature control and documentation
76
77
The library handles complex scenarios including generators, coroutines, async generators, and maintains compatibility across Python versions (2.7+ and 3.5+) using appropriate backports.
78
79
## Capabilities
80
81
### Dynamic Function Creation
82
83
Core functionality for creating functions dynamically from signature specifications, supporting both string and Signature object inputs with comprehensive metadata control.
84
85
```python { .api }
86
def create_function(
87
func_signature: Union[str, Signature],
88
func_impl: Callable[[Any], Any],
89
func_name: str = None,
90
inject_as_first_arg: bool = False,
91
add_source: bool = True,
92
add_impl: bool = True,
93
doc: str = None,
94
qualname: str = None,
95
co_name: str = None,
96
module_name: str = None,
97
**attrs
98
) -> FunctionType:
99
"""
100
Creates a function with signature func_signature that calls func_impl.
101
102
Parameters:
103
- func_signature: Union[str, Signature], signature specification
104
- func_impl: Callable[[Any], Any], implementation function to call
105
- func_name: str, optional name override
106
- inject_as_first_arg: bool, inject created function as first arg
107
- add_source: bool, add __source__ attribute
108
- add_impl: bool, add __func_impl__ attribute
109
- doc: str, optional docstring override
110
- qualname: str, optional qualified name
111
- co_name: str, optional code object name
112
- module_name: str, optional module name
113
- **attrs: additional attributes to set
114
115
Returns:
116
FunctionType: Generated function with specified signature
117
"""
118
```
119
120
[Dynamic Function Creation](./function-creation.md)
121
122
### Signature-based Decorators
123
124
Decorators for modifying function signatures while preserving metadata and introspection capabilities, offering enhanced alternatives to standard Python decorators.
125
126
```python { .api }
127
def with_signature(
128
func_signature: Union[str, Signature],
129
func_name: str = None,
130
inject_as_first_arg: bool = False,
131
add_source: bool = True,
132
add_impl: bool = True,
133
doc: str = None,
134
qualname: str = None,
135
co_name: str = None,
136
module_name: str = None,
137
**attrs
138
) -> Callable[[Callable], Callable]:
139
"""
140
Decorator to change function signature.
141
142
Parameters:
143
- func_signature: Union[str, Signature], new signature specification
144
- func_name: str, optional name override
145
- inject_as_first_arg: bool, inject created function as first arg
146
- add_source: bool, add __source__ attribute
147
- add_impl: bool, add __func_impl__ attribute
148
- doc: str, optional docstring override
149
- qualname: str, optional qualified name
150
- co_name: str, optional code object name
151
- module_name: str, optional module name
152
- **attrs: additional attributes to set
153
154
Returns:
155
Callable[[Callable], Callable]: Decorator function
156
"""
157
```
158
159
[Signature-based Decorators](./decorators.md)
160
161
### Enhanced Wrapping
162
163
Advanced function wrapping capabilities that extend functools.wraps with signature modification, parameter addition/removal, and better introspection support.
164
165
```python { .api }
166
def wraps(
167
wrapped_fun: Callable,
168
new_sig: Union[str, Signature] = None,
169
prepend_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
170
append_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
171
remove_args: Union[str, Iterable[str]] = None,
172
func_name: str = None,
173
co_name: str = None,
174
inject_as_first_arg: bool = False,
175
add_source: bool = True,
176
add_impl: bool = True,
177
doc: str = None,
178
qualname: str = None,
179
module_name: str = None,
180
**attrs
181
) -> Callable[[Callable], Callable]:
182
"""
183
Enhanced functools.wraps with signature modification capabilities.
184
185
Parameters:
186
- wrapped_fun: Callable, function to wrap
187
- new_sig: Union[str, Signature], new signature specification
188
- prepend_args: Union[str, Parameter, Iterable], arguments to prepend
189
- append_args: Union[str, Parameter, Iterable], arguments to append
190
- remove_args: Union[str, Iterable[str]], arguments to remove
191
- func_name: str, optional name override
192
- co_name: str, optional code object name
193
- inject_as_first_arg: bool, inject created function as first arg
194
- add_source: bool, add __source__ attribute
195
- add_impl: bool, add __func_impl__ attribute
196
- doc: str, optional docstring override
197
- qualname: str, optional qualified name
198
- module_name: str, optional module name
199
- **attrs: additional attributes to set
200
201
Returns:
202
Callable[[Callable], Callable]: Decorator function
203
"""
204
205
def create_wrapper(
206
wrapped: Callable,
207
wrapper: Callable,
208
new_sig: Union[str, Signature] = None,
209
prepend_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
210
append_args: Union[str, Parameter, Iterable[Union[str, Parameter]]] = None,
211
remove_args: Union[str, Iterable[str]] = None,
212
func_name: str = None,
213
inject_as_first_arg: bool = False,
214
add_source: bool = True,
215
add_impl: bool = True,
216
doc: str = None,
217
qualname: str = None,
218
co_name: str = None,
219
module_name: str = None,
220
**attrs
221
) -> Callable:
222
"""
223
Creates signature-preserving wrapper function.
224
Equivalent to wraps(wrapped, **kwargs)(wrapper).
225
226
Parameters: Same as wraps()
227
228
Returns:
229
Callable: Generated wrapper function
230
"""
231
```
232
233
[Enhanced Wrapping](./wrapping.md)
234
235
### Partial Function Support
236
237
Enhanced partial function implementation with better introspection, documentation generation, and signature handling compared to functools.partial.
238
239
```python { .api }
240
def partial(
241
f: Callable,
242
*preset_pos_args: Any,
243
**preset_kwargs: Any
244
) -> Callable:
245
"""
246
Enhanced functools.partial with better introspection and documentation.
247
248
Parameters:
249
- f: Callable, function to partially apply
250
- *preset_pos_args: Any, positional arguments to preset
251
- **preset_kwargs: Any, keyword arguments to preset
252
253
Returns:
254
Callable: Partial function with enhanced metadata
255
"""
256
257
def with_partial(
258
*preset_pos_args: Any,
259
**preset_kwargs: Any
260
) -> Callable[[Callable], Callable]:
261
"""
262
Decorator version of partial function.
263
264
Parameters:
265
- *preset_pos_args: Any, positional arguments to preset
266
- **preset_kwargs: Any, keyword arguments to preset
267
268
Returns:
269
Callable[[Callable], Callable]: Decorator function
270
"""
271
```
272
273
[Partial Function Support](./partial.md)
274
275
### Signature Manipulation
276
277
Utilities for programmatically modifying function signatures by adding or removing parameters, enabling dynamic signature construction.
278
279
```python { .api }
280
def add_signature_parameters(
281
s: Signature,
282
first: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (),
283
last: Union[str, Parameter, Iterable[Union[str, Parameter]]] = (),
284
custom: Union[Parameter, Iterable[Parameter]] = (),
285
custom_idx: int = -1
286
) -> Signature:
287
"""
288
Adds parameters to an existing signature.
289
290
Parameters:
291
- s: Signature, original signature to modify
292
- first: Union[str, Parameter, Iterable], parameters to add at beginning
293
- last: Union[str, Parameter, Iterable], parameters to add at end
294
- custom: Union[Parameter, Iterable[Parameter]], parameters to add at custom position
295
- custom_idx: int, position for custom parameters
296
297
Returns:
298
Signature: New signature with added parameters
299
"""
300
301
def remove_signature_parameters(
302
s: Signature,
303
*param_names: str
304
) -> Signature:
305
"""
306
Removes parameters from an existing signature.
307
308
Parameters:
309
- s: Signature, original signature to modify
310
- *param_names: str, names of parameters to remove
311
312
Returns:
313
Signature: New signature with removed parameters
314
"""
315
```
316
317
[Signature Manipulation](./signature-utils.md)
318
319
### Compilation Utilities
320
321
Function compilation utilities for masking implementation details from debuggers while preserving source code access for development purposes.
322
323
```python { .api }
324
def compile_fun(
325
recurse: Union[bool, Callable] = True,
326
except_names: Iterable[str] = ()
327
) -> Union[Callable, Callable[[Callable], Callable]]:
328
"""
329
Decorator to compile functions for debugging convenience.
330
331
Parameters:
332
- recurse: Union[bool, Callable], recursively compile referenced functions
333
- except_names: Iterable[str], function names to exclude from compilation
334
335
Returns:
336
Union[Callable, Callable[[Callable], Callable]]: Decorator or compiled function
337
"""
338
```
339
340
[Compilation Utilities](./compilation.md)
341
342
## Version Information
343
344
```python { .api }
345
__version__: str
346
"""Package version string, managed by setuptools_scm."""
347
```
348
349
## Exception Classes
350
351
```python { .api }
352
class UndefinedSymbolError(NameError):
353
"""Exception raised by compile_fun when function requires undefined symbols."""
354
355
class UnsupportedForCompilation(TypeError):
356
"""Exception raised by compile_fun when target is not supported for compilation."""
357
358
class SourceUnavailable(OSError):
359
"""Exception raised by compile_fun when function source code is not available."""
360
```