2.4. 打包加密脚本成为 Wheel
测试项目的目录结构如下:
$ tree test-project
test-project
├── MANIFEST.in
├── pyproject.toml
├── setup.cfg
└── src
└── parent
├── child
│ └── __init__.py
└── __init__.py
文件 MANIFEST.in
的内容如下:
recursive-include dist/parent/pyarmor_runtime_00xxxx *.so
文件 pyproject.toml
[build-system]
requires = [
"setuptools>=66.1.1",
"wheel"
]
build-backend = "setuptools.build_meta"
文件 setup.cfg
[metadata]
name = parent.child
version = attr: parent.child.VERSION
[options]
package_dir =
=dist/
packages =
parent
parent.child
parent.pyarmor_runtime_00xxxx
include_package_data = True
src/parent/__init__.py
和 src/parent/child/__init__.py
是相同的:
VERSION = '0.0.1'
首先加密包:
$ cd test-project
$ pyarmor gen --recursive -i src/parent
加密成功之后输出的目录结构如下:
$ tree dist
dist
└── parent
├── child
│ ├── __init__.py
│ └── __pycache__
│ └── __init__.cpython-311.pyc
├── __init__.py
└── pyarmor_runtime_00xxxx
├── __init__.py
└── pyarmor_runtime.so
接着就构建 wheel:
$ python -m build --skip-dependency-check --no-isolation
但是却报错了
* Building sdist...
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/setuptools/config/expand.py", line 81, in __getattr__
return next(
^^^^^
StopIteration
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/setuptools/config/expand.py", line 191, in read_attr
return getattr(StaticModule(module_name, spec), attr_name)
检查错误堆栈发现问题出现在 StaticModule
,通过异常中文件名称和行号,查看在包 setuptools
源代码中这个类的定义,它使用了 ast.parse
直接解析源代码获取模块的局部变量,这当然在加密脚本中行不通的。为了解决这个问题,可以直接在加密后的脚本 dist/parent/child/__init__.py
中增加一行
from pyarmor_runtime_00xxxx import __pyarmor__
VERSION = '0.0.1'
...
但是默认情况下加密脚本是不允许修改的,为了能够修改这个脚本,需要使用下面的命令进行配置:
$ pyarmor cfg -p parent.child.__init__ restrict_module = 0
$ pyarmor gen --recursive -i src/parent
其中选项 pyarmor cfg -p
parent.child.__init__
是只取消对单个模块的 parent/child/__init__.py
的限制,而其他模块依旧使用约束模式。
现在修改 dist/parent/child/__init__.py
之后再次运行下面的命令进行打包:
$ python -m build --skip-dependency-check --no-isolation
自定义运行辅助包的名称
如果你想自定义运行辅助包的名称为 libruntime
,并且存放到子目录 parent.child
下面,你需要修改 MANIFEST.in
:
recursive-include dist/parent/child/libruntime *.so
和 setup.cfg
:
[options]
...
packages =
parent
parent.child
parent.child.libruntime
...
然后使用下面的配置进行加密:
$ pyarmor cfg package_name_format "libruntime"
$ pyarmor gen --recursive --prefix parent.child src/parent
在创建 wheel 之前不要忘记对 dist/parent/child/__init__.py
进行修改:
$ python -m build --skip-dependency-check --no-isolation
更进一步
为了能够在加密完成之后自动修改 dist/parent/child/__init__.py
,你可以创建一个 加密插件 .pyarmor/myplugin.py
:
__all__ = ['VersionPlugin']
class VersionPlugin:
@staticmethod
def post_build(ctx, inputs, outputs, pack):
script = os.path.join(outputs[0], 'parent', 'child', '__init__.py')
with open(script, 'a') as f:
f.write("\nVERSION = '0.0.1'")
然后启用这个插件:
$ pyarmor cfg plugins + "myplugin"
这样以后每次打包只需要运行下面的命令就可以了:
$ pyarmor gen --recursive --prefix parent.child src/parent
$ python -m build --skip-dependency-check --no-isolation