跳转到主要内容

使用本地目录__pypackages__中的包运行Python

项目描述

pythonloc:从本地目录导入包的Python替代品

PyPI version

pythonlocpythonpip的替代品,它可以自动识别一个__pypackages__目录,并优先导入安装在此位置的包。如果你熟悉node,__pypackages__的工作方式与node_modules类似。

因此,你不用运行python,而是运行pythonloc,它将首先搜索__pypackages__路径中的包。同样,你不用运行pip,而是运行piploc,它将从这个__pypackages__中安装/卸载。

这是使用虚拟环境的一种替代方案。

这是PEP 582的Python实现,"Python本地包目录"。pythonloc的目标是在讨论将此功能添加到CPython本身的同时,提供一个可访问的工具。如果你愿意,你可以使用这些更改而不是pythonloc构建自己的CPython

请注意,PEP 582尚未被接受。它可能最终会被接受。pythonloc是实验性的,其API可能在将来发生变化。

示例

脚本

# myapp.py
import requests
print(requests)
> piploc install requests
Installing collected packages: urllib3, certifi, chardet, idna, requests
Successfully installed certifi-2018.11.29 chardet-3.0.4 idna-2.8 requests-2.21.0 urllib3-1.24.1

> pipfreezeloc
requests==2.21.0

> pythonloc myapp.py  # works!
<module 'requests' from '/tmp/demo/__pypackages__/3.6/lib/requests/__init__.py'>

客户评价

在Python bytes播客的第117期节目中展出:节目 #117

"Chad一直在打包/pip空间中工作并编写一些令人兴奋的python工具和文章。"

—— Jeff Triplett,Python软件基金会董事

"我对__pypackages__如何帮助简化并优化Python依赖项工作流程感到非常热情。为人们提供早期原型实现,做得很好!”

—— Florimond Manca,Bocadillo Project的创始人,Bocadillo Project

系统要求

  • Python 2.7+
  • pip

安装:盒子里的内容

使用以下方式安装后

pip install --user pythonloc

python3 -m pip install --user pythonloc

您将拥有四个可用的CLI工具:pythonlocpiplocpipxpipfreezeloc

pythonloc

简称“python local”,它是python的一个直接替代品,但有一个重要的不同之处:将本地目录__pypackages__//lib添加到sys.path的前面。<version>是Python版本,例如3.7。所有参数都传递给python

因此,您将运行

python ...

而不是

pythonloc ...

如果采用PEP 582,那么python本身将具有这种行为。

piploc

简称“pip local”,它使用与pythonloc相同的sys.path调用pip。如果安装包,目标安装目录将修改为__pypackages__而不是全局的site-packages

如果__pypackages__目录不存在,它将被创建。

所有参数都传递给pip

因此,您将运行

pip ...

而不是

piploc ...

如果采用PEP 582,我认为pip应该默认在适当的__pypackages__目录下工作。如果需要,可以添加一个标志将其安装到site-packages。

pipx

注意:pipx仅包含在Python 3.6+的pythonloc中。

安装到__pypackages__的具有所谓“入口点”的包会引发问题。这些入口点或“二进制文件”在您的$PATH中不再可用,就像您在虚拟环境中或系统上安装它们时一样。这些二进制文件非常流行且有用。二进制文件的示例包括blackpytesttoxflake8mypypoetrypipenv(以及实际上pythonloc本身)。

pipx是Python的二进制安装程序和运行器,当运行时,它会在适当的__pypackages__位置搜索二进制文件并运行它。如果您熟悉JavaScript的npx,它与之类似。

因此,您将运行

BINARY [BINARY ARGS]

而不是

pipx run BINARY [BINARY ARGS]

如果没有找到,pipx将从临时目录安装和运行它。如果您需要二进制文件在__pypackages__目录中,您可以运行

pipx run --pypackages BINARY [BINARY ARGS]

如果二进制文件未找到,将显示错误。

注意:在将新包安装到现有的__pypackages__目录时,不会在例如.../3.6/lib/bin中创建入口点,如果那里已经存在某些内容。为此,您需要运行piploc install -U PACKAGE。当您这样做时,目录的全部内容将被替换。修复此问题需要修改pip本身。

