python pipenv_Pipenv:新Python打包工具指南

python pipenv

Pipenv is a packaging tool for Python that solves some common problems associated with the typical workflow using pip, virtualenv, and the good old requirements.txt.

Pipenv是Python的打包工具,它使用pipvirtualenv和良好的旧的requirements.txt解决了与典型工作流相关的一些常见问题。

In addition to addressing some common issues, it consolidates and simplifies the development process to a single command line tool.

除了解决一些常见问题外,它还将开发过程整合和简化为一个命令行工具。

This guide will go over what problems Pipenv solves and how to manage your Python dependencies with Pipenv. Additionally, it will cover how Pipenv fits in with previous methods for package distribution.

本指南将介绍Pipenv解决的问题以及如何使用Pipenv管理Python依赖项。 此外,它将介绍Pipenv如何与以前的软件包分发方法配合使用。

Free Bonus: Click here to get access to a free 5-day class that shows you how to avoid common dependency management issues with tools like Pip, PyPI, Virtualenv, and requirements files.

免费奖金: 单击此处可获得5天免费课程 ,该课程向您展示如何使用Pip,PyPI,Virtualenv和需求文件之类的工具避免常见的依赖项管理问题。

Pipenv解决的问题 (Problems that Pipenv Solves)

To understand the benefits of Pipenv, it’s important to walk through the current methods for packaging and dependency management in Python.

要了解Pipenv的好处,重要的是要逐步了解Python中当前的打包和依赖管理方法。

Let’s start with a typical situation of handling third-party packages. We’ll then build our way towards deploying a complete Python application.

让我们从处理第三方程序包的典型情况开始。 然后,我们将构建部署完整的Python应用程序的方式。

具有requirements.txt依赖关系管理 (Dependency Management with requirements.txt)

Imagine you’re working on a Python project that uses a third-party package like flask. You’ll need to specify that requirement so that other developers and automated systems can run your application.

想象一下,您正在使用一个使用诸如flask的第三方包的Python项目。 您需要指定该要求,以便其他开发人员和自动化系统可以运行您的应用程序。

So you decide to include the flask dependency in a requirements.txt file:

因此,您决定在requirements.txt文件flask包括flask依赖项:

 flask
flask

Great, everything works fine locally, and after hacking away on your app for a while, you decide to move it to production. Here’s where things get a little scary…

太好了,一切在本地都可以正常工作,并且在入侵了您的应用一段时间后,您决定将其移至生产环境。 这是有些令人恐惧的地方...

The above requirements.txt file doesn’t specify which version of flask to use. In this case, pip install -r requirements.txt will install the latest version by default. This is okay unless there are interface or behavior changes in the newest version that break our application.

上面的requirements.txt文件未指定要使用的flask版本。 在这种情况下, pip install -r requirements.txt将默认安装最新版本。 除非最新版本中的界面或行为更改会破坏我们的应用程序,否则都可以。

For the sake of this example, let’s say that a new version of flask got released. However, it isn’t backward compatible with the version you used during development.

就本例而言,假设发布了新版本的flask 但是,它与您在开发期间使用的版本不向后兼容。

Now, let’s say you deploy your application to production and do a pip install -r requirements.txt. Pip gets the latest, not-backward-compatible version of flask, and just like that, your application breaks… in production.

现在,假设您将应用程序部署到生产环境并执行pip install -r requirements.txt Pip获得了flask的最新的,非向后兼容的版本,这样,您的应用程序就在生产中中断了。

“But hey, it worked on my machine!”—I’ve been there myself, and it’s not a great feeling.

“但是,它在我的机器上工作了!” —我亲自去过那里,感觉不是很好。

At this point, you know that the version of flask you used during development worked fine. So, to fix things, you try to be a little more specific in your requirements.txt. You add a version specifier to the flask dependency. This is also called pinning a dependency:

至此,您知道在开发过程flask使用的flask版本工作正常。 所以,解决的事情,你试试在你的更具体一点requirements.txt 您将版本说明符添加到flask依赖项。 这也称为固定依赖项:

Pinning the flask dependency to a specific version ensures that a pip install -r requirements.txt sets up the exact version of flask you used during development. But does it really?

flask依赖项固定到特定版本可确保pip install -r requirements.txt设置您在开发期间使用的flask的确切版本。 但是真的吗?

Keep in mind that flask itself has dependencies as well (which pip installs automatically). However, flask itself doesn’t specify exact versions for its dependencies. For example, it allows any version of Werkzeug>=0.14.

请记住, flask本身也具有依赖项(该pip会自动安装)。 但是, flask本身并未为其依赖项指定确切的版本。 例如,它允许Werkzeug>=0.14任何版本。

Again, for the sake of this example, let’s say a new version of Werkzeug got released, but it introduces a show-stopper bug to your application.

再次,为了这个示例,我们假设发布了新版本的Werkzeug ,但它向您的应用程序引入了show-stopper错误。

When you do pip install -r requirements.txt in production this time, you will get flask==0.12.1 since you’ve pinned that requirement. However, unfortunately, you’ll get the latest, buggy version of Werkzeug. Again, the product breaks in production.

这次在生产环境中进行pip install -r requirements.txt时,由于已固定该要求,因此将得到flask==0.12.1 但是,不幸的是,您将获得Werkzeug的最新,错误版本。 再次,产品中断了生产。

