动态重新加载 Cython 模块

2024-01-21

我正在尝试自动更新我的 python 程序即时使用的 Cython .so 模块。下载新模块后del module and import modulePython 似乎仍在导入旧版本。

From 这个问题 https://stackoverflow.com/questions/17955194/how-to-reload-a-cython-module-interactively-using-pyximport,我已经尝试过,但没有成功:

from importlib import reload
import pyximport
pyximport.install(reload_support=True)
import module as m
reload(m)

From 这个问题 https://stackoverflow.com/questions/21630060/unloading-a-module-in-python-3-x,我也尝试过这个,但它也不起作用:

del sys.modules['module']
del module
import module

我也尝试过这个但没有成功:

from importlib import reload
import my_module

my_module = reload(my_module)

知道如何即时导入 Cython .SO 文件吗?


EDIT: Adding code for update check and download
update_filename = "my_module.cpython-37m-darwin.so"

if __name__ == '__main__':
    response = check_for_update()
    if response != "No new version available!":
        print (download_update(response))

def check_for_update():
    print("MD5 hash: {}".format(md5(__file__)))
    s = setup_session()
    data = {
        "hash": md5(__file__),
        "type": "md5",
        "platform": platform.system()
    }
    response = s.post(UPDATE_CHECK_URL, json=data)
    return response.text

def download_update(url):
    s = setup_session()
    with s.get(url, stream=True) as r:
        r.raise_for_status()
        with open(update_filename, 'wb') as f:
            for chunk in r.iter_content(chunk_size=8192): 
                if chunk:
                    f.write(chunk)
    return update_filename

下载新的 SO 文件后,我手动输入上面列出的命令。


所以我从来没有找到正确的方法来做到这一点,而是通过将我的程序分成两个单独的部分来解决这个问题:

  1. 不变的“运行程序”部分,只需导入 .SO 文件(或 Windows 上的 .PYD 文件)并在其中运行函数
  2. 包含核心逻辑的实际 .SO(或 .PYD)文件

不变的脚本检查 .SO/.PYD 文件的更新(使用它的 SHA256 哈希 + 模块版本),当找到更新版本时,它会下载它并替换现有的 .SO/.PYD 文件并重新启动自身,从而加载更新的模块。

当未找到更新时,它会导入本地 .SO/.PYD 文件并运行其中的函数。这种方法在 Windows 和 OSX 上都对我有效。

运行程序脚本 (run.py)

import requests, os, sys
from pathlib import Path
from shutil import move

original_filename = "my_module.cp38-win32.pyd" # the filename of the Cython module to load
update_filename = f"{original_filename}.update"
UPDATE_SERVER = "https://example.com/PROD/update-check"

def check_for_update():
    replace_current_pyd_with_previously_downloaded_update() # Actually perform the update
    # Add your own update check logic here
    # This one checks with {UPDATE_SERVER} for updates to {original_filename} and returns the direct link to the updated PYD file if an update exists
    s = requests.Session()
    data = {
        "hash": sha256(original_filename),
        "type": "sha256",
        "current_version": get_daemon_version(),
        "platform": platform.system()
    }
    response = s.post(UPDATE_SERVER, json=data)
    return response.text # direct link to newer version of PYD file if update exists

def download_update(url):
    # Download updated PYD file from update server and write/replace {update_filename}

def replace_current_pyd_with_previously_downloaded_update():
    print("Checking for previously downloaded update file")
    update_file_path = Path(update_filename)
    if update_file_path.is_file():
        print(f"Update file found! Performing update by replacing {original_filename} with the updated version and deleting {update_filename}")
        move(update_filename, original_filename)
    else:
        print("No previously downloaded update file found. Checking with update server for new versions")

def get_daemon_version():
    from my_module import get_version
    return get_version() # my_module.__version__.lower().strip()

def restart():
    print ("Restarting to apply update...\r\n")
    python = sys.executable
    os.execl(python, python, *sys.argv)

def apply_update():
    restart()

def start_daemon():
    import my_module
    my_module.initiate()
    my_module.start()

if __name__ == "__main__":
    response = None
    print ("Checking to see if an update is available...")
    try:
        response = check_for_update()
    except Exception as ex:
        print ("Unable to check for updates")
        pass
    if response is None:
        print ("Unable to check for software updates. Using locally available version.")
        start_daemon()
    elif response != "No new version available!" and response != '':
        print ("Newer version available. Updating...")
        print ("Update downloaded: {}".format(download_update(response)))
        apply_update()
        start_daemon()
    else:
        print ("Response from update check API: {}\r\n".format(response))
        start_daemon()

.SO/.PYD 文件

实际的 .SO 文件(在本例中为 .PYD 文件)应包含一个名为的方法get_version它应该返回模块的版本,并且您的更新服务器应该包含逻辑来确定更新是否可用于(SHA256 + module_version)的组合。

您当然可以以完全不同的方式实现更新检查。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

动态重新加载 Cython 模块 的相关文章

