标签归档:packaging

如何构造包含Cython代码的Python包

问题:如何构造包含Cython代码的Python包

我想制作一个包含一些Cython代码的Python包。我的Cython代码运行良好。但是,现在我想知道如何最好地打包它。

对于大多数只想安装软件包的人,我想包括.cCython创建的文件,并安排对其setup.py进行编译以生成模块。然后,用户不需要安装Cython即可安装软件包。

但是对于那些可能想要修改程序包的人,我也想提供Cython .pyx文件,并以某种方式还允许setup.py使用Cython构建它们(因此这些用户需要安装Cython)。

我应该如何构造软件包中的文件以适应这两种情况?

用Cython文档提供了一些指导。但这并没有说明如何制作一个setup.py处理Cython情况的单例。

I’d like to make a Python package containing some Cython code. I’ve got the the Cython code working nicely. However, now I want to know how best to package it.

For most people who just want to install the package, I’d like to include the .c file that Cython creates, and arrange for setup.py to compile that to produce the module. Then the user doesn’t need Cython installed in order to install the package.

But for people who may want to modify the package, I’d also like to provide the Cython .pyx files, and somehow also allow for setup.py to build them using Cython (so those users would need Cython installed).

How should I structure the files in the package to cater for both these scenarios?

The Cython documentation gives a little guidance. But it doesn’t say how to make a single setup.py that handles both the with/without Cython cases.


回答 0

我现在已经在Python程序包simplerandomBitBucket repo-编辑:now github)中亲自完成了这个任务(我不希望这是一个受欢迎的程序包,但这是学习Cython的好机会)。

此方法依赖于以下事实:.pyx使用Cython.Distutils.build_ext(至少使用Cython版本0.14)构建文件似乎总是.c在与源.pyx文件相同的目录中创建文件。

这是一个精简版setup.py,我希望其中显示要点:

from distutils.core import setup
from distutils.extension import Extension

try:
    from Cython.Distutils import build_ext
except ImportError:
    use_cython = False
else:
    use_cython = True

cmdclass = {}
ext_modules = []

if use_cython:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.pyx"]),
    ]
    cmdclass.update({'build_ext': build_ext})
else:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.c"]),
    ]

setup(
    name='mypackage',
    ...
    cmdclass=cmdclass,
    ext_modules=ext_modules,
    ...
)

我还进行了编辑,MANIFEST.in以确保将mycythonmodule.c其包含在源分发中(使用创建的源分发python setup.py sdist):

...
recursive-include cython *
...

我不承诺mycythonmodule.c版本控制“ trunk”(或Mercurial的“ default”)。发布时,我需要记住先进行操作python setup.py build_ext,以确保mycythonmodule.c该源代码是最新的并且是最新的。我还创建了一个release分支,并将C文件提交到该分支中。这样,我就拥有与该发行版一起分发的C文件的历史记录。

I’ve done this myself now, in a Python package simplerandom (BitBucket repo – EDIT: now github) (I don’t expect this to be a popular package, but it was a good chance to learn Cython).

This method relies on the fact that building a .pyx file with Cython.Distutils.build_ext (at least with Cython version 0.14) always seems to create a .c file in the same directory as the source .pyx file.

Here is a cut-down version of setup.py which I hope shows the essentials:

from distutils.core import setup
from distutils.extension import Extension

try:
    from Cython.Distutils import build_ext
except ImportError:
    use_cython = False
else:
    use_cython = True

cmdclass = {}
ext_modules = []

if use_cython:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.pyx"]),
    ]
    cmdclass.update({'build_ext': build_ext})
else:
    ext_modules += [
        Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.c"]),
    ]

setup(
    name='mypackage',
    ...
    cmdclass=cmdclass,
    ext_modules=ext_modules,
    ...
)

I also edited MANIFEST.in to ensure that mycythonmodule.c is included in a source distribution (a source distribution that is created with python setup.py sdist):

...
recursive-include cython *
...

I don’t commit mycythonmodule.c to version control ‘trunk’ (or ‘default’ for Mercurial). When I make a release, I need to remember to do a python setup.py build_ext first, to ensure that mycythonmodule.c is present and up-to-date for the source code distribution. I also make a release branch, and commit the C file into the branch. That way I have a historical record of the C file that was distributed with that release.


回答 1

克雷格·麦昆(Craig McQueen)的答案有所添加:请参见下文,了解如何覆盖sdist命令以使Cython在创建源代码分发之前自动编译源文件。

这样一来,您就可以避免意外分发过期C资源的风险。在您对分发过程的控制有限的情况下(例如,通过持续集成自动创建分发时),这也很有帮助。

from distutils.command.sdist import sdist as _sdist

...

class sdist(_sdist):
    def run(self):
        # Make sure the compiled Cython files in the distribution are up-to-date
        from Cython.Build import cythonize
        cythonize(['cython/mycythonmodule.pyx'])
        _sdist.run(self)
cmdclass['sdist'] = sdist

Adding to Craig McQueen’s answer: see below for how to override the sdist command to have Cython automatically compile your source files before creating a source distribution.

That way your run no risk of accidentally distributing outdated C sources. It also helps in the case where you have limited control over the distribution process e.g. when automatically creating distributions from continuous integration etc.

from distutils.command.sdist import sdist as _sdist

...

class sdist(_sdist):
    def run(self):
        # Make sure the compiled Cython files in the distribution are up-to-date
        from Cython.Build import cythonize
        cythonize(['cython/mycythonmodule.pyx'])
        _sdist.run(self)
cmdclass['sdist'] = sdist

回答 2

http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules

强烈建议您分发生成的.c文件以及Cython源,以便用户无需使用Cython即可安装模块。

还建议您分发的版本中默认不启用Cython编译。即使用户安装了Cython,他也可能不想仅使用它来安装模块。另外,他使用的版本可能与您使用的版本不同,并且可能无法正确编译您的源代码。

这只是意味着您附带的setup.py文件将只是生成的.c文件上的常规distutils文件,对于基本示例,我们将使用:

from distutils.core import setup
from distutils.extension import Extension
 
setup(
    ext_modules = [Extension("example", ["example.c"])]
)

http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules

It is strongly recommended that you distribute the generated .c files as well as your Cython sources, so that users can install your module without needing to have Cython available.

It is also recommended that Cython compilation not be enabled by default in the version you distribute. Even if the user has Cython installed, he probably doesn’t want to use it just to install your module. Also, the version he has may not be the same one you used, and may not compile your sources correctly.

This simply means that the setup.py file that you ship with will just be a normal distutils file on the generated .c files, for the basic example we would have instead:

from distutils.core import setup
from distutils.extension import Extension
 
setup(
    ext_modules = [Extension("example", ["example.c"])]
)

回答 3

最简单的方法是同时包含两者,而仅使用c文件?包括.pyx文件是不错的选择,但是无论如何只要有了.c文件就不需要了。想要重新编译.pyx的人可以安装Pyrex并手动进行。

否则,您需要有一个用于distutils的自定义build_ext命令,该命令首先生成C文件。Cython已经包含一个。http://docs.cython.org/src/userguide/source_files_and_compilation.html

该文档没有做的是说如何使其成为条件,但是

try:
     from Cython.distutils import build_ext
except ImportError:
     from distutils.command import build_ext

应该处理。

The easiest is to include both but just use the c-file? Including the .pyx file is nice, but it’s not needed once you have the .c file anyway. People who want to recompile the .pyx can install Pyrex and do it manually.

Otherwise you need to have a custom build_ext command for distutils that builds the C file first. Cython already includes one. http://docs.cython.org/src/userguide/source_files_and_compilation.html

What that documentation doesn’t do is say how to make this conditional, but

try:
     from Cython.distutils import build_ext
except ImportError:
     from distutils.command import build_ext

Should handle it.


回答 4

包含(Cython)生成的.c文件非常奇怪。尤其是当我们在git中包含它时。我更喜欢使用setuptools_cython。当Cython不可用时,它将构建一个具有内置Cython环境的鸡蛋,然后使用该鸡蛋构建代码。

一个可能的示例:https : //github.com/douban/greenify/blob/master/setup.py


更新(2017-01-05):

因为setuptools 18.0,没有必要使用setuptools_cython是一个从头开始构建Cython项目而无需的示例setuptools_cython

Including (Cython) generated .c files are pretty weird. Especially when we include that in git. I’d prefer to use setuptools_cython. When Cython is not available, it will build an egg which has built-in Cython environment, and then build your code using the egg.

A possible example: https://github.com/douban/greenify/blob/master/setup.py


Update(2017-01-05):

Since setuptools 18.0, there’s no need to use setuptools_cython. Here is an example to build Cython project from scratch without setuptools_cython.


回答 5

这是我编写的安装脚本,它使在构建中包括嵌套目录更加容易。需要从一个程序包中的文件夹运行它。

Givig结构如下:

__init__.py
setup.py
test.py
subdir/
      __init__.py
      anothertest.py

setup.py

from setuptools import setup, Extension
from Cython.Distutils import build_ext
# from os import path
ext_names = (
    'test',
    'subdir.anothertest',       
) 

cmdclass = {'build_ext': build_ext}
# for modules in main dir      
ext_modules = [
    Extension(
        ext,
        [ext + ".py"],            
    ) 
    for ext in ext_names if ext.find('.') < 0] 
# for modules in subdir ONLY ONE LEVEL DOWN!! 
# modify it if you need more !!!
ext_modules += [
    Extension(
        ext,
        ["/".join(ext.split('.')) + ".py"],     
    )
    for ext in ext_names if ext.find('.') > 0]

setup(
    name='name',
    ext_modules=ext_modules,
    cmdclass=cmdclass,
    packages=["base", "base.subdir"],
)
#  Build --------------------------
#  python setup.py build_ext --inplace

编译愉快;)

This is a setup script I wrote which makes it easier to include nested directories inside the build. One needs to run it from folder within a package.

Givig structure like this:

__init__.py
setup.py
test.py
subdir/
      __init__.py
      anothertest.py

setup.py

from setuptools import setup, Extension
from Cython.Distutils import build_ext
# from os import path
ext_names = (
    'test',
    'subdir.anothertest',       
) 

cmdclass = {'build_ext': build_ext}
# for modules in main dir      
ext_modules = [
    Extension(
        ext,
        [ext + ".py"],            
    ) 
    for ext in ext_names if ext.find('.') < 0] 
# for modules in subdir ONLY ONE LEVEL DOWN!! 
# modify it if you need more !!!
ext_modules += [
    Extension(
        ext,
        ["/".join(ext.split('.')) + ".py"],     
    )
    for ext in ext_names if ext.find('.') > 0]

setup(
    name='name',
    ext_modules=ext_modules,
    cmdclass=cmdclass,
    packages=["base", "base.subdir"],
)
#  Build --------------------------
#  python setup.py build_ext --inplace

Happy compiling ;)


回答 6

我想到的简单技巧:

from distutils.core import setup

try:
    from Cython.Build import cythonize
except ImportError:
    from pip import pip

    pip.main(['install', 'cython'])

    from Cython.Build import cythonize


setup(…)

