CLI tool
dashingsoft/pyarmor avatar
dashingsoft/pyarmor

Pyarmor: Obfuscating Python Scripts, Binding Them to Machines, and Setting Expiry Dates

A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.

5,206 stars366 forksPythonNOASSERTION

At a glance

What is it?
Pyarmor is a command-line tool that turns Python source into obfuscated .py files that still run as normal modules. This review covers what it does, how the runtime hook works, what the free trial limits, and when Nuitka is the better answer.
Who is it for?
Adopt Pyarmor if you ship Python to customers you do not control and you need machine binding or an expiry date without changing how the code is imported. Do not adopt it if your threat model includes a determined reverse engineer with the runtime binary in hand, or if you only need to hide a few constants: a compiled extension or a server-side API is a cleaner boundary.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 14 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Pyarmor Solves, and Who Actually Needs It

Python ships as readable source. If you hand a script to a customer, a contractor or an on-premise appliance, they have your logic. Pyarmor exists for that moment: the README describes it as a command-line tool for obfuscating Python scripts, binding obfuscated scripts to specific machines, and setting expiration dates. The three capabilities are separate and can be combined, which matters because most tools in this space only do the first.

The binding and expiry features are the real differentiator. Machine binding means the obfuscated file checks the host it runs on. Expiry means it stops working after a date. Those two mechanisms turn a Python script into something closer to a licensed product: a trial build that dies at the end of the month, or a build that only runs on the server you sold it for. If you are distributing an internal tool to a known fleet, you do not need any of this. If you are distributing to people who could copy the file to another machine, you probably do.

The audience is narrow but real: independent software vendors shipping Python desktop or appliance software, consultancies delivering code they do not want reused, and teams that need a time-limited evaluation build without maintaining two codebases.

The Runtime Hook: How an Obfuscated Script Still Runs as a .py File

The mechanism is visible in the README's own example. After obfuscation, the generated file at dist/foo.py is not compiled bytecode and not an executable. It is a short Python file that imports a runtime and calls into it with a byte blob. The README shows the shape: a line importing __pyarmor__ from pyarmor_runtime, followed by a call to __pyarmor__ taking __name__, __file__ and a bytes literal.

So the data flow is: your original module becomes an opaque byte payload, and a small stub hands that payload to a native runtime that reconstructs and executes the code. Because the stub is still a normal .py file, it can replace the original script in most cases, which the README calls seamless replacement. That is the design choice worth pausing on. The obfuscated artifact keeps the same import path and the same file extension, so your packaging, your entry points and your imports do not change. You pay for that convenience with a runtime dependency: the pyarmor_runtime package has to travel with the script, and it contains a platform-specific native binary.

On top of that base layer, the README lists several obfuscation modes. Names are renamed: functions, methods, classes, variables and arguments. Some Python functions can be converted to C functions and compiled with high optimization options, which the README describes as irreversible. There is also optional Themida protection, Windows only, layered over the obfuscated script. The README frames the modes as a way to balance security and performance, which is an honest way of saying that the stronger modes cost you something.

Installing Pyarmor and Obfuscating Your First Script

Pyarmor installs from PyPI. The README gives a single command, and it is the same package name people search for on PyPI.

bash
pip install pyarmor

Once installed, the entry point is the pyarmor command. The README's quick start obfuscates a file named foo.py with one subcommand:

bash
pyarmor gen foo.py

The output lands in a dist directory. According to the README, dist/foo.py looks like this:

python
from pyarmor_runtime import __pyarmor__
__pyarmor__(__name__, __file__, b'\x28\x83\x20\x58....')

That is the whole artifact. There is no build step to configure and no manifest to write for the basic case. You run it exactly as you would run the original:

bash
python dist/foo.py

Two things to check after that first run. First, the pyarmor_runtime package must sit next to the obfuscated file, because the stub imports it by name; if you move dist/foo.py somewhere else on its own, the import fails. Second, the README points to a getting started tutorial for anything beyond this single-file case, and that is where binding and expiry options live. The README itself does not document the flags for machine binding or expiration dates, so treat the tutorial as required reading rather than optional.

What the Free Trial Does Not Give You

Pyarmor is not open source in the usual sense. The README states plainly that it is published as shareware, and that the free trial version never expires but has some limitations. Which limitations, exactly, is not spelled out in the README; it defers to the licence page for types, features, limitations and purchasing. The repository carries several licence files, including LICENSE, LICENSE-ZH and versioned variants LICENSE.7, LICENSE-ZH.7, which suggests the terms have changed across major versions and that you should read the one matching the version you install.

