一个系统,可以自动处理在编写脚本和简单程序时通常遇到的情况中的 virtualenvs,甚至可以帮助管理大型项目。
项目描述
什么是渐变?
fades 是一个系统,它自动处理在编写脚本和简单程序时通常遇到的情况下的虚拟环境,甚至帮助管理大型项目。
fades 将自动创建一个新的虚拟环境(或重用之前创建的一个),安装必要的依赖项,并在该虚拟环境中执行您的脚本,唯一的要求是使用 fades 执行脚本,并标记所需的依赖项。
(如果您不知道为什么这是必要的或有用的,我建议您阅读有关 Python 和依赖项管理 的简短文本。)
第一个非选项参数(如果有)将是要执行的子程序,之后的任何其他参数都将原样传递给该子脚本。
fades 也可以在不传递要执行的子脚本的情况下执行:在这种模式下,它将在创建/重用的虚拟环境中打开一个 Python 交互式解释器(从 --dependency 或 --requirement 选项中获取依赖项)。
如何使用它?
点击以下图片查看一个视频/屏幕录制,它展示了 fades 的主要功能只需 5 分钟...
...或者检查 这些几个小 GIF,每个 GIF 都展示了一个特定的 fades 功能,但请继续阅读以获取更多信息...
是的,请让我阅读
当您编写脚本时,您必须采取两项特殊措施
需要使用 fades(而不是 python)执行它
需要标记那些依赖项
在执行脚本的那一刻,fades 将搜索带有标记依赖项的虚拟环境,如果不存在,fades 将创建它,并在该环境中执行脚本。
如何使用 fades 执行脚本?
您始终可以直接使用 fades 调用您的脚本
fades myscript.py
然而,为了确保您不会忘记 fades 并直接使用 python 执行它,最好在脚本的开头放置操作系统的指示,表明它应该使用 fades 执行...
#!/usr/bin/env fades
...并且也要设置脚本的可执行位
chmod +x yourscript.py
您还可以直接从网络执行脚本,直接传递粘贴脚本的地方的 URL(支持大多数粘贴板,如 pastebin.com、gist、linkode.org,如果 URL 直接指向脚本,也支持)
fades http://myserver.com/myscript.py
如何标记要安装的依赖项?
标记脚本导入的模块为 由 fades 安装的依赖项 的方法是通过使用注释。
此注释通常与导入语句在同一行(推荐,未来更少混淆和错误),但也可以放在前一行。
最简单的注释如下
import somemodule # fades from somepackage import othermodule # fades
fades 是强制性的,在此示例中,仓库是 PyPI,关于其他示例请参阅下方的 不同仓库的说明。
有了这条注释,fades 将自动在虚拟环境中安装 PyPI 上的 somemodule 或 somepackage。
此外,您还可以指定特定的版本条件,例如
import somemodule # fades == 3 import somemodule # fades >= 2.1 import somemodule # fades >=2.1,<2.8,!=2.6.5
有时,项目本身与模块名称不匹配;在这些情况下,您可以指定项目名称(可选,在版本之前)
import bs4 # fades beautifulsoup4 import bs4 # fades beautifulsoup4 == 4.2
如果没有提供要执行的脚本怎么办?
如果没有传递脚本或程序执行,fades 将提供包含所有指定依赖关系的虚拟环境,然后在虚拟环境上下文中打开交互式解释器。
在这种情况下,-i/--ipython 选项非常有用,如果该 REPL 比标准 REPL 更受青睐。
在使用交互式解释器的情况下,自动导入所有指定依赖关系也非常有用,可以通过传递 --autoimport 参数来实现。
其他指定依赖项的方法
除了在源文件中标记导入之外,还有其他方法告诉 fades 在虚拟环境中安装哪些依赖关系。
一种方法是通过命令行,传递 --dependency 参数。此选项可以多次指定(每个依赖关系一次),每次的格式是 repository::dependency。依赖关系可以有版本说明,仓库是可选的(默认为‘pypi’)。
另一种方法是在文本文件中指定依赖关系,每行一个依赖关系,每行的格式与 --dependency 参数之前描述的格式相同。然后通过 --requirement 参数将该文件指示给 fades。此选项可以多次指定。
如果定义了相同的依赖关系的多个实例,则命令行将覆盖所有其他内容,而需求文件将覆盖源代码中指定的内容。
最后,您可以在脚本文档字符串中包含包名称,在写有“fades”的行之后,直到文档字符串的末尾;例如
"""Script to do stuff. It's a very important script. We need some dependencies to run ok, installed by fades: request otherpackage """
关于不同的仓库
fades 支持从多个仓库安装所需的依赖关系:除了 PyPI 之外,您还可以指定指向 GitHub、Launchpad 等项目的 URL(基本上,所有由 pip 本身支持的项目)。
当指定依赖关系时,fades 会推断正确的仓库。例如,在以下示例中,fades 将在第一个情况下从 PyPI 安装 requests 的最新修订版,在第二个情况下从 GitHub 的项目本身安装最新修订版。
-d requests -d git+https://github.com/kennethreitz/requests.git#egg=requests
如果您愿意,可以明确指出 fades 应使用哪种类型的仓库,通过在依赖关系前加上特殊标记双冒号(::)来实现。
-d pypi::requests -d vcs::git+https://github.com/kennethreitz/requests.git#egg=requests
有两个基本仓库:pypi,将使 fades 从 PyPI 安装所需的依赖关系,以及 vcs,将使 fades 将依赖关系视为版本控制系统网站的 URL。在前者的情况下,对于 PyPI,可以指定全范围的版本比较器,如通常一样。对于 vcs 仓库,尽管如此,比较始终是精确的:如果指定了相同的依赖关系,则重用 virtualenv,否则将创建一个新的并填充它。
在两种情况下(显式或隐式指定仓库)都没有区别,无论是通过命令行、requirements.txt 文件、脚本文档字符串等方式指定依赖项。在脚本中直接标记 import 的情况下略有不同。
在标记 import 时,通常情况是待安装的包的名称与导入的模块名称相同,因此只能在 PyPI 上找到。因此,在以下情况下,pypi 仓库不仅被推导出来,而且是不可避免的。
import requests # fades from foo import bar # fades import requests # fades <= 3
但是,如果指定了包(通常需要因为它与模块名称不同),或者指定了版本控制系统 URL,那么上述提到的可能性都是可用的:让 fades 推导适当的仓库或显式标记它。
import bs4 # fades beautifulsoup import bs4 # fades pypi::beautifulsoup import requests # fades git+https://github.com/kennethreitz/requests.git#egg=requests import requests # fades vcs::git+https://github.com/kennethreitz/requests.git#egg=requests
关于 vcs 仓库的最后一个细节:编写 URL 的格式与 pip 本身支持的格式相同(有关更多详细信息,请参阅 pip 文档)。
此外,您可以从本地项目安装。使用以 file: 开头的依赖项是没有问题的。例如(请注意三斜线,因为我们正在将协议指示与路径混合)
fades -d file:///home/crazyuser/myproject/allstars/
如何控制虚拟环境的创建和使用?
您可以影响与 virtualenv 相关的所有过程的多个细节。
最重要的细节是 virtualenv 将使用哪个版本的 Python。当然,您需要在系统中安装相应的 Python 版本,但您可以精确控制使用哪个版本。
无论您以何种方式执行脚本(见上文),您都可以传递一个 -p 或 --python 参数,仅用数字(2.7)、完整名称(python2.7)或完整路径(/usr/bin/python2.7)来指定要使用的 Python 版本。
其他细节是 fades 在说明正在做什么时的详细程度。默认情况下,fades 只会使用 stderr 来告知正在创建虚拟环境,并让用户知道正在执行需要活跃网络连接的操作(例如,安装新的依赖项)。
如果您使用 -v 或 --verbose 调用 fades,它将发送所有内部调试行到 stderr,这如果在出现任何问题时可能非常有用。另一方面,如果您传递 -q 或 --quiet 参数,fades 将不会显示任何内容(除非它真的有问题),因此原始脚本的 stderr 完全不会被污染。
如果您想使用 IPython shell,您需要使用 -i 或 --ipython 选项调用 fades。此选项将 IPython 添加为 fades 的依赖项,并将启动此 shell 而不是 Python shell。
您还可以使用 --system-site-packages 来创建一个可以访问系统库的 venv。
最后,无论虚拟环境是如何创建的,您都可以使用 --get-venv-dir 选项在您的系统中始终获取虚拟环境的基本目录。
在虚拟环境中运行程序
-x/--exec 参数允许您在 virtualenv 的上下文中执行任何程序(而不仅仅是 Python 程序)。
默认情况下,必须给出的参数被认为是可执行文件名称,相对于虚拟环境的 bin 目录,因此这对于通过声明的依赖项执行安装的脚本/程序特别有用。例如。
fades -d flake8 -x flake8 my_script_to_be_verified_by_flake8.py
请注意,您可以传递一个绝对路径,并且它将被尊重(但不能传递一个相对路径,因为它将取决于虚拟环境的位置)。
例如,如果你想运行一个shell脚本,该脚本又运行一个需要在virtualenv环境中执行的Python程序,你可以这样做
fades -r requirements.txt --exec /var/lib/foobar/special.sh
最后,如果你打算运行的是作为模块执行的代码(你通常会用python3 -m some_module运行),你可以在virtualenv中使用相同的参数来运行该模块
fades -r requirements.txt -m some_module
如何处理 PyPI 中升级的包?
当你告诉fades使用一个依赖项创建virtualenv并且没有指定版本时,它会从PyPI安装最新版本。
例如,你执行fades -d foobar,它会安装7.0版本的foobar。在某个时候,foobar在PyPI上发布了新版本8.0,但如果再次执行fades -d foobar,它将只是重用之前创建的版本为7.0的virtualenv,不会下载新版本并创建一个带有新版本的新的virtualenv!
你可以告诉fades这样做,只需这样做
fades -d foobar --check-updates
…然后fades将在PyPI上搜索该包的更新,并发现版本8.0后,将使用最新版本创建一个新的virtualenv。
从那时起,如果你请求fades -d foobar,它将带有一个新版本的virtualenv。如果你想为任何依赖项获取一个不是最新版本的virtualenv,只需指定正确的版本。
你甚至可以在指定包版本时使用--check-updates参数。假设你调用fades -d foobar==7,fades将安装7.0版本,无论哪个版本是最新的。但如果你这样做
fades -d foobar==7 --check-updates
…它仍然会使用版本7.0,但会通知你有一个新版本可用!
关于依赖项固定怎么办?
fades的一个很好的好处是,每次你的项目中的依赖项发生变化时,你实际上都会自动使用一个新的virtualenv。
如果你没有在requirements文件中锁定依赖项,这将产生另一个很好的副作用:每次你在新的环境中使用它们(或者如果你设置了–check-updates)时,你将获得最新版本,有效地避免了永远停留在旧版本中的陷阱。
然而,这也有一个坏处。如果在你运行测试和你的项目部署到服务器之间,你的项目的某个依赖项发布了一个修订版,那么你实际上可能会在生产环境中使用一个未经测试的组合。此外,即使你确实锁定了依赖项,这些依赖项的依赖项可能没有被锁定,你可能会陷入相同的境地。
例如,你可能有一个requests == 2.19.1的依赖项,但requests声明了自己的依赖项,例如chardet >= 3.0.2,在本地运行测试时,你可能得到的是chardet的版本3.0.3,但没有任何保证当你将你的项目部署到服务器(实际上是从头开始构建一切)时,你不会得到chardet的新版本,这可能是完全正常的,但事实上它是你没有在本地测试的事情。
在这里,fades通过使用–freeze选项来挽救局面。如果给出了这个参数,fades将像通常一样运行,但还会将pip freeze的结果输出到指定的文件。
所以,继续上面的例子,你可以像这样运行你的测试
fades -d "requests == 2.19.1" --freeze=reqs-frozen.txt -x python3 -m unittest
…这将为你留下一个类似以下内容的reqs-frozen.txt文件
certifi==2018.4.16 chardet==3.0.4 pip==18.0 requests==2.19.1 ...
然后您可以使用该文件进行部署,该文件已将所有软件包固定,因此您将得到您所期望的。
内部选项
对于特定的用例,您可以向 virtualenv、pip 和 python 发送特定的参数。分别使用 --virtuaenv-options、--pip-options 和 --python-options。您必须为每个参数使用该参数。
示例
fades -d requests --virtualenv-options="--always-copy" --virtualenv-options="--extra-search-dir=/tmp"
fades -d requests --pip-options="--index-url='http://example.com'"
fades --python-options=-B foo.py
使用配置文件设置选项
您还可以使用 .ini 配置文件来配置 fades。fades 将在 /etc/fades/fades.ini 中搜索配置文件,搜索系统路径指示的路径(例如 ~/config/fades/fades.ini)和 .fades.ini。
因此,您可以在系统、用户和项目级别拥有不同的设置。
安装 fades 后,您可以让您的配置目录运行
python -c "from fades.helpers import get_confdir; print(get_confdir())"
配置文件是 .ini 格式。(configparser)并且 fades 将搜索 [fades] 部分。
您必须使用与 CLI 中相同的配置。唯一的区别是带有短划线的配置选项,必须将其替换为下划线。
[fades] ipython=true verbose=true python=python3 check_updates=true dependency=requests;django>=1.8 # separated by semicolon
在 fades 处理这些设置方面存在一些细微差别:“依赖”、“pip 选项”和“virtualenv 选项”。在这些情况下,您必须使用分号分隔的列表。
最重要的是,这些选项将合并。因此,如果您在 /etc/fades/fades.ini 中配置“依赖 = requests”,您将在 fades 创建的所有虚拟环境中都有 requests。
如何清理旧虚拟环境?
当使用 fades 虚拟环境时,您不需要考虑这些环境。 fades 将做正确的事情并创建一个符合所需依赖项的新虚拟环境。但是,在某些情况下,您可能希望清理磁盘上的不必要的虚拟环境。
通过以 --rm 参数运行 fades,如果存在匹配提供的 UUID 的虚拟环境,则 fades 将删除该虚拟环境(一个找到虚拟环境 UUID 的简单方法是使用 --get-venv-dir 选项调用 fades)。
另一种清理缓存的方法是删除长时间未使用的所有 venv。为此,您需要使用 --clean-unused-venvs 调用 fades。当 fades 使用此选项时,它将在维护模式下运行,这意味着 fades 将在完成此任务后退出。所有未使用超过指定参数值的天的虚拟环境都将被删除。
建议您以某种自动方式运行此选项;即,添加一个 cron 任务来执行此命令
fades --clean-unused-venvs=42
一些命令行示例
在 fades 下执行 foo.py,将 --bar 参数传递给子程序,在源代码中指示的依赖项的虚拟环境中
fades foo.py --bar
在 fades 下执行 foo.py,显示所有 fades 消息(详细模式)
fades -v foo.py
在 fades 下执行 foo.py(将其 --bar 参数传递给它),在源代码中指示的依赖项的虚拟环境中,以及 dependency1 和 dependency2(任何版本 > 3.2)
fades -d dependency1 -d "dependency2>3.2" foo.py --bar
在安装了 dependency1 的虚拟环境中运行 Python 交互式解释器
fades -d dependency1
在虚拟环境中安装所有从 requirements.txt 文件中获取的依赖项后,执行 Python 交互式解释器
fades -r requirements.txt
在虚拟环境中安装所有从文件 requirements.txt 和 requirements_devel.txt 中获取的依赖项后,执行 Python 交互式解释器
fades -r requirements.txt -r requirements_devel.txt
使用 django-admin.py 脚本启动名为 foo 的新项目,无需事先安装 django
fades -d django -x django-admin.py startproject foo
从磁盘和缓存索引中删除与给定 uuid 匹配的虚拟环境
fades --rm 89a2bf83-c280-4918-a78d-c35506efd69d
从给定的 pastebin 下载脚本并执行它(当然,在执行之前先构建一个虚拟环境,其中包含该 pastebin 中指示的依赖项)
fades http://linkode.org/#4QI4TrPlGf1gK2V7jPBC47
在一个项目中运行所有测试(直接作为模块运行 pytest 以获得更好的行为),并同时冻结依赖项以供后续部署
fades -r requirements.txt --freeze -m pytest -v
一些在项目脚本中使用 fades 的示例
在项目辅助脚本中包含 渐变 可以使您在处理该项目时不必担心虚拟环境的激活/取消激活,同时还可以解决如果依赖项发生变化则需要更新/更改/修复已创建的虚拟环境的问题。
这是一个运行您项目的脚本可能看起来的样子示例
#!/bin/sh if (command -v fades > /dev/null) then # fades FTW! fades -r requirements.txt bin/start else echo 2 # hope you are in the correct virtualenv python3 bin/start fi
要运行测试,有一个同时处理开发依赖项的脚本非常有用
#!/bin/sh fades -r requirements.txt -r reqs-dev.txt -x python -m pytest -s "$@"
如果我的系统中的 Python 被更新了怎么办?
由 fades 创建的虚拟环境依赖于创建它们时使用的 Python 版本,考虑到其主要和次要版本。
这意味着如果在运行 fades 时使用了一个 Python 版本,然后再次使用不同的 Python 版本运行它,它可能需要创建一个新的虚拟环境。
让我们看看一些示例。假设您使用 python 运行 fades,这是指向 /usr/bin/ 中 python3.4 的符号链接(直接手动运行或因为 fades 安装为使用该 Python 版本)。
如果您在系统中安装了 Python 3.4.2,并且它已升级到 Python 3.4.3,fades 将继续重用已创建的虚拟环境,因为只有微版本发生了变化,没有次要或主要版本。
但是,如果系统中安装了 Python 3.5,并且默认的 python 指向这个新版本,fades 将开始使用这个新版本重新创建所有虚拟环境。
这是好事,因为您希望虚拟环境中使用一个特定 Python 版本安装的依赖项继续由相同的 Python 版本使用。
但是,如果您想避免这种行为,请确保始终使用特定的 Python 版本(例如 /usr/bin/python3.4 或 python3.4),这样就不会介意系统中是否有新版本可用。
如何安装它
在不同平台上安装 fades 的几个说明。
最简单的方法
在某些系统中,您可以直接安装 fades,无需事先安装任何依赖项。
如果您在 debian 不稳定版或测试版中,只需这样做
sudo apt-get install fades
对于 Arch Linux,您可以使用任何 AUR 辅助工具 从 AUR 安装它,例如使用 pikaur
pikaur -S fades
在具有 Snaps 的系统中
sudo snap install fades –classic
(为什么是 –classic?因为这是 fades 在 snap 内部访问系统其余部分的唯一方式,以防您想使用不同的 Python 版本,或需要编译的依赖项等)。
对于 Mac OS X(以及 Homebrew)
brew install fades
否则,继续阅读以了解如何首先安装依赖项,并在您的系统中淡入。
依赖项
除了需要Python 3.3或更高版本外,fades还依赖于pkg_resources包,该包随setuptools一起提供。它在几乎所有地方都安装了,但无论如何,您可以在Ubuntu/Debian中使用以下命令安装它:
apt-get install python3-setuptools
在Arch Linux上使用:
pacman -S python-setuptools
它还依赖于python-xdg包。这个包应该安装在任何带有freedesktop.org GUI的GNU/Linux操作系统上。然而,它是一个可选依赖项。
您可以在Ubuntu/Debian中使用以下命令安装它:
apt-get install python3-xdg
在Arch Linux上使用:
pacman -S python-xdg
Fades还需要virtualenv包来支持子执行时的不同Python版本。(请参阅--python选项。)
对于其他 Debian 和 Ubuntu
如果您不在debian不稳定或测试版(如果您是,请参阅上面的说明以获得更好的说明),则可以使用此.deb。
下载并执行以下操作安装它:
sudo dpkg -i fades_*.deb
如果你想使用 pip
pip3 install fades
多平台存档
最后,您始终可以获取多平台tar包,并以传统方式安装它
wget http://ftp.debian.org/debian/pool/main/f/fades/fades_9.0.1.orig.tar.gz tar -xf fades_*.tar.gz cd fades-* sudo ./setup.py install
我可以不安装它来试用吗?
是的!分支项目并使用可执行文件
git clone https://github.com/PyAr/fades.git cd fades bin/fades your_script.py
Windows 呢?
Windows是fades支持的平台。
然而,我们没有合适的Windows安装程序(.exe或.msi),但您可以使用pip安装它,或从tar包安装它,或直接从项目中尝试它。所有这些选项都已在上面正确描述。
我们确实想要一个Windows安装程序。如果您能在这方面帮助我们,请与我们联系。我们还希望有一个在Windows上运行的Travis,这样GitHub在合并任何代码之前也会在这个平台上运行所有测试。谢谢!
获取一些帮助,提供一些反馈
您可以在邮件列表中提出任何问题或发送任何建议或请求。
在IRC上与我们聊天。#fades频道位于Freenode网络。
此外,您还可以在此处(如果您发现任何问题,请务必这样做!)打开一个问题。
提前感谢您的宝贵时间。
如何开发 fades 本身
快速指南,帮助您在fades开发中快速启动。
获取代码
克隆项目
git clone git@github.com:PyAr/fades.git
安装依赖项
fades管理自己的依赖项,因此不需要安装任何其他内容。
要尝试它,只需执行以下操作:
bin/fades -V
如何运行测试
在开始开发时,始终,尤其是在合并新分支之前,您需要确保所有测试都通过。
实际上,这非常简单,只需运行
./test
这将不仅检查测试用例,还会检查代码是否符合美学建议,以及README文档的格式是否正确。
如果您只想运行一个特定的测试,只需指定它。例如:
./test tests.test_main:DepsMergingTestCase.test_two_different
开发流程
只需从列表中选择一个问题。
开发,确保./test运行正常,提交,推送,创建拉取请求等。
请,如果您旨在创建带有新代码(功能或修复)的拉取请求,请包括您更改的测试。
谢谢!祝您玩得开心。