Debugging Shed Skin programs involves understanding type inference errors, resolving compilation issues, and debugging the generated C++ code when necessary.
Common Compilation Errors
Type Inference Failures
Shed Skin must infer concrete types for all variables. When it can’t, you’ll see errors.
Error: “Variable has no type”
# Problem: Function never called
def calculate(x, y):
return x + y
# Shed Skin doesn't know what types x and y are!
Solution: Call functions to establish types
def calculate(x, y):
return x + y
if __name__ == '__main__':
# Now Shed Skin knows: x and y are ints
print(calculate(5, 10))
# Or floats
print(calculate(2.5, 3.7))
Always include a if __name__ == '__main__' block that exercises all code paths.
Error: “Incompatible types”
# Problem: Variable assigned different types
def process(use_float):
if use_float:
result = 3.14 # float
else:
result = "N/A" # str - ERROR!
return result
Solution: Keep types consistent
# Option 1: Use same type
def process(use_float):
if use_float:
result = 3.14
else:
result = 0.0 # Also float
return result
# Option 2: Split into separate functions
def process_float(value):
return value * 3.14
def process_string(text):
return text.upper()
Error: “Cannot mix types in collection”
# Problem: Mixed-type list
data = [1, 2.5, "three"] # ERROR!
# Problem: Mixed-type dict values
config = {
'timeout': 30, # int
'host': 'localhost' # str - ERROR!
}
Solution: Use classes for heterogeneous data
class Config:
def __init__(self):
self.timeout = 30
self.host = 'localhost'
config = Config()
Module Import Errors
Error: “Cannot locate module”
import mymodule # ERROR: Can't find mymodule.py
Solutions:
Ensure the module is in the same directory or in a known location:
ls
# main.py
# mymodule.py ← Must be present
Use -L Flag for Custom Paths
shedskin build -L /path/to/modules main
For packages, ensure __init__.py exists:
mypackage/
__init__.py ← Required
module1.py
module2.py
Error: “Unsupported module”
import pandas # ERROR: Not supported by Shed Skin
Solution: Use supported modules only
See Supported Modules for the list of supported modules. For unsupported modules:
- Create an extension module (using
-e flag)
- Import it in pure Python code
- Use the unsupported library in the Python code
# fast_module.py - Compiled with Shed Skin
def compute_intensive_task(data):
result = []
for x in data:
# Expensive computation
result.append(x ** 2 + x * 3.14)
return result
if __name__ == '__main__':
compute_intensive_task([1.0, 2.0, 3.0])
# main.py - Pure Python with pandas
import pandas as pd
import fast_module # Compiled extension
df = pd.read_csv('data.csv')
processed = fast_module.compute_intensive_task(df['values'].tolist())
df['processed'] = processed
None Type Errors
Error: “Cannot mix None with scalar type”
# Problem: None with int
x = 10
if something:
x = None # ERROR!
# Problem: Optional scalar parameter
def process(threshold=None): # ERROR if called with int!
pass
process(42)
Solution: Use sentinel values for scalars
# Use -1 or another sentinel
x = 10
if something:
x = -1 # Valid sentinel
def process(threshold=-1):
if threshold == -1:
threshold = 100 # Default
# ... use threshold
if __name__ == '__main__':
process(42)
process(-1)
None can only be mixed with objects, lists, and other non-scalar types.
Debugging Type Inference
Use Analyze Command
Check for errors without generating code:
shedskin analyze myprogram.py
This validates:
- Type consistency
- Module imports
- Supported features
Generate Annotated Source
See what types Shed Skin inferred:
shedskin translate -a myprogram
This creates myprogram.ss.py with type annotations:
# Original
def calculate(x, y):
result = x + y
return result
# Annotated (myprogram.ss.py)
def calculate(x, y): # x: int, y: int → int
result = x + y # result: int
return result
Enable Debug Output
Get detailed type inference information:
shedskin translate -d 1 myprogram # Level 1 debugging
shedskin translate -d 2 myprogram # Level 2 (more verbose)
C++ Compilation Errors
Missing Dependencies
Error: “gc.h: No such file”
fatal error: gc.h: No such file or directory
Solution: Install Boehm GC development files
# Ubuntu/Debian
sudo apt-get install libgc-dev
# Fedora/RedHat
sudo dnf install gc-devel
# macOS
brew install bdw-gc
Error: “pcre2.h: No such file”
Solution: Install PCRE2 development files
# Ubuntu/Debian
sudo apt-get install libpcre2-dev
# Fedora/RedHat
sudo dnf install pcre2-devel
# macOS
brew install pcre2
Error: “Python.h: No such file”
Only for extension modules (-e flag):
# Ubuntu/Debian
sudo apt-get install python3-dev
# Fedora/RedHat
sudo dnf install python3-devel
Template/Syntax Errors
Sometimes the generated C++ has issues:
error: no matching function for call to 'max'
Causes:
- Type inference created invalid type combination
- Edge case in code generation
Solution: Simplify the problematic code
# Before: Complex expression
result = max([func(x) for x in data if x > 0], default=0)
# After: Break it down
valid_data = [x for x in data if x > 0]
processed = [func(x) for x in valid_data]
if processed:
result = max(processed)
else:
result = 0
Runtime Debugging
Segmentation Faults
Segfaults usually indicate:
- Null pointer dereference (accessing None)
- Invalid array access (especially with
--nobounds)
- Stack overflow (deep recursion)
First, verify the Python version works:
If Python crashes too, fix the Python code first.
Rebuild Without Optimizations
Remove safety-disabling flags:
# Don't use --nobounds or --nowrap
shedskin build myprogram
If it works now, the issue is bounds-related.
shedskin translate myprogram
cd build/
g++ -g -O0 myprogram.cpp -o myprogram -lgc -lpcre2-8
gdb ./myprogram
(gdb) run
# Program crashes
(gdb) backtrace # See where it crashed
(gdb) frame 0 # Inspect the crash location
(gdb) print variable_name # Inspect variables
def process(data):
print("Processing", len(data), "items")
for i, item in enumerate(data):
print(f"Item {i}: {item}")
result = compute(item)
print(f"Result: {result}")
return result
Incorrect Results
If compiled code produces different output than Python:
Check Integer Overflow
# With default int32
x = 2_000_000_000
y = x * 2 # Overflow!
# Solution: Use --int64
shedskin build --int64 myprogram
Check Evaluation Order
Argument evaluation order differs between Python and C++.
# Problem: Depends on evaluation order
count = 0
def get_next():
global count
count += 1
return count
print(get_next(), get_next()) # Order undefined!
Solution: Make order explicit
count = 0
def get_next():
global count
count += 1
return count
a = get_next()
b = get_next()
print(a, b) # Now deterministic
Check Float Precision
With -ffast-math, floating-point results may differ slightly:
# Exact IEEE floating-point
shedskin build myprogram
# Fast but less precise
echo "-O3 -ffast-math" > FLAGS
shedskin build myprogram
Memory Issues
Use Valgrind to detect memory problems:
shedskin build myprogram
valgrind --leak-check=full build/myprogram
For extension modules, disable GC first:
shedskin build -e --nogc mymodule
valgrind --leak-check=full python main.py
Extension Module Issues
Import Fails
>>> import mymodule
ImportError: libgc.so.1: cannot open shared object file
Solution: Check library path
# Find missing libraries
ldd build/mymodule.so
# Add to LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
python
>>> import mymodule # Should work now
Type Conversion Errors
>>> import mymodule
>>> mymodule.process("test")
Segmentation fault
Cause: Type mismatch between Python call and C++ expectation
Solution: Check what types the function expects
# Generate annotated source
shedskin translate -a -e mymodule
cat mymodule.ss.py # Check parameter types
Ensure Python calls match:
# If function expects list of ints
mymodule.process([1, 2, 3]) # Correct
mymodule.process("123") # Wrong!
Global Variable Issues
# mymodule.py
COUNTER = 0
def increment():
global COUNTER
COUNTER += 1
def get_counter():
return COUNTER
>>> import mymodule
>>> mymodule.increment()
>>> mymodule.COUNTER # Still 0!
Cause: Globals are converted once at initialization
Solution: Use getter functions
>>> mymodule.increment()
>>> mymodule.get_counter() # Returns 1
Debugging Workflow
Ensure the Python version works correctly:
shedskin analyze myprogram.py
Compile Without Optimizations
Test the compiled version:
Verify identical behavior:
python myprogram.py > python_output.txt
build/myprogram > cpp_output.txt
diff python_output.txt cpp_output.txt
Add Optimizations Gradually
Once it works, add optimizations:
# Add --nobounds
shedskin build --nobounds myprogram
build/myprogram # Test
# Add --nowrap
shedskin build --nobounds --nowrap myprogram
build/myprogram # Test
Common Workarounds
Exclude code from compilation:
print("Results:", results)
#{
import matplotlib.pyplot as plt
plt.plot(results)
plt.show()
#}
The visualization code runs in Python but is ignored by Shed Skin.
Separate Test Code
Use separate test files:
# mymodule.py - compilable
def compute(data):
return [x * 2 for x in data]
if __name__ == '__main__':
print(compute([1.0, 2.0, 3.0]))
# test_mymodule.py - Python only
import mymodule
import pytest
def test_compute():
assert mymodule.compute([1, 2, 3]) == [2, 4, 6]
Add comments documenting expected types:
def process(data, threshold):
# data: list[float]
# threshold: float
# returns: list[float]
return [x for x in data if x > threshold]
While Shed Skin ignores these, they help you maintain type consistency.
Getting Help
If you encounter issues:
- Check documentation - Review restrictions
- Search examples - Look for similar code in
/examples/
- Report bugs - File issues at https://github.com/shedskin/shedskin/issues
- Ask questions - Join the mailing list
When reporting bugs, include:
- Your Shed Skin version (
shedskin --version)
- Minimal reproducible example
- Full error message
- Platform (OS, Python version)