This is the single biggest practical constraint, and it is a licensing one rather than a technical one. A tool that never expires but restricts features is easy to start with and awkward to plan around: you can build a prototype today and discover next quarter that the feature you need sits behind a paid tier. The related searches around licence price, licence purchase and being out of licence reflect that friction. If your use case is commercial distribution with binding or expiry, budget for a licence before you architect around Pyarmor, not after.

The repository is not archived, and the last push was on 2026-09-19. Releases are frequent: v9.2.7 on 2026-08-26, v9.2.6 on 2026-07-30, v9.2.5 on 2026-05-20. The README keeps separate changelogs for the 8.x and 9.x lines and warns readers to read the changelog carefully before upgrading, which implies compatibility breaks between major versions. Plan for a migration cost at each major bump, not just a version pin.

Where Pyarmor Is the Wrong Tool

Obfuscation is not encryption, and Pyarmor does not claim otherwise. The obfuscated script still has to execute on the user's machine, which means the runtime has to be able to recover the code. Anyone willing to attach a debugger, dump memory or reverse the native runtime is working against a speed bump, not a wall. The README's language is careful here: it says irreversible about the renaming and the C function conversion, not about the payload being unrecoverable. If your code's value is high enough that a motivated attacker will spend weeks on it, moving the sensitive logic to a server you control is the honest answer, and Pyarmor is not a substitute for that decision.

There is a second, less obvious failure mode. Because the artifact is a .py file that imports a runtime, anything that inspects, rewrites or freezes Python code has to cope with the stub. The README lists examples directories for py2exe and cx_Freeze, which tells you these combinations are known territory, but it also means the obfuscation step has to happen at the right point in your build pipeline. Obfuscate too early and your freezer may not follow the runtime; obfuscate too late and you may ship unprotected modules by accident.

Finally, consider whether you need this at all. If you are shipping to a server you own, or to an internal team, Pyarmor adds a runtime dependency, a licence decision and a build step for a threat that may not exist.

Pyarmor vs Nuitka: Two Different Answers to the Same Question

The most common comparison people search for is Pyarmor against Nuitka, and the difference is in what each one produces. Pyarmor's output is a Python script plus a native runtime that reconstitutes and executes the original logic. Nuitka compiles Python into a native executable, so the shipped artifact is machine code rather than a stub calling into a decoder.

That distinction drives the trade-offs. A compiled executable has no Python runtime to import and no pyarmor_runtime package to keep beside it, which simplifies distribution. But compilation changes your build: you are now producing a binary per platform and architecture, and the build is slower and more sensitive to what your code does at import time. Pyarmor keeps the .py file and the import semantics, which is why the README can call it a replacement in most cases, and why it slots into an existing Python packaging flow with a single extra command.

If your problem is shipping a runnable, licensed artifact to end users and you want expiry and machine binding, Pyarmor's feature set is the closer match. If your problem is that you do not want Python source on the target machine at all, and you are willing to own a compile step per platform, a compiler is the more direct route. Note that the README's C function conversion already borrows part of that idea for selected functions.

Editorial conclusion

Adopt Pyarmor if you ship Python to customers you do not control and you need machine binding or an expiry date without changing how the code is imported. Do not adopt it if your threat model includes a determined reverse engineer with the runtime binary in hand, or if you only need to hide a few constants: a compiled extension or a server-side API is a cleaner boundary. Before committing, verify two things yourself: which licence tier covers the features you plan to use, since the README states the free trial version has limitations and points to the licence page, and whether your target architecture appears in the environments reference, because the setup.py data file list only ships _pytransform binaries for windows x86, windows x86_64, linux x86, linux x86_64 and darwin x86_64.

Frequently asked questions

What is Pyarmor used for?

The README describes it as a command-line tool for obfuscating Python scripts, binding obfuscated scripts to specific machines, and setting expiration dates for obfuscated scripts. In practice that covers shipping Python code to people you do not control, and giving a build a limited lifetime.

Is Pyarmor free to use?

The README states that Pyarmor is published as shareware, and that the free trial version never expires but has some limitations. It points to the licence page for the types, features and limitations of each licence.

How do I install Pyarmor?

The README's quick start installs it from PyPI with pip install pyarmor, then runs pyarmor gen foo.py to produce an obfuscated script in the dist directory.

How can I obfuscate Python code with Pyarmor?

Run pyarmor gen on the script, for example pyarmor gen foo.py. The README shows the result at dist/foo.py as a short file that imports __pyarmor__ from pyarmor_runtime and passes a bytes payload to it.

What is the price of Pyarmor?

The README does not list prices. It says the licence page covers licence types, features, limitations and purchasing, and directs business and security inquiries to [email protected].

Official sources

  1. dashingsoft/pyarmor on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dashingsoft-pyarmor.svg)](https://hysenlabs.com/projects/dashingsoft-pyarmor)