0
# Compilation Utilities
1
2
Function compilation utilities for masking implementation details from debuggers while preserving source code access for development purposes. These utilities provide a way to create "compiled" versions of functions that hide their implementation from debugging tools while maintaining functionality.
3
4
```python
5
from typing import Union, Callable, Iterable
6
```
7
8
## Capabilities
9
10
### Function Compilation Decorator
11
12
Decorator that compiles functions to mask their implementation from debuggers while preserving source code access.
13
14
```python { .api }
15
def compile_fun(recurse: Union[bool, Callable] = True,
16
except_names: Iterable[str] = ()) -> Union[Callable, Callable[[Callable], Callable]]:
17
"""
18
Decorator to compile functions for debugging convenience.
19
20
Compiles any existing function so that users can't debug through it,
21
which can be handy to mask some code from users for convenience.
22
The source code is preserved in the __source__ attribute.
23
24
Parameters:
25
- recurse: Union[bool, Callable], default True
26
If True, recursively compile referenced functions in closure.
27
If Callable, apply compilation immediately (no-args decorator usage).
28
- except_names: Iterable[str], default ()
29
Function names to exclude from recursive compilation
30
31
Returns:
32
Union[Callable, Callable[[Callable], Callable]]:
33
- If called with parentheses: returns decorator function
34
- If called without parentheses: returns compiled function directly
35
36
Raises:
37
UnsupportedForCompilation: If target is not a function
38
UndefinedSymbolError: If function references undefined symbols
39
SourceUnavailable: If function source code cannot be retrieved
40
41
Note:
42
- Compilation does not improve performance (per Python design)
43
- Primary use is hiding implementation details during debugging
44
- Source code remains available via __source__ attribute
45
- Recursively compiles closure functions by default
46
"""
47
```
48
49
### Exception Classes
50
51
```python { .api }
52
class UndefinedSymbolError(NameError):
53
"""
54
Raised by compile_fun when function requires symbols not yet defined.
55
56
This typically occurs when compilation is applied before all required
57
symbols (variables, functions, classes) have been defined in the scope.
58
"""
59
60
class UnsupportedForCompilation(TypeError):
61
"""
62
Raised by compile_fun when the decorated target is not supported.
63
64
Only function objects can be compiled. Other types (classes, modules,
65
built-ins, etc.) are not supported.
66
"""
67
68
class SourceUnavailable(OSError):
69
"""
70
Raised by compile_fun when function source code is not available.
71
72
This occurs when inspect.getsource() cannot retrieve the source code,
73
typically for built-in functions, C extensions, or functions defined
74
in interactive sessions without source preservation.
75
"""
76
```
77
78
### Usage Examples
79
80
#### Basic Function Compilation
81
82
```python
83
from makefun import compile_fun
84
85
@compile_fun
86
def secret_algorithm(x: int, y: int) -> int:
87
"""Perform secret calculation."""
88
# Complex implementation that we want to hide
89
intermediate = x * 2 + y
90
result = intermediate ** 2 - x
91
return result % 1000
92
93
# Function works normally
94
print(secret_algorithm(5, 3)) # Result: 121
95
96
# Source code is preserved for reference
97
print(secret_algorithm.__source__)
98
# Shows the original function definition
99
100
# But debugger cannot step into the implementation
101
# (implementation is compiled bytecode, not original source)
102
```
103
104
#### Compilation with Parameters
105
106
```python
107
from makefun import compile_fun
108
109
# Compile with recursive compilation disabled
110
@compile_fun(recurse=False)
111
def simple_function(x: int) -> int:
112
"""Simple function without recursive compilation."""
113
return x * 2
114
115
# Compile with exception list
116
def helper_function(x):
117
return x + 1
118
119
@compile_fun(recurse=True, except_names=["helper_function"])
120
def main_function(x: int) -> int:
121
"""Main function that uses helper."""
122
return helper_function(x) * 2
123
124
print(main_function(5)) # 12
125
# main_function is compiled, but helper_function is not
126
```
127
128
#### No-Arguments Decorator Usage
129
130
```python
131
from makefun import compile_fun
132
133
# Direct application without parentheses
134
@compile_fun
135
def immediate_compilation(data: list) -> int:
136
"""Function compiled immediately."""
137
return sum(data) if data else 0
138
139
print(immediate_compilation([1, 2, 3, 4])) # 10
140
```
141
142
#### Hiding Complex Logic
143
144
```python
145
from makefun import compile_fun
146
147
@compile_fun
148
def proprietary_calculation(values: list, config: dict) -> dict:
149
"""Proprietary algorithm for data processing."""
150
# Complex proprietary logic that should be hidden
151
weights = config.get("weights", [1.0] * len(values))
152
153
processed = []
154
for i, val in enumerate(values):
155
weight = weights[i] if i < len(weights) else 1.0
156
# Complex transformation
157
transformed = (val * weight + config.get("bias", 0)) ** config.get("power", 1)
158
processed.append(transformed)
159
160
return {
161
"processed_values": processed,
162
"total": sum(processed),
163
"average": sum(processed) / len(processed) if processed else 0,
164
"config_used": config
165
}
166
167
# Function works normally but implementation is hidden from debugger
168
config = {"weights": [1.5, 2.0, 1.0], "bias": 10, "power": 1.2}
169
result = proprietary_calculation([100, 200, 150], config)
170
print(f"Total: {result['total']:.2f}")
171
```
172
173
#### Recursive Compilation Example
174
175
```python
176
from makefun import compile_fun
177
178
def helper1(x):
179
return x * 2
180
181
def helper2(x):
182
return x + 10
183
184
@compile_fun(recurse=True)
185
def main_with_helpers(x: int) -> int:
186
"""Function that uses helper functions."""
187
# Both helper functions will be compiled recursively
188
intermediate = helper1(x)
189
return helper2(intermediate)
190
191
print(main_with_helpers(5)) # 20 (5*2 + 10)
192
193
# All functions in the closure are compiled
194
# main_with_helpers, helper1, and helper2 are all masked from debugger
195
```
196
197
#### Selective Compilation
198
199
```python
200
from makefun import compile_fun
201
202
def public_utility(x):
203
"""This should remain debuggable."""
204
return x ** 2
205
206
def private_helper(x):
207
"""This should be hidden."""
208
return x * 3.14159
209
210
@compile_fun(recurse=True, except_names=["public_utility"])
211
def mixed_function(x: float) -> float:
212
"""Function with mixed compilation needs."""
213
# public_utility remains debuggable
214
# private_helper gets compiled and hidden
215
squared = public_utility(x)
216
return private_helper(squared)
217
218
print(mixed_function(2.0)) # ~12.57
219
# public_utility can be debugged, private_helper cannot
220
```
221
222
#### Error Handling
223
224
```python
225
from makefun import compile_fun, UnsupportedForCompilation, UndefinedSymbolError, SourceUnavailable
226
227
# Trying to compile non-function
228
try:
229
compiled_class = compile_fun(str) # str is not a function
230
except UnsupportedForCompilation as e:
231
print(f"Cannot compile non-function: {e}")
232
233
# Undefined symbol error
234
def function_with_undefined_ref():
235
return undefined_variable # This variable doesn't exist
236
237
try:
238
compiled_func = compile_fun(function_with_undefined_ref)
239
except UndefinedSymbolError as e:
240
print(f"Undefined symbol: {e}")
241
242
# Built-in function source unavailable
243
try:
244
compiled_builtin = compile_fun(len) # Built-in function
245
except SourceUnavailable as e:
246
print(f"Source not available: {e}")
247
```
248
249
#### Integration with Other Makefun Features
250
251
```python
252
from makefun import compile_fun, create_function, with_signature
253
254
def secret_implementation(name, age, location):
255
"""Secret implementation logic."""
256
# Complex logic we want to hide
257
score = len(name) * age + hash(location) % 1000
258
return f"Score for {name}: {score}"
259
260
# First create function with specific signature
261
public_func = create_function("calculate_score(person_name: str, person_age: int, city: str = 'Unknown')",
262
secret_implementation)
263
264
# Then compile to hide implementation
265
@compile_fun
266
def compiled_calculator(person_name: str, person_age: int, city: str = 'Unknown') -> str:
267
return public_func(person_name, person_age, city)
268
269
print(compiled_calculator("Alice", 25, "New York"))
270
# Function works but implementation is hidden from debugger
271
```
272
273
#### Library Development Pattern
274
275
```python
276
from makefun import compile_fun
277
278
class DataProcessor:
279
"""Public API class with hidden implementations."""
280
281
@compile_fun
282
def _internal_algorithm(self, data: list) -> list:
283
"""Internal algorithm that should be hidden."""
284
# Proprietary processing logic
285
return [x * 2 + 1 for x in data if x > 0]
286
287
@compile_fun
288
def _optimization_step(self, data: list) -> list:
289
"""Internal optimization that should be hidden."""
290
# Complex optimization logic
291
return sorted(data, reverse=True)[:10]
292
293
def process(self, data: list) -> list:
294
"""Public API method - not compiled."""
295
# This method remains debuggable for users
296
if not data:
297
return []
298
299
# Internal methods are compiled and hidden
300
processed = self._internal_algorithm(data)
301
optimized = self._optimization_step(processed)
302
return optimized
303
304
# Usage
305
processor = DataProcessor()
306
result = processor.process([1, -2, 3, 4, -5, 6])
307
print(result)
308
309
# Users can debug process() method but not the internal algorithms
310
```
311
312
### Development vs Production Usage
313
314
The compilation feature is particularly useful for distinguishing between development and production environments:
315
316
```python
317
from makefun import compile_fun
318
import os
319
320
# Conditional compilation based on environment
321
PRODUCTION = os.getenv("ENVIRONMENT") == "production"
322
323
def apply_compilation(func):
324
"""Apply compilation only in production."""
325
if PRODUCTION:
326
return compile_fun(func)
327
return func
328
329
@apply_compilation
330
def sensitive_algorithm(data: dict) -> dict:
331
"""Algorithm that should be hidden in production."""
332
# Development: debuggable
333
# Production: compiled and hidden
334
return {"processed": True, "data_size": len(data)}
335
```
336
337
### Performance Considerations
338
339
**Important**: Function compilation does NOT improve performance. According to Python's design principles, compiled bytecode runs at the same speed as interpreted code. The primary purpose is to hide implementation details during debugging sessions.
340
341
```python
342
from makefun import compile_fun
343
import time
344
345
def regular_function(n: int) -> int:
346
"""Regular function for performance comparison."""
347
return sum(i * i for i in range(n))
348
349
@compile_fun
350
def compiled_function(n: int) -> int:
351
"""Compiled function for performance comparison."""
352
return sum(i * i for i in range(n))
353
354
# Performance is identical
355
n = 10000
356
357
start = time.time()
358
result1 = regular_function(n)
359
time1 = time.time() - start
360
361
start = time.time()
362
result2 = compiled_function(n)
363
time2 = time.time() - start
364
365
print(f"Regular: {time1:.6f}s, Compiled: {time2:.6f}s")
366
print(f"Results equal: {result1 == result2}")
367
# Performance difference is negligible
368
```