【问题标题】:Check if my application runs in development/editable mode检查我的应用程序是否在开发/可编辑模式下运行
【发布时间】:2016-11-10 14:28:38
【问题描述】:

我的 Python 应用程序可以正常安装,也可以使用 pip 在开发/可编辑模式下安装,如下所示:

virtualenv my_app
source my_app/bin/activate
pip install -e my_app

如何创建一个函数来自省我的 virtualenv 并检查我的应用程序是否在开发/可编辑模式下运行?

sys 模块中是否有任何“标志”?

动机:在开发模式和生产中具有不同的配置。

编辑:我比较 virtualenvpackage 目录。

import os
import sys

import pkg_resources

main_pkg = 'my_app'
package_dir = pkg_resources.resource_filename(main_pkg, '__init__.py')
virtualenv_dir = os.path.dirname(os.path.dirname(sys.executable))
common_path = os.path.commonprefix([package_dir, virtualenv_dir])
is_dev_mode = not common_path.startswith(virtualenv_dir)

我测试 package_dir 是否是 virtualenv_dir 的子目录:如果不是子目录,则我处于开发模式。

EDIT2:

有没有更可靠的解决方案?

我想知道环境中是否没有数据/标志可以清楚地向我表明我的应用程序正在开发模式下运行。

如果另一个依赖也处于开发模式会发生什么?

【问题讨论】:

标签: python


【解决方案1】:

使用来自pip 的代码我们可以确定:

import pip
import pkg_resources

# I've done `pip install -e .` for a git repo I'm working in inside
# a virtualenv
distributions = {v.key: v for v in pkg_resources.working_set}
# >>> distribution
# pre-commit 0.9.3 (/home/asottile/workspace/pre-commit)
distribution = distributions['pre-commit']

# Below is approximately how `pip freeze` works, see the end of
# the answer for a simpler approach, still using pip

# Turn into a pip FrozenRequirement (I'm using pip 9.0.1, it may
# be different for your version)
# I've passed an empty list for the second argument (dependency_links)
# I don't think it's necessary?
frozen_requirement = pip.FrozenRequirement.from_dist(distribution, [])

# Query whether the requirement is installed editably:
print(frozen_requirement.editable)

它的神奇之处在于 pip (pip.utils) 内部的一个小函数:

def dist_is_editable(dist):
    """Is distribution an editable install?"""
    for path_item in sys.path:
        egg_link = os.path.join(path_item, dist.project_name + '.egg-link')
        if os.path.isfile(egg_link):
            return True
    return False

这里的dist 是一个pkg_resources 分布(正如我们在上面获得的)。你当然可以直接使用dist_is_editable函数,而不是通过FrozenRequirement

# With `distribution` as above:
from pip.utils import dist_is_editable
print(dist_is_editable(distribution))  # True in my case ;)

【讨论】:

  • 听起来不错 ;-) 键是 pkg_resources.working_set 包名称 (import pkg_name) 还是库名称(如 setup.py 中的 `name="lib_name")?
  • 这些键最终将成为“规范化”的包名称(因此对于yaml,您将寻找pyyaml,对于pre_commit,您将寻找pre-commit)。规范化规则遵循python.org/dev/peps/pep-0440 (PEP440)(尽管通常它最终是.replace('_', '-').lower()
  • 来自 pip docs-you must not use pip’s internal APIs in this way。无论如何,信息已经过时了,现在可以在direct_url.json而不是egg-link中记录分发是否可编辑。
  • @wim 当然这是在不同的时间写的,现在是 5 年前 :)
  • 是的,虽然当时 pip 也没有任何公共 API(参考:#4696)。更重要的是,最好使用当前有效/支持的方式更新答案。
【解决方案2】:

顶级解决方案需要针对更新版本的 pip 进行更新,其中 FrozenRequirement 类不再可以在 pip 的命名空间中访问。

我在相关行中使用了这种解决方法。

from pip._internal.operations.freeze import FrozenRequirement 
frozen_requirement = FrozenRequirement.from_dist(distribution)

【讨论】:

    【解决方案3】:

    我不确定是否有可靠的方法来确定这一点。事实上,我建议您不要进行这样的测试路径,因为您可能会在不同的操作系统或环境中遇到不同的特殊情况。

    我推荐几个替代方案:

    1) 如果这是一个命令行实用程序,我建议允许加载可通过命令行标志配置的自定义配置文件:

    from argparse import ArgumentParser
    import sys
    import json
    
    parser = ArgumentParser(description='...')
    parser.add_argument('-c', '--config', default='config.json')
    
    def main(argv):
        args = parser.parse_args(argv)
        print('loading config file:', args.config)
        with open(args.config, 'r') as config:
            config = json.loads(config.read())
        print('loaded config', config) 
        # TODO do something with the config
    
    if __name__ == '__main__':
        main(sys.argv[1:])
    

    运行:python3 test1.py -c config-dev.json

    2) 如果这不是 CLI 应用程序,您可以通过使用环境变量来实现类似的事情:

    import os
    import json
    
    os.environ.get('CONFIG', 'config.json')
    
    def main():
        config_file = os.environ.get('CONFIG', 'config.json')
        print('loading config file:', config_file)
        with open(config_file, 'r') as config:
            config = json.loads(config.read())
        print('loaded config', config) 
        # TODO do something with the config
    
    if __name__ == '__main__':
        main()
    

    运行:CONFIG=config-dev.json python3 test2.py,或:

    export CONFIG=config-dev.json
    python3 test2.py
    

    您还可以制作一个 shell 脚本来帮助设置您的开发环境,我们称之为customenv

    source env/bin/activate
    export CONFIG=config-dev.json
    

    然后你可以使用这个文件来激活开发环境:

    source customenv
    

    3)如果您真的希望在开发环境的代码中使用特殊情况,您也可以通过环境变量来指定:

    import os
    is_dev_mode = 'MY_APP_DEV' in os.environ and os.environ['MY_APP_DEV'] == '1'
    if is_dev_mode:
        print('dev mode!')
    

    使用MY_APP_DEV=1 python3 test3.py 运行,或者:

    export MY_APP_DEV=1
    python3 -m test3.py
    

    4) 更多自定义:

    import os
    app_mode = os.environ.get('MY_APP_MODE', 'prod')
    print(app_mode)
    

    【讨论】:

    • 我同意你的观点,但这不是我想要的。对不起,但是,我真的需要检查我是否处于 development 模式。
    猜你喜欢
    • 2017-01-24
    • 1970-01-01
    • 2016-12-02
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 2014-07-26
    • 2016-12-29
    • 2014-09-17
    相关资源
    最近更新 更多