我的 Python 开发工作流程
这是一个开发 Python 包的基本过程,其中包含我认为社区中的最佳实践。这是基本的——如果你真的很想开发 Python 包,还有更多内容,每个人都有自己的偏好,但它应该作为一个模板来开始,然后了解更多关于所涉及的部分。基本步骤是:
虚拟环境
首先,我建议使用virtualenv 来获得一个独立的环境来开发你的包。在开发过程中,你需要安装、升级、降级和卸载包的依赖项,你不需要想要
- 你的开发依赖会污染你的系统范围
site-packages
- 您的系统范围内的
site-packages 影响您的开发环境
- 版本冲突
污染您的系统范围site-packages 是不好的,因为您在那里安装的任何包都将可用于您安装的所有使用系统 Python 的 Python 应用程序,即使您的小项目只需要该依赖项。它刚刚安装在一个新版本中,覆盖了系统范围内的site-packages,并且与依赖它的 ${important_app} 不兼容。你明白了。
让您的系统范围内的site-packages 影响您的开发环境是不好的,因为您的项目可能依赖于您已经在系统 Python 的 site-packages 中获得的模块。因此,您忘记正确声明您的项目依赖于该模块,但一切正常,因为它始终存在于您的本地开发盒中。直到你发布你的包并且人们尝试安装它,或者将它推送到生产环境等等......在一个干净的环境中开发会迫使你正确地声明你的依赖关系。
因此,virtualenv 是一个独立的环境,具有自己的 Python 解释器和模块搜索路径。它基于您之前安装的 Python 安装,但与它隔离。
要创建 virtualenv,请安装 virtualenv 包,方法是使用 easy_install 或 pip 将其安装到系统范围的 Python:
sudo pip install virtualenv
请注意,这将是唯一您以 root 身份(使用 sudo)将某些东西安装到您的全局站点包中的时间。之后的一切都将发生在您即将创建的 virtualenv 中。
现在创建一个 virtualenv 来开发你的包:
cd ~/pyprojects
virtualenv --no-site-packages foobar-env
这将创建一个目录树~/pyprojects/foobar-env,这是您的虚拟环境。
要激活 virtualenv,cd 进入其中,source bin/activate script:
~/pyprojects $ cd foobar-env/
~/pyprojects/foobar-env $ . bin/activate
(foobar-env) ~/pyprojects/foobar-env $
注意前导点.,它是source shell 命令的简写。还要注意提示是如何变化的:(foobar-env) 表示您在激活的 virtualenv 内部(并且始终需要隔离才能工作)。因此,每次打开新的终端选项卡或 SSH 会话等时都要激活您的环境。
如果您现在在激活的 env 中运行 python,它实际上将使用 ~/pyprojects/foobar-env/bin/python 作为解释器,具有自己的 site-packages 和独立的模块搜索路径。
一个安装工具包
现在开始创建你的包。基本上你会想要一个带有setup.py 的setuptools 包来正确声明你的包的元数据和依赖项。您可以按照setuptools documentation 自行完成此操作,或使用Paster templates 创建包骨架。要使用 Paster 模板,请将 PasteScript 安装到您的 virtualenv 中:
pip install PasteScript
让我们为我们的新包创建一个源目录以使事情井井有条(也许您希望将项目拆分为多个包,或者稍后使用源中的依赖项):
mkdir src
cd src/
现在创建你的包,做
paster create -t basic_package foobar
并回答交互式界面中的所有问题。大多数都是可选的,只需按 ENTER 即可保留默认设置。
这将创建一个名为foobar 的包(或更准确地说,是一个setuptools 发行版)。这是这个名字
- 人们将使用
easy_install 或pip install foobar 来安装您的软件包
- 在
setup.py 中其他包将使用的名称依赖于您的名称
-
PyPi 上将调用什么
在内部,您几乎总是创建一个名为“__init__.py”的 Python 包(如在“带有__init__.py 的目录中)。这不是必需的,顶级 Python 包的名称可以是任何有效的包名称,但它是将其命名为与发行版相同的通用约定。这就是为什么将两者分开很重要但并不总是那么容易的原因。因为顶级 python 包名称是什么
- 人们(或您)将使用
import foobar 或from foobar import baz 导入您的包
因此,如果您使用了 paste 模板,它已经为您创建了该目录:
cd foobar/foobar/
现在创建您的代码:
vim models.py
models.py
class Page(object):
"""A dumb object wrapping a webpage.
"""
def __init__(self, content, url):
self.content = content
self.original_url = url
def __repr__(self):
return "<Page retrieved from '%s' (%s bytes)>" % (self.original_url, len(self.content))
还有一个client.py在使用models.py的同一目录中:
client.py
import requests
from foobar.models import Page
url = 'http://www.stackoverflow.com'
response = requests.get(url)
page = Page(response.content, url)
print page
在setup.py中声明对requests模块的依赖:
install_requires=[
# -*- Extra requirements: -*-
'setuptools',
'requests',
],
版本控制
src/foobar/ 是您现在要置于版本控制之下的目录:
cd src/foobar/
git init
vim .gitignore
.gitignore
*.egg-info
*.py[co]
git add .
git commit -m 'Create initial package structure.
将你的包安装为开发鸡蛋
现在是时候在开发模式下安装你的包了:
python setup.py develop
这将安装requests 依赖项和你的 包作为开发蛋。因此,它已链接到您的 virtualenv 的站点包,但仍位于 src/foobar,您可以在其中进行更改并让它们立即在 virtualenv 中处于活动状态,而无需重新安装您的包。
现在对于您最初的问题,使用相对路径导入:我的建议是,不要这样做。现在您已经有了一个正确的 setuptools 包,它已安装并可导入,您当前的工作目录应该不再重要了。只需执行from foobar.models import Page 或类似操作,声明该对象所在的完全限定名称。这使您的源代码对您自己和其他阅读您的代码的人来说更具可读性和可发现性。
您现在可以通过在已激活的 virtualenv 中的任何位置执行 python client.py 来运行您的代码。 python src/foobar/foobar/client.py 工作正常,您的软件包已正确安装,您的工作目录不再重要。
如果您想更进一步,您甚至可以为您的 CLI 脚本创建一个 setuptools 入口点。这将在您的 virtualenv 中创建一个 bin/something 脚本,您可以从 shell 运行该脚本。
setuptools console_scripts 入口点
setup.py
entry_points='''
# -*- Entry points: -*-
[console_scripts]
run-fooobar = foobar.main:run_foobar
''',
client.py
def run_client():
# ...
main.py
from foobar.client import run_client
def run_foobar():
run_client()
重新安装你的包来激活入口点:
python setup.py develop
然后,bin/run-foo。
一旦你(或其他人)在 virtualenv 之外真正安装了你的包,入口点将在 /usr/local/bin/run-foo 或类似的地方,它会自动在 $PATH 中。
进一步的步骤
推荐阅读: