Python Module Bank - 单文件模块仓库
把 Python 模块打包进一个文件(.mbank),运行时直接从包里导入,支持 AES 字节码加密
和 PyArmor 代码混淆 双重保护。
存储层是 sqlite_vfs:
.mbank 就是一个 标准 svfs 包——一个用 SQLite 实现的虚拟文件系统,模块、源码、
PyArmor 运行时、第三方依赖都以文件形式躺在里面。
🌟 特性
- 单文件分发 - 所有模块打包到单个
.mbank;它同时是标准.svfs包,svfs/vfsverify/vfsunpack/svfs publish这些工具都能直接处理它 - AES 字节码加密 - 编译后的字节码使用 Fernet (AES-128-CBC) 加密存储
- PyArmor 代码混淆 - 支持使用 PyArmor 对 Python 源代码进行混淆保护
- 双层保护 - 可同时使用 PyArmor 混淆 + AES 字节码加密,提供双重安全保障
- 动态导入 - 运行时直接从包加载模块,无缝集成 Python 导入系统
- 完整包支持 - 支持包结构和子模块导入
- 第三方依赖随包分发 - 自动扫描 import 或显式指定,把打包机上已安装的第三方
包(含 C 扩展、数据文件、
.dist-info)一起收进包里的packages/;运行时按需 解包,目标机不需要再安装这些依赖 - 内容去重与压缩 - 内容按 sha256 寻址(同一份运行时/文件只存一次),写入时 zlib 压缩(压不动的内容原样存,不浪费)
- 可校验 - 快照带摘要,
vfsverify能验证包内容是否被改过 - CLI 工具 - 提供完整的命令行接口
📦 安装
从源码安装
git clone http://124.71.68.6:3000/chakcy/module_bank.git
cd module-bank
pip install -e .
使用 uv(推荐)
git clone http://124.71.68.6:3000/chakcy/module_bank.git
cd module-bank
uv sync
可选依赖
- PyArmor (强烈推荐):
uv add pyarmor或pip install pyarmor- 为模块提供 Python 源代码级别的混淆保护
- 商业版可去除试用版水印
存储层依赖
sqlite-vfs 是必装依赖,在 pyproject.toml 里以 git 依赖声明。发布到 PyPI 之前,
v0.4.0 那个 tag 必须先推到 Gitea,否则 uv sync / pip install 装不上(那个
仓库是私有的话,使用者还要能访问它,比如配好凭据助手或 .netrc)。
本地开发期间还没推 tag 时,把 pyproject.toml 里注释掉的 [tool.uv.sources]
覆盖打开(指向本机 sqlite_vfs 目录),或者直接
uv pip install -e <sqlite_vfs 路径>。
🚀 快速开始
1. 创建示例模块
# my_package/__init__.py
def hello():
print("Hello from my_package!")
return "success"
VERSION = "1.0.0"
# my_package/utils.py
def add(a, b):
return a + b
2. 打包模块到数据库
使用 AES 加密(推荐)
# 生成密钥并打包
mbank pack my_package --db my_package.mbank --key "$(python -c "from module_bank.encryption import Encryption; print(Encryption.generate_key())")"
使用 PyArmor 混淆
# 使用 PyArmor 保护源代码
mbank pack my_package --db my_package.mbank --pyarmor
使用双层保护
# PyArmor 混淆 + AES 加密
mbank pack my_package --db my_package.mbank --pyarmor --key "your-encryption-key"
连同第三方依赖一起打包
依赖需要先装在打包环境里(工具不联网、不执行 pip,只从已安装的包里收文件):
# 自动扫描源码里的 import,把自己写的包用到、且已安装的第三方依赖一起收进来
mbank pack my_package --db my_package.mbank --with-deps
# 显式指定(发行版名或导入名都行;默认沿 Requires-Dist 收传递依赖)
mbank pack my_package --db my_package.mbank --dep requests --dep yaml
# 从 requirements.txt 读依赖名(同样要求已安装)
mbank pack my_package --db my_package.mbank --requirements requirements.txt
打包结果可以自检:
mbank deps --db my_package.mbank # 列出随包分发的第三方依赖及版本
3. 从数据库导入
# import_example.py
from module_bank.python_to_sqlite import PythonToSQLite
packer = PythonToSQLite("my_package.mbank")
finder = packer.install_importer(key="your-encryption-key") # 如果加密了需要提供密钥
from my_package import utils
from my_package import hello
print(hello())
print(utils.add(3, 4))
🛡️ 安全保护机制
第一层:PyArmor 代码混淆
PyArmor 对 Python 源代码进行混淆,将代码转换为难以阅读和逆向的形式:
- 混淆后的代码依赖运行时二进制文件(
.pyd/.so),无法直接运行 - 支持混淆级别控制(代码混淆、模块混淆)
- 运行时文件会自动存储在包中(
runtime/),加载时自动部署到临时目录 - 整个包只跑一次 PyArmor,因此整包只存一份运行时:PyArmor 每次调用都会 生成一份自己的运行时(同名、内含那一次的新密钥、约 639 KB),逐模块调一次就会 让包体积按模块数线性膨胀(实测 6 个模块 2.3 倍、30 个模块约 6 倍)
# 高级混淆选项
mbank pack my_module.py --name my_module --db modules.mbank \
--pyarmor \
--pyarmor-obf-code 1 \
--pyarmor-obf-mod 1
第二层:AES 字节码加密
编译后的字节码使用 Fernet (AES-128-CBC) 加密:
# 生成密钥
python -c "from module_bank.encryption import Encryption; print(Encryption.generate_key())" > my_key.key
# 使用密钥打包
mbank pack my_module.py --name my_module --db modules.mbank --key "$(cat my_key.key)"
# 使用时提供密钥
mbank install --db modules.mbank --key "$(cat my_key.key)"
把密钥存进包(可选,注意权衡)
packer_key / get_key 可以把打包密钥写进包里,省掉"分发时要另传密钥"的麻烦:
packer = PythonToSQLite("modules.mbank", key=aes_key)
packer.pack_directory("src/")
packer.packer_key(aes_key) # 存进包根部(是 packer_key 文件,不是模块)
packer.close()
# 使用方拿到包就能直接跑(不用再传 key)
packer = PythonToSQLite("modules.mbank", readonly=True)
key = packer.get_key() # 没存过返回 None
packer.install_importer(key=key)
先把话说清楚:密钥和密文躺在同一个文件里,AES 这一层对"包泄露"就不再是 保护——能读包的人就能解开。它的价值是省事,真正的保护来自 PyArmor 那一层。 要真保密,就别用这两个方法,让使用方自己持有 key。
安全建议
- 密钥管理:加密密钥不要硬编码在代码中,使用环境变量或密钥管理服务
- 删除源代码:打包后可从数据库删除源代码,仅保留混淆后的代码:
# 删除所有模块的源代码
mbank delete_source --db modules.mbank
# 删除指定模块的源代码
mbank delete_source --db modules.mbank --module my_module
📖 详细使用
命令行工具
# 打包单个模块
mbank pack my_module.py --name my_module --db modules.mbank
# 打包整个目录(自动识别包结构)
mbank pack my_package/ --db modules.mbank
# 使用 PyArmor 混淆打包
mbank pack my_module.py --name my_module --db modules.mbank --pyarmor
# 使用 AES 加密打包
mbank pack my_module.py --name my_module --db modules.mbank --key "your-key"
# 双层保护
mbank pack my_module.py --name my_module --db modules.mbank --pyarmor --key "your-key"
# 连同第三方依赖一起打包(自动扫描 import)
mbank pack my_package/ --db modules.mbank --with-deps
# 显式指定依赖(可重复),或从 requirements.txt 读
mbank pack my_package/ --db modules.mbank --dep requests --dep idna
mbank pack my_package/ --db modules.mbank --requirements requirements.txt
# 排除某个依赖(例如平台专属、运行环境自带的包)
mbank pack my_package/ --db modules.mbank --with-deps --dep-exclude pywin32
# 列出数据库中的模块
mbank list --db modules.mbank
# 列出随包分发的第三方依赖
mbank deps --db modules.mbank
# 删除源代码
mbank delete_source --db modules.mbank
mbank delete_source --db modules.mbank --module my_module
# 安装导入器并进入交互模式
mbank install --db modules.mbank
mbank install --db modules.mbank --key "your-key"
编程接口
打包模块
from module_bank import PythonToSQLite
from module_bank.encryption import Encryption
# 生成加密密钥
key = Encryption.generate_key()
# 使用 AES 加密打包
packer = PythonToSQLite("modules.mbank", key=key)
# 或使用 PyArmor 混淆打包
packer = PythonToSQLite(
"modules.mbank",
pyarmor_obfuscate=True,
pyarmor_obf_code=1,
pyarmor_obf_mod=1,
)
# 打包单个模块
packer.pack_module("module.py", "module_name")
# 打包整个目录(自动识别包结构)
packer.pack_directory("my_package/")
# 验证包结构
packer.verify_package_structure()
打包第三方依赖
from module_bank import PythonToSQLite
from module_bank.dependencies import find_third_party_imports
packer = PythonToSQLite("modules.mbank")
# 显式指定:发行版名、导入名、requirements.txt 路径,或它们的列表
packer.pack_dependencies(["requests", "yaml"], recursive=True)
# 自动扫描自己的源码,把已安装的第三方依赖一起收进来
detected = find_third_party_imports(
["my_package/"], # 目录或 .py 文件
packed_top_levels=["my_package"], # 自己的包不算第三方
)
packer.pack_dependencies(optional=detected) # 找不到只提示,不报错
# 排除某些依赖(支持发行版名或导入名)
packer.pack_dependencies(["requests"], exclude=["pywin32"])
# 看包里到底带了什么
for dependency in packer.list_dependencies():
print(dependency["distribution"], dependency["version"],
dependency["top_level"], dependency["files"])
requirements= 里的名字找不到会直接抛 DependencyError(名字写错不该静默产出
一个缺依赖的包);optional= 里找不到只打印提示(代码里的可选导入很常见)。
导入模块
from module_bank import PythonToSQLite
# 如果数据库中的模块被 AES 加密了,需要提供密钥
packer = PythonToSQLite("modules.mbank")
# 安装导入器到 sys.meta_path
finder = packer.install_importer(key="your-key")
# 列出所有可用模块
modules = packer.list_modules()
for module in modules:
package_flag = " [包]" if module["is_package"] else ""
print(f" - {module['module_name']}{package_flag}")
# 直接导入数据库中的模块(就像普通模块一样)
import my_package
import my_package.submodule
print(my_package)
my_package.hello()
🏗️ 架构设计
核心组件
src/module_bank/
├── layout.py # 包内布局:模块名 ↔ svfs 路径的唯一映射处
├── python_to_sqlite.py # 主打包类
├── dependencies.py # 第三方依赖:发现、文件收集、依赖清单
├── sqlite_module_importer.py # 存储管理器(写侧:模块、依赖与 PyArmor 运行时)
├── sqlite_meta_path_finder.py # 元路径查找器(只读打开 + 模块清单缓存 + 依赖解包)
├── sqlite_module_loader.py # 模块加载器(读包、解密、部署运行时)
├── encryption.py # AES 密钥管理
├── pyarmor_encryption.py # PyArmor 混淆封装
├── cli.py # 命令行接口
└── __init__.py # 模块导出
数据流
1. 打包阶段:
.py 文件 → (可选: PyArmor 混淆) → 编译为字节码 → (可选: AES 加密)
→ 作为文件写进 svfs 包(modules/ 下)
第三方依赖(packages/):
已安装的发行版 → 按 RECORD/顶层目录收文件(.py / .pyd / 数据 / dist-info)
→ 原样写进 svfs 包(packages/ 下)+ 依赖清单
2. 导入阶段:
导入请求 → MetaPathFinder 查内存缓存 → ModuleLoader 读包
→ (AES 解密) → (PyArmor 运行时部署到临时目录) → 执行模块
第一次 import 到某个第三方依赖:
解出 packages/<顶层名>/ + 所有 dist-info → 临时目录 → sys.path
→ 标准路径查找器加载(原生扩展、数据文件、importlib.metadata 都按真实文件工作)
包内布局
.mbank 是一个标准 svfs 包(schema v3),把它 unpack 出来就是下面这棵树——
所以"包里有什么"看一眼目录就知道:
bank.mbank
├─ modules/a/b.pyc 字节码(marshal,可选 AES 加密)← 模块存在的锚点
├─ modules/a/b.py 源码(PyArmor 混淆后的原文;可删)
├─ modules/a/b.meta.json 标志位与用户元数据(全默认值时不写这个文件)
├─ modules/pkg/__init__.pyc 包(is_package)用 __init__
├─ modules/pkg/__init__.py
├─ modules/pkg/__init__.meta.json
├─ packages/requests/__init__.py 第三方依赖:按安装时的文件原样存
├─ packages/requests-2.34.2.dist-info/ 依赖元数据(importlib.metadata 用)
├─ packages/.manifest.json 依赖清单(发行版/版本/文件列表)
├─ runtime/pyarmor_runtime_000000/pyarmor_runtime.pyd
└─ runtime/pyarmor_runtime_000000/__init__.py
几条约定:
-
点分模块名里的点换成目录分隔符:
a.b→modules/a/b,所以包的字节码落在modules/a/b/__init__.pyc,与普通模块modules/a/b.pyc不冲突;is_package完全由路径决定(不记在元数据里,免得两处说法打架) -
.pyc是锚点:每个模块一定有字节码(打包时总是从源码编译),源码和元数据 都是可选的——delete_source删掉的就是.py那个文件 -
元数据文件里只有不可推导的信息:
{ "format": 1, "encrypted": false, "pyarmor_protected": true, "pyarmor_runtime": "pyarmor_runtime_000000", "metadata": { "version": "1.0" } }
-
一个模块的源码 + 元数据 + 字节码写在同一个事务里,所以不会出现"新元数据配 旧字节码"的中间态
用 svfs 的工具链直接操作包
因为 .mbank 就是 svfs 包,下列操作不需要 module_bank 参与:
svfs info bank.mbank # 统计与快照信息
vfsverify bank.mbank # 校验内容摘要
vfsunpack bank.mbank ./out # 导出成上面那棵目录树
svfs sign bank.mbank --key "$K" # 给快照做 HMAC 签名(防篡改)
from sqlite_vfs.core import SQLiteVFS
vfs = SQLiteVFS("bank.mbank", readonly=True)
print(vfs.get_stats())
print([i["name"] for i in vfs.list_directory("modules")])
vfs.close()
🔧 高级功能
打包第三方依赖
它做了什么
packages/ 是打包机 site-packages 的一个裁剪镜像:每个被选中的发行版按
RECORD 收齐它自己的文件(.py、.pyd/.so、数据文件、licenses),
连同它的 <name>-<version>.dist-info/ 一起写进包。运行时第一次 import 到某个
依赖的顶层包时,把这棵子树解到临时目录、挂到 sys.path 最前面,之后就是标准
Python 导入——C 扩展能加载、importlib.resources 能读数据、
importlib.metadata.version() 能取到版本号。
依赖清单(packages/.manifest.json)记录每个发行版的版本、顶层名与文件列表,
供 mbank deps 展示,也用于增量替换:同一个发行版重新打包时,先写新版本,
再按旧清单删掉新版本已经没有的文件,不会留下旧的 dist-info。
怎么选依赖
--with-deps:静态扫描源码里的import/from ... import/ 字面量importlib.import_module("x"),排掉标准库和自己的包,剩下的作为候选。只收 打包环境里已经安装的包,不联网、不执行 pip。--dep NAME:显式指定,发行版名(PyYAML)或导入名(yaml)都行;找不到 直接报错。--requirements FILE:读 requirements.txt 里的名字(-r、--index-url等 选项忽略)。- 默认沿
Requires-Dist递归收传递依赖(--no-dep-recursive关掉);extra == "..."标记的可选依赖不收。 --dep-exclude NAME:排除某个依赖,应对平台专属或运行环境自带的包。
运行时行为与限制
- 依赖第一次被 import 时解到系统临时目录(
mbank_deps_*),关闭查找器 (finder.close()或进程退出)时清理。目标机需要可写的临时目录。Windows 上 已加载的.pyd在进程退出前无法删除,临时目录可能残留(平台限制,与 PyArmor 运行时的清理是同一个问题)。 - 依赖是明文:第三方代码本来就是公开的,这一层不做 PyArmor/AES;保护只
针对你自己放在
modules/里的模块。 - 包里的依赖是为打包平台与 Python 版本准备的:带 C 扩展的依赖(numpy、 cryptography…)不能跨系统/跨版本直接用,需要在目标平台重新打包。
- 自动扫描是静态的:动态拼接的 import(
importlib.import_module(name)的变量 形式)发现不了,用--dep补。 - 不会安装 console script(依赖自带的命令行工具);
entry_points元数据会随 dist-info 一起带上,但入口脚本本身没有安装。 .pth文件、安装器写入 site-packages 之外的脚本/数据不在收集范围内。- 子进程里 import 依赖时,需要子进程自己也调用
install_importer()——sys.path的改动是进程内的。 - 同名冲突:
modules/里你自己的模块优先;依赖之间同名顶层包按sys.path顺序(后解出来的包在前)。
排除模式
# 打包时排除特定文件
packer.pack_directory(
"my_project/",
exclude_patterns=["*_test.py", "*.pyc", "__pycache__"],
)
元数据存储
# 为模块添加元数据
packer.importer.add_module(
"my_module",
source_code,
is_package=False,
metadata={"version": "1.0", "author": "me"},
)
混合导入
# 数据库导入器默认插入到 meta_path 开头,优先级高于文件系统
import sys
from module_bank import PythonToSQLite
packer = PythonToSQLite("modules.mbank")
finder = packer.install_importer()
# 如果需要文件系统优先,将查找器追加到末尾
sys.meta_path.remove(finder)
sys.meta_path.append(finder)
验证运行时完整性
from module_bank.sqlite_module_importer import SQLiteModuleImporter
importer = SQLiteModuleImporter("modules.mbank")
runtimes = importer.list_runtimes()
for rt in runtimes:
print(f"运行时: {rt['runtime_name']} (创建于: {rt['created_at']})")
⚠️ 注意事项
安全性
- 模块字节码直接执行,确保包来源可信
- AES 加密密钥必须安全保管,丢失后将无法解密模块
- PyArmor 混淆提供源代码级别的保护,但商业版才能去除试用版水印
- 生产环境建议 PyArmor 混淆 + AES 加密同时使用
delete_source会把源码文件及其内容从包里删掉(svfs 会回收不再被引用的内容), 但和所有 SQLite 删除一样,这不是安全擦除:旧内容可能还留在数据库的空闲页里。 真要彻底消除,打一个不含源码的新包,或者打完之后用VACUUM压一遍
兼容性
- 0.4.0 起存储层换成 sqlite_vfs:
.mbank从"自建的表结构"变成 svfs 包 (modules/+runtime/文件树)。旧包不兼容,需要用mbank pack重新打包—— 旧包被打开时会直接报错说明这一点,不会静默给出一个空包 - 0.5.0 起支持第三方依赖:依赖解析结果存在
packages/+ 依赖清单里;没有 清单的旧包行为不变,不需要重新打包 - 字节码不跨 Python 版本兼容(3.12 编译的模块无法在 3.11 加载)
- 你自己的模块不能是 C 扩展(打包时按源码编译为字节码);第三方依赖可以 连同 C 扩展一起打包
- 打包的第三方依赖与平台、Python 版本相关:带 C 扩展的依赖只能用于对应平台
(如 Windows 的
.pyd不能拿到 Linux 用),需要在目标平台重新打包 - PyArmor 运行时文件与操作系统相关(Windows 用
.pyd,Linux 用.so) - PyArmor 运行时与第三方依赖都需在目标系统上重新打包
- Python 3.10+(跟着 sqlite-vfs 与本项目实际用到的语法走)
性能
- 启动时:一次遍历包内容建模块清单(纯内存查表,与包大小无关),外加字节码 反序列化/运行时部署开销
- 运行时:与传统导入性能相同(使用 sys.modules 缓存)
- 最佳适用:长期运行的服务、桌面应用
更新模块
# 重新打包会自动更新(同一批文件在一个事务里替换,不会出现新旧混搭)
packer.pack_module("updated_module.py", "module_name")
删除模块
没有单独的"删模块"命令:不再需要的模块用 svfs 直接删掉目录项即可。更常见的
做法是删掉源码只留字节码(见上面的 delete_source)——那是一份 .mbank 该
有的状态。
from sqlite_vfs.core import SQLiteVFS
vfs = SQLiteVFS("modules.mbank")
vfs.remove("modules/module_to_remove.pyc") # 锚点没了,模块即不存在
vfs.remove("modules/module_to_remove.py")
vfs.close()
备份与恢复
# 包是单个文件,易于备份
cp modules.mbank modules.backup.mbank
# 恢复
cp modules.backup.mbank modules.mbank
版本管理
包里的版本就是 svfs 的快照(版本之间共享内容 blob,多留一版几乎不占空间)。 分工是:sqlite_vfs 只负责"把你要的那一版内容给你",选哪一版、什么时候留版 是 module_bank 这一层的事。
定格一个版本
from module_bank import PythonToSQLite
packer = PythonToSQLite("modules.mbank")
packer.pack_directory("src/")
packer.tag_version("release-1.0") # 把当前内容定格成 release-1.0
packer.close()
# 之后继续改、继续打包,写的是自动派生的工作版本(名字叫 work),
# release-1.0 那份不再变动
packer = PythonToSQLite("modules.mbank")
packer.pack_directory("src/")
packer.tag_version("release-2.0")
for v in packer.list_versions():
print(v["id"], v["name"], v["total_files"], "当前" if v["current"] else "")
packer.close()
为什么
tag_version不是简单调一次create_snapshot(name):svfs 的快照 语义是"当前那一版"(写入落进当前版本),所以create_snapshot("release-1.0", copy_entries=True)得到的名字落在会继续变动的那一版上——实测结果是打完 v1、tag 成 release-1.0、再打 v2 之后,release-1.0里是 v2。tag_version因此是"先把当前快照改名(定格),再派生一个工作版本接手后续写入"。
从指定版本加载
# 加载 release-1.0 那一份(id 或名字都行)
packer = PythonToSQLite("modules.mbank", readonly=True, snapshot="release-1.0")
packer.install_importer() # 之后 import 到的都是 v1.0 的代码
packer.close()
不指定 snapshot 就是跟着最新(工作版本)走;指定了就钉死在那一版,
包后续新增多少版本都不影响它——灰度、回滚、给老客户重发旧版都用这个。
snapshot 也可以传给 install_importer(snapshot=...),或者在包里用
use_version(...) 切换当前版本。可写句柄不能直接打开一个历史版本(那是
"顺手改掉发出去的那份"):确实要改,先显式 use_version("release-1.0")。
mbank list --db modules.mbank --snapshot release-1.0 # 看某一版里有什么
mbank install --db modules.mbank --snapshot release-1.0
防篡改:签名与验签
签的是快照摘要(HMAC-SHA256,对称密钥,只挡"发出后被改过",不挡伪造):
packer = PythonToSQLite("modules.mbank") # 签名要写入签名记录 → 可写句柄
packer.sign_version("共享密钥", key_id="ci-2026", snapshot="release-1.0")
packer.close()
key_id 是"用哪把密钥签的"(同一版可以有多把密钥的签名,靠它区分),要签哪一版
用 snapshot=。验签(包括"加载前先验")在只读句柄上就能做:
packer = PythonToSQLite("modules.mbank", readonly=True)
report = packer.verify_version("共享密钥", snapshot="release-1.0", key_id="ci-2026")
print(report["ok"], report["errors"]) # {"ok": bool, "errors": [...]}
packer.close()
验不验签是加载方的策略,默认不验(不传就当没这回事):
# 加载前先验,验不过拒绝加载(抛 SignatureVerificationError)
finder = packer.install_importer(
signature_key="共享密钥",
signature_key_id="ci-2026", # 可选:只认这个 key_id 的签名
allow_unsigned=False, # 那一版还没签过时是否放行(默认放行)
)
mbank install --db modules.mbank --signature-key "$KEY" \
--signature-key-id ci-2026 --require-signature
install_importer 的结论落在返回的 finder 上(finder.signature_report):报告里
signature 为 None 表示那一版没有匹配的签名记录(按了 key_id 就只认那个
key_id 的记录),默认策略下放行;这与"签名不匹配"是两回事——后者一律拒绝加载。
传了 signature_key 不等于验过了,脚本里要如实报,就看这个字段。
上面这些验签(verify_version、install_importer)都跑在只读连接上,不需要写权限。
更细的操作(快照清单、导出、发 CDN)直接用 svfs 的工具链:
svfs info modules.mbank # 统计与当前快照
vfsverify modules.mbank # 校验内容摘要
vfsunpack modules.mbank ./out # 导出成目录树
svfs sign modules.mbank --key "$K" --key-id ci-2026 # 命令行签名(等价)
📚 应用场景
- 商业软件分发 - PyArmor 混淆保护源代码知识产权
- 安全敏感环境 - AES 加密确保即使数据库泄露也无法还原代码
- 插件系统 - 动态加载数据库中的加密/混淆插件模块
- 教育平台 - 安全分发练习代码,防止学生抄袭
- 微服务 - 打包多个服务模块到单个加密文件
- 嵌入式系统 - 减少文件系统依赖,提高安全性
注意: 本工具主要用于模块分发和部署场景,不适合开发阶段的频繁修改。
许可证: MIT License
Metadata
Release files for module-bank 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| module_bank-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / module_bank-0.5.0-py3-none-any.whl
| Download URL | module_bank-0.5.0-py3-none-any.whl |
|---|---|
| Size | 64.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8629bc3143cdebd45deac3e2ac134a7d3235b081aac6371f2c96d9ef89dbb2ce
|
|
BLAKE2b-256 checksum How to use checksums |
cf9d7324ff1cffd469f1748b9dd546dfc5737aff14af3ae2db7a4932f28f728d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Security for module-bank 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.