如果无法导入,只需安装Cython。一个人可能不应该共享此代码,但是对于我自己的依赖关系来说已经足够了。

The simple hack I came up with:

from distutils.core import setup

try:
    from Cython.Build import cythonize
except ImportError:
    from pip import pip

    pip.main(['install', 'cython'])

    from Cython.Build import cythonize


setup(…)

Just install Cython if it could not be imported. One should probably not share this code, but for my own dependencies it’s good enough.


回答 7

所有其他答案都依赖

  • 发行版
  • 从导入Cython.Build,在通过cython setup_requires导入和导入cython之间会产生鸡与蛋的问题。

一种现代的解决方案是改用setuptools,请参见以下答案(自动处理Cython扩展需要setuptools 18.0,即,它已经可用了很多年)。setup.py具有需求处理,入口点和cython模块的现代标准可能如下所示:

from setuptools import setup, Extension

with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setup(
    name='MyPackage',
    install_requires=requirements,
    setup_requires=[
        'setuptools>=18.0',  # automatically handles Cython extensions
        'cython>=0.28.4',
    ],
    entry_points={
        'console_scripts': [
            'mymain = mypackage.main:main',
        ],
    },
    ext_modules=[
        Extension(
            'mypackage.my_cython_module',
            sources=['mypackage/my_cython_module.pyx'],
        ),
    ],
)

All other answers either rely on

  • distutils
  • importing from Cython.Build, which creates a chicken-and-egg problem between requiring cython via setup_requires and importing it.

A modern solution is to use setuptools instead, see this answer (automatic handling of Cython extensions requires setuptools 18.0, i.e., it’s available for many years already). A modern standard setup.py with requirements handling, an entry point, and a cython module could look like this:

from setuptools import setup, Extension

with open('requirements.txt') as f:
    requirements = f.read().splitlines()

setup(
    name='MyPackage',
    install_requires=requirements,
    setup_requires=[
        'setuptools>=18.0',  # automatically handles Cython extensions
        'cython>=0.28.4',
    ],
    entry_points={
        'console_scripts': [
            'mymain = mypackage.main:main',
        ],
    },
    ext_modules=[
        Extension(
            'mypackage.my_cython_module',
            sources=['mypackage/my_cython_module.pyx'],
        ),
    ],
)

回答 8

我发现仅使用setuptools而非功能受限的distutils的最简单方法是

from setuptools import setup
from setuptools.extension import Extension
try:
    from Cython.Build import cythonize
except ImportError:
    use_cython = False
else:
    use_cython = True

ext_modules = []
if use_cython:
    ext_modules += cythonize('package/cython_module.pyx')
else:
    ext_modules += [Extension('package.cython_module',
                              ['package/cython_modules.c'])]

setup(name='package_name', ext_modules=ext_modules)

The easiest way I found using only setuptools instead of the feature limited distutils is

from setuptools import setup
from setuptools.extension import Extension
try:
    from Cython.Build import cythonize
except ImportError:
    use_cython = False
else:
    use_cython = True

ext_modules = []
if use_cython:
    ext_modules += cythonize('package/cython_module.pyx')
else:
    ext_modules += [Extension('package.cython_module',
                              ['package/cython_modules.c'])]

setup(name='package_name', ext_modules=ext_modules)

回答 9

我想我通过提供自定义build_ext命令找到了一种很好的方法。这个想法如下:

  1. 我通过重写finalize_options()import numpy在函数的主体中添加numpy标头,很好地避免了numpy在setup()安装之前不可用的问题。

  2. 如果cython在系统上可用,它将挂接到命令的check_extensions_list()方法中,并通过cython化所有过时的cython模块,将其替换为C扩展,稍后可通过该build_extension() 方法处理。我们也只是在模块中提供功能的后一部分:这意味着,如果cython不可用,但是我们有C扩展名,它仍然可以工作,从而可以进行源代码分发。

这是代码:

import re, sys, os.path
from distutils import dep_util, log
from setuptools.command.build_ext import build_ext

try:
    import Cython.Build
    HAVE_CYTHON = True
except ImportError:
    HAVE_CYTHON = False

class BuildExtWithNumpy(build_ext):
    def check_cython(self, ext):
        c_sources = []
        for fname in ext.sources:
            cname, matches = re.subn(r"(?i)\.pyx$", ".c", fname, 1)
            c_sources.append(cname)
            if matches and dep_util.newer(fname, cname):
                if HAVE_CYTHON:
                    return ext
                raise RuntimeError("Cython and C module unavailable")
        ext.sources = c_sources
        return ext

    def check_extensions_list(self, extensions):
        extensions = [self.check_cython(ext) for ext in extensions]
        return build_ext.check_extensions_list(self, extensions)

    def finalize_options(self):
        import numpy as np
        build_ext.finalize_options(self)
        self.include_dirs.append(np.get_include())

这样一来,人们就可以编写setup()参数而不必担心导入以及是否有可用的cython的问题:

setup(
    # ...
    ext_modules=[Extension("_my_fast_thing", ["src/_my_fast_thing.pyx"])],
    setup_requires=['numpy'],
    cmdclass={'build_ext': BuildExtWithNumpy}
    )

I think I found a pretty good way of doing this by providing a custom build_ext command. The idea is the following:

  1. I add the numpy headers by overriding finalize_options() and doing import numpy in the body of the function, which nicely avoids the problem of numpy not being available before setup() installs it.

  2. If cython is available on the system, it hooks into the command’s check_extensions_list() method and by cythonizes all out-of-date cython modules, replacing them with C extensions that can later handled by the build_extension() method. We just provide the latter part of the functionality in our module too: this means that if cython is not available but we have a C extension present, it still works, which allows you to do source distributions.

Here’s the code:

import re, sys, os.path
from distutils import dep_util, log
from setuptools.command.build_ext import build_ext

try:
    import Cython.Build
    HAVE_CYTHON = True
except ImportError:
    HAVE_CYTHON = False

class BuildExtWithNumpy(build_ext):
    def check_cython(self, ext):
        c_sources = []
        for fname in ext.sources:
            cname, matches = re.subn(r"(?i)\.pyx$", ".c", fname, 1)
            c_sources.append(cname)
            if matches and dep_util.newer(fname, cname):
                if HAVE_CYTHON:
                    return ext
                raise RuntimeError("Cython and C module unavailable")
        ext.sources = c_sources
        return ext

    def check_extensions_list(self, extensions):
        extensions = [self.check_cython(ext) for ext in extensions]
        return build_ext.check_extensions_list(self, extensions)

    def finalize_options(self):
        import numpy as np
        build_ext.finalize_options(self)
        self.include_dirs.append(np.get_include())

This allows one to just write the setup() arguments without worrying about imports and whether one has cython available:

setup(
    # ...
    ext_modules=[Extension("_my_fast_thing", ["src/_my_fast_thing.pyx"])],
    setup_requires=['numpy'],
    cmdclass={'build_ext': BuildExtWithNumpy}
    )

如何编写setup.py以包含Git存储库作为依赖项

问题:如何编写setup.py以包含Git存储库作为依赖项

我正在尝试setup.py为我的包裹写东西。我的软件包需要指定对另一个Git存储库的依赖。

这是我到目前为止所拥有的:

from setuptools import setup, find_packages

setup(
    name='abc',
    packages=find_packages(),
    url='https://github.abc.com/abc/myabc',
    description='This is a description for abc',
    long_description=open('README.md').read(),
    install_requires=[
        "requests==2.7.0",
        "SomePrivateLib>=0.1.0",
        ],
    dependency_links = [
     "git+git://github.abc.com/abc/SomePrivateLib.git#egg=SomePrivateLib",
    ],
    include_package_data=True,
)

当我跑步时:

pip install -e https://github.abc.com/abc/myabc.git#egg=analyse

我懂了

找不到满足SomePrivateLib> = 0.1.0要求的版本(来自分析)(来自版本:)找不到SomePrivateLib> = 0.1.0(来自分析)的匹配分布

我究竟做错了什么?

I am trying to write setup.py for my package. My package needs to specify a dependency on another git repo.

This is what I have so far:

from setuptools import setup, find_packages

setup(
    name='abc',
    packages=find_packages(),
    url='https://github.abc.com/abc/myabc',
    description='This is a description for abc',
    long_description=open('README.md').read(),
    install_requires=[
        "requests==2.7.0",
        "SomePrivateLib>=0.1.0",
        ],
    dependency_links = [
     "git+git://github.abc.com/abc/SomePrivateLib.git#egg=SomePrivateLib",
    ],
    include_package_data=True,
)

When I run:

pip install -e https://github.abc.com/abc/myabc.git#egg=analyse

I get

Could not find a version that satisfies the requirement SomePrivateLib>=0.1.0 (from analyse) (from versions: ) No matching distribution found for SomePrivateLib>=0.1.0 (from analyse)

What am I doing wrong ?


回答 0

您可以在此处找到正确的方法。

dependency_links=['http://github.com/user/repo/tarball/master#egg=package-1.0']

关键不是提供指向Git存储库的链接,而是提供指向tarball的链接。如果您/tarball/master像上面那样添加,GitHub会为您创建master分支的压缩包。

You can find the right way to do it here.

dependency_links=['http://github.com/user/repo/tarball/master#egg=package-1.0']

The key is not to give a link to a git repository, but a link to a tarball. Github creates a tarball of the master branch for you if you append /tarball/master as shown above.


回答 1

在通过上面的评论中@muon链接的pip问题3939PEP-508规范后,我发现成功地通过setup.py使用以下规范模式来安装我的私有repo依赖项install_requires(不再dependency_links):

install_requires = [
  'some-pkg @ git+ssh://git@github.com/someorgname/pkg-repo-name@v1.1#egg=some-pkg',
]

@v1.1指示在GitHub上创建的发布标志,并可以用一个分支,提交,或不同类型的标签来代替。

After digging through the pip issue 3939 linked by @muon in the comments above and then the PEP-508 specification, I found success getting my private repo dependency to install via setup.py using this specification pattern in install_requires (no more dependency_links):

install_requires = [
  'some-pkg @ git+ssh://git@github.com/someorgname/pkg-repo-name@v1.1#egg=some-pkg',
]

The @v1.1 indicates the release tag created on github and could be replaced with a branch, commit, or different type of tag.


回答 2

以下答案不适用于Pip 19+


