【问题标题】:Packaging local module with pex使用 pex 打包本地模块
【发布时间】:2017-03-21 02:00:42
【问题描述】:

我正在尝试使用 pex 打包我的本地模块,但我似乎无法做到。

我创建了一个简单的项目:

→ python --version
Python 2.7.10
→ pex --version
pex 1.1.15
→ tree .
.
├── bla
│   ├── __init__.py
│   └── main.py
└── setup.py

bla/__init__.py

import main

bla/main.py

if __name__ == '__main__':
   print 'yo'

在我看来这是最简单的项目。

→ pex -v . -o v.pex --disable-cache
Traceback (most recent call last):
  File "/Users/Charly/repos/load_tester/venv/bin/pex", line 11, in <module>
   sys.exit(main())
 File "/Users/Charly/repos/load_tester/venv/lib/python2.7/site-packages/pex/bin/pex.py", line 540, in main
    pex_builder = build_pex(reqs, options, resolver_options_builder)
 File "/Users/Charly/repos/load_tester/venv/lib/python2.7/site-packages/pex/bin/pex.py", line 475, in build_pex
    resolvables = [Resolvable.get(arg, resolver_option_builder) for arg in args]
  File "/Users/Charly/repos/load_tester/venv/lib/python2.7/site-packages/pex/resolvable.py", line 61, in get
    raise cls.InvalidRequirement('Unknown requirement type: %s' % resolvable_string)
 pex.resolvable.InvalidRequirement: Unknown requirement type: .

也尝试过python setup.py bdist_pex,但失败了,也找不到命令。

我似乎真的误解了一些基本的东西,但我不知道是什么。

【问题讨论】:

    标签: python build setuptools distutils python-pex


    【解决方案1】:

    我最近与pex 发生了争执,试图使其包含本地模块。我学到的是:

    1. 必须为您的模块提供一个有效的setup.py 文件,这样才能正常工作,并且:
    2. 必须指定应用程序的入口点

    这有几个原因很难弄清楚。通过阅读文档,我能够推断出在我的案例中正确的命令应该是这样的:

    $ pex . -v -e usersnotifier:main -o usersnotifier.pex
    

    但是,当我尝试这样做时,我一直收到错误消息:

    pex.resolvable.InvalidRequirement: Unknown requirement type: .
    

    出现了针对此错误的网络搜索——因为它的第一个命中——this Github issue,在我输入时它仍然处于打开状态。由于这个错误,A 花了很长时间认为上述命令不起作用。在this SO answer 暗示有必要提供setup.py 文件之前,我尝试降级setuptools 并进行了六次其他徒劳的尝试来“解决”该问题。 (那个 Github 问题原来是一个红鲱鱼。据我所知,它提到的 setuptools 错误已得到修复。)

    所以...我写了一个setup.py 文件。起初,我一直收到 Unknown requirement type: . 的错误消息,但后来我意识到我的 setup.py 只是包含一个非常明显的印刷错误。在这种情况下,pex 发出的错误消息实际上非常清楚,但随后是一个大的堆栈跟踪和Unknown requirement type: . 消息。我只是没有密切关注,错过的时间比我愿意承认的要长。

    我终于注意到了我的错字并修复了它,但是我的setup.py 中的另一个缺陷未能包含我的本地模块。 pex 在这种情况下有效,但生成的文件没有:

    $ pex . -v -e usersnotifier:main -o usersnotifier.pex --disable-cache                                                                                                                     
      usersnotifier 0.1: Resolving distributions :: Packaging paho-mqtt    
      pyinotify 0.9.6
      paho-mqtt 1.3.1
    pex: Building pex: 2704.3ms                                        
    pex:   Resolving distributions: 2393.2ms
    pex:       Packaging usersnotifier: 319.3ms
    pex:       Packaging pyinotify: 347.4ms
    pex:       Packaging paho-mqtt: 361.1ms
    Saving PEX file to usersnotifier.pex
    
    $ ./usersnotifier.pex 
    Traceback (most recent call last):
      File ".bootstrap/_pex/pex.py", line 367, in execute
      File ".bootstrap/_pex/pex.py", line 293, in _wrap_coverage
      File ".bootstrap/_pex/pex.py", line 325, in _wrap_profiling
      File ".bootstrap/_pex/pex.py", line 410, in _execute
      File ".bootstrap/_pex/pex.py", line 468, in execute_entry
      File ".bootstrap/_pex/pex.py", line 482, in execute_pkg_resources
      File ".bootstrap/pkg_resources/__init__.py", line 2297, in resolve
    ImportError: No module named 'usersnotifier'
    

    这是最终对我有用的基本setup.py

    from setuptools import setup                                                                                                                                                              
    
    setup(
        name='usersnotifier',
        version='0.1',
        py_modules=['usersnotifier', 'userswatcher'],
        install_requires=[
            'paho-mqtt>=1.3.1',
            'pyinotify>=0.9.6',
        ],
        include_package_data=True,
        zip_safe=False
    )
    

    它之前不起作用的原因是我不小心将参数py_module 传递给setup() 而不是py_modules(复数)。 ¯\_(ツ)_/¯

    @cmcginty 对这个问题的回答中提到了我遇到的最后一个障碍,即:除非您的模块版本号发生更改,否则pex 将缓存/重用您上次运行它时的工件。因此,如果您修复 setup.py 中的问题并重新运行 pex,它实际上不会合并您的更改,除非您:a) 修改版本号,或 b) 在调用 pex 时传递 --disable-cache .

    最后,整个事情变成了一个练习,写一个正确的setup.py,然后运行:

    $ pex . -v -e mymodule:main -o mymodule.pex --disable-cache
    

    以下是我可以提供的一些提示(可能是给未来的我自己):

    提示 1

    使用python setup.py sdist 测试您的setup.py 文件。 出人意料地很容易搞砸,除非你确定你的包裹有正确的内容,否则涉及pex 是没有意义的。运行python setup.py sdist 后,尝试将它生成的源包(位于dist 文件夹中)安装到一个新的venv 中,看看它是否包含您期望的所有文件。 之后才可以继续调用pex

    提示 2

    总是--disable-cache 传递给pex,除非你有充分的理由不这样做。

    提示 3

    在解决所有这些问题时,我发现我可以运行:

    $ unzip mymodule.pex
    

    提取 PEX 文件的内容。这有助于解决 sdist 包内容与 pex 化应用程序之间存在的任何差异。

    【讨论】:

      【解决方案2】:

      一种方法是:

      1. create 使用python setup.py sdist 创建源分发(tarball、zip 文件等)
      2. 然后使用-f DIST_DIR 开关运行pex 命令

        例如。 pex $(pip freeze) -o aflaskapp.pex -e 'aflaskapp.app' -f dist -v

      【讨论】:

        【解决方案3】:

        我发现了一些额外的细节。如果你运行:

        pex .
        

        它将尝试使用目录中的setup.py 构建。如果你没有那个,那么pex 将会失败。

        默认情况下,pex 将缓存本地包输出,因此如果您更改您的 setup.py,请使用命令确保您的更改在下一次运行 pex 时应用。

        pex . --disable-cache
        

        【讨论】:

        • 很奇怪。在我的例子中,运行这个命令会打开一个 python 交互式提示。怎么回事?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-26
        • 1970-01-01
        • 2013-11-06
        • 1970-01-01
        • 1970-01-01
        • 2020-06-28
        相关资源
        最近更新 更多