# How to hide the code of the script module?

**URL:** <https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135>\
**Category:** Development\
**Tags:** python, scripted\
**Created:** [November 8, 2022, 1:20pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135 "2022-11-08T13:20:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![qiqi5210](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/qiqi5210/32/15920_2.png) [@qiqi5210](https://discourse.slicer.org/u/qiqi5210)\
**Post date:** [November 8, 2022, 1:20pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/1 "2022-11-08T13:20:00Z")

</div>

Hello everyone,  
I would like to ask how to hide the code of the script module. I am developing the script module recently, and I feel that it is a bit insecure to be able to directly see all the code. Hope to get everyone’s help. thanks!

best wishes,  
Mary

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [November 8, 2022, 1:36pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/2 "2022-11-08T13:36:14Z")

</div>

You can search the internet for ways to hide your python code. You may be able to make it harder for people to see the code, but it won’t be possible to hide it completely.

---

<div class="post-metadata">

**Author:** ![qiqi5210](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/qiqi5210/32/15920_2.png) [@qiqi5210](https://discourse.slicer.org/u/qiqi5210)\
**Post date:** [November 9, 2022, 3:08am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/3 "2022-11-09T03:08:26Z")

</div>

Thanks Pieper.I will try this method. I learned that python code can be hidden by generating PYD files, and I also saw PYD files in Slicer’s generated project bin file, so when should I generate PYD files?Thanks again.  
Mary

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [November 9, 2022, 1:06pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/4 "2022-11-09T13:06:45Z")

</div>

You’ll need to do some research on this. By default Slicer expects python scripts to be available in source form with any optimizations like compiling to byte codes being handled automatically by the python infrastructure.

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 19, 2024, 2:53pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/5 "2024-01-19T14:53:08Z")

</div>

Hello @qiqi5210 , continuing this discussion further,

I am interested in knowing if you have found any working methods for this?

Thanks,  
Mujassim

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 20, 2024, 1:25pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/6 "2024-01-20T13:25:32Z")

</div>

You should be able to replace the original .py source code file by the automatically generated .pyc bytecode files or a .py file that to have run through a Python obfuscator tool.

---

<div class="post-metadata">