如果采用PEP 582,那么pipx将是一个运行二进制文件的好伴侣工具。

pipfreezeloc

运行pip freeze会引发问题,因为它显示所有已安装的Python包:在site-packages中以及在__pypackages__中。您可能只想输出安装到__pypackages__的包,这正是pipfreezeloc所做的工作。

它是pip freeze的等价物,但只输出__pypackages__中的包。这是因为没有内置的方式使用标准pip来完成此操作。例如,命令pip freeze --target __pypackages__不存在。

pipfreezeloc不处理任何参数。

因此,您将运行

pip freeze > requirements.txt

而不是

pipfreezeloc > requirements.txt

如果采用PEP 582,则应创建一个更健壮的方案来冻结__pypackages__的状态。

从requirements.txt/Lockfiles安装

这和pip中的操作一样。您只需要一个requirements.txt文件来安装。

requirements.txt安装

piploc install -r requirements.txt
pythonloc <app>

poetry.lock安装

pip无法读取poetry.lock文件,因此您需要生成一个requirements.txt文件。

Poetry 1.x提供export命令

poetry self:update --preview #  install 1.x version of Poetry
poetry export -f requirements.txt
piploc install -r requirements.txt
pythonloc <app>

对于Poetry 0.x,您可以采用以下方法

poetry run pip freeze > requirements.txt
piploc install -r requirements.txt
pythonloc <app>

Pipfile.lock安装

pip还不能读取Pipfile,只有pipenv可以。因此,您需要使用pipenv生成requirements.txt。

pipenv lock --requirements
pipenv lock --requirements --dev
piploc install -r requirements.txt
pythonloc <app>

从长远来看,工具将能够直接安装到__pypackages__,或者piploc将能够读取各种lockfile格式。

命令行界面

您可以使用pythonloc运行任何Python命令,它将在底层运行Python

> pythonloc --help
> pythonloc --version

另一个示例展示了导入是如何工作的

> ls

> pythonloc -c "import requests; print(requests)"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'requests'

> piploc install requests  # installs to __pypackages__/3.6/lib/requests
Installing collected packages: urllib3, certifi, chardet, idna, requests
Successfully installed certifi-2018.11.29 chardet-3.0.4 idna-2.8 requests-2.21.0 urllib3-1.24.1

> pythonloc -c "import requests; print(requests)"  # requests is now found
<module 'requests' from '/tmp/demo/__pypackages__/3.6/lib/requests/__init__.py'>

> piploc uninstall requests  # uninstalls from __pypackages__/3.6/lib/requests
Successfully uninstalled requests-2.21.0

入口点/二进制文件

> piploc install cowsay
Collecting cowsay
  Using cached https://files.pythonhosted.org/packages/e7/e7/e93f311adf63ac8936beb962223771b1ab61227ae3d9ec86e8d9f8f9da1c/cowsay-2.0-py2.py3-none-any.whl
Installing collected packages: cowsay
Successfully installed cowsay-2.0

> pipx run cowsay moooo from local __pypackages__!
  ________________________________
< moooo from local __pypackages__! >
  ================================
                                     \
                                      \
                                        ^__^
                                        (oo)\_______
                                        (__)\       )\/       ||----w |
                                            ||     ||


缺点?

虽然这个PEP非常令人兴奋,但它也有一些没有解决的问题。

  • 操作系统依赖的包:在__pypackages__中的目录结构在Python版本上是命名空间化的,因此Python 3.6的包不会与3.7的包混合,这是非常好的。但有时不同操作系统上的包安装方式不同,例如Windows可能不会与mac匹配等。
  • site-packages:此PEP首先查找__pypackages__,但会回退到在site-packages中查找。这并不完全封闭,可能会导致一些混淆,不清楚使用了哪些包。我更愿意默认搜索路径仅为__pypackages__,而不使用其他任何内容。
  • 感知的缺点——膨胀:许多人在各种论坛中提出了这一点,将其与node_modules进行比较,但我认为这不适用。首先,相同或更多内容被安装到虚拟环境中,所以这只是在本地目录中移动。没有额外的膨胀。事实上,这更加明显,可以删除,因为它不在虚拟环境目录中隐藏。但更重要的是,我认为它膨胀或将被滥用的假设源于JavaScript的生态系统。JavaScript有一个臭名昭著的有限标准库,开发人员需要更频繁地寻找第三方包。此外,JavaScript社区严重依赖于许多插件和转译。Python不是。我没有找到膨胀论据令人信服。
  • 一些pip安装的怪癖。例如,使用pip install--target时,如果传递了-U标志,将会清除lib/bin目录中的内容,如果没有传递该标志,则不会放置任何内容。