The real issue here is that the build isn’t deterministic. What I mean by that is that, given the same input (the requirements.txt file), pip doesn’t always produce the same environment. At the moment, you can’t easily replicate the exact environment you have on your development machine in production.

这里真正的问题是构建不是确定性的 我的意思是,给定相同的输入( requirements.txt文件),pip并不总是产生相同的环境。 目前,您无法轻松复制生产环境中开发计算机上的确切环境。

The typical solution to this problem is to use pip freeze. This command allows you to get exact versions for all 3rd party libraries currently installed, including the sub-dependencies pip installed automatically. So you can freeze everything in development to ensure that you have the same environment in production.

解决此问题的典型方法是使用pip freeze 此命令使您可以获得当前安装的所有第3方库的确切版本,包括自动安装的子依赖项pip。 因此,您可以冻结开发中的所有内容,以确保在生产中拥有相同的环境。

Executing pip freeze results in pinned dependencies you can add to a requirements.txt:

执行pip freeze导致固定的依赖项,您可以将其添加到requirements.txt

 clickclick ==== 6.7
6.7
FlaskFlask ==== 0.120.12 .. 1
1
itsdangerousitsdangerous ==== 0.24
0.24
Jinja2Jinja2 ==== 2.10
2.10
MarkupSafeMarkupSafe ==== 1.0
1.0
WerkzeugWerkzeug ==== 0.140.14 .. 1
1

With these pinned dependencies, you can ensure that the packages installed in your production environment match those in your development environment exactly, so your product doesn’t unexpectedly break. This “solution,” unfortunately, leads to a whole new set of problems.

通过这些固定的依赖关系,您可以确保生产环境中安装的软件包与开发环境中的软件包完全匹配,因此产品不会意外损坏。 不幸的是,这种“解决方案”导致了一系列全新的问题。

Now that you’ve specified the exact versions of every third-party package, you are responsible for keeping these versions up to date, even though they’re sub-dependencies of flask. What if there’s a security hole discovered in Werkzeug==0.14.1 that the package maintainers immediately patched in Werkzeug==0.14.2? You really need to update to Werkzeug==0.14.2 to avoid any security issues arising from the earlier, unpatched version of Werkzeug.

现在,您已经指定了每个第三方软件包的确切版本,您有责任使这些版本保持最新,即使它们是flask子依赖关系。 如果在Werkzeug==0.14.1中发现一个安全漏洞,而软件包维护者立即在Werkzeug==0.14.2修补, Werkzeug==0.14.2怎么Werkzeug==0.14.2 您确实需要更新到Werkzeug==0.14.2以避免由于Werkzeug的早期未修补版本引起的任何安全问题。

First, you need to be aware that there’s an issue with the version you have. Then, you need to get the new version in your production environment before someone exploits the security hole. So, you have to change your requirements.txt manually to specify the new version Werkzeug==0.14.2. As you can see in this situation, the responsibility of staying up to date with necessary updates falls on you.

首先,您需要意识到所使用的版本存在问题。 然后,在有人利用安全漏洞之前,您需要在生产环境中获取新版本。 因此,您必须手动更改您的requirements.txt以指定新版本Werkzeug==0.14.2 如您所见,在这种情况下,保持必要更新的责任落在您身上。

The truth is that you really don’t care what version of Werkzeug gets installed as long as it doesn’t break your code. In fact, you probably want the latest version to ensure that you’re getting bug fixes, security patches, new features, more optimization, and so on.

事实是,只要不破坏您的代码,您实际上就不会在乎安装什么版本的Werkzeug 实际上,您可能想要最新版本以确保获得错误修复,安全补丁,新功能,更多优化等。

The real question is: “How do you allow for deterministic builds for your Python project without gaining the responsibility of updating versions of sub-dependencies?”

真正的问题是: “如何在不承担更新子依赖项版本的责任的情况下,为Python项目提供确定性的构建?”

Spoiler alert: The easy answer is using Pipenv.

剧透警告:简单的答案是使用Pipenv。

开发具有不同依赖关系的项目 (Development of Projects with Different Dependencies)

Let’s switch gears a bit to talk about another common issue that arises when you’re working on multiple projects. Imagine that ProjectA needs django==1.9, but ProjectB needs django==1.10.

让我们来讨论一下在处理多个项目时出现的另一个常见问题。 想象一下ProjectA需要django==1.9 ,但ProjectB需要django==1.10

By default, Python tries to store all your third-party packages in a system-wide location. This means that every time you want to switch between ProjectA and ProjectB, you have to make sure the right version of django is installed. This makes switching between projects painful because you have to uninstall and reinstall packages to meet the requirements for each project.

默认情况下,Python尝试将所有第三方软件包存储在系统范围内。 这意味着每次要在ProjectAProjectB之间切换时,都必须确保安装了正确版本的django 这使项目之间的切换变得很痛苦,因为您必须卸载并重新安装软件包才能满足每个项目的要求。

The standard solution is to use a virtual environment that has its own Python executable and third-party package storage. That way, ProjectA and ProjectB are adequately separated. Now you can easily switch between projects since they’re not sharing the same package storage location. PackageA can have whatever version of django it needs in its own environment, and PackageB can have what it needs totally separate. A very common tool for this is virtualenv (or venv in Python 3).

