如何维护具有依赖关系的python应用程序,包括我自己的自定义库?

如何维护具有依赖关系的python应用程序,包括我自己的自定义库?,python,windows,python-3.x,packaging,python-venv,Python,Windows,Python 3.x,Packaging,Python Venv,我正在使用Python开发一些特定于公司的应用程序。有一个自定义的共享模块(“库”),它描述了一些数据和算法,并且有几十个Python脚本与这个库一起工作。这些文件相当多,所以它们被组织在子文件夹中 myproject apps main_apps app1.py app2.py ... utils util1.py util2.py

我正在使用Python开发一些特定于公司的应用程序。有一个自定义的共享模块(“库”),它描述了一些数据和算法,并且有几十个Python脚本与这个库一起工作。这些文件相当多,所以它们被组织在子文件夹中

myproject
    apps
        main_apps
            app1.py
            app2.py
            ...
        utils
            util1.py
            util2.py
            ...
    library
        __init__.py
        submodule1
            __init__.py
            file1.py
            ...
        submodule2
            ...
用户只需转到myproject\utils并启动“py util2.py some_params”即可运行这些脚本。这些用户中有许多是开发人员,因此他们经常希望编辑库并立即使用更新的代码重新运行脚本。这个项目还使用了一些第三方库,我想确保每个人都在使用这些库的相同版本

现在,我遇到了两个关键问题:

  • 如何从(应用程序)引用(库)
  • 如何管理第三方依赖关系
  • 第一个问题对于许多Python开发人员来说都很熟悉,并且被问了很多次:指示Python从“…\library”导入包是相当困难的。我测试了几种不同的方法,但python似乎不愿意在任何地方搜索包,而是在标准库位置或脚本本身的文件夹中

    • 相对导入不起作用,因为脚本不是库的一部分(即使它是库的一部分,当直接执行脚本时,它仍然不起作用,除非它被放在我希望避免的“根”项目文件夹中)
    • 将.pth文件(阅读时可能会想到)放入脚本文件夹显然没有任何效果
    当然,直接干预sys.path工作,但是在每个脚本文件中,像这样的样板代码看起来都非常糟糕

    import sys, os.path
    here = os.path.dirname(os.path.realpath(__file__))
    module_root = os.path.abspath(os.path.join(here, '../..'))
    sys.path.append(python_root)
    import my_library
    
    我意识到这是因为Python希望正确地“安装”我的库,如果这个库与使用它的脚本分开开发,那么这确实是唯一正确的方法。但不幸的是,情况并非如此,我认为每次库发生更改时重新“安装”库将非常不方便,并且容易出错

    第二个问题很简单。有人向我们的app/lib添加了一个新的第三方模块,其他人在更新他们的app后开始看到导入问题。开发的几个分支,用户进行pip安装的不同时刻,很少回滚,最终每个人都会使用不同版本的第三方模块。在我的例子中,很多开发人员在使用较旧的Python2.x代码的同时还要继续使用Python3.x,这使得事情变得更加复杂

    在为我的问题寻找可能的解决方案时,我发现Python中有一个非常优秀的虚拟环境特性。事情看起来相当光明:

  • 为myproject创建一个venv
  • 将Requirements.txt文件作为应用程序的一部分分发,并提供相应填充venv的脚本
  • 将我自己的库符号链接到venv site_packages文件夹,以便Python始终能够检测到它
  • 这个解决方案看起来非常自然和健壮。我正在为我的项目明确地设置我自己的环境,并将我需要的任何东西放入这个venv中,包括我自己的库,我仍然可以动态编辑它。这确实有效。但是调用activate.bat来激活这个python环境,调用另一个批处理文件来停用它,这是一个混乱的过程,尤其是在Windows平台上。编辑sys.path的样板代码看起来很糟糕,但至少它不会像这个潜在的修复程序那样干扰用户体验

    所以我想问一个问题

  • 有没有办法将特定的python venv绑定到特定的文件夹,以便python launcher将自动使用该venv来处理这些文件夹中的脚本
  • 有没有更好的方法来处理我所缺少的这种情况

  • 我的项目环境是运行在Windows 10上的Python 3.6。

    我想我终于找到了一个合理的答案。只要在venv中添加指向python解释器的shebang行就足够了,例如

    #!../../venv/Scripts/python
    
    完整的项目结构如下所示

    myproject
        apps
            main_apps
                app1.py (with shebang)
                app2.py (with shebang)
                ...
            utils
                util1.py (with shebang)
                util2.py (with shebang)
                ...
        library
            __init__.py
            submodule1
                __init__.py
                file1.py
                ...
            submodule2
                ...
        venv
            (python interpreter, 3rd party modules)
            (symlink to library)
        requirements.txt
        init_environment.bat
    
    事情是这样的:

  • venv是一个虚拟python环境,包含项目所需的所有内容
  • init_environment.bat是一个脚本,它根据requirements.txt填充venv,并将指向我的库的符号链接放置到venv站点模块中
  • 所有脚本都以指向venv解释器的shebang行(带相对路径)开始
  • 有一个完全定制的环境,包含所有的lib,包括我自己的lib,使用它的脚本都会有非常自然的导入。PythonLauncher还将自动选择Python3.6作为解释器,并在我的项目中任何面向用户的脚本从控制台或windows资源管理器启动时加载相关模块

    缺点:

  • 如果从其他文件夹调用脚本,则相对shebang将不起作用
  • 用户仍然需要手动运行init_environment.bat以根据requirements.txt更新虚拟环境
  • Windows上的init_环境scrip需要提升权限才能创建符号链接(但希望2017年4月即将进行的Win10更新能够修复MS奇怪的决定)
  • 然而,我可以接受这些限制。希望这将帮助其他寻找类似问题的人


    如果还能听到其他选项(作为答案)和评论(作为评论),那就太好了。

    您是否在使用
    setuptools.py
    进行“安装”?如果是这样,您可以使用
    develope
    命令行参数而不是
    install
    ,请参阅讨论。这使您能够处理库并立即查看所做的更改。不幸的是,据我所知,这种对您有帮助的工具在Windows上并不真正可用。例如,您可以尝试寻找“谢谢”的对应词!这是一个我完全错过的好选择。现在在我的项目中,没有“安装”过程,而scrips只是看看