Skip to main content

obfus

A comprehensive Python code obfuscation engine.

Python 3.9+ License: MIT

Features

  • String Obfuscation - Multiple encoding methods (XOR, Base64, ROT13, multi-layer)
  • Name Mangling - Local variables, arguments, code names, attributes
  • Code Object Obfuscation - Bytecode encryption and protection
  • Module Protection - Prevent modification and inspection
  • Wrap Mode - Dynamic deobfuscation at runtime
  • RFT (Refactoring) - Complete identifier renaming
  • Import Obfuscation - Hide import statements
  • Control Flow Obfuscation - Opaque predicates, dead code injection
  • Zero Dependencies - Pure Python, no external packages required

Installation

pip install obfus

Or install from source:

git clone https://github.com/rodmena-limited/obfus.git
cd obfus
pip install -e .

Quick Start

Basic Usage

from obfus import ObfuscationConfig, ObfuscationEngine

# Use preset configurations
config = ObfuscationConfig.minimal()    # Light obfuscation
config = ObfuscationConfig.standard()   # Balanced obfuscation
config = ObfuscationConfig.aggressive() # Heavy obfuscation

# Create engine and obfuscate
engine = ObfuscationEngine(config)
obfuscated = engine.obfuscate_source('''
def hello(name):
    return f"Hello, {name}!"

print(hello("World"))
''')
print(obfuscated)

Convenience Functions

from obfus import obfuscate, obfuscate_file, obfuscate_directory

# Obfuscate a string
result = obfuscate("print('Hello')")

# Obfuscate a file
obfuscate_file("input.py", "output.py")

# Obfuscate entire directory
obfuscate_directory("src/", "dist/")

Command Line

# Obfuscate a single file
obfus input.py -o output.py

# Obfuscate a directory
obfus src/ -o dist/

# With specific preset
obfus input.py -o output.py --preset aggressive

Configuration

Presets

Preset Description Use Case
minimal() Light obfuscation, preserves readability Development, debugging
standard() Balanced protection and performance General distribution
aggressive() Heavy obfuscation, harder to reverse Production releases
maximum() Maximum protection, slower execution High-security applications

Custom Configuration

from obfus import ObfuscationConfig, ObfuscationEngine, WrapMode

config = ObfuscationConfig(
    # Name obfuscation
    mix_localnames=True,      # Obfuscate local variable names
    mix_argnames=False,       # Keep argument names (for keyword args)
    mix_coname=1,             # Hide code object names (0-2)
    mix_attr=False,           # Obfuscate attribute names

    # String obfuscation
    mix_str=True,             # Obfuscate string constants
    mix_str_threshold=8,      # Min string length to obfuscate

    # Module protection
    obf_module=True,          # Obfuscate module bytecode
    obf_code=1,               # Code object obfuscation level (0-2)
    wrap_mode=WrapMode.SIMPLE, # Dynamic deobfuscation

    # Advanced features
    enable_rft=False,         # Full identifier renaming
    enable_control_flow=False, # Control flow obfuscation
    enable_dead_code=False,   # Dead code injection
)

engine = ObfuscationEngine(config)

Configuration Options Reference

Name Obfuscation

Option Type Default Description
mix_localnames bool True Obfuscate local variable names
mix_argnames bool False Obfuscate function argument names
mix_coname int 0 Hide code object names (0=off, 1=partial, 2=full)
mix_attr bool False Obfuscate attribute access names

String Obfuscation

Option Type Default Description
mix_str bool False Enable string constant obfuscation
mix_str_threshold int 8 Minimum string length to obfuscate

Module Protection

Option Type Default Description
obf_module bool True Obfuscate module-level bytecode
obf_code int 1 Code object encryption level (0-2)
wrap_mode WrapMode SIMPLE Dynamic deobfuscation mode
restrict_module RestrictionLevel BASIC Module access restrictions
readonly_module bool False Make module attributes read-only

Advanced Features

Option Type Default Description
enable_rft bool False Enable full refactoring/renaming
enable_control_flow bool False Add control flow obfuscation
enable_dead_code bool False Inject dead code blocks
enable_opaque_predicates bool False Add opaque predicates

