草庐IT

Esky 的 Python 项目结构

coder 2024-06-05 原文

我的问题本质上是“我应该如何构建卡住的、已部署的基于 Python 的 Windows 应用程序的文件和文件夹的结构。”为了了解我的情况,这里有一些背景:

我正在为我的工作场所构建一个使用 Python 2.7 的桌面应用程序。它是基于 PyQt 构建的基于 GUI 的应用程序。我正在使用 Esky 构建应用程序这是一个跨平台的卡住和更新框架。 Esky 基本上包装/调用 py2exe、py2app、bb_freeze 或您已安装的适用于当前平台的任何工具。 Esky 创建了一个压缩包,如下所示:

prog.exe                     - esky bootstrapping executable
appdata/                     - container for all the esky magic
  appname-X.Y.platform/      - specific version of the application
    prog.exe                 - executable(s) as produced by freezer module
    library.zip              - pure-python frozen modules
    pythonXY.dll             - python DLL
    esky-files/              - esky control files
      bootstrap/             - files not yet moved into bootstrapping env
      bootstrap-manifest.txt - list of files expected in bootstrap env
      lockfile.txt           - lockfile to block removal of in-use versions
      ...other deps...
  updates/                   - work area for fetching/unpacking updates

然后可以将这些压缩包放在 Esky 寻找更新的文件服务器上。提供了许多方法来管理更新,包括非常简单的 auto_update()。发生更新时,appname-X.Y.platform 文件夹基本上被替换为下一个版本文件夹...因此 myApp.0.1.win32 文件夹被替换为 myApp.0.2.win32 文件夹。

您应该知道的背景的另一方面是我正在将应用程序分发给我的同事,他们没有安装 Python。我不是在分发 Python 包或库,我是在部署桌面应用程序(我的同事并不特别关心它是用什么编写的,只关心它是否有效)。我构建了一个 Inno 安装程序,用于安装应用程序、提供卸载程序和各种快捷方式。因为团队中的每个人都拥有基本相同的 Windows 7 64 位环境,所以我非常安全地只为该平台构建。

所以,回到结构问题。我读过为项目框架推荐某种格式的指南,例如 Learn Python the Hard Way, Exercise 46Hitchhiker's Guide to Packaging .然而,这些指南面向 Python 包开发人员,而不是编译应用程序开发人员。

我也遇到了 Esky 的 appname-X.Y.platform 文件夹的问题,因为每次更新程序时它都会更改名称(以反射(reflect)版本号)。因为我希望“开始”菜单中的一些快捷方式始终引用文档、变更日志等,所以我让安装程序将其中一些文件放在 appdata 文件夹下。当程序更新时,我有一些代码来检查我希望在外部“可见”的那些文件的更新版本,并将更新版本从 appname-X.Y.platform 文件夹中复制出来,并覆盖 appdata 文件夹中的副本。然后我还需要一种存储持久用户设置的方法,因此该程序会生成并使用一个 appdata\settings 文件夹(否则每次更新时设置都会被删除)。

我是否应该继续让应用程序在更新后将新文件推送到 appdata 文件夹的过程?我是否应该构建自己的文档、示例、设置等结构,并让程序在必要时用更新的文件填充这些文件夹?我应该尝试改变或更好地利用 Esky 的行为以更好地适应我的使用吗?也许我应该重新设计我的应用程序,使其既可以作为 Python 包又可以作为最终用户应用程序分发?

这个问题与this one about static files with Esky有关, this one about Python deployed application structure ,以及许多关于 Python 项目结构的一般性问题,这些问题没有使用 Esky 专门解决。还提供了一些讨论 Esky 的视频 herehere .

我正在寻求有关应对这些挑战的“最佳实践”方法的建议。如果这不符合 StackOverflow 问题格式,我会很乐意尝试重新措辞或缩小问题的范围。

最佳答案

尽管 Esky 的自动更新会在每次更新时更改我的应用程序文件夹的名称,但这是我提到的关于使文件可用于静态位置的快捷方式的问题的解决方案。下面的函数在 QMainWindow 的类定义中。

如果您的应用程序不使用日志记录模块,则日志记录语句可以替换为打印语句,但我强烈建议使用日志记录,尤其是在部署这样的独立应用程序时。

import os
import shutil
import logging

def push_updated_files(self):
    """
    Manually push auto-updated files from the application folder up to the appdata folder
    This enables shortcuts and other features on the computer to point to these files since the application
      directory name changes with each update.
    """
    logger = logging.getLogger(__name__)

    #Verify whether running script or frozen/deployed application
    if getattr(sys, 'frozen', False):
        logger.info("Verifying Application Integrity...")

        #Files which should by copied to appdata directory to be easily referenced by shortcuts, etc.
        data_files = ['main.ico',
                      'uninstall.ico',
                      'ReadMe.txt',
                      'changelog.txt',
                      'WhatsNew.txt',
                      'copyright.txt',
                      'Documentation.pdf']

        logger.debug("  App Path: {0}".format(self._app_path))

        #Get application top directory
        logger.debug("  AppData Directory: {0}".format(self._appdata_path))

        #Get application internal file path
        for f in data_files:
            a_file = f
            int_path = os.path.join(self._app_path, a_file)
            logger.debug("  Internal File Path: {0}".format(int_path))

            #Get file's creation time
            mtime_int = os.stat(int_path).st_mtime
            logger.debug("  Internal File Modified Time: {0}".format(time.ctime(mtime_int)))

            #Get external file path
            ext_path = os.path.join(self._appdata_path, a_file)
            if os.path.exists(ext_path):
                mtime_ext = os.stat(ext_path).st_mtime
                logger.debug("  External File Modified Time: {0}".format(time.ctime(mtime_ext)))

                if mtime_int > mtime_ext:
                    logger.debug("  Replacing external file with new file...")
                    try:
                        os.remove(ext_path)
                        shutil.copy(int_path, ext_path)
                    except Exception, e:
                        logger.error("  Failed to replace the external file...", exc_info=True)
                else:
                    logger.debug("  External file is newer than internal file - all is well.")
            else:
                logger.debug("  Copying file to appdata to be externally accessible")
                shutil.copy(int_path, ext_path)

也与此相关,在处理用户设置时(目前只是一个用于填充最近文件列表的 history.txt 文件)我在 appdata 下有一个 settings 文件夹,但在 application 文件夹之外,这样设置就不会丢失每次更新。我可能会为文档和图标制作类似的文件夹。

关于Esky 的 Python 项目结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20475868/

有关Esky 的 Python 项目结构的更多相关文章

  1. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  5. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  6. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  7. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  8. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  9. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  10. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

随机推荐