All notable changes to this project will be documented in this file.
The format follows Keep a Changelog.
This project uses Semantic Versioning.
Complete rewrite from a regex-based implementation to a fully AST-based pipeline.
ObfuscationConfig— immutable frozen dataclass for selecting techniques. Factory methods:all_enabled(),only(*names),.without(*names),.with_added(*names).- Technique registry —
@registerclass decorator; techniques self-register by name.all_technique_names()andget_transforms(enabled)for pipeline construction. variable_renamer— two-pass AST renamer. First pass collects renameable names (excludes builtins, imports, dunders, and attribute-accessed names); second pass applies the mapping. Also renamesnonlocalandglobalstatement name lists.string_hex_encoder— converts string literals tobytes.fromhex(…).decode('utf-8')call nodes. Skips f-strings where replacing aConstantwith aCallis invalid.dead_code_injector— recursively injects dead variable assignments at every scope level: module body, function bodies, class bodies, if/for/while/try/with branches. Some assignments reference earlier dead variables (intra-scope cross-references) to simulate computation. AcceptsInjectionParamsand a seededrandom.Randomfor reproducible output.exec_wrapper— wraps the entire module inexec(ast.unparse(tree)), reducing the top-level AST to one statement.Obfuscatorclass — caches the transform pipeline across multipleobfuscate()calls.obfuscate()module-level helper — convenience wrapper for one-shot use.- CLI (
pyobfuscate) —--disable/-dflag accepts technique names;--stdout;--version/-V. - E2E test suite with correctness and benchmark tests across six complex programs.
- Per-technique runtime benchmarks showing individual overhead contribution.
- 100 % branch coverage enforced in CI.
- Python 3.10–3.14 test matrix.
- Priority ordering now encoded in
TechniqueMetadata.priorityrather than list position. VariableNameGeneratorandRandomDataTypeGeneratoraccept an optionalrngargument for deterministic testing._NameCollectorexposesall_bound_names(assigned + imported + builtins) for use by the dead-code injector's exclusion set.
- All regex-based technique implementations (
techniques.py). regexruntime dependency (was used only for the old hex-encoding approach).SourceTransformbase class andsource_transformspackage.
VariableRenamernow updatesnonlocalandglobalstatement name lists, preventingSyntaxError: no binding for nonlocal '…' foundafter renaming.VariableRenamerexcludes attribute-accessed names from renaming to preventAttributeErrorwhen calling methods by the original name after their definition is renamed._interleavepreserves relative ordering of injected statements (sorted random slots) so intra-scope cross-references never appear before their definitions.
Initial public release with regex-based obfuscation techniques.
one_liner— collapsed newlines into semicolons (superceded byexec_wrapper).variable_renamer— regex-based name replacement.add_random_variables— prepended/appended random assignments at module level.str_to_hex_bytes— regex-based string-to-hex conversion.