常见问题解答

这与虚拟环境有何不同?

  • 虚拟环境可能包含或不包含系统包,而pythonloc将首先在.中查找包,然后是__pypackages__,然后是在用户或site-packages等其他位置。
  • pythonloc不需要激活或关闭
  • pythonloc只查找一个名为__pypackages__的本地目录。另一方面,虚拟环境激活会修改您的PATH,以便无论您处于哪个目录,都可以访问虚拟环境中的包。

它是如何工作的?

这非常简单,代码少于100行。它使用Python和pip中已经构建的功能。

它所做的只是在调用Python和pip时提供一定程度的间接性。当运行Python时,它修改PYTHONPATH环境变量以包含__pypackages__

如果您查看python --help的输出,您会看到以下内容

PYTHONPATH是一个以“:”分隔的目录列表,它作为默认模块搜索路径的前缀。结果是sys.path。

pythonlocPYTHONPATH=.:__pypackages__/<version>/lib:$PYTHONPATH python PYTHONARGS的别名

要将包安装到__pypackages__目录,它使用pip并运行

PYTHONPATH=.:__pypackages__/<version>/lib:$PYTHONPATH python -m pip PIPARGS

其中PIPARGS是您传递给它的任何参数,例如piploc install requests

如果您正在安装软件包,它将插入参数 --target __pypackages__

实际上 __pypackages__ 中放置了什么内容?

安装的软件包会被放置在那里。这包括它们的源代码,例如下面的 requests 目录。软件包的元数据存储在 *.dist-info 目录中。

如果您想修改或调试已安装软件包的源代码,这非常简单。只需在 __pypackages__ 中打开相应的文件并编辑即可!

> piploc install requests
Installing collected packages: urllib3, certifi, chardet, idna, requests
Successfully installed certifi-2018.11.29 chardet-3.0.4 idna-2.8 requests-2.21.0 urllib3-1.24.1


> ls  # note __pypackages__ was created
__pypackages__

> ls __pypackages__/3.6/lib
bin                           idna-2.8.dist-info
certifi                       requests
certifi-2018.11.29.dist-info  requests-2.21.0.dist-info
chardet                       urllib3
chardet-3.0.4.dist-info       urllib3-1.24.1.dist-info
idna

我如何从 __pypackages__ 中卸载软件包?

piploc 将自动将 __pypackages__ 添加到 $PYTHONPATH,因此

piploc uninstall PACKAGE

将生效。

如果您遇到错误

未在 ..., 环境外部卸载软件包 PACKAGE

然后运行 deactivate 以确保您没有使用虚拟环境,然后再次尝试。

我能否让 python 来执行此操作而不是调用 pythonloc

要实现此行为的一种简单方法是,在您的本地目录中创建一个符号链接

ln -s `which pythonloc` python
ln -s `which piploc` pip

然后使用以下命令运行它们

./python
./pip

否则,您将不得不自己构建带有 GitHub 上 参考实现 的 CPython。

为什么不使用 PEP 582 的参考实现?

构建和分发自定义 CPython 构建的开销比安装 pip 软件包要大。

如果您感兴趣,则鼓励您查看它,它非常酷!

如果它被接受并添加到 CPython 中,那么 pythonloc 可能就不再需要了。

项目详情


下载文件

下载您平台上的文件。如果您不确定要选择哪个,请了解更多关于 安装软件包 的信息。

源分发

pythonloc-0.1.2.2.tar.gz (9.5 kB 查看哈希值)

上传时间

构建分发

pythonloc-0.1.2.2-py3-none-any.whl (9.1 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面