标准解决方案是使用具有自己的Python可执行文件和第三方程序包存储的虚拟环境 。 这样一来, ProjectAProjectB可以充分分开了。 现在,您可以在项目之间轻松切换,因为它们不会共享相同的程序包存储位置。 PackageA可以在其自己的环境中具有所需的django版本,而PackageB可以将其完全独立。 一个非常常见的工具是virtualenv (或Python 3中的venv )。

Pipenv has virtual environment management built in so that you have a single tool for your package management.

Pipenv内置了虚拟环境管理,因此您可以使用一个工具进行软件包管理。

依赖解决 (Dependency Resolution)

What do I mean by dependency resolution? Let’s say you’ve got a requirements.txt file that looks something like this:

依存关系解析是什么意思? 假设您有一个requirements.txt文件,看起来像这样:

Let’s say package_a has a sub-dependency package_c, and package_a requires a specific version of this package: package_c>=1.0. In turn, package_b has the same sub-dependency but needs package_c<=2.0.

假设package_a有一个子依赖package_c ,而package_a需要此包的特定版本: package_c>=1.0 反过来, package_b具有相同的子依赖关系,但需要package_c<=2.0

Ideally, when you try to install package_a and package_b, the installation tool would look at the requirements for package_c (being >=1.0 and <=2.0) and select a version that fulfills those requirements. You’d hope that the tool resolves the dependencies so that your program works in the end. This is what I mean by “dependency resolution.”

理想情况下,当您尝试安装package_apackage_b ,安装工具将查看package_c的要求( >=1.0<=2.0 ),然后选择一个满足这些要求的版本。 您希望该工具能够解决依赖关系,以便您的程序最终可以工作。 这就是我所说的“依赖解决方案”。

Unfortunately, pip itself doesn’t have real dependency resolution at the moment, but there’s an open issue to support it.

不幸的是,pip本身目前还没有真正的依赖关系解决方案,但是有一个开放的问题需要支持。

The way pip would handle the above scenario is as follows:

pip处理上述情况的方式如下:

  1. It installs package_a and looks for a version of package_c that fulfills the first requirement (package_c>=1.0).

  2. Pip then installs the latest version of package_c to fulfill that requirement. Let’s say the latest version of package_c is 3.1.

  1. 它安装package_a并查找满足第一个要求的package_c版本( package_c>=1.0 )。

  2. 然后,Pip安装最新版本的package_c来满足该要求。 假设package_c的最新版本是3.1。

This is where the trouble (potentially) starts.

这是麻烦(可能)开始的地方。

If the version of package_c selected by pip doesn’t fit future requirements (such as package_b needing package_c<=2.0), the installation will fail.

如果pip选择的package_c版本不符合将来的要求(例如package_b需要package_c<=2.0 ),则安装将失败。

The “solution” to this problem is to specify the range required for the sub-dependency (package_c) in the requirements.txt file. That way, pip can resolve this conflict and install a package that meets those requirements:

该问题的“解决方案”是在requirements.txt文件中指定子依赖性( package_c )所需的范围。 这样,pip可以解决此冲突并安装满足那些要求的软件包:

 package_cpackage_c >=>= 1.01.0 ,, <=<= 2.0
2.0
package_a
package_a
package_b
package_b

Just like before though, you’re now concerning yourself directly with sub-dependencies (package_c). The issue with this is that if package_a changes their requirement without you knowing, the requirements you specified (package_c>=1.0,<=2.0) may no longer be acceptable, and installation may fail… again. The real problem is that once again, you’re responsible for staying up to date with requirements of sub-dependencies.

就像以前一样,您现在直接将自己与子依赖关系( package_c )联系起来。 这样做的问题在于,如果package_a在您不知情的情况下更改了其要求,则您指定的要求( package_c>=1.0,<=2.0 )可能不再可以接受,并且安装可能会再次失败。 真正的问题是,您有责任再次保持对子依赖项的要求。

Ideally, your installation tool would be smart enough to install packages that meet all the requirements without you explicitly specifying sub-dependency versions.

理想情况下,您的安装工具应足够聪明,可以安装满足所有要求的软件包,而无需您明确指定子依赖版本。

Pipenv介绍 (Pipenv Introduction)

Now that we’ve addressed the problems, let’s see how Pipenv solves them.

现在我们已经解决了问题,让我们看看Pipenv如何解决它们。

First, let’s install it:

首先,让我们安装它:

Once you’ve done that, you can effectively forget about pip since Pipenv essentially acts as a replacement. It also introduces two new files, the Pipfile (which is meant to replace requirements.txt) and the Pipfile.lock (which enables deterministic builds).

完成此操作后,由于Pipenv本质上是替代品,因此您可以有效地忽略pip 它还引入了两个新文件,即Pipfile (用于替换requirements.txt )和Pipfile.lock (用于启用确定性构建)。

Pipenv uses pip and virtualenv under the hood but simplifies their usage with a single command line interface.

Pipenv在后台使用pipvirtualenv ,但通过单个命令行界面简化了它们的使用。

用法示例 (Example Usage)

Let’s start over with creating your awesome Python application. First, spawn a shell in a virtual environment to isolate the development of this app:

让我们从创建很棒的Python应用程序开始。 首先,在虚拟环境中生成外壳程序以隔离此应用程序的开发:

 $ pipenv shell
$ pipenv shell

This will create a virtual environment if one doesn’t already exist. Pipenv creates all your virtual environments in a default location. If you want to change Pipenv’s default behavior, there are some environmental variables for configuration.