不幸的是,其他答案不适用于私有存储库,这是最常见的用例之一。我最终的确使用了如下setup.py文件:

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository - needs entry in `dependency_links`
        'ExampleRepo'
    ],

    dependency_links=[
        # Make sure to include the `#egg` portion so the `install_requires` recognizes the package
        'git+ssh://git@github.com/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

较新版本的pip消除了使用“ dependency_links”的需要,从而使操作更加轻松-

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository
        'ExampleRepo @ git+ssh://git@github.com/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

The following answer is deprecated for Pip 19+


Unfortunately the other answer does not work with private repositories, which is one of the most common use cases for this. I eventually did get it working with a setup.py file that looks like this:

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository - needs entry in `dependency_links`
        'ExampleRepo'
    ],

    dependency_links=[
        # Make sure to include the `#egg` portion so the `install_requires` recognizes the package
        'git+ssh://git@github.com/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

Newer versions of pip make this even easier by removing the need to use “dependency_links”-

from setuptools import setup, find_packages

setup(
    name = 'MyProject',
    version = '0.1.0',
    url = '',
    description = '',
    packages = find_packages(),
    install_requires = [
        # Github Private Repository
        'ExampleRepo @ git+ssh://git@github.com/example_organization/ExampleRepo.git#egg=ExampleRepo-0.1'
    ]
)

回答 3

一个更一般的答案:要从requirements.txt文件中获取信息,请执行以下操作:

from setuptools import setup, find_packages
from os import path

loc = path.abspath(path.dirname(__file__))

with open(loc + '/requirements.txt') as f:
    requirements = f.read().splitlines()

required = []
dependency_links = []

# Do not add to required lines pointing to Git repositories
EGG_MARK = '#egg='
for line in requirements:
    if line.startswith('-e git:') or line.startswith('-e git+') or \
            line.startswith('git:') or line.startswith('git+'):
        if EGG_MARK in line:
            package_name = line[line.find(EGG_MARK) + len(EGG_MARK):]
            required.append(package_name)
            dependency_links.append(line)
        else:
            print('Dependency to a git repository should have the format:')
            print('git+ssh://git@github.com/xxxxx/xxxxxx#egg=package_name')
    else:
        required.append(line)

setup(
    name='myproject',  # Required
    version='0.0.1',  # Required
    description='Description here....',  # Required
    packages=find_packages(),  # Required
    install_requires=required,
    dependency_links=dependency_links,
)

A more general answer, to get the information from the requeriments.txt file I do:

from setuptools import setup, find_packages
from os import path

loc = path.abspath(path.dirname(__file__))

with open(loc + '/requirements.txt') as f:
    requirements = f.read().splitlines()

required = []
dependency_links = []
# do not add to required lines pointing to git repositories
EGG_MARK = '#egg='
for line in requirements:
    if line.startswith('-e git:') or line.startswith('-e git+') or \
            line.startswith('git:') or line.startswith('git+'):
        if EGG_MARK in line:
            package_name = line[line.find(EGG_MARK) + len(EGG_MARK):]
            required.append(package_name)
            dependency_links.append(line)
        else:
            print('Dependency to a git repository should have the format:')
            print('git+ssh://git@github.com/xxxxx/xxxxxx#egg=package_name')
    else:
        required.append(line)

setup(
    name='myproject',  # Required
    version='0.0.1',  # Required
    description='Description here....',  # Required
    packages=find_packages(),  # Required
    install_requires=required,
    dependency_links=dependency_links,
) 

回答 4

实际上,如果您希望递归安装软件包(YourCurrentPackage包含SomePrivateLib),例如,当您希望将YourCurrentPackage包含到另一个软件包中(例如OuterPackage→YourCurrentPackage→SomePrivateLib)时,您将同时需要:

install_requires=[
    ...,
    "SomePrivateLib @ git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
],
dependency_links = [
    "git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
]

并确保您使用版本号创建了一个标签。

同样,如果您的Git项目是私有的,并且您想将其安装在容器中(例如DockerGitLab运行器),那么您将需要对存储库的授权访问。请考虑将Git + HTTPS与访问令牌一起使用(例如在GitLab上:https : //docs.gitlab.com/ee/user/profile/personal_access_tokens.html ):

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    ....

    install_requires=[
            ...,
            f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ],
    dependency_links = [
            f"git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

Actually if you like to make your packages installable recursivelly (YourCurrentPackage includes your SomePrivateLib), e.g. when you want to include YourCurrentPackage into another one (like OuterPackage -> YourCurrentPackage -> SomePrivateLib) you’ll need both:

install_requires=[
    ...,
    "SomePrivateLib @ git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
],
dependency_links = [
    "git+ssh://github.abc.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
]

And make sure you have a tag created with your version number.

Also if your git project is private and you like to install it inside the container e.g. Docker or GitLab runner, you will need authorized access to your repo. Please consider to use git+https with access tokens (like on GitLab: https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html):

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    ....

    install_requires=[
            ...,
            f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ],
    dependency_links = [
            f"git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

回答 5

我在GitLab中成功使用了这三个选项。我正在使用GitLab版本11。

选项1-未指定令牌。Shell将提示输入用户名/密码。

from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        "SomePrivateLib @ git+https://gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

选项2-指定了用户访问令牌。通过转到GitLab→帐户右上方→设置→访问令牌生成的令牌。创建具有read_repository权限的令牌。

例:

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

选项3-指定存储库级别的令牌。通过转到存储库→设置→存储库→部署令牌生成的令牌。在这里,创建一个具有read_repository权限的令牌。

例:

import os
from setuptools import setup

TOKEN_USER = os.getenv('EXPORTED_TOKEN_USER')
TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://{TOKEN_USER}:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

在这三者中,我都可以简单地做:“ SomePrivateLib @ git + https://gitlab.server.com/abc/SomePrivateLib.git”,最后没有#egg标记。

I was successful with these 3 options in gitlab. I am using version 11 of gitlab.

option 1 – no token specified. shell will prompt for username/password.

from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        "SomePrivateLib @ git+https://gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

option 2 – user access token specified. token generated by going to gitlab > account top right > settings > access tokens. create token with read_repository rights.

example:

import os
from setuptools import setup

TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://gitlab-ci-token:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

option 3 – repository-level token specified. token generated by going to the repository > settings > repository > deploy tokens. from here create a token with read_repository rights.

example:

import os
from setuptools import setup

TOKEN_USER = os.getenv('EXPORTED_TOKEN_USER')
TOKEN_VALUE = os.getenv('EXPORTED_VAR_WITH_TOKEN')

setup(
    install_requires=[
        f"SomePrivateLib @ git+https://{TOKEN_USER}:{TOKEN_VALUE}@gitlab.server.com/abc/SomePrivateLib.git@0.1.0#egg=SomePrivateLib"
    ]
)

In all 3, I was able to do simply: “SomePrivateLib @ git+https://gitlab.server.com/abc/SomePrivateLib.git” without the #egg marking at the end.


setuptools与distutils:为什么distutils仍然是一回事?

问题:setuptools与distutils:为什么distutils仍然是一回事?

Python就可以用于包装和说明项目工具混淆历史:这些包括distutils标准库中,distributedistutils2,和setuptools(也许更多)。看来,distributedistutils2投票赞成的停产setuptools,这让两个相互竞争的标准。

据我所知,setuptools提供了更多的选择(例如,声明依赖项,测试等)distutils,但是它没有包含在Python标准库中(还可以吗?)。

现在推荐《Python打包用户指南》 [ 1 ]:

使用setuptools定义的项目和创建源代码分发。

并说明:

尽管您可以将pure distutils用于许多项目,但它不支持定义对其他项目的依赖关系,并且缺少一些便捷实用程序来自动正确填充所提供的包元数据setuptools。在标准库之外,setuptools还为不同版本的Python提供了更一致的功能集,并且(与不同distutilssetuptools将进行更新,以在所有受支持的版本上生成即将到来的“ Metadata 2.0”标准格式。

即使对于确实选择使用的项目distutils,当pip直接从源代码(而不是从预构建的wheel文件安装)安装此类项目时,它实际上也会使用setuptools来构建您的项目。

但是,查看各种项目的setup.py文件可以发现,这似乎并不是一个实际的标准。许多软件包仍在使用,distutils而那些支持的软件包则setuptools经常setuptoolsdistutils回退导入结合使用:

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

然后尝试找到一种写可以由setuptools和安装的安装程序的方法distutils。由于distutils不支持设置功能中的依赖关系,因此通常包括各种容易出错的依赖关系检查方式。

人们为什么还要付出额外的努力来支持distutilssetuptools标准库中没有的事实是唯一的原因吗?distutils编写仅支持setup.py文件的优点和缺点是什么setuptools

Python has a confusing history of tools that can be used to package and describe projects: these include distutils in the Standard Library, distribute, distutils2, and setuptools (and maybe more). It appears that distribute and distutils2 were discontinued in favor of setuptools, which leaves two competing standards.

To my understanding setuptools offers far more options (e.g. declaring dependencies, tests, etc.) than distutils, however it is not included in the Python standard library (yet?).

The Python Packaging User Guide[1] recommends now:

Use setuptools to define projects and create Source Distributions.

And explains:

Although you can use pure distutils for many projects, it does not support defining dependencies on other projects and is missing several convenience utilities for automatically populating package metadata correctly that are provided by setuptools. Being outside the standard library, setuptools also offers a more consistent feature set across different versions of Python, and (unlike distutils), setuptools will be updated to produce the upcoming “Metadata 2.0” standard formats on all supported versions.

Even for projects that do choose to use distutils, when pip installs such projects directly from source (rather than installing from a prebuilt wheel file), it will actually build your project using setuptools instead.

However, looking into various project’s setup.py files reveals that this does not seem to be an actual standard. Many packages still use distutils and those that support setuptools often mix setuptools with distutils e.g. by doing a fallback import:

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

Followed by an attempt to find a way to write a setup that can be installed by both setuptools and distutils. This often includes various ways of error-prone dependency checking, since distutils does not support dependencies in the setup function.

Why are people still making the extra effort to support distutils – is the fact that setuptools is not in the standard library the only reason? What are the advantages of distutils and are there any drawbacks of writing setup.py files that only support setuptools.


回答 0

看看这个SO问题。它很好地解释了所有打包方法,并可能在某种程度上帮助您回答问题:distribute,distutils,setuptools和distutils2之间的区别?

Distutils仍然是使用Python打包的标准工具。它包含在标准库中(Python 2和Python 3.0至3.3)。它对简单的Python发行版很有用,但缺少功能。它介绍了可以在setup.py脚本中导入的distutils Python软件包。

Setuptools是为克服Distutils的限制而开发的,未包含在标准库中。它引入了一个名为easy_install的命令行实用程序。它还介绍了可以在setup.py脚本中导入的setuptools Python软件包,以及可以在您的代码中导入以查找随发行版一起安装的数据文件的pkg_resources Python软件包。它的陷阱之一是它对distutils Python软件包进行了Monkey修补。它应该与pip配合良好。最新版本于2013年7月发布。

因此,正如您所见,setuptools应该比distutils更受青睐,而且我知道您的问题是从哪里来的,但是我看不到distutils会很快失去支持,因为简单地说,它在许多情况下都与一些流行的旧版程序一起使用。 。正如您可能知道的那样,在旧版程序中更改此类操作可能会很痛苦,并且会遇到很多问题,例如不兼容,这将导致开发人员不得不重写源代码。因此,distutils是标准python库的一部分,而setuptools不是。因此,如果您现在正在创建python程序,请使用setuptools,但是请记住,如果没有distutils,setuptools将永远不存在。

Have a look at this SO question. It explains all the packaging methods very well, and might help answer your question to some extent: Differences between distribute, distutils, setuptools and distutils2?

Distutils is still the standard tool for packaging in Python. It is included in the standard library (Python 2 and Python 3.0 to 3.3). It is useful for simple Python distributions, but lacks features. It introduces the distutils Python package that can be imported in your setup.py script.

Setuptools was developed to overcome Distutils’ limitations, and is not included in the standard library. It introduced a command-line utility called easy_install. It also introduced the setuptools Python package that can be imported in your setup.py script, and the pkg_resources Python package that can be imported in your code to locate data files installed with a distribution. One of its gotchas is that it monkey-patches the distutils Python package. It should work well with pip. The latest version was released in July 2013.

So, as you can see setuptools should be preferred to distutils, and I see where your question comes from, however I don’t see distutils losing support anytime soon, as, simply put, it is used in many cases with some popular legacy programs. And as you probably know changing these sorts of things in legacy programs can be quite a pain and come with quite a few problems, for example incompatibilities, which would then lead to the developer having to rewrite the source code. So there is that, and also the fact that distutils is a part of the standard python library whereas setuptools is not. So, if you are creating a python program, in this day and age, use setuptools, however keep in mind that without distutils, setuptools would have never existed.


回答 1

事实是setuptools不在标准库中的唯一原因

那是原因之一。以下直接来自NumPysetup.py

if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or
        sys.argv[1] in ('--help-commands', 'egg_info', '--version',
                        'clean')):
    # Use setuptools for these commands (they don't work well or at all
    # with distutils).  For normal builds use distutils.
    try:
        from setuptools import setup
    except ImportError:
        from distutils.core import setup

因此,NumPy setuptools希望找到它。但是后来SciPy才这样做,直到在某些情况下被修补为更喜欢它为止distutils。引用提交日志:

Setuptools sets mode +x on the test scripts, so that Nose refuses to run
them. Better not do that.

当然,一个合并之间setuptoolsdistribute应该解决这一切在适当的时间,但许多软件包仍然需要支持的Python 2.6的安装。

is the fact that setuptools is not in the standard library the only reason

That’s one reason. The following is straight from the NumPy setup.py:

if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or
        sys.argv[1] in ('--help-commands', 'egg_info', '--version',
                        'clean')):
    # Use setuptools for these commands (they don't work well or at all
    # with distutils).  For normal builds use distutils.
    try:
        from setuptools import setup
    except ImportError:
        from distutils.core import setup

So NumPy prefers setuptools if it can find it. But then SciPy used to do this, until it was patched to prefer distutils in some situations. Citing the commit log:

Setuptools sets mode +x on the test scripts, so that Nose refuses to run
them. Better not do that.

Of course, a merger between setuptools and distribute should resolve all this in due time, but many packages still need to support Python 2.6 installations.


回答 2

尽管setuptools无疑是更好的工具集,但仍有许多原因值得我们讨论和使用distutils。

首先,distutils随处可见。如果您希望构建一个与他人共享的模块,并且没有任何复杂的要求,那么可以保证它可以在您的工作机器上使用。如果您必须支持旧版本的python,或者发现自己在陌生的环境中工作,那么这尤其重要。

其次,setuptools提供了对distutils的增强。因此,它是根据distutils工具集建模的,并从那里开始获取其所有结构。setuptools的文档假定读者熟悉distutils,并且仅记录其如何增强基本工具集。您可以想到distutils定义了方言,而setuptools增强了该方言。

我对新项目的个人方法是从我将要使用distutils的假设开始的。只有随着项目的增长需要设置工具的功能,我才进行升级。setuptools是distutils的替代品,它是对setup.py的单行更改。

There are several reasons we still talk about and use distutils, even though setuptools is without a doubt the better tool set.

Firstly, distutils is available everywhere. If you are looking to build a module for sharing with others, and don’t have any complicated requirements, it is guaranteed to be available on your work machine. This is particularly important if you have to support older versions of python, or if you find yourself working in an unfamiliar environment.

Secondly, setuptools provides enhancements to distutils. It is therefore modeled after the distutils tool set and takes all of it’s structure from there. The documentation for setuptools assumes the reader is familiar with distutils and only documents how it enhances the base tool set. You can think of it that distutils defines the dialect and setuptools enhances that dialect.

My personal approach for new projects is start with the assumption I’m going to use distutils. Only as the project grows to require a feature of setuptools do I make the upgrade. The setuptools is a drop-in-replacement for distutils, it’s a one-line change to my setup.py.


回答 3

基本上,这是由于职责划分。

setuptools不是Python标准库的一部分,因为它是由第三方而不是Python核心团队维护的。除其他外,这意味着:

  • 它不包含在核心测试套件中,也不依赖于核心功能
  • 本身并没有为附加模块设置核心标准(它们的位置,导入方式,C扩展的二进制接口等)。
  • 它独立于Python版本进行更新和发布

有效地,核心团队缩小了distutils的范围,自己保留了“核心标准”和“最小必要编译”部分,同时将超出此范围的所有东西(扩展的编译器/软件包格式/任何支持)留给了第三方。为了向后兼容,以前覆盖那些“扩展部分”的代码已过时

来自分发Python模块-Python 2.7.12文档

尽管distutils逐步淘汰了直接使用,但它仍为当前的包装和分发基础架构奠定了基础,它不仅仍然是标准库的一部分,而且其名称还可以通过其他方式(例如邮件列表的名称)保留下来。用于协调Python打包标准的开发)。

对于其他操作系统软件包同样可能提供setuptoolspip单独-由于上述原因

  • 并且因为在系统上已经存在另一个软件包管理器时,它们不是必需的-甚至对可维护性有害。

Basically, it’s due to the division of responsibilities.

setuptools is not a part of Python standard library because it’s maintained by a 3rd party rather than Python core team. Which means, among other things:

  • it isn’t covered by the core test suite and isn’t relied upon by core functionality
  • it doesn’t itself set core standards for add-on modules (their location, means of import, C extensions’ binary interface etc.).
  • it’s updated and released independently from Python releases

Effectively, the core team has narrowed down the scope of distutils, reserving the “core standards” and “minimal necessary compilation” parts for themselves while leaving all the stuff beyond that (extended compiler/package format/whatever support) to 3rd parties. The code that was previously covering those “extended parts” was left stale for backwards compatibility.

From Distributing Python Modules — Python 2.7.12 documentation:

While direct use of distutils is being phased out, it still laid the foundation for the current packaging and distribution infrastructure, and it not only remains part of the standard library, but its name lives on in other ways (such as the name of the mailing list used to coordinate Python packaging standards development).

Packages for other OSes are likewise likely to provide setuptools and pip separately – for the aforementioned reasons

  • and because they aren’t necessary – or are even detrimental for maintainability – when there’s already another package manager on the system.

py2exe-生成单个可执行文件

问题:py2exe-生成单个可执行文件

我以为我听说py2exe可以做到这一点,但我从来没有想过。有人成功做到了吗?我可以看到您的setup.py文件以及使用的哪些命令行选项吗?

基本上,我正在考虑给它提供一个可执行文件,该文件可执行将自身解压缩到/ temp并运行的操作。

I thought I heard that py2exe was able to do this, but I never figured it out. Has anyone successfully done this? Can I see your setup.py file, and what command line options you used?

Basically I’m thinking of it giving me a single executable file that does something like unzips itself to maybe /temp and runs.


回答 0

PyInstaller将创建一个没有依赖关系的.exe文件;使用该--onefile选项。它通过将所有需要的共享库打包到可执行文件中,并在运行之前解压缩它们来完成此操作,正如您所描述的那样(编辑:py2exe也具有此功能,请参见minty的答案

我使用的是svn的PyInstaller版本,因为最新版本(1.3)有点过时了。对于依赖于PyQt,PyQwt,numpy,scipy等应用程序的应用程序来说,它的运行情况非常好。

PyInstaller will create a single .exe file with no dependencies; use the --onefile option. It does this by packing all the needed shared libs into the executable, and unpacking them before it runs, just as you describe (EDIT: py2exe also has this feature, see minty’s answer)

I use the version of PyInstaller from svn, since the latest release (1.3) is somewhat outdated. It’s been working really well for an app which depends on PyQt, PyQwt, numpy, scipy and a few more.


回答 1

使用py2exe进行此操作的方法是在setup.py文件中使用bundle_files选项。对于单个文件,您将需要设置bundle_files为1,compressed为True,并将zipfile选项设置为None。这样,它会创建一个压缩文件以便于分发。

这是直接从py2exe网站引用的bundle_file选项的更完整说明*

使用“ bundle_files”和“ zipfile”

创建单文件可执行文件的一种更简单(更好)的方法是将bundle_files设置为1或2,并将zipfile设置为None。这种方法不需要将文件提取到一个临时位置,从而可以更快地启动程序。

bundle_files的有效值为:

  • 3(默认)不捆绑
  • 2捆绑除Python解释器以外的所有内容
  • 1捆绑一切,包括Python解释器

如果zipfile设置为None,则文件将捆绑在可执行文件中,而不是在library.zip中。

这是一个示例setup.py:

from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

setup(
    options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
    windows = [{'script': "single.py"}],
    zipfile = None,
)

The way to do this using py2exe is to use the bundle_files option in your setup.py file. For a single file you will want to set bundle_files to 1, compressed to True, and set the zipfile option to None. That way it creates one compressed file for easy distribution.

Here is a more complete description of the bundle_file option quoted directly from the py2exe site*

Using “bundle_files” and “zipfile”

An easier (and better) way to create single-file executables is to set bundle_files to 1 or 2, and to set zipfile to None. This approach does not require extracting files to a temporary location, which provides much faster program startup.

Valid values for bundle_files are:

  • 3 (default) don’t bundle
  • 2 bundle everything but the Python interpreter
  • 1 bundle everything, including the Python interpreter

If zipfile is set to None, the files will be bundle within the executable instead of library.zip.

Here is a sample setup.py:

from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

setup(
    options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
    windows = [{'script': "single.py"}],
    zipfile = None,
)

回答 2

就像其他海报提到的那样,py2exe将生成一个可执行文件和一些要加载的库。您还可以将一些数据添加到程序中。

下一步是使用安装程序,将所有这些程序打包到一个易于使用的可安装/不可安装程序中。

我使用InnoSetup(http://www.jrsoftware.org/isinfo.php)已经有好几年了,并且用于商业程序,所以我衷心推荐它。

As the other poster mention, py2exe, will generate an executable + some libraries to load. You can also have some data to add to your program.

Next step is to use an installer, to package all this into one easy-to-use installable/unistallable program.

I have used InnoSetup ( http://www.jrsoftware.org/isinfo.php ) with delight for several years and for commercial programs, so I heartily recommend it.


回答 3

我已经能够将所有资源嵌入到exe中来创建一个exe文件。我在Windows上构建。这样就可以解释我正在使用的os.system调用。

首先,我尝试将所有图像转换为位垫,然后将所有数据文件转换为文本字符串。但这导致最终exe变得非常大。

谷歌搜索一周后,我想出了如何更改py2exe脚本以满足我的需求。

这是我提交的有关sourceforge的补丁程序链接,请发表评论,以便我们将其包含在下一个发行版中。

http://sourceforge.net/tracker/index.php?func=detail&aid=3334760&group_id=15583&atid=315583

这使所做的所有更改无效,我只是在设置行中添加了一个新选项。这是我的setup.py。

我将尽我所能评论。请知道我的setup.py很复杂,因为我要按文件名访问图像。所以我必须存储一个列表来跟踪它们。

这是我试图制作的“想要”屏幕保护程序。

我使用exec在运行时生成设置,这样更容易剪切和粘贴。

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

分解

脚本= PY脚本,我想转向一个EXE

icon_resources = exe的图标

file_resources =我要嵌入exe的文件

other_resources =要嵌入到exe中的字符串,在这种情况下为文件列表。

options = py2exe用于将所有内容创建到一个exe文件中的选项

bitmap_strings =要包含的文件列表

请注意,只有按照上述链接中所述编辑py2exe.py文件后,file_resources才是有效选项。

第一次尝试在此站点上发布代码,如果我弄错了,请不要解雇我。

from distutils.core import setup
import py2exe #@UnusedImport
import os

#delete the old build drive
os.system("rmdir /s /q dist")

#setup my option for single file output
py2exe_options = dict( ascii=True,  # Exclude encodings
                       excludes=['_ssl',  # Exclude _ssl
                                 'pyreadline', 'difflib', 'doctest', 'locale',
                                 'optparse', 'pickle', 'calendar', 'pbd', 'unittest', 'inspect'],  # Exclude standard library
                       dll_excludes=['msvcr71.dll', 'w9xpopen.exe',
                                     'API-MS-Win-Core-LocalRegistry-L1-1-0.dll',
                                     'API-MS-Win-Core-ProcessThreads-L1-1-0.dll',
                                     'API-MS-Win-Security-Base-L1-1-0.dll',
                                     'KERNELBASE.dll',
                                     'POWRPROF.dll',
                                     ],
                       #compressed=None,  # Compress library.zip
                       bundle_files = 1,
                       optimize = 2                        
                       )

#storage for the images
bitmap_string = '' 
resource_string = ''
index = 0

print "compile image list"                          

for image_name in os.listdir('images/'):
    if image_name.endswith('.jpg'):
        bitmap_string += "( " + str(index+1) + "," + "'" + 'images/' + image_name + "'),"
        resource_string += image_name + " "
        index += 1

print "Starting build\n"

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

print "Removing Trash"
os.system("rmdir /s /q build")
os.system("del /q *.pyc")
print "Build Complete"

好的,这就是setup.py了,现在魔术需要访问图像。我在开发此应用程序时没有考虑到py2exe,后来又添加了它。因此您会看到两种情况的访问权限。如果找不到图像文件夹,它将尝试从exe资源中提取图像。代码将对此进行解释。这是我的Sprite类的一部分,它使用Directx。但是您可以使用所需的任何api或仅访问原始数据。没关系

def init(self):
    frame = self.env.frame
    use_resource_builtin = True
    if os.path.isdir(SPRITES_FOLDER):
        use_resource_builtin = False
    else:
        image_list = LoadResource(0, u'INDEX', 1).split(' ')

    for (model, file) in SPRITES.items():
        texture = POINTER(IDirect3DTexture9)()
        if use_resource_builtin: 
            data = LoadResource(0, win32con.RT_RCDATA, image_list.index(file)+1) #windll.kernel32.FindResourceW(hmod,typersc,idrsc)               
            d3dxdll.D3DXCreateTextureFromFileInMemory(frame.device,   #Pointer to an IDirect3DDevice9 interface
                                              data,                #Pointer to the file in memory
                                              len(data),           #Size of the file in memory
                                              byref(texture))      #ppTexture
        else:
            d3dxdll.D3DXCreateTextureFromFileA(frame.device, #@UndefinedVariable
                                               SPRITES_FOLDER + file,
                                               byref(texture))            
        self.model_sprites[model] = texture
    #else:
    #    raise Exception("'sprites' folder is not present!")

任何问题都可以随意提出。

I’ve been able to create a single exe file with all resources embeded into the exe. I’m building on windows. so that will explain some of the os.system calls i’m using.

First I tried converting all my images into bitmats and then all my data files into text strings. but this caused the final exe to be very very large.

After googleing for a week i figured out how to alter py2exe script to meet my needs.

here is the patch link on sourceforge i submitted, please post comments so we can get it included in the next distribution.

http://sourceforge.net/tracker/index.php?func=detail&aid=3334760&group_id=15583&atid=315583

this explanes all the changes made, i’ve simply added a new option to the setup line. here is my setup.py.

i’ll try to comment it as best I can. Please know that my setup.py is complex do to the fact that i’m access the images by filename. so I must store a list to keep track of them.

this is from a want-to-b screen saver I was trying to make.

I use exec to generate my setup at run time, its easyer to cut and paste like that.

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

breakdown

script = py script i want to turn to an exe

icon_resources = the icon for the exe

file_resources = files I want to embed into the exe

other_resources = a string to embed into the exe, in this case a file list.

options = py2exe options for creating everything into one exe file

bitmap_strings = a list of files to include

Please note that file_resources is not a valid option untill you edit your py2exe.py file as described in the link above.

first time i’ve tried to post code on this site, if I get it wrong don’t flame me.

from distutils.core import setup
import py2exe #@UnusedImport
import os

#delete the old build drive
os.system("rmdir /s /q dist")

#setup my option for single file output
py2exe_options = dict( ascii=True,  # Exclude encodings
                       excludes=['_ssl',  # Exclude _ssl
                                 'pyreadline', 'difflib', 'doctest', 'locale',
                                 'optparse', 'pickle', 'calendar', 'pbd', 'unittest', 'inspect'],  # Exclude standard library
                       dll_excludes=['msvcr71.dll', 'w9xpopen.exe',
                                     'API-MS-Win-Core-LocalRegistry-L1-1-0.dll',
                                     'API-MS-Win-Core-ProcessThreads-L1-1-0.dll',
                                     'API-MS-Win-Security-Base-L1-1-0.dll',
                                     'KERNELBASE.dll',
                                     'POWRPROF.dll',
                                     ],
                       #compressed=None,  # Compress library.zip
                       bundle_files = 1,
                       optimize = 2                        
                       )

#storage for the images
bitmap_string = '' 
resource_string = ''
index = 0

print "compile image list"                          

for image_name in os.listdir('images/'):
    if image_name.endswith('.jpg'):
        bitmap_string += "( " + str(index+1) + "," + "'" + 'images/' + image_name + "'),"
        resource_string += image_name + " "
        index += 1

print "Starting build\n"

exec "setup(console=[{'script': 'launcher.py', 'icon_resources': [(0, 'ICON.ico')],\
      'file_resources': [%s], 'other_resources': [(u'INDEX', 1, resource_string[:-1])]}],\
      options={'py2exe': py2exe_options},\
      zipfile = None )" % (bitmap_string[:-1])

print "Removing Trash"
os.system("rmdir /s /q build")
os.system("del /q *.pyc")
print "Build Complete"

ok, thats it for the setup.py now the magic needed access the images. I developed this app without py2exe in mind then added it later. so you’ll see access for both situations. if the image folder can’t be found it tries to pull the images from the exe resources. the code will explain it. this is part of my sprite class and it uses a directx. but you can use any api you want or just access the raw data. doesn’t matter.

def init(self):
    frame = self.env.frame
    use_resource_builtin = True
    if os.path.isdir(SPRITES_FOLDER):
        use_resource_builtin = False
    else:
        image_list = LoadResource(0, u'INDEX', 1).split(' ')

    for (model, file) in SPRITES.items():
        texture = POINTER(IDirect3DTexture9)()
        if use_resource_builtin: 
            data = LoadResource(0, win32con.RT_RCDATA, image_list.index(file)+1) #windll.kernel32.FindResourceW(hmod,typersc,idrsc)               
            d3dxdll.D3DXCreateTextureFromFileInMemory(frame.device,   #Pointer to an IDirect3DDevice9 interface
                                              data,                #Pointer to the file in memory
                                              len(data),           #Size of the file in memory
                                              byref(texture))      #ppTexture
        else:
            d3dxdll.D3DXCreateTextureFromFileA(frame.device, #@UndefinedVariable
                                               SPRITES_FOLDER + file,
                                               byref(texture))            
        self.model_sprites[model] = texture
    #else:
    #    raise Exception("'sprites' folder is not present!")

Any questions fell free to ask.


回答 4

如前所述,您应该创建一个安装程序。即使也可以通过将bundle_files选项设置为1并将zipfile关键字参数设置为None来让py2exe将所有内容捆绑到一个可执行文件中,但我不建议PyGTK应用程序使用此方法。

这是因为GTK +试图从其加载目录中加载其数据文件(本地,主题等)。因此,您必须确保可执行文件的目录还包含GTK +使用的库以及GTK +安装中的目录lib,share等。否则,您将在未在全系统范围内安装GTK +的计算机上运行应用程序时遇到问题。

有关更多详细信息,请阅读我的PyGTK应用程序py2exe指南。它还说明了如何捆绑除GTK +之外的所有内容。

You should create an installer, as mentioned before. Even though it is also possible to let py2exe bundle everything into a single executable, by setting bundle_files option to 1 and the zipfile keyword argument to None, I don’t recommend this for PyGTK applications.

That’s because of GTK+ tries to load its data files (locals, themes, etc.) from the directory it was loaded from. So you have to make sure that the directory of your executable contains also the libraries used by GTK+ and the directories lib, share and etc from your installation of GTK+. Otherwise you will get problems running your application on a machine where GTK+ is not installed system-wide.

For more details read my guide to py2exe for PyGTK applications. It also explains how to bundle everything, but GTK+.


回答 5

我被告知bbfreeze将创建一个文件.EXE,并且比py2exe更新。

I’m told bbfreeze will create a single file .EXE, and is newer than py2exe.


回答 6

尝试 c_x Frozen 它可以创建一个很好的独立版本

try c_x freeze it can create a good standalone


回答 7

我最近使用py2exe创建了一个用于后期审阅的可执行文件,用于将审阅发送到ReviewBoard。

这是我使用的setup.py

from distutils.core import setup
import py2exe

setup(console=['post-review'])

它创建了一个目录,其中包含exe文件和所需的库。我认为无法使用py2exe来获取单个.exe文件。如果需要,首先需要使用py2exe,然后使用某种形式的安装程序来制作最终的可执行文件。

需要注意的一件事是,您在应用程序中使用的任何egg文件都需要解压缩,否则py2exe不能包含它们。py2exe文档中对此进行了介绍。

I recently used py2exe to create an executable for post-review for sending reviews to ReviewBoard.

This was the setup.py I used

from distutils.core import setup
import py2exe

setup(console=['post-review'])

It created a directory containing the exe file and the libraries needed. I don’t think it is possible to use py2exe to get just a single .exe file. If you need that you will need to first use py2exe and then use some form of installer to make the final executable.

One thing to take care of is that any egg files you use in your application need to be unzipped, otherwise py2exe can’t include them. This is covered in the py2exe docs.


回答 8

不,就您以后只有一个文件的意义而言,它没有给您单个可执行文件-但您有一个目录,其中包含运行程序所需的所有文件,包括exe文件。

我今天才写了这个setup.py。您只需要调用python setup.py py2exe

No, it’s doesn’t give you a single executable in the sense that you only have one file afterwards – but you have a directory which contains everything you need for running your program, including an exe file.

I just wrote this setup.py today. You only need to invoke python setup.py py2exe.


Python-for-android 将Python应用程序转换为Android APK

Python-for-Android

Python-for-Android是在Android上打包Python应用程序的工具。您可以创建自己的Python发行版,包括所需的模块和依赖项,并将其与您自己的代码捆绑在APK中

功能包括:

  • 不同的应用程序后端,包括Kivy、PySDL2和带有Python Web服务器的WebView
  • 自动支持大多数纯Python模块,并内置了对许多其他模块的支持,包括流行的依赖项,如Numpy和sqlalChemy
  • 多个架构目标,适用于在任何给定设备上优化的APK

有关文档和支持,请参阅:

文档

请遵循quickstart
instructions
安装并开始创建APK的步骤

快速说明:安装Python-for-Android,安装方式为:

pip install python-for-android

(对于开发分支:pip install git+https://github.com/kivy/python-for-android.git)

与安装配合使用的测试:

p4a --version

要构建任何实际的应用程序,设置Android SDK和NDKquickstart使用快速入门中的SDK/NDK API级别和NDK版本,其他API级别可能不起作用

全部安装完毕后,使用SDL2构建APK,例如:

p4a apk --requirements=kivy --private /home/username/devel/planewave_frozen/ --package=net.inclem.planewavessdl2 --name="planewavessdl2" --version=0.5 --bootstrap=sdl2

对于完整的指令和参数选项,看见the
documentation

支持

如果您需要帮助,可以在我们的邮件列表上寻求帮助:

我们还有#support Discord channel

贡献

我们喜欢提出请求和讨论新奇的想法。查看Kivy项目contribution guide并且可以随意改进python-for-android(适用于android的python)

看见our
documentation
有关Python-for-Android开发和发布模型的更多信息,请不要担心细节。您只需要提个拉流请求,我们会处理睡觉的

以下邮件列表和IRC频道专门用于讨论开发Kivy框架及其姊妹项目:

我们还有#dev Discord channel

许可证

Python-for-Android是根据麻省理工学院的许可条款发布的。请参考许可证文件

历史

2015年,这些工具进行了重写,以提供一个新的、更易于使用和扩展的界面。如果您想浏览旧的工具链,其状态记录在https://github.com/kivy/python-for-android/tree/old_toolchain

2018年最后一个季度,python的食谱发生了变化。python3的新配方(3.7.1)有一个新的构建系统,它应用于古老的python配方,允许我们将python2的版本号提升到2.7.15。这一更改统一了两个Python食谱的构建过程,并可能解决了多年来检测到的各种问题。这些统一的Python食谱需要一个最低目标API水平为21Android 5.0-棒棒糖如果您需要构建的API级别低于21,则应该使用旧版本的python-for-Android(<=0.7.1)

在2020年3月,我们不再支持创建使用Python2的应用程序。支持构建Python2的最新Python-for-Android版本是2019.10.6版

贡献者

这个项目的存在要归功于所有做出贡献的人。[Contribute]

支持者

感谢我们所有的支持者!🙏[Become a backer]

赞助商

通过成为赞助商来支持这个项目。您的徽标将在此处显示,并带有指向您的网站的链接。[Become a sponsor]










发行版,distutils,setuptools和distutils2之间的区别?

问题:发行版,distutils,setuptools和distutils2之间的区别?

情况

我正在尝试将开放源代码库移植到Python3。(SymPy,如果有人想知道的话。)

因此,2to3在为Python 3构建时,我需要自动运行。为此,我需要使用distribute。因此,我需要移植当前的系统(根据doctest)是distutils


问题

不幸的是,我不知道什么是这些模块-之间的区别distutilsdistributesetuptools。该文档最好是粗略的,因为它们似乎都是彼此的分支,旨在在大多数情况下兼容(但实际上并非全部)……等等。


问题

有人可以解释差异吗?我应该用什么?什么是最现代的解决方案?(Distribute顺便说一句,我也很感谢有关向移植的一些指南,但这超出了问题的范围……)

The Situation

I’m trying to port an open-source library to Python 3. (SymPy, if anyone is wondering.)

So, I need to run 2to3 automatically when building for Python 3. To do that, I need to use distribute. Therefore, I need to port the current system, which (according to the doctest) is distutils.


The Problem

Unfortunately, I’m not sure what’s the difference between these modules—distutils, distribute, setuptools. The documentation is sketchy as best, as they all seem to be a fork of one another, intended to be compatible in most circumstances (but actually, not all)…and so on, and so forth.


The Question

Could someone explain the differences? What am I supposed to use? What is the most modern solution? (As an aside, I’d also appreciate some guide on porting to Distribute, but that’s a tad beyond the scope of the question…)


回答 0

截至2020年3月,该问题的大多数其他答案已经过时了几年。当您遇到有关Python包装问题的建议时,请记住查看发布日期,并且不要相信过时的信息。

Python包装用户指南》值得一读。每个页面上都显示有“最后更新”日期,因此您可以检查手册的最新性,并且内容非常全面。它托管在Python Software Foundation的python.org的子域中,这本身就增加了可信度。“ 项目摘要”页面在这里尤其重要。

工具摘要:

以下是Python封装环境的摘要:

支持的工具:

弃用/废弃的工具:

  • distribute是的叉子setuptools。它共享相同的命名空间,因此,如果您安装了Distribute,则import setuptools实际上将导入使用Distribute分发的软件包。Distribute被合并回Setuptools 0.7中,因此您不再需要使用Distribute。实际上,Pypi上的版本只是安装Setuptools的兼容层。

  • distutils2就是把最好的尝试distutilssetuptoolsdistribute成为列入Python的标准库中的标准工具。想法是distutils2将其分发给旧的Python版本,distutils2并将其重命名packaging为Python 3.3,并将其包含在其标准库中。这些计划没有按计划进行,但是目前distutils2是一个废弃的项目。最新版本于2012年3月发布,其Pypi主页最终已更新以反映其死亡。

其他:

如果您有兴趣,还有其他工具,请阅读《 Python打包用户指南》中的“ 项目摘要 ”。我就不一一列举,不重复该网页,并随时回答匹配的问题,这是只有约distributedistutilssetuptoolsdistutils2

建议:

如果这一切对您来说都是新手,并且您不知道从哪里开始,那么我建议您将学习setuptools,和pipvirtualenv一起很好地结合使用。

如果你正在寻找到virtualenv,你可能有兴趣在这样一个问题:是什么区别venvpyvenvpyenvvirtualenvvirtualenvwrapper,等?。(是的,我知道,我和你一起吟。)

As of March 2020, most of the other answers to this question are several years out-of-date. When you come across advice on Python packaging issues, remember to look at the date of publication, and don’t trust out-of-date information.

The Python Packaging User Guide is worth a read. Every page has a “last updated” date displayed, so you can check the recency of the manual, and it’s quite comprehensive. The fact that it’s hosted on a subdomain of python.org of the Python Software Foundation just adds credence to it. The Project Summaries page is especially relevant here.

Summary of tools:

Here’s a summary of the Python packaging landscape:

Supported tools:

Deprecated/abandoned tools:

  • distribute was a fork of setuptools. It shared the same namespace, so if you had Distribute installed, import setuptools would actually import the package distributed with Distribute. Distribute was merged back into Setuptools 0.7, so you don’t need to use Distribute any more. In fact, the version on Pypi is just a compatibility layer that installs Setuptools.

  • distutils2 was an attempt to take the best of distutils, setuptools and distribute and become the standard tool included in Python’s standard library. The idea was that distutils2 would be distributed for old Python versions, and that distutils2 would be renamed to packaging for Python 3.3, which would include it in its standard library. These plans did not go as intended, however, and currently, distutils2 is an abandoned project. The latest release was in March 2012, and its Pypi home page has finally been updated to reflect its death.

Others:

There are other tools, if you are interested, read Project Summaries in the Python Packaging User Guide. I won’t list them all, to not repeat that page, and to keep the answer matching the question, which was only about distribute, distutils, setuptools and distutils2.

Recommendation:

If all of this is new to you, and you don’t know where to start, I would recommend learning setuptools, along with pip and virtualenv, which all work very well together.

If you’re looking into virtualenv, you might be interested in this question: What is the difference between venv, pyvenv, pyenv, virtualenv, virtualenvwrapper, etc?. (Yes, I know, I groan with you.)


回答 1

我是distutils维护者和distutils2 / packaging贡献者。我在ConFoo 2011上谈论了Python封装,如今,我正在编写它的扩展版本。它尚未发布,因此以下是一些有助于定义内容的摘录。

  • Distutils是用于包装的标准工具。它可以满足简单的需求,但功能有限,扩展范围也不小。

  • Setuptools是一个旨在填补缺少的distutils功能并探索新方向的项目。在某些子社区中,这是事实上的标准。它使用了Python核心开发人员不喜欢的Monkey补丁和魔术。

  • Distribute是Setuptools的一个分支,由开发人员启动,觉得它的开发速度太慢并且无法对其进行开发。当distutils2由同一组启动时,其开发速度大大减慢。2013年8月更新:分发重新合并到setuptools中并停止使用。

  • Distutils2是一个新的distutils库,它是distutils代码库的一个分支,从安装工具(其中一些已在PEP中进行了详细讨论)中汲取了好主意,并且是受pip启发的基本安装程序。 用来导入Distutils2的实际名称packaging在Python 3.3+标准库中,或者distutils2在2.4+和3.1-3.2中。(将很快提供一个反向端口。) Distutils2并未发布Python 3.3版本,因此被搁置了。

更多信息:

我希望很快完成我的指南,它将包含有关每个图书馆的优缺点的更多信息以及过渡指南。

I’m a distutils maintainer and distutils2/packaging contributor. I did a talk about Python packaging at ConFoo 2011 and these days I’m writing an extended version of it. It’s not published yet, so here are excerpts that should help define things.

  • Distutils is the standard tool used for packaging. It works rather well for simple needs, but is limited and not trivial to extend.

  • Setuptools is a project born from the desire to fill missing distutils functionality and explore new directions. In some subcommunities, it’s a de facto standard. It uses monkey-patching and magic that is frowned upon by Python core developers.

  • Distribute is a fork of Setuptools that was started by developers feeling that its development pace was too slow and that it was not possible to evolve it. Its development was considerably slowed when distutils2 was started by the same group. 2013-August update: distribute is merged back into setuptools and discontinued.

  • Distutils2 is a new distutils library, started as a fork of the distutils codebase, with good ideas taken from setup tools (of which some were thoroughly discussed in PEPs), and a basic installer inspired by pip. The actual name you use to import Distutils2 is packaging in the Python 3.3+ standard library, or distutils2 in 2.4+ and 3.1–3.2. (A backport will be available soon.) Distutils2 did not make the Python 3.3 release, and it was put on hold.

More info:

I hope to finish my guide soon, it will contain more info about each library’s strong and weak points and a transition guide.


回答 2

注意:已弃用答案,现在分发已过时。自Python打包机构成立以来,该答案不再有效,并且已经做了很多工作来清理此问题。


是的,您知道了。:-o我认为目前首选的软件包是Distribute,它是setuptools的一个分支,是distutils(原始打包系统)的扩展。Setuptools并未得到维护,因此已被分叉并重命名,但是在安装时,它使用setuptools的软件包名称!我认为大多数Python开发人员现在都使用Distribute,并且可以肯定地说我确实这样做。

NOTE: Answer deprecated, Distribute now obsolete. This answer is no longer valid since the Python Packaging Authority was formed and has done a lot of work cleaning this up.


Yep, you got it. :-o I think at this time the preferred package is Distribute, which is a fork of setuptools, which are an extension of distutils (the original packaging system). Setuptools was not being maintained so is was forked and renamed, however when installed it uses the package name of setuptools! I think most Python developers now use Distribute, and I can say for sure that I do.


回答 3

我意识到我已经回答了您的第二个问题,但没有解决您原始问题中的毫无疑问的假设:

我正在尝试将开放源代码库(SymPy,如果有人想知道)移植到Python3。为此,在构建Python 3时,我需要自动运行2to3。

可能不是需要。其他策略请参见http://docs.python.org/dev/howto/pyporting

为此,我需要使用分配,

可能 :) distutils以不同的分发方式支持代码(不是docstrings)的构建时2to3转换:http : //docs.python.org/dev/howto/pyporting#during-installation

I realize that I have replied to your secondary question without addressing unquestioned assumptions in your original problem:

I’m trying to port an open-source library (SymPy, if anyone is wondering) to Python 3. To do this, I need to run 2to3 automatically when building for Python 3.

You may, not need. Other strategies are described at http://docs.python.org/dev/howto/pyporting

To do that, I need to use distribute,

You may :) distutils supports build-time 2to3 conversion for code (not docstrings), in a different manner that distribute’s: http://docs.python.org/dev/howto/pyporting#during-installation


回答 4

2014年底更新了这个问题,幸运的是,Continuum的“ conda ”软件包管理器已大大消除了Python的包装混乱。

特别是,conda可以快速创建conda“ 环境 ”。您可以使用不同版本的Python配置您的环境。例如:

conda create -n py34 python=3.4 anaconda

conda create -n py26 python=2.6 anaconda

将使用不同版本的Python创建两个(“ py34”或“ py26”)Python环境。

之后,您可以使用以下特定版本的Python调用环境:

source activate <env name>

在必须处理不同版本的Python的情况下,此功能似乎特别有用。

而且,conda具有以下功能:

  • 不可知的Python
  • 跨平台
  • 无需管理员权限
  • 智能依赖性管理(通过SAT求解器)
  • 很好地处理了您可能必须链接的C,Fortran和系统级库

如果您身处科学计算领域,那么最后一点尤其重要。

Updating this question in late 2014 where fortunately the Python packaging chaos has been greatly cleaned up by Continuum’s “conda” package manager.

In particular, conda quickly enables the creation of conda “environments“. You can configure your environments with different versions of Python. For example:

conda create -n py34 python=3.4 anaconda

conda create -n py26 python=2.6 anaconda

will create two (“py34” or “py26”) Python environments with different versions of Python.

Afterwards you can invoke the environment with the specific version of Python with:

source activate <env name>

This feature seems especially useful in your case where you are having to deal with different version of Python.

Moreover, conda has the following features:

  • Python agnostic
  • Cross platform
  • No admin privileges required
  • Smart dependency management (by way of a SAT solver)
  • Nicely deals with C, Fortran and system level libraries that you may have to link against

That last point is especially important if you are in the scientific computing arena.


Pip-Python软件包安装程序

PIP-Python软件包安装程序

PIP是package installer为了Python。您可以使用pip从Python Package Index和其他索引

请查看我们的文档,了解如何安装和使用pip:

我们定期发布更新,每3个月更新一次。有关更多详细信息,请参阅我们的文档:

在PIP20.3中,我们已经made a big improvement to the heart of piplearn more我们需要你的意见,所以sign up for our user experience research studies来帮助我们做好这件事

注意事项:pip 21.0,在2021年1月,删除了对每个pip的Python 2支持Python 2 support policy请迁移到Python 3

如果您发现错误、需要帮助或想与开发人员交谈,请使用我们的邮件列表或聊天室:

如果您想参与到GitHub获取源代码,请查看我们的开发文档,并随时跳转到开发人员邮件列表和聊天室:

行为规范

在pip项目的代码库、问题跟踪器、聊天室和邮件列表中交互的每个人都应该遵循PSF Code of Conduct

Poetry 简化Python依赖项管理和打包

诗歌:Python的依赖项管理

POLITY可帮助您声明、管理和安装Python项目的依赖项,确保您随时随地都拥有正确的堆栈

支持Python 2.7和3.5+

注意事项:在下一个功能版本(1.2)中将不再支持Python 2.7和3.5。您应该考虑将Python版本更新为支持的版本

这个complete documentation可在official website

安装

POLITY提供了一个自定义安装程序,该安装程序将安装poetry与您系统的睡觉隔离

osx/linux/bashonwindows安装说明

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py | python -

Windows PowerShell安装说明

(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/install-poetry.py -UseBasicParsing).Content | python -

警告:上一次get-poetry.py安装程序现在已弃用,如果您当前正在使用它,则应迁移到新的、受支持的install-poetry.py安装程序

安装程序将安装poetry诗歌的工具bin目录。此位置取决于您的系统:

  • $HOME/.local/bin对于Unix
  • %APPDATA%\Python\Scripts在Windows上

如果此目录不在您的PATH,您需要手动添加,如果您想要用简单的poetry

或者,您可以使用完整路径来poetry使用它

一旦安装了Poetry,您就可以执行以下操作:

poetry --version

如果你看到类似这样的东西Poetry (version 1.2.0)那么您就可以使用诗歌了。如果您认为“诗歌”不适合您,您可以通过使用以下命令再次运行安装程序将其从系统中完全删除--uninstall选项,或通过将POETRY_UNINSTALL环境变量,然后执行安装程序

python install-poetry.py --uninstall
POETRY_UNINSTALL=1 python install-poetry.py

默认情况下,“诗歌”安装到用户特定于平台的主目录中。如果您希望更改此设置,您可以定义POETRY_HOME环境变量:

POETRY_HOME=/etc/poetry python install-poetry.py

如果要安装预发行版本,可以通过传递--preview选项以执行以下操作install-poetry.py或使用POETRY_PREVIEW环境变量:

python install-poetry.py --preview
POETRY_PREVIEW=1 python install-poetry.py

同样,如果要安装特定版本,可以使用--version选项或POETRY_VERSION环境变量:

python install-poetry.py --version 1.2.0
POETRY_VERSION=1.2.0 python install-poetry.py

您还可以为git存储库通过使用--git选项:

python install-poetry.py --git https://github.com/python-poetry/poetry.git@master

注意事项:请注意,安装程序不支持Python<3.6

正在更新poetry

将诗歌更新到最新的稳定版本非常简单,只需调用self update命令

警告:使用现已弃用的软件安装的诗歌版本get-poetry.py安装程序将无法使用此命令更新到1.2版或更高版本。迁移到使用install-poetry.py安装程序或pipx

poetry self update

如果要安装预发行版本,可以使用--preview选项

poetry self update --preview

最后,如果要安装特定版本,可以将其作为参数传递给self update

poetry self update 1.2.0

启用Bash、Fish或Zsh的制表符完成

poetry支持为Bash、Fish和Zsh生成完成脚本。看见poetry help completions获取完整的详细信息,但要点很简单,只需使用以下选项之一:

# Bash poetry completions bash > /etc/bash_completion.d/poetry.bash-completion # Bash (Homebrew) poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion # Fish poetry completions fish > ~/.config/fish/completions/poetry.fish # Fish (Homebrew) poetry completions fish > (brew --prefix)/share/fish/vendor_completions.d/poetry.fish # Zsh poetry completions zsh > ~/.zfunc/_poetry # Zsh (Homebrew) poetry completions zsh > $(brew --prefix)/share/zsh/site-functions/_poetry # Zsh (Oh-My-Zsh) mkdir $ZSH_CUSTOM/plugins/poetry poetry completions zsh > $ZSH_CUSTOM/plugins/poetry/_poetry # Zsh (prezto) poetry completions zsh > ~/.zprezto/modules/completion/external/src/_poetry

注:您可能需要重新启动shell才能使更改生效

zsh,则必须在您的~/.zshrc在此之前compinit(不适用于自制安装):

fpath+=~/.zfunc

引言

poetry是一个处理依赖项安装以及构建和打包Python包的工具。它只需要一个文件就可以完成所有这些任务:新的、standardizedpyproject.toml

换句话说,诗歌使用pyproject.toml替换setup.pyrequirements.txtsetup.cfgMANIFEST.in和新添加的Pipfile

tool.poetry] name = "my-package" version = "0.1.0" description = "The description of the package" license = "MIT" authors = [ "Sébastien Eustace <sebastien@eustace.io>" ] readme = 'README.md' # Markdown files are supported repository = "https://github.com/python-poetry/poetry" homepage = "https://github.com/python-poetry/poetry" keywords = ['packaging', 'poetry'] [tool.poetry.dependencies] python = "~2.7 || ^3.2" # Compatible python versions must be declared here toml = "^0.9" # Dependencies with extras requests = { version = "^2.13", extras = [ "security" ] } # Python specific dependencies with prereleases allowed pathlib2 = { version = "^2.2", python = "~2.7", allow-prereleases = true } # Git dependencies cleo = { git = "https://github.com/sdispater/cleo.git", branch = "master" } # Optional dependencies (extras) pendulum = { version = "^1.4", optional = true } [tool.poetry.dev-dependencies] pytest = "^3.0" pytest-cov = "^2.4" [tool.poetry.scripts] my-script = 'my_package:main'

这里有一些我们可以注意到的事情:

  • 它将试图强制执行semantic versioning作为版本命名的最佳实践
  • 您可以指定自述文件、包含文件和排除文件:不能更多MANIFEST.inpoetry还将使用VCS忽略文件(如.gitignore)以填充exclude部分
  • 可以指定关键字(最多5个),并将其作为包装站点上的标签
  • 依赖关系部分支持脱字符、代字号、通配符、不等式和多个要求
  • 您必须指定软件包兼容的Python版本

poetry还将检测您是否在Virtualenv中,并相应地安装软件包。所以,poetry可以在全球范围内安装并在任何地方使用

poetry还附带一个完整的依赖项解析库

为什么?

Python中的打包系统和依赖项管理相当复杂,对于新手来说很难理解。即使对于经验丰富的开发人员来说,创建Python项目中所需的所有文件有时也可能很麻烦:setup.pyrequirements.txtsetup.cfgMANIFEST.in和新添加的Pipfile

因此,我想要一个工具,它可以将所有操作都限制在单个配置文件中来完成:依赖项管理、打包和发布

它需要从其他语言中存在的工具中获得灵感,比如composer(PHP)或cargo(生锈)

最后,我开始poetry为Python社区带来另一个详尽的依赖解析器Conda’s

那皮佩诺夫呢?

简而言之:我不喜欢它提供的CLI,也不喜欢它做出的一些决定,我认为我们可以做出更好、更直观的决定。这里有几件我不喜欢的东西

依赖项解析

依赖项解析不稳定,即使有解决方案也会失败。让我们举个例子:

pipenv install oslo.utils==1.4.0

将失败,并显示此错误:

Could not find a version that matches pbr!=0.7,!=2.1.0,<1.0,>=0.6,>=2.0.0

而诗会给你提供一套合适的套餐:

poetry add oslo.utils=1.4.0

结果是:

  - Installing pytz (2018.3)
  - Installing netifaces (0.10.6)
  - Installing netaddr (0.7.19)
  - Installing oslo.i18n (2.1.0)
  - Installing iso8601 (0.1.12)
  - Installing six (1.11.0)
  - Installing babel (2.5.3)
  - Installing pbr (0.11.1)
  - Installing oslo.utils (1.4.0)

这要归功于诗歌核心的高效依赖解析器

以下是这里具体发生的情况的细目:

oslo.utils (1.4.0)取决于:

  • pbr (>=0.6,!=0.7,<1.0)
  • Babel (>=1.3)
  • six (>=1.9.0)
  • iso8601 (>=0.1.9)
  • oslo.i18n (>=1.3.0)
  • netaddr (>=0.7.12)
  • netifaces (>=0.10.4)

我们感兴趣的是pbr (>=0.6,!=0.7,<1.0)

在这一点上,诗歌将选择pbr==0.11.1哪个是与约束匹配的最新版本

接下来,它将尝试选择oslo.i18n==3.20.0哪个是匹配的最新版本oslo.i18n (>=1.3.0)

但是,此版本要求pbr (!=2.1.0,>=2.0.0)这与不兼容pbr==0.11.1,所以poetry将尝试查找一个版本的oslo.i18n那是令人满意的pbr (>=0.6,!=0.7,<1.0)

通过分析oslo.i18n,它会找到oslo.i18n==2.1.0这就需要pbr (>=0.11,<2.0)在这一点上,决议的睡觉是直截了当的,因为不再有冲突

资源

Pipenv-面向人类的Python开发工作流

Pipenv 是一个旨在带来最好的包装世界的工具(捆扎师、作曲家、NPM、货物、纱线等)来到Python世界在我们的世界里,Windows是一等公民

它会自动为您的项目创建和管理一个虚拟环境,并在您的Pipfile当您安装/卸载软件包时。它还产生了非常重要的Pipfile.lock,它用于生成确定性构建。

Pipenv寻求解决的问题是多方面的:

  • 您不再需要使用pipvirtualenv分开的。他们一起工作
  • 管理requirements.txt文件can be
    problematic
    ,因此Pipenv使用即将到来的PipfilePipfile.lock取而代之的是,对于基本用例,哪个更优越
  • 散列总是在任何地方使用。保安。自动暴露安全漏洞
  • 让您深入了解依赖关系图(例如$ pipenv graph)
  • 通过加载简化开发工作流.env文件

您可以在浏览器中快速播放Pipenv:

安装

如果您使用的是Debian Buster+:

$ sudo apt install pipenv

或者,如果您使用的是Fedora:

$ sudo dnf install pipenv

或者,如果您使用的是FreeBSD:

# pkg install py36-pipenv

或者,如果您使用的是Windows:

# pip install --user pipenv

当以上选项都不存在时,建议使用Pipx

$ pipx install pipenv

否则,请参阅documentation有关说明,请参阅

✨🍰✨

☤用户表彰

大卫·刚(David Gang)

这个包管理器真的很棒。这是我第一次确切地知道我安装的依赖项是什么,以及可传递依赖项是什么。再加上安装是确定性的这一事实,使得这个包管理器像货物一样是一流的

贾斯汀·迈尔斯·福尔摩斯

Pipenv最终是一种抽象,其目的是让头脑参与进来,而不仅仅是文件系统

☤功能

  • 真正实现确定性构建,同时轻松指定只有你想要的
  • 生成并检查锁定依赖项的文件哈希
  • 自动安装所需的Python,如果pyenv有空房吗?
  • 自动递归地查找您的项目主目录,方法是查找Pipfile
  • 自动生成一个Pipfile,如果不存在
  • 自动在标准位置创建一个Virtualenv
  • 自动将包添加/删除到Pipfile卸载/安装它们时
  • 自动加载.env文件(如果存在)

主要命令有installuninstall,以及lock,它会生成一个Pipfile.lock这些都是用来取代$ pip install用法以及手动虚拟环境管理(要激活虚拟环境,请运行$ pipenv shell)

基本概念

  • 当虚拟环境不存在时,将自动创建一个虚拟环境
  • 当没有参数传递给install,所有套餐[packages]将安装指定的
  • 要初始化Python 3虚拟环境,请运行$ pipenv --three
  • 要初始化Python 2虚拟环境,请运行$ pipenv --two
  • 否则,无论viralenv缺省值是什么,都将是缺省值

其他命令

  • shell将在激活了viralenv的情况下生成一个shell
  • run将运行来自Virtualenv的给定命令,并转发任何参数(例如$ pipenv run python)
  • check断言当前环境满足PEP 508要求
  • graph将打印所有已安装依赖项的漂亮图表

外壳完井

例如,对于鱼,把这个放在你的~/.config/fish/completions/pipenv.fish

eval (pipenv --completion)

或者,使用bash,将此内容放入您的.bashrc.bash_profile

eval "$(pipenv --completion)"

魔术外壳完成现已启用!还有一个fish
plugin
,它将自动为您激活您的子壳!

鱼是最好的贝壳。你应该用它

☤使用率

$ pipenv
Usage: pipenv [OPTIONS] COMMAND [ARGS]...

Options:
  --where          Output project home information.
  --venv           Output virtualenv information.
  --py             Output Python interpreter information.
  --envs           Output Environment Variable options.
  --rm             Remove the virtualenv.
  --bare           Minimal output.
  --completion     Output completion (to be eval'd).
  --man            Display manpage.
  --three / --two  Use Python 3/2 when creating virtualenv.
  --python TEXT    Specify which version of Python virtualenv should use.
  --site-packages  Enable site-packages for the virtualenv.
  --version        Show the version and exit.
  -h, --help       Show this message and exit.


Usage Examples:
   Create a new project using Python 3.7, specifically:
   $ pipenv --python 3.7

   Remove project virtualenv (inferred from current directory):
   $ pipenv --rm

   Install all dependencies for a project (including dev):
   $ pipenv install --dev

   Create a lockfile containing pre-releases:
   $ pipenv lock --pre

   Show a graph of your installed dependencies:
   $ pipenv graph

   Check your installed dependencies for security vulnerabilities:
   $ pipenv check

   Install a local setup.py into your virtual environment/Pipfile:
   $ pipenv install -e .

   Use a lower-level pip command:
   $ pipenv run pip freeze

Commands:
  check      Checks for security vulnerabilities and against PEP 508 markers
             provided in Pipfile.
  clean      Uninstalls all packages not specified in Pipfile.lock.
  graph      Displays currently–installed dependency graph information.
  install    Installs provided packages and adds them to Pipfile, or (if no
             packages are given), installs all packages from Pipfile.
  lock       Generates Pipfile.lock.
  open       View a given module in your editor.
  run        Spawns a command installed into the virtualenv.
  scripts    Displays the shortcuts in the (optional) [scripts] section of 
             Pipfile. 
  shell      Spawns a shell within the virtualenv.
  sync       Installs all packages specified in Pipfile.lock.
  uninstall  Un-installs a provided package and removes it from Pipfile.

找到项目:

$ pipenv --where
/Users/kennethreitz/Library/Mobile Documents/com~apple~CloudDocs/repos/kr/pipenv/test

找到Virtualenv:

$ pipenv --venv
/Users/kennethreitz/.local/share/virtualenvs/test-Skyy4vre

找到Python解释器:

$ pipenv --py
/Users/kennethreitz/.local/share/virtualenvs/test-Skyy4vre/bin/python

安装软件包:

$ pipenv install
Creating a virtualenv for this project...
...
No package provided, installing all dependencies.
Virtualenv location: /Users/kennethreitz/.local/share/virtualenvs/test-EJkjoYts
Installing dependencies from Pipfile.lock...
...

To activate this project's virtualenv, run the following:
$ pipenv shell

从GIT安装:

您可以使用按照以下规则格式化的URL从GIT和其他版本控制系统安装带有Pipenv的软件包:

<vcs_type>+<scheme>://<location>/<user_or_organization>/<repository>@<branch_or_tag>#<package_name>

唯一可选的部分是@<branch_or_tag>部分。在SSH上使用GIT时,您可以使用速记VC和方案别名git+git@<location>:<user_or_organization>/<repository>@<branch_or_tag>#<package_name>请注意,这将被转换为git+ssh://git@<location>在解析时

的有效值<vcs_type>包括gitbzrsvn,以及hg的有效值<scheme>包括http,httpsssh,以及file在特定情况下,您还可以访问其他方案:svn可以与svn作为一个计划,并且bzr可以与sftplp

请注意,它是强烈推荐在可编辑模式下安装任何受版本控制的依赖项,请使用pipenv install -e,以确保每次执行依赖项解析时都可以使用存储库的最新副本执行依赖项解析,并确保它包括所有已知的依赖项

以下是安装位于以下位置的git存储库的用法示例https://github.com/requests/requests.gitFrom标签v2.19.1作为包名称requests

$ pipenv install -e git+https://github.com/requests/requests.git@v2.19#egg=requests
Creating a Pipfile for this project...
Installing -e git+https://github.com/requests/requests.git@v2.19.1#egg=requests...
[...snipped...]
Adding -e git+https://github.com/requests/requests.git@v2.19.1#egg=requests to Pipfile's [packages]...
[...]

您可以阅读更多关于pip’s implementation of vcs support here

安装开发依赖项:

$ pipenv install pytest --dev
Installing pytest...
...
Adding pytest to Pipfile's [dev-packages]...

显示依赖关系图:

$ pipenv graph
requests==2.18.4
  - certifi [required: >=2017.4.17, installed: 2017.7.27.1]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: >=2.5,<2.7, installed: 2.6]
  - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]

生成锁定文件:

$ pipenv lock
Assuring all dependencies from Pipfile are installed...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...
Note: your project now has only default [packages] installed.
To install [dev-packages], run: $ pipenv install --dev

安装所有开发人员依赖项:

$ pipenv install --dev
Pipfile found at /Users/kennethreitz/repos/kr/pip2/test/Pipfile. Considering this to be the project home.
Pipfile.lock out of date, updating...
Assuring all dependencies from Pipfile are installed...
Locking [dev-packages] dependencies...
Locking [packages] dependencies...

卸载所有内容:

$ pipenv uninstall --all
No package provided, un-installing all dependencies.
Found 25 installed package(s), purging...
...
Environment now purged and fresh!

使用外壳:

$ pipenv shell
Loading .env environment variables...
Launching subshell in virtual environment. Type 'exit' or 'Ctrl+D' to return.
$ ▯

☤文档

文档位于pipenv.pypa.io