I decided to code and package my own, called bobskater. It turned out to be surprisingly easy with Python's
ast library, the invaluable documentation at GreenTreeSnakes, and a little library called
astunparse. Being completely AST based, it won't die on weird syntax or require special formatting. All obfuscation decisions are based on AST node type. There are a few limitations as of now but they're all documented in the repository.
There do exist a lot of libraries/techniques out there (free and pay) that perport to do this, with mixed results:
- Compile to
compile(). Even at the highest optimization you can still extract the original code, variable names, and docstrings with uncompyle6 in literally just one command.
- Encrypt your modules and hook the import functionality to decrypt them when loading them at runtime. Too simple to reverse in my opinion.
- Compile your modules using Cython, which removes Python bytecode though introduces it's own set of problems, like not being able to call using named kwargs (see this citrisbyte article for more details). I could see this not playing nicely with Blender's import system.
- opy - For a Regex-based obfuscator it worked surprisingly well except for one or two corner cases. Doesn't scale well though as all external identifiers that shouldn't get obfuscated need to be manually entered. Requires specific source code formatting but isn't an issue if your code is based on Python's recommendations
- pyminifier - An unmaintained, hybrid regex/token-based obfuscator. 80 open issues and seemingly errors in very basic cases.
- pyobfuscate - Last updated in 2013, not particularly well documented and non hopeful open issues.
- mnfy - Python minifier but no obfuscation.