如果尚不存在,则会创建一个虚拟环境。 Pipenv在默认位置创建所有虚拟环境。 如果要更改Pipenv的默认行为,则可以使用一些环境变量进行配置 。

You can force the creation of a Python 2 or 3 environment with the arguments --two and --three respectively. Otherwise, Pipenv will use whatever default virtualenv finds.

您可以强制一个Python 2或3环境的创建与参数--two--three分别。 否则,Pipenv将使用默认virtualenv找到的任何内容。

Sidenote: If you require a more specific version of Python, you can provide a --python argument with the version you require. For example: --python 3.6

旁注:如果您需要更特定的Python版本,则可以在--python的版本中提供--python参数。 例如:-- --python 3.6

Now you can install the 3rd party package you need, flask. Oh, but you know that you need version 0.12.1 and not the latest version, so go ahead and be specific:

现在,您可以安装所需的3rd party软件包flask 哦,但是您知道您需要版本0.12.1而不是最新版本,所以请继续并具体说明:

You should see something like the following in your terminal:

您应该在终端中看到以下内容:

Adding flask==0.12.1 to Pipfile's [packages]…
Pipfile.lock not found, creating…
Adding flask==0.12.1 to Pipfile's [packages]…
Pipfile.lock not found, creating…

You’ll notice that two files get created, a Pipfile and Pipfile.lock. We’ll take a closer look at these in a second. Let’s install another 3rd party package, numpy, for some number-crunching. You don’t need a specific version so don’t specify one:

您会注意到创建了两个文件,一个PipfilePipfile.lock 我们将在一秒钟内仔细研究这些内容。 让我们安装另一个第三方软件包numpy ,以进行一些数字运算。 您不需要特定版本,因此不要指定一个版本:

If you want to install something directly from a version control system (VCS), you can! You specify the locations similarly to how you’d do so with pip. For example, to install the requests library from version control, do the following:

如果您想直接从版本控制系统(VCS)安装某些软件,则可以! 您可以使用pip来指定位置。 例如,要从版本控制安装requests库,请执行以下操作:

 $ pipenv install -e git+https://github.com/requests/requests.git#egg$ pipenv install -e git+https://github.com/requests/requests.git#egg =requests
= requests

Note the -e argument above to make the installation editable. Currently, this is required for Pipenv to do sub-dependency resolution.

注意上面的-e参数以使安装可编辑。 当前, 这对于Pipenv进行子依赖关系解析是必需的。

Let’s say you also have some unit tests for this awesome application, and you want to use pytest for running them. You don’t need pytest in production so you can specify that this dependency is only for development with the --dev argument:

假设您还对该超赞应用程序进行了一些单元测试,并且希望使用pytest来运行它们。 您不需要在生产环境中使用pytest ,因此可以使用--dev参数指定此依赖项仅用于开发:

Providing the --dev argument will put the dependency in a special [dev-packages] location in the Pipfile. These development packages only get installed if you specify the --dev argument with pipenv install.

提供了--dev参数将放在一个特殊的依赖性[dev-packages]中的位置Pipfile 仅当在pipenv install指定--dev参数时, pipenv install这些开发包。

The different sections separate dependencies needed only for development from ones needed for the base code to actually work. Typically, this would be accomplished with additional requirements files like dev-requirements.txt or test-requirements.txt. Now, everything is consolidated in a single Pipfile under different sections.

