Skip to content

Protecting Raw Python Scripts

This guide covers protecting raw .py, .pyz, and .pyw files with PyLocket. This is a niche use case — for most scenarios, we recommend building a standalone executable first.

End users need Python installed

Unlike .exe or .app artifacts, protected Python scripts require Python on the end user's machine. If you are distributing to end users who may not have Python, use PyInstaller, cx_Freeze, or Briefcase to create a standalone executable, then protect that instead.


How It Works

A raw .py file cannot run standalone after protection. PyLocket protects .py files by:

  1. Compiling them to .pyc bytecode
  2. Encrypting each function body with industry-standard authenticated encryption
  3. Replacing function bodies with lightweight stubs that delegate to the native runtime
  4. Repacking everything into a ZIP archive with the runtime and manifest

The protected output is not a standalone .py file — it is a repacked artifact (ZIP) containing:

File Purpose
Encrypted .pyc modules Your code with function bodies replaced by stubs
Native runtime library Decrypts functions on demand
Protection manifest Encrypted metadata for license validation
Bootstrap module Initializes the runtime at startup

The end user needs Python installed and a valid license key to run the protected application.


When to Use This

Raw .py protection is appropriate when:

  • Developer tools / CLI apps — your users are developers who already have Python
  • Internal distribution — within an organization where Python is standard
  • Python libraries — scripts distributed as part of a larger Python project (consider wheels instead)
  • Rapid prototyping — testing protection before setting up a full build pipeline

For all other cases, especially distributing to end users:

Target Audience Recommended Approach
End users (no Python) PyInstaller.exe / binary
macOS end users Briefcase.app bundle
Python developers Wheel.whl (pip installable)
Internal teams Raw .py (this guide) or ZIP

Important: Your Script Must Contain Functions

PyLocket protects code by encrypting function bodies (def statements). If your script contains only top-level statements (e.g., print("Hello")) with no function or class definitions, protection will fail because there is nothing to encrypt.

Will NOT work

# No functions — nothing to protect
print("Hello World")
x = 1 + 2
input("Press Enter to exit...")

Will work

def main():
    print("Hello World")
    x = 1 + 2
    input("Press Enter to exit...")

if __name__ == "__main__":
    main()

Rule of thumb: Wrap your logic in at least one function. PyLocket encrypts function bodies and replaces them with runtime stubs — top-level code outside functions is NOT encrypted.


Step 1: Prepare Your Script

Package your .py file(s) into a ZIP archive:

# Single script
zip myapp.zip myapp.py

# Multiple scripts with dependencies
zip -r myapp.zip myapp.py utils.py config.py

For .pyz (zipapp) files:

python -m zipapp myproject -o myapp.pyz -m "myapp:main"

Step 2: Upload and Protect

pylocket protect \
  --app <APP_ID> \
  --artifact myapp.zip \
  --platform cross_platform \
  --python 3.12
  1. Go to Apps → select your app → Upload Build
  2. Select your .py, .pyz, or .zip file
  3. Set Artifact Type to .py, .pyz, or .zip
  4. Set Platform to Cross-platform
  5. Click Upload Build

Step 3: Distribute to Users

After protection completes, download the protected artifact:

pylocket fetch --build <BUILD_ID> --out dist/protected/

The protected output is a ZIP archive. Distribute it to users with instructions:

# End user extracts and runs:
unzip myapp-protected.zip -d myapp/
cd myapp/
python myapp.py
# → License prompt appears on first run

The native runtime library and protection manifest must be in the same directory as the script.


Using Protected Functions in Your Own Code

If you are distributing a protected Python library (not a standalone script), the consumer must import the bootstrap before importing any protected module:

import _pylocket_bootstrap   # Initialize runtime — must be first!
from mylib import my_function

result = my_function(42)     # Decrypted and executed transparently

The bootstrap activates the PyLocket runtime. Without this import, protected functions will not work.

For library distribution, use wheels instead

Protecting as a .whl (wheel) lets you add the bootstrap import to your package's __init__.py so consumers don't need to know about it. See Protecting a Wheel.


Limitations

Limitation Details
Must contain functions Only code inside def or class bodies is encrypted. Top-level statements are NOT protected. Scripts with zero functions will be rejected.
Requires Python End user must have Python installed (same major.minor version used during protection)
Not a standalone executable The output is a ZIP archive, not a double-clickable application
Native runtime required The native runtime library must be present alongside the script
Platform-specific runtime The native extension is compiled for a specific OS — distribute the correct one

Next Steps

Topic Link
Build standalone executables instead PyInstaller, Briefcase
Protect a wheel for pip distribution Wheel
Protect a ZIP archive ZIP
How protection works under the hood How Protection Works