**Author:** ![jamesobutler](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jamesobutler/32/7511_2.png) [@jamesobutler](https://discourse.slicer.org/u/jamesobutler)\
**Post date:** [January 20, 2024, 3:08pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/7 "2024-01-20T15:08:43Z")

</div>

I suggest others also see the easily available uncompiling tools as well to take obfuscated Python code back to human readable.

See uncompyle6 as an example:

> **[uncompyle6](https://pypi.org/project/uncompyle6/)**
>
> Python cross-version byte-code decompiler

> **[GitHub - rocky/python-uncompyle6: A cross-version Python bytecode decompiler](https://github.com/rocky/python-uncompyle6/)**
>
> A cross-version Python bytecode decompiler. Contribute to rocky/python-uncompyle6 development by creating an account on GitHub.

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 22, 2024, 7:33am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/8 "2024-01-22T07:33:47Z")

</div>

@lassoan and @jamesobutler, thank you for your inputs.

Is there any way to have Slicer load scripted modules from `.pyd` files instead of `.py` files? Why does Slicer specifically look for `module_name.py` files in `qt-scripted-modules` directory?

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 22, 2024, 4:11pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/9 "2024-01-22T16:11:22Z")

</div>

> [@MJamal](#):
>
> Is there any way to have Slicer load scripted modules from `.pyd` files instead of `.py` files? Why does Slicer specifically look for `module_name.py` files in `qt-scripted-modules` directory?

.pyd files are not relevant if you develop your code in Python because .pyd files are created by compiling C/C++ code. The module factory is looking for .py (source) and .pyc (byte code) files in scripted module folders.

Probably the simplest solution for hiding your source code is to replace .py files by .pyc files. If you use obfuscation tools then you can keep using .py files but you need to be careful about keeping some publicly used symbols unchanged (e.g., the Slicer module and widget class names must not be obfuscated).

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 23, 2024, 4:02am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/10 "2024-01-23T04:02:57Z")

</div>

> [@lassoan](#):
>
> .pyd files are not relevant if you develop your code in Python because .pyd files are created by compiling C/C++ code.

Indeed, I generated those .pyd files using the Cython build process.

> [@lassoan](#):
>
> The module factory is looking for .py (source) and .pyc (byte code) files in scripted module folders.

Does this imply that the module factory utilizes these .py or .pyc files as a package (e.g., importing from .py) to be registered in the factory manager? If that’s the case, then .py files could potentially be replaced with .pyd files, as they are also usable as packages.

> [@lassoan](#):
>
> Probably the simplest solution for hiding your source code is to replace .py files by .pyc files. If you use obfuscation tools then you can keep using .py files but you need to be careful about keeping some publicly used symbols unchanged (e.g., the Slicer module and widget class names must not be obfuscated).

However, there’s a challenge. As suggested by @jamesobutler and confirmed through my own experiments on obfuscated scripts (or .pyc files), I discovered that these can be translated back into a human-readable form. Therefore, using .pyc files or obfuscation tools to conceal the source code might not be a secure approach. This is why I am exploring a way to use .pyd (or .so, .dylib) files in place of .py or .pyc files. There should be a solution!

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 23, 2024, 5:00am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/11 "2024-01-23T05:00:25Z")

</div>

> [@MJamal](#):
>
> Indeed, I generated those .pyd files using the Cython build process.

If you write your code in C++ then you can create a C++ loadable module, as most of the Slicer core modules. There is no need to use Python then.

> [@MJamal](#):
>
> Does this imply that the module factory utilizes these .py or .pyc files as a package (e.g., importing from .py) to be registered in the factory manager?

The .py/.pyc file is imported and then the module and widget classes are instantiated.

> [@MJamal](#):
>
> I discovered that these can be translated back into a human-readable form

Yes, you can disassemble any code (including .pyd files) back to human-readable form. You can try to make it harder with some extra work, but you cannot prevent it completely.

Your extra measures would incur extra costs and there many ways around all of them anyway. Even if you run your software as a service on a server, your competitors can still hire your employees, hack into your system, deduce how you do things by observing what your software does, etc.

It would be also irresponsible to try to protect your key technologies just by attempting to keep them secret. Trade secrets are not protected, so any other company can come up with the same product (by taking ideas from you or inventing it independently) and sell it and you may not be able to do anything about it. The other company might even block you from using the technology that you (also) invented if they patent it first. If you patent the idea then it can ensure that only you can use it (and may significantly increase the value of your company), but it can be quite expensive. If you want to avoid patenting cost but want to ensure that you can use your ideas then you may consider publicly disclosing them (e.g., instead of trying to obfuscate the code, you could decide to make the source code publicly available or describe the idea in a research paper).

Overall, if you want to make it harder for people to see how your modules work, distributing .pyc files instead of .py files may be a resonable tradeoff between maixmum protection and minimizing extra costs and complexities.

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 23, 2024, 4:21pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/12 "2024-01-23T16:21:37Z")

</div>

Thanks a lot andras! I completely agree with your insights and suggestions.

By the way, I am working on my university end-semester research project, focusing on optimizing and securing Python source code. I came across Slicer and found it to be a good starting point, especially with the demonstration on scripted modules.

> [@lassoan](#):
>
> If you write your code in C++ then you can create a C++ loadable module, as most of the Slicer core modules. There is no need to use Python then.

Yes, I have already created my own Python module, so I’m not planning to rewrite it in C++.

> [@lassoan](#):
>
> The .py/.pyc file is imported and then the module and widget classes are instantiated.

Could you please guide me to the file(s) where this happens? Your explanation would be quite helpful.

> [@lassoan](#):
>
> if you want to make it harder for people to see how your modules work, distributing .pyc files instead of .py files may be a resonable tradeoff

It seems like I don’t have many choices but .pyc. Anyways, instead of manually distributing the .pyc files, how can i automate this in the Slicer build process to generate and utilize .pyc files in the qt-scripted-module directory and completely eliminate the .py files?

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 23, 2024, 9:31pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/13 "2024-01-23T21:31:56Z")

</div>

> [@MJamal](#):
>
> Could you please guide me to the file(s) where this happens?

You can search for “.pyc” in the slice source tree.

> [@MJamal](#):
>
> It seems like I don’t have many choices but .pyc. Anyways, instead of manually distributing the .pyc files, how can i automate this in the Slicer build process to generate and utilize .pyc files in the qt-scripted-module directory and completely eliminate the .py files?

The simplest is probably to write a short Python script that compiles your .py files and then replaces the .py files by the .pyc files.

This script could added as a custom build or installation step in your extension build CMake files. If you are not sure how to do it, you can ask advice on the CMake forum or contract a CMake expert at Kitware.

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 27, 2024, 4:00pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/14 "2024-01-27T16:00:05Z")

</div>

> [@lassoan](#):
>
> The simplest is probably to write a short Python script that compiles your .py files and then replaces the .py files by the .pyc files.

I found that `.pyc` files were already generated in ` __pycache__ ` folder of scripted modules after the build process. Can I use those .pyc files directly instead of recompiling .py files?

Furthermore, is there any Slicer-specific CMake flag to determine the directory path of Qt scripted modules?

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 27, 2024, 4:21pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/15 "2024-01-27T16:21:16Z")

</div>

Yes, those are cached automatically compiled files. You can certainly use them.

Slicer application looks for scripted module files in `lib\Slicer-5.6\qt-scripted-modules` folder and folders in the “additional module paths” (stored in application settings).

---

<div class="post-metadata">

**Author:** ![jcfr](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jcfr/32/17825_2.png) [@jcfr](https://discourse.slicer.org/u/jcfr)\
**Post date:** [January 27, 2024, 9:27pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/16 "2024-01-27T21:27:51Z")

</div>

**Background:** Support for discovering and loading scripted modules from `.pyc` files has already been implemented for all scripted plugins and modules. You can find the related changes in the [Slicer GitHub repository](https://github.com/search?q=repo%3ASlicer%2FSlicer%20.pyc&type=code).

However, it’s crucial to note that, starting with Python 3.2, the default behavior of [py\_compile.compile](https://docs.python.org/3/library/py_compile.html#py_compile.compile), which is utilized in [ctk\_compile\_python\_scripts.cmake.in](https://github.com/commontk/CTK/blob/master/CMake/ctk_compile_python_scripts.cmake.in), is to generate files like ` __pycache__ /scriptname.cpython-XY.pyc`, following the specifications in [PEP-3147](https://peps.python.org/pep-3147/). This explains why we may not have `*.pyc` files compiled after building the `CompileSlicerPythonFiles` target.

* * *

**Update** : To address this, a pull request has been submitted to the CTK repository. This pull request, available at [https://github.com/commontk/CTK/pull/1188](https://github.com/commontk/CTK/pull/1188), aims to ensure that Slicer scripts are consistently compiled as legacy `.pyc` files.

After you have a chance to test and review, we will look into integrating the corresponding changes into Slicer.

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [January 28, 2024, 1:49pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/17 "2024-01-28T13:49:27Z")

</div>

@jcfr, I have reviewed the pull request. Thanks for bringing it up!

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [February 1, 2024, 5:01am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/18 "2024-02-01T05:01:11Z")

</div>

Hello @jcfr,

I have written the following script in `slicersources-src\CMake\LastConfigureStep\CMakeLists.txt` to replace .py with .pyc files during last configuration step. I didn’t encounter any errors during the build process; however, it appears that the script is not functioning as expected. Could you please help me troubleshoot this issue?

```auto
function(replace_py_with_pyc ${SCRIPTED_MODULE_PYCACHE_DIR_PATH})
  if (EXISTS ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/ __pycache__ AND IS_DIRECTORY ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/ __pycache__ )
    message("--- Attempting to copy .pyc files...")
    file(GLOB PYC_FILES ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/ __pycache__ /*.pyc)
    file(COPY ${PYC_FILES} DESTINATION ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/)

    message("--- Attempting to remove .py files...")
    file(GLOB PY_FILES ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/*.py)
    file(REMOVE ${PY_FILES})
  endif()

  file(GLOB SUBDIRS LIST_DIRECTORIES True ${SCRIPTED_MODULE_PYCACHE_DIR_PATH}/*)
  foreach(subdir ${SUBDIRS})
    replace_py_with_pyc(${subdir})
  endforeach()

  message("--- Done copying .pyc files.")
endfunction()

replace_py_with_pyc(${Slicer_INSTALL_QTSCRIPTEDMODULES_LIB_DIR})

```

---

<div class="post-metadata">

**Author:** ![MJamal](https://avatars.discourse-cdn.com/v4/letter/m/d26b3c/32.png) [@MJamal](https://discourse.slicer.org/u/MJamal)\
**Post date:** [February 1, 2024, 12:05pm UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/19 "2024-02-01T12:05:11Z")

</div>

Never mind, the script is working now. However, I noticed that the build process is still copying Python script files again to the scripted modules.

![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/1/71759326181b7bc2b42785d70d744a16ebef2e32.png)

@lassoan, how can I execute the script on slicer’s post build?

---

<div class="post-metadata">

**Author:** ![jcfr](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jcfr/32/17825_2.png) [@jcfr](https://discourse.slicer.org/u/jcfr)\
**Post date:** [February 2, 2024, 4:33am UTC](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135/20 "2024-02-02T04:33:45Z")

</div>

Technically, the `.py` files are not replaced, there are removed.

The target `CompileSlicerPythonFiles` depends on the `CopySlicerPythonScriptFiles` one, these are defined using the `ctkFunctionAddCompilePythonScriptTargets` CMake function.  
See [Slicer/CMakeLists.txt#L1280-L1309](https://github.com/Slicer/Slicer/blob/4efda831815917174b421fb710d1a76e7a9e68f2/CMakeLists.txt#L1280-L1309)

To properly support “compiling” source file exclusively to `.pyc`, the CMake function `ctkFunctionAddCompilePythonScriptTargets` should be improved to accept an new parameter option (e.g `SKIP_SCRIPT_COPY`).  
See [CTK/CMake/ctkMacroCompilePythonScript.cmake](https://github.com/commontk/CTK/blob/4aba4e20341c7111f5637337952a089464dc15db/CMake/ctkMacroCompilePythonScript.cmake#L101)

The `ctkMacroCompilePythonScript.cmake` CMake module could also be updated to define an option for controlling the behavior globally (e.g `CTK_COMPILE_PYTHON_SCRIPT_SKIP_SCRIPT_COPY`).

This new option should be added to `SlicerConfig.cmake.in`, that way extension build against Slicer would also leverage it.

This should provide you with enough hints to move forward and create a pull request at [https://github.com/commontk/CTK](https://github.com/commontk/CTK)

We will address corner cases during the review process.

[Next page](https://discourse.slicer.org/t/how-to-hide-the-code-of-the-script-module/26135.md?page=2)