不同部分将仅开发所需的依赖关系与基本代码实际起作用所需的依赖关系分开。 通常,这可以通过其他需求文件(例如dev-requirements.txttest-requirements.txt 现在,所有内容都被合并到不同部分下的单个Pipfile

Okay, so let’s say you’ve got everything working in your local development environment and you’re ready to push it to production. To do that, you need to lock your environment so you can ensure you have the same one in production:

好的,假设您在本地开发环境中已完成所有工作,并准备将其投入生产。 为此,您需要锁定环境,以确保生产环境中具有相同的环境:

 $ pipenv lock
$ pipenv lock

This will create/update your Pipfile.lock, which you’ll never need to (and are never meant to) edit manually. You should always use the generated file.

这将创建/更新您的Pipfile.lock ,您将不需要(也不希望)进行手动编辑。 您应该始终使用生成的文件。

Now, once you get your code and Pipfile.lock in your production environment, you should install the last successful environment recorded:

现在,一旦在生产环境中获取了代码和Pipfile.lock ,就应该安装最后记录的成功环境:

This tells Pipenv to ignore the Pipfile for installation and use what’s in the Pipfile.lock. Given this Pipfile.lock, Pipenv will create the exact same environment you had when you ran pipenv lock, sub-dependencies and all.

这告诉Pipenv忽略要安装的Pipfile并使用Pipfile.lock中的Pipfile.lock 有了这个Pipfile.lock ,Pipenv将创建与运行pipenv lock ,子依赖关系以及所有pipenv lock时完全相同的环境。

The lock file enables deterministic builds by taking a snapshot of all the versions of packages in an environment (similar to the result of a pip freeze).

锁定文件通过对环境中所有版本的软件包进行快照来启用确定性构建(类似于pip freeze的结果)。

Now let’s say another developer wants to make some additions to your code. In this situation, they would get the code, including the Pipfile, and use this command:

现在,假设另一个开发人员想要对您的代码进行一些补充。 在这种情况下,他们将获得包括Pipfile在内的Pipfile ,并使用以下命令:

 $ pipenv install --dev
$ pipenv install --dev

This installs all the dependencies needed for development, which includes both the regular dependencies and those you specified with the --dev argument during install.

这将安装开发所需的所有依赖项,包括常规依赖项和在install期间使用--dev参数指定的依赖项。

When an exact version isn’t specified in the Pipfile, the install command gives the opportunity for dependencies (and sub-dependencies) to update their versions.

如果在Pipfile中未指定确切版本,则install命令会为依赖项(和子依赖项)提供更新其版本的机会。

This is an important note because it solves some of the previous problems we discussed. To demonstrate, let’s say a new version of one of your dependencies becomes available. Because you don’t need a specific version of this dependency, you don’t specify an exact version in the Pipfile. When you pipenv install, the new version of the dependency will be installed in your development environment.

这是一个重要说明,因为它解决了我们之前讨论的一些问题。 为了演示,假设您的一个依赖项的新版本可用。 由于不需要此依赖项的特定版本,因此无需在Pipfile指定确切的版本。 当您pipenv install ,新版本的依赖项将安装在您的开发环境中。

Now you make your changes to the code and run some tests to verify everything is still working as expected. (You do have unit tests, right?) Now, just as before, you lock your environment with pipenv lock, and an updated Pipfile.lock will be generated with the new version of the dependency. Just as before, you can replicate this new environment in production with the lock file.

现在,您对代码进行更改并运行一些测试,以验证一切仍按预期进行。 (您确实有单元测试,对吗?)现在,和以前一样,您使用pipenv lock锁定环境,并且将使用新版本的依赖项生成更新的Pipfile.lock 和以前一样,您可以使用锁定文件在生产环境中复制此新环境。

As you can see from this scenario, you no longer have to force exact versions you don’t truly need to ensure your development and production environments are the same. You also don’t need to stay on top of updating sub-dependencies you “don’t care about.” This workflow with Pipenv, combined with your excellent testing, fixes the issues of manually doing all your dependency management.

从这种情况下可以看出,您不必再强制使用您真正不需要的确切版本来确保您的开发和生产环境相同。 您也不需要保持更新“无关”的子依赖关系。 Pipenv的此工作流程与出色的测试相结合,解决了手动执行所有依赖项管理的问题。

Pipenv的依赖性解决方法 (Pipenv’s Dependency Resolution Approach)

Pipenv will attempt to install sub-dependencies that satisfy all the requirements from your core dependencies. However, if there are conflicting dependencies (package_a needs package_c>=1.0, but package_b needs package_c<1.0), Pipenv will not be able to create a lock file and wil output an error like the following:

Pipenv将尝试安装满足您的核心依赖项所有要求的子依赖项。 但是,如果存在冲突的依赖项( package_a需要package_c>=1.0 ,而package_b需要package_c<1.0 ),Pipenv将无法创建锁定文件,并且将输出如下错误:

As the warning says, you can also show a dependency graph to understand your top-level dependencies and their sub-dependencies:

如警告所述,您还可以显示一个依赖关系图,以了解您的顶级依赖关系及其子依赖关系:

 $ pipenv graph
$ pipenv graph

This command will print out a tree-like structure showing your dependencies. Here’s an example:

此命令将打印出一个树状结构,显示您的依赖关系。 这是一个例子:

From the output of pipenv graph, you can see the top-level dependencies we installed previously (Flask, numpy, pytest, and requests), and underneath you can see the packages they depend on.

pipenv graph的输出中,您可以看到我们之前安装的顶级依赖项( Flasknumpypytestrequests ),并且在下面可以看到它们所依赖的软件包。

Additionally, you can reverse the tree to show the sub-dependencies with the parent that requires it:

此外,您可以反转树以显示与需要它的父级的子依赖关系:

 $ pipenv graph --reverse
$ pipenv graph --reverse

This reversed tree may be more useful when you are trying to figure out conflicting sub-dependencies.

当您试图找出冲突的子依赖项时,这种反向树可能会更有用。

Pipfile (The Pipfile)

Pipfile intends to replace requirements.txt. Pipenv is currently the reference implementation for using Pipfile. It seems very likely that pip itself will be able to handle these files. Also, it’s worth noting that Pipenv is even the official package management tool recommended by Python itself.

Pipfile打算替换requirements.txt Pipenv当前是使用Pipfile的参考实现。 pip本身很可能能够处理这些文件 。 另外,值得注意的是Pipenv甚至是Python本身推荐的官方软件包管理工具 。

The syntax for the Pipfile is TOML, and the file is separated into sections. [dev-packages] for development-only packages, [packages] for minimally required packages, and [requires] for other requirements like a specific version of Python. See an example file below:

Pipfile的语法为TOML ,并且文件分为几部分。 [dev-packages]用于仅开发的软件包, [packages]用于最低要求的软件包, [requires]其他要求,例如特定版本的Python。 请参阅下面的示例文件:

Ideally, you shouldn’t have any sub-dependencies in your Pipfile. What I mean by that is you should only include the packages you actually import and use. No need to keep chardet in your Pipfile just because it’s a sub-dependency of requests. (Pipenv will install it automatically.) The Pipfile should convey the top-level dependencies your package requires.

理想情况下,您的Pipfile不应包含任何子依赖Pipfile 我的意思是,您应该只包括您实际导入和使用的软件包。 无需仅将chardet保留在Pipfile ,因为它是Pipfile的子依赖requests (Pipenv将自动安装它。) Pipfile应该传达您的程序包所需的顶级依赖关系。

Pipfile.lock (The Pipfile.lock)

This file enables deterministic builds by specifying the exact requirements for reproducing an environment. It contains exact versions for packages and hashes to support more secure verification, which pip itself now supports as well. An example file might look like the following. Note that the syntax for this file is JSON and that I’ve excluded parts of the file with ...:

通过指定复制环境的确切要求,此文件启用确定性构建。 它包含软件包和哈希的确切版本,以支持更安全的验证, pip本身现在也支持该验证。 示例文件可能如下所示。 请注意,此文件的语法为JSON,并且我已经使用...排除了文件的某些部分:

 {
    {
    "_meta""_meta" : : {
        {
        ...
    ...
    },
    },
    "default""default" : : {
        {
        "flask""flask" : : {
            {
            "hashes""hashes" : : [
                [
                "sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242""sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242" ,
                ,
                "sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
            "sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
            ],
            ],
            "version""version" : : "==0.12.1"
        "==0.12.1"
        },
        },
        "requests""requests" : : {
            {
            "editable""editable" : : truetrue ,
            ,
            "git""git" : : "https://github.com/requests/requests.git""https://github.com/requests/requests.git" ,
            ,
            "ref""ref" : : "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
        "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
        },
        },
        "werkzeug""werkzeug" : : {
            {
            "hashes""hashes" : : [
                [
                "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b""sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" ,
                ,
                "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
            "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
            ],
            ],
            "version""version" : : "==0.14.1"
        "==0.14.1"
        }
        }
        ...
    ...
    },
    },
    "develop""develop" : : {
        {
        "pytest""pytest" : : {
            {
            "hashes""hashes" : : [
                [
                "sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d""sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d" ,
                ,
                "sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
            "sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
            ],
            ],
            "version""version" : : "==3.4.1"
        "==3.4.1"
        },
        },
        ...
    ...
    }
}
}
}

Note the exact version specified for every dependency. Even the sub-dependencies like werkzeug that aren’t in our Pipfile appear in this Pipfile.lock. The hashes are used to ensure you’re retrieving the same package as you did in development.

注意为每个依赖项指定的确切版本。 甚至不存在于我们Pipfile类似werkzeug的子依赖项Pipfile出现在此Pipfile.lock 散列用于确保您检索与开发中相同的程序包。

It’s worth noting again that you should never change this file by hand. It is meant to be generated with pipenv lock.

再次值得注意的是,您永远不要手动更改此文件。 它是用pipenv lock生成的。

Pipenv额外功能 (Pipenv Extra Features)

Open a third-party package in your default editor with the following command:

使用以下命令在默认编辑器中打开第三方程序包:

This will open the flask package in the default editor, or you can specify a program with an EDITOR environmental variable. For example, I use Sublime Text, so I just set EDITOR=subl. This makes it super simple to dig into the internals of a package you’re using.

这将在默认编辑器flask打开flask包,或者您可以使用EDITOR环境变量指定程序。 例如,我使用Sublime Text ,所以我只设置EDITOR=subl 这使得挖掘正在使用的软件包的内部变得非常简单。



You can run a command in the virtual environment without launching a shell:

您可以在虚拟环境中运行命令而无需启动外壳程序:

 $ pipenv run $ pipenv run command here>
command here>


Check for security vulnerabilities (and PEP 508 requirements) in your environment:

检查您的环境中的安全漏洞(和PEP 508要求):



Now, let’s say you no longer need a package. You can uninstall it:

现在,假设您不再需要软件包。 您可以卸载它:

 $ pipenv uninstall numpy
$ pipenv uninstall numpy

Additionally, let’s say you want to completely wipe all the installed packages from your virtual environment:

另外,假设您要从虚拟环境中完全擦除所有已安装的软件包:

You can replace --all with --all-dev to just remove dev packages.

您可以将--all替换为--all-dev来删除开发包。



Pipenv supports the automatic loading of environmental variables when a .env file exists in the top-level directory. That way, when you pipenv shell to open the virtual environment, it loads your environmental variables from the file. The .env file just contains key-value pairs:

当顶级目录中存在.env文件时,Pipenv支持自动加载环境变量。 这样,当您通过pipenv shell打开虚拟环境时,它将从文件中加载环境变量。 .env文件仅包含键值对:

SOME_ENV_CONFIG=some_value
SOME_OTHER_ENV_CONFIG=some_other_value
SOME_ENV_CONFIG=some_value
SOME_OTHER_ENV_CONFIG=some_other_value


Finally, here are some quick commands to find out where stuff is. How to find out where your virtual environment is:

最后,这里有一些快速的命令可以找出东西在哪里。 如何找出您的虚拟环境在哪里:

How to find out where your project home is:

如何找到您的项目主页在哪里:

 $ pipenv --where
$ pipenv --where

包装分配 (Package Distribution)

You may be asking how this all works if you intend to distribute your code as a package.

如果您打算将代码打包分发,您可能会问这一切如何工作。

是的,我需要打包分发代码 (Yes, I need to distribute my code as a package)

How does Pipenv work with setup.py files?

Pipenv如何处理setup.py文件?

There are a lot of nuances to that question. First, a setup.py file is necessary when you’re using setuptools as your build/distribution system. This has been the de facto standard for a while now, but recent changes have made the use of setuptools optional.

这个问题有很多细微差别。 首先,当您使用setuptools作为构建/分发系统时,必须使用setup.py文件。 这已经成为事实上的标准了一段时间,但是最近的更改使setuptools的使用setuptools可选。

This means that projects like flit can use the new pyproject.toml to specify a different build system that doesn’t require a setup.py.

这意味着flit之类的项目可以使用新的pyproject.toml来指定一个不需要setup.py的其他构建系统。

All that being said, for the near future setuptools and an accompanying setup.py will still be the default choice for many people.

话虽如此,对于不久的将来的setuptools和随附的setup.py仍然是许多人的默认选择。

Here’s a recommended workflow for when you are using a setup.py as a way to distribute your package:

当您使用setup.py作为分发软件包的方式时,以下是推荐的工作流程:

  • setup.py
  • install_requires keyword should include whatever the package “minimally needs to run correctly.”
  • Pipfile
  • Represents the concrete requirements for your package
  • Pull the minimally required dependencies from setup.py by installing your package using Pipenv:
    • Use pipenv install '-e .'
    • That will result in a line in your Pipfile that looks something like "e1839a8" = {path = ".", editable = true}.
  • Pipfile.lock
  • Details for a reproducible environment generated from pipenv lock
  • setup.py
  • install_requires关键字应包括“最低要求才能正常运行”的任何软件包。
  • Pipfile
  • 代表您包装的具体要求
  • 通过使用Pipenv安装软件包,从setup.py获取最低限度的依赖项:
    • 使用pipenv install '-e .'
    • 这将导致您的Pipfile中的一行看起来类似于"e1839a8" = {path = ".", editable = true}
  • Pipfile.lock
  • pipenv lock生成的可复制环境的详细信息

To clarify, put your minimum requirements in setup.py instead of directly with pipenv install. Then use the pipenv install '-e .' command to install your package as editable. This gets all the requirements from setup.py into your environment. Then you can use pipenv lock to get a reproducible environment.

为了明确pipenv install ,请将最低要求放入setup.py而不要直接使用pipenv install 然后使用pipenv install '-e .' 命令以可编辑的方式安装您的软件包。 这会将所有需求从setup.py转移到您的环境中。 然后,您可以使用pipenv lock来获得可重现的环境。

我不需要将代码打包分发 (I don’t need to distribute my code as a package)

Great! If you are developing an application that isn’t meant to be distributed or installed (a personal website, a desktop application, a game, or similar), you don’t really need a setup.py.

大! 如果您要开发的应用程序不是要分发或安装的(个人网站,桌面应用程序,游戏或类似产品),则实际上不需要setup.py

In this situation, you could use Pipfile/Pipfile.lock combo for managing your dependencies with the flow described previously to deploy a reproducible environment in production.

在这种情况下,您可以使用Pipfile / Pipfile.lock组合使用Pipfile描述的流程来管理依赖项,以在生产环境中部署可重现的环境。

我已经有一个requirements.txt 如何转换为Pipfile (I already have a requirements.txt. How do I convert to a Pipfile?)

If you run pipenv install it should automatically detect the requirements.txt and convert it to a Pipfile, outputting something like the following:

如果运行pipenv install它将自动检测requirements.txt并将其转换为Pipfile ,输出类似以下内容:

Take note of the above warning.

注意上述警告。

If you have pinned exact versions in your requirements.txt file, you’ll probably want to change your Pipfile to only specify exact versions you truly require. This will allow you to gain the real benefits of transitioning. For example, let’s say you have the following but really don’t need that exact version of numpy:

如果您在requirements.txt文件中固定了确切的版本,则可能需要更改Pipfile使其仅指定您真正需要的确切版本。 这将使您获得过渡的真正好处。 例如,假设您具有以下内容,但实际上并不需要该确切版本的numpy

 [packages]
[packages]
numpy numpy = = "==1.14.1"
"==1.14.1"

If you don’t have any specific version requirements for your dependencies, you can use the wildcard character * to tell Pipenv that any version can be installed:

如果您的依赖项没有任何特定的版本要求,则可以使用通配符*告诉Pipenv可以安装任何版本:

If you feel nervous about allowing any version with the *, it’s typically a safe bet to specify greater than or equal to the version you’re already on so you can still take advantage of new versions:

如果您对允许使用*任何版本感到不安,通常可以选择指定大于或等于您已经在使用的版本,这样一来,您仍然可以利用新版本:

 [packages]
[packages]
numpy numpy = = ">=1.14.1"
">=1.14.1"

Of course, staying up to date with new releases also means you’re responsible for ensuring your code still functions as expected when packages change. This means a test suite is essential to this whole Pipenv flow if you want to ensure functioning releases of your code.

当然,与新版本保持最新也意味着您有责任确保在更改软件包时代码仍按预期运行。 这意味着如果您要确保代码的正常发布,则对于整个Pipenv流程来说,测试套件必不可少。

You allow packages to update, run your tests, ensure they all pass, lock your environment, and then you can rest easy knowing that you haven’t introduced breaking changes. If things do break because of a dependency, you’ve got some regression tests to write and potentially some more restrictions on versions of dependencies.

您允许软件包更新,运行测试,确保它们全部通过,锁定环境,然后您就可以放心了,因为您尚未引入重大更改。 如果事情确实由于依赖关系而中断,那么您需要编写一些回归测试,并可能会对依赖关系的版本进行更多限制。

For example, if numpy==1.15 gets installed after running pipenv install and it breaks your code, which you hopefully either notice during development or during your tests, you have a couple options:

例如,如果在运行pipenv install之后pipenv install numpy==1.15 ,并且它破坏了您的代码(希望您在开发或测试期间注意到该代码),则可以使用以下两种方法:

  1. Update your code to function with the new version of the dependency.

    If backward compatibility with previous versions of the dependency isn’t possible, you’ll also need to bump your required version in your Pipfile:

  2. Restrict the version of the dependency in the Pipfile to be < the version that just broke your code:

    [packages]
    numpy = ">=1.14.1,<1.15"
    
    
  1. 更新您的代码以使用新版本的依赖项。

    如果无法与该依赖关系的先前版本向后兼容,则还需要在Pipfile所需的版本:

  2. Pipfile中的依赖项版本限制为<刚破坏代码的版本:

     [packages]
    numpy = ">=1.14.1,<1.15"
    

Option 1 is preferred as it ensures that your code is using the most up-to-date dependencies. However, Option 2 takes less time and doesn’t require code changes, just restrictions on dependencies.

优选使用选项1,因为它可确保您的代码使用的是最新的依赖关系。 但是,选项2花费的时间更少,不需要更改代码,而只是对依赖项的限制。



You can also install from requirement files with the same -r argument pip takes:

您还可以从需求文件安装具有相同的-r参数pip

If you have a dev-requirements.txt or something similar, you can add those to the Pipfile as well. Just add the --dev argument so it gets put in the right section:

如果您有dev-requirements.txt或类似文件,也可以将其添加到Pipfile中。 只需添加--dev参数,即可将其放入正确的部分:

 $ pipenv install -r dev-requirements.txt --dev
$ pipenv install -r dev-requirements.txt --dev

Additionally, you can go the other way and generate requirements files from a Pipfile:

另外,您可以采用另一种方法,并从Pipfile生成需求文件:

下一步是什么? (What’s next?)

It appears to me that a natural progression for the Python ecosystem would be a build system that uses the Pipfile to install the minimally required dependencies when retrieving and building a package from a package index (like PyPI). It is important to note again that the Pipfile design specification is still in development, and Pipenv is just a reference implementation.

在我看来,Python生态系统的自然发展将是一个构建系统,该构建系统在从包索引(例如PyPI)中检索和构建包时,将使用Pipfile安装所需的最低限度的依赖项。 再次需要注意的是, Pipfile设计规范仍在开发中,而Pipenv只是参考实现。

That being said, I could see a future where the install_requires section of setup.py doesn’t exist, and the Pipfile is referenced for minimal requirements instead. Or the setup.py is gone entirely, and you get metadata and other information in a different manner, still using the Pipfile to get the necessary dependencies.

话虽如此,我可能会看到一个不存在setup.pyinstall_requires部分的未来,而Pipfile是为了满足最低要求而引用的。 或者setup.py完全消失了,并且您以其他方式获取元数据和其他信息,仍然使用Pipfile获取必需的依赖项。

Pipenv值得一试吗? (Is Pipenv worth checking out?)

Definitely. Even if it’s just as a way to consolidate the tools you already use (pip & virtualenv) into a single interface. However, it’s much more than that. With the addition of the Pipfile, you only specify the dependencies you truly need.

绝对是 即使这只是将您已经使用的工具( pipvirtualenv )整合到一个界面中的一种方式。 但是,不仅如此。 通过添加Pipfile ,您只需指定真正需要的依赖项。

You no longer have the headache of managing the versions of everything yourself just to ensure you can replicate your development environment. With the Pipfile.lock, you can develop with peace of mind knowing that you can exactly reproduce your environment anywhere.

您再也不用为了确保可以复制开发环境而自己管理所有内容的版本了。 使用Pipfile.lock ,您可以放心地开发,因为您知道可以在任何地方精确地复制环境。

In addition to all that, it seems very likely that the Pipfile format will get adopted and supported by official Python tools like pip, so it’d be beneficial to be ahead of the game. Oh, and make sure you’re updating all your code to Python 3 as well: 2020 is coming up fast.

除此之外, Pipfile格式很可能会被pip等官方Python工具采用和支持,因此领先于游戏将是有益的。 哦,请确保还要将所有代码也更新到Python 3: 2020年快到了 。

参考资料,进一步阅读,有趣的讨论等 (References, further reading, interesting discussions, and so forth)

  • Official Pipenv documentation
  • Official Pipfile Project
  • Issue addressing install_requires in regards to Pipfile
  • More discussion on setup.py vs Pipfile
  • Post talking about PEP 518
  • Post on Python packaging
  • Comment suggesting Pipenv usage
  • 官方Pipenv文档
  • 官方Pipfile项目
  • 解决关于Pipfile install_requires问题
  • 关于setup.pyPipfile更多讨论
  • 谈论PEP 518
  • 张贴在Python包装上
  • 建议使用Pipenv的评论

Free Bonus: Click here to get access to a free 5-day class that shows you how to avoid common dependency management issues with tools like Pip, PyPI, Virtualenv, and requirements files.

免费奖金: 单击此处可获得5天免费课程 ,该课程向您展示如何使用Pip,PyPI,Virtualenv和需求文件之类的工具避免常见的依赖项管理问题。

翻译自: https://www.pybloggers.com/2018/04/pipenv-a-guide-to-the-new-python-packaging-tool/

python pipenv

你可能感兴趣的:(python pipenv_Pipenv:新Python打包工具指南)