使用pex打包本地模块

时间:2016-11-07 16:34:13

标签: python build setuptools distutils python-pex

我试图用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,但这失败了,因为它无法找到命令。

看起来我似乎误解了一些根本性的东西,但我无法弄清楚是什么。

3 个答案:

答案 0 :(得分:5)

我最近与pex进行了一些斗争,试图让它包含本地模块。我学到的是:

  1. 必须为您的模块提供有效的setup.py文件才能实现此目的,并且:
  2. 必须指定应用程序的入口点
  3. 由于几个原因,这很难理解。通过阅读文档,我能够推断出我的案例中的正确命令应该是这样的:

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

    然而,当我尝试这个时,我不断收到错误说:

    pex.resolvable.InvalidRequirement: Unknown requirement type: .
    

    此错误的网络搜索会随着第一次点击 - this Github issue而显示 - 我输入时仍会打开。花了很长时间以为上面的命令因为这个bug而无法正常工作。我试图降级setuptools,并在this SO answer暗示提供setup.py文件的必要性之前做了六次其他无效的尝试来“解决”问题。 (那个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)通过{{1},否则它实际上不会包含您的更改}在调用--disable-cache时。

    在一天结束时,整个过程变成了写一个合适的pex并运行的练习:

    setup.py

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

    提示1

    使用$ pex . -v -e mymodule:main -o mymodule.pex --disable-cache 来测试您的python setup.py sdist文件。令人惊讶的是 很容易搞砸了,在你确定你的包装有正确的内容之前,没有必要涉及setup.py。运行pex后,尝试将其生成的源包(位于python setup.py sdist文件夹中)安装到新的venv中,看看它是否包含您期望的所有文件。只有在这个工作之后再继续调用dist

    提示2

    始终pex传递给--disable-cache,除非您有充分理由不这样做。

    提示3

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

    pex

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

答案 1 :(得分:2)

一种方法是:

  1. 使用python setup.py sdist
  2. 创建源分发(tarball,zip文件等)
  3. 然后使用pex开关

    运行-f DIST_DIR命令

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

答案 2 :(得分:0)

我发现了一些其他细节。如果您运行:

pex .

它将尝试在目录中使用setup.py版本。如果您没有,那么pex将失败。

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

pex . --disable-cache