参考: - https://docs.python.org/zh-cn/3/library/zipimport.html - zipimport --- 从 Zip 存档中导入模块 - https://stackoverflow.com/questions/30032686/how-to-run-a-python-script-from-a-password-protected-zip - 从加密 zip 文件中 import 文件 - https://github.com/Dakkaron/ArchiveImporter/tree/master - 从加密 zip 文件中 import 文件
1. 创建一个可导入的 zip 文件
1.1 目录结构
例如 code 目录是一个 package 目录
code/
code/__init__.py
code/hello.py
1.2 创建压缩包
创建一个加密的 zip 压缩包
cd code &&
zip -r -e ../xxx.zip *
-r
遍历目录-e
加密(只解密文件,不加密目录结构。所以可以看到有哪些文件)
方法一:使用 ArchiveImporter import zip 包(可能有缺陷)
不太搞的懂 ArchiveImporter
,貌似有缺陷
import sys
from ArchiveImporter import addZip
addZip(sys.argv[1], password='Hello@World')
import hello
hello.say()
addZip()
导入 zip 中的文件,需要输入密码hello.say()
调用 zip 中的函数
方法二:使用 zipimport
参考:https://learnku.com/docs/pymotw/zipimport-load-python-code-from-zip-archives/3494
需要把官方的 zipimport
包中的 _get_data
函数替换掉,以便有办法使用密码解密文件。
import zipimport
import zipfile
pwd = 'Hello@World'
def _get_data(archive, toc_entry, fullname=None):
datapath, compress, data_size, file_size, file_offset, time, date, crc = toc_entry
fullpath = datapath[len(archive) + 1:]
#logger.debug(f"archive: {archive} , toc_entry: {toc_entry} , fullpath: {fullpath}")
with zipfile.ZipFile(archive) as arch:
with arch.open(fullpath, pwd=pwd.encode()) as file:
data = file.read()
#logger.debug(str(data))
return data
zipimport._get_data = _get_data
importer = zipimport.zipimporter('./service.zip')
module = importer.load_module('syncapi')
app.register_blueprint(module.app, url_prefix='/api')
方法三:从字符串导入包 loader hooks(未验证)
来源:https://stackoverflow.com/questions/65009309/dynamically-import-module-from-memory-in-python-3-using-hooks
import importlib
import sys
import types
class StringLoader(importlib.abc.Loader):
def __init__(self, modules):
self._modules = modules
def has_module(self, fullname):
return (fullname in self._modules)
def create_module(self, spec):
if self.has_module(spec.name):
module = types.ModuleType(spec.name)
exec(self._modules[spec.name], module.__dict__)
return module
def exec_module(self, module):
pass
class StringFinder(importlib.abc.MetaPathFinder):
def __init__(self, loader):
self._loader = loader
def find_spec(self, fullname, path, target=None):
if self._loader.has_module(fullname):
return importlib.machinery.ModuleSpec(fullname, self._loader)
if __name__ == '__main__':
modules = {
'my_module': """
BAZ = 42
class Foo:
def __init__(self, *args: str):
self.args = args
def bar(self):
return ', '.join(self.args)
"""}
finder = StringFinder(StringLoader(modules))
sys.meta_path.append(finder)
import my_module
foo = my_module.Foo('Hello', 'World!')
print(foo.bar())
print(my_module.BAZ)