views:

641

answers:

5

Is it possible to distribute only the bytecode version (.pyc file) of a Python script instead of the original .py file? My app embeds the Python interpreter and calls PyImport_Import to load a script. How can I tell it to look for a .pyc file and import that?

+2  A: 

This should not be a problem, if you create a stand alone program using py2exe you only get the .pyc files.

Normally you don't need to tell python to look for .pyc files, it does so anyway. Only if there is a newer .py source file this is used.

However, the level of protection of you source code may not be very high.

Ber
My app is written in C++, not Python. py2exe is not an option. I am referring to the Python/C API.
George Edison
+2  A: 

I did it by creating .py library and simple .py program that uses that library. Then I compiled library to .pyc and distributed: program as .py source and library as compiled .pyc.

Michał Niklas
This might work. I'll give it a try.
George Edison
Worked like a charm! Thanks.
George Edison
+8  A: 

use the freeze tool, which is included in the Python source tree as Tools/freeze. It converts Python byte code to C arrays; a C compiler you can embed all your modules into a new program, which is then linked with the standard Python modules.

Note that freeze requires a C compiler

Other utilities:

1- PyInstaller

2- Py2Exe

3- Squeeze

4- cx_freeze

more info

Michel Kogan
The scripts are distributed separately from the app.
George Edison
so distribute scripts separately ... is there any problem ?
Michel Kogan
Well... the scripts aren't a part of it either. In fact some third parties will write some of them - and they shouldn't have to install a compiler just to write them.
George Edison
so look @Ned Batchelder answer ...
Michel Kogan
+1  A: 

In the interactive interpreter, that's automatic - if there is no .py, the .pyc will still be used:

$ echo 'print "hello"' > test.py
$ python -m compileall .
$ rm test.py
$ python -m test
hello
$

Could you just try if that works the same way with the API?

Edited to add: I agree with Ber in that your code protection will be rather weak. -O will remove docstrings, if that doesn't change the behaviour of your programme, that may make reconstructing behaviour harder, but what you'd really need some sort of bytecode obfuscation.

I don't know if a ready-made obfuscation tool exists for python, but this sounds viable, if you want to / can invest the time (and don't feel all too silly doing it, and can ship your own interpreter).

Bernd Haug
I'll try it when I get the chance. If I remember correctly though, this didn't work.
George Edison
I tried it. It didn't work.
George Edison
+3  A: 

Since you are writing your main program in C++, you can do whatever you want to protect your Python files. You could encrypt them for distribution, then decrypt them just in time to import them into the Python interpreter, for example.

Since you are using PyImport_Import, you can write your own __import__ hook to import the modules not from a file but from a memory buffer, so your transformation to .pyc file can happen all in memory, with no understandable Python code on disk at all.

Ned Batchelder
+1 for encryption
Michel Kogan
Too complicated for the third parties...
George Edison