RFT (Refactoring) Mode

RFT mode performs complete identifier renaming across your codebase:

config = ObfuscationConfig(
    enable_rft=True,
    rft_excludes={'main', 'setup'},  # Names to preserve
    rft_preserve_exports=True,        # Keep __all__ names
)

RFT Options

Option Type Default Description
rft_excludes Set[str] {} Names to exclude from renaming
rft_auto_exclude int 1 Auto-exclude behavior (0-2)
rft_preserve_exports bool True Preserve names in __all__

Limitations and Compatibility

Works With

  • Pure Python code
  • Standard library usage
  • Internal class hierarchies
  • Async/await patterns
  • Generators and iterators
  • Context managers
  • Decorators
  • Metaclasses
  • Dataclasses and enums

May Break

Scenario Risk Level Mitigation
exec()/eval() with string names High Use rft_excludes
getattr()/setattr() with strings High Use rft_excludes
Serialization (pickle, JSON) High Use minimal() preset
Framework magic (Django, Flask) High Use minimal() or skip
pytest fixtures Medium Don't obfuscate test files
CLI tools (Click, argparse) Medium Keep argument names
External API contracts Medium Use rft_excludes
Reflection-based libraries Medium Test thoroughly

Safe Usage Guidelines

# For libraries with external interfaces
config = ObfuscationConfig.minimal()

# For standalone scripts
config = ObfuscationConfig.aggressive()

# For maximum protection (internal tools only)
config = ObfuscationConfig.maximum()

Performance

Obfuscation adds minimal runtime overhead:

Operation Overhead
Import time ~0-5%
Simple operations ~0-10%
String-heavy code ~10-20%
With wrap mode ~5-15%

Test suite performance is typically within 5% of original code.

Examples

Obfuscate a Package

from obfus import obfuscate_directory, ObfuscationConfig

config = ObfuscationConfig.standard()
obfuscate_directory(
    "mypackage/",
    "dist/mypackage/",
    config=config,
    recursive=True,
)

Preserve Specific Names

config = ObfuscationConfig(
    enable_rft=True,
    rft_excludes={
        'main',
        'run',
        'setup',
        'teardown',
        '__init__',
        '__call__',
    },
)

Skip Certain Files

from pathlib import Path
from obfus import ObfuscationEngine, ObfuscationConfig

config = ObfuscationConfig.standard()
engine = ObfuscationEngine(config)

for py_file in Path("src").rglob("*.py"):
    # Skip test files and configs
    if "test" in py_file.name or py_file.name == "config.py":
        continue

    source = py_file.read_text()
    obfuscated = engine.obfuscate_source(source)

    output = Path("dist") / py_file.relative_to("src")
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_text(obfuscated)

Testing

# Run all tests
pytest

# Run with coverage
pytest --cov=obfus --cov-report=html

# Run specific test class
pytest tests/test_obfuscator.py::TestAllFeatures -v

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Metadata

Release files for obfus 3.7.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for obfus 3.7.2
File Size Uploaded
obfus-3.7.2.tar.gz 39.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for obfus 3.7.2
File Interpreter ABI Platform
obfus-3.7.2-py3-none-any.whl Python 3 none any Details

Total release size: 64.4 kB

Release files / obfus-3.7.2.tar.gz

Download URL obfus-3.7.2.tar.gz
Size 39.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2610fe0c288a6f4baf205fc53b9a7069774924a14c028bdb71ae1c70e0e52350
BLAKE2b-256 checksum
How to use checksums
4bc29271b3141eabb319e314f816f1568b7ea8f2c6268c6697ea56dcb0def285
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release files / obfus-3.7.2-py3-none-any.whl

Download URL obfus-3.7.2-py3-none-any.whl
Size 24.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
61def12aa307e74a1d1b2a7decc1d5f24281cd3f7de1354709caef441e8e7c68
BLAKE2b-256 checksum
How to use checksums
4555809498359ed4487b9042ea1ddd8ab6aad7f56e064ff624bdf44679a8e25d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

3.7.2 This release

2 release files

2.0.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page