随机推荐

  • 替换指定位置的部分字符串

    我想用javascript中的另一个字符串替换指定位置 开始 结束 的字符串的一部分 这是一个例子 Hello world this is a question 我想用 friends 替换该字符串中从 5 开始到 10 结束的部分 输出将
  • 在哪里实现缓存 - 类库或 Windows 服务

    我有一个 Windows 服务 它使用计时器定期调用类库 在工作线程上 该类库具有所有必需的应用程序功能 而 Windows 服务只不过是一个简单的托管环境 作为其执行的一部分 库需要调用数据库并获取一堆记录 这些记录不会经常更改 想想几周
  • 应用程序终止后无法保存我的首选项

    您好 我正在尝试在我的 Android 应用程序上实现一个设置页面 我定义了一个 xml Preference 文件 在其中实现了 CheckBoxPreference 和 EditTextPreference 运行应用程序时 所有设置都可
  • 如何在Python中获取表单字段名称和值?

    我在用 python 开发的网页中遇到问题 我的表单中有几个字段 复选框 文本区域等 每个字段都有一些唯一的名称 我可以保存已知字段的值 i e field name fl textarea field value form getvalu
  • 在 Three.js 中将带有孔的 SVG 路径转换为挤压形状

    我有一个由 4 个多边形组成的形状 2 个无孔多边形和 2 个有孔多边形 这只是一个例子 实际上 可能存在由 50 个多边形组成的形状 其中 20 个是非孔多边形 30 个是孔多边形 在 SVG 路径中 可以通过组合 moveto s 和
  • FreeMarker编码混乱

    当我使用 FreeMarker 读取 UTF 8 编码模板时 特殊字符在浏览器中正确呈现 尽管freeMarkerConfig getDefaultEncoding 返回 Cp1252 如果我设置freeMarkerConfig setDe
  • 删除mongoDB中数组字段大小小于3的文档

    我有一个名为的 mongoDB 集合col有类似这样的文档 intField 123 strField hi arrField 1 2 3 intField 12 strField hello arrField 1 2 3 4 intFie
  • 实现自重置 XMLHttpRequest 对象

    我正在尝试使用 XMLHttpResponse 对象实现彗星风格的长轮询连接 这个想法是保持与服务器的开放连接 该服务器在可用时发送数据 伪造推送 XHR 对象完成后 我需要生成一个新对象来等待任何新数据 下面是一段代码 概述了一个有效的解
  • 如何自动调整移动网站的图像大小?

    我尝试了谷歌搜索 但仍然无法弄清楚如何根据各种移动设备的宽度调整图像的大小 这是我的尝试 CSS img test width 100 height auto HTML
  • 确定两个未排序的数组是否相同?

    给定两个unsorted arrays A and B具有不同的元素 确定是否A and B可以重新排列 使它们相同 我的策略如下 首先 使用确定性选择算法O N 是时候找到Max of A and Max of B 如果他们没有相同的Ma
  • 读取由空格分隔的单词,并且字符串值在批处理脚本中也包含空格

    我需要从批处理脚本读取注册表的默认值 某些项目的名称包含一些空格 另外我想在批处理文件中执行 for 循环一次两次 rem echo OFF setlocal ENABLEEXTENSIONS set KEY NAME HKEY CURRE
  • 如何在 Play 之外使用 Anorm?

    在 Scala 之外如何使用 Anorm 在玩的 Anorm 文档中 它简单地使用了类似的内容 DB withConnection implicit c gt val result Boolean SQL Select 1 execute
  • clang-query:检查函数参数类型的模板参数名称

    我有一个大项目 以及大量以下形式的 C 类成员函数 Return CClass MemberFunction Arg1 arg1 std weak ptr
  • 应用程序崩溃但没有 TestFlight 崩溃报告

    我有一位用户 使用 iPhone 5 报告说 我的应用程序在屏幕变黑 启动画面为黑色 后大约 15 秒后崩溃 用户下载了 TestFlight 版本 其中我在应用程序委托中包含了检查点 但我没有得到这些检查点被交叉的证据 而且我从未收到崩溃
  • 我可以用C++中的成员变量地址获取对象的引用吗?

    如果我只有该对象的成员变量的地址 是否可以获得对该对象的引用 struct example int var int main example exampleObject int point exampleObject var can i g
  • 让查询与参数和“like”一起使用

    我见过很多关于在 Sql 查询和 like 中使用参数的问题 但我已经尝试了所有我见过的编码方法 但仍然无法让我的查询给出结果 如果我在查询本身中输入一个值 它就会正常运行 当我运行列出的第一个查询时 出现错误 必须声明标量变量 Searc
  • QML 可以看到我的 Q_GADGET 但看不到 Q_OBJECT

    为什么我的可以Q GADGET在 QML JS 中可以完美阅读 但不是我的Q OBJECT 在 Ubuntu 14 04 上运行 Qt 5 8 0 我正在尝试返回一个列表 QVariantMap 的对象到 QML 我现在保持简单 没有指针等
  • 如果 body 有此类,则将此内容放入 #mydiv,否则将其他内容放入 #mydiv

    JS初学者在这里 我需要一个脚本帮助 根据页面正文标记是否具有 home 类来将不同的内容放置在 div 中 我正在尝试使用 hasClass html 来实现此目的 看起来应该非常简单 但我无法弄清楚 缺乏正确的语法知识 声明不正确 我不
  • 给定一个私钥,是否可以推导出它的公钥?

    根据我通过阅读各种材料所了解的一点点 公钥 私钥对是非对称加密的基础 也是选择 2 个素数 大致是您的私钥 并将它们相乘 大致是您的公钥 的基础 在我看来 如果您知道私钥 就可以生成公钥 这是正确的还是我弄错了什么 让我更困惑的是 不可能将
  • 动态重新加载 Cython 模块

    我正在尝试自动更新我的 python 程序即时使用的 Cython so 模块 下载新模块后del module and import modulePython 似乎仍在导入旧版本 From 这个问题 https stackoverflow