目录

十月末-solo博客

talk less,code more.

X

PDM-基于PEP 582的python包管理

预备知识:pythonpathpyvenvPEP 582
官网 https://pdm.fming.dev/

简易使用说明

  1. 安装 pipx install pdm,添加至 $PATH,bash 配置 pdm 自动补全 pdm completion bash | sudo tee /etc/bash_completion.d/_pdm
  2. pdm config 查看全局
    开启 pdm 缓存:pdm config install.cache on
    配置 pypi_url 源:pdm config pypi https://mirrors.tencent.com/pypi/simple/
    删除配置:pdm config --delete foo bar
  3. 初始化 python 项目:pdm init,在项目目录下生成 pyproject.toml.pdm.toml 等文件
    切换 python 版本:pdm use pythonx.x
    环境查看:pdm info
PDM version:        1.14.0
Python Interpreter: $HOME/.local/pipx/venvs/pdm/bin/python (3.8)
Project Root:       $HOME/py-program
Project Packages:   $HOME/__pypackages__/3.8
  1. 包管理,在项目目录下

    • 导入 requirements.txt 环境配置:pdm import -f {file}
    • 安装包:pdm add <pkg>
    • 更新包:pdm update <pkg>[--dry-run] 显示差异,并不实际安装 [--save-minimum] 保持最小依赖版本的包
    • 卸载包:pdm remove <pkg>
    • 导出包:
      • requirements.txt pdm export -o requirements.txt
      • setup.py pdm export -f setuppy -o setup.py
    • 查看本地包:pdm list
    • 搜索包:pdm search
  2. 运行

  • 方案 1 pdm run python main.py
  • 方案 2(流程执行推荐) 修改 pyproject.toml 文件,设置 pdm 脚本
[tool.pdm.scripts]
# 支持shell命令
echo = {shell = "echo 'hello'"}
# 执行python文件
start = "python main.py"
# 支持参数指定的写法,调用的是shell脚本
start = {shell = [
    "python",
    "main.py",
    # Important comment here about always using port 54321
    "-xxx", "yyy"
]}
# 上面等效于
start.shell = "python main.py -xxx yyy"
# 前置命令
pre_start = "{{ Run BEFORE the `start` script }}"
# 后置命令
post_start = "{{ Run AFTER the `start` script }}"

使用 pdm start 执行对应的 start 脚本。pre_start、post_start 会在 start 前后执行,可以简单的编排任务。
使用 pdm run --list 可以查看配置的 pdm 脚本

  • 方案 3 (命令行推荐),修改当前的 PYTHONPATH
$ pdm --pep582
if [ -n "$PYTHONPATH" ]; then
    export PYTHONPATH='xxxx':$PYTHONPATH
else
    export PYTHONPATH='xxx'
fi

PDM 原理

运行机制

  • 选择 python 解释器,pdm 会先读取 .pdm.toml 文件中的 python 解释器路径。

  • 添加 PYTHONPATH python -m site 看到当前环境的 PYTHONPATH
    pdm 在当前项目下,创建 __pypackages__ 目录,管理当前添加的包。pdm run 命令或 tool.pdm.script 会执行两个步骤:

    1. 在执行命令前,插入 pypackages 目录到 PYTHONPATH
    2. 在执行命令后,删除 PYTHONPATH 中的 pypackages 目录
    # 默认PYTHONPATH
    python -m site
    sys.path = [
    '$HOME/py-program',
    '/usr/lib/python38.zip',
    '/usr/lib/python3.8',
    '/usr/lib/python3.8/lib-dynload',
    '$HOME/.local/pipx/venvs/pdm/lib/python3.8/site-packages',
    

]

pdm run 后的 PYTHONPATH

pdm run python -m site
sys.path = [
'$HOME/py-program',
'/usr/lib/python38.zip',
'/usr/lib/python3.8',
'/usr/lib/python3.8/lib-dynload',
'$HOME/py-program/pypackages/3.8/lib',
'$HOME/.local/pipx/venvs/pdm/lib/python3.8/site-packages',
]


### 缓存机制

pdm利用缓存机制实现了PEP582。

1. PDM的PYTHON解释器只是软链接,并没有重新下载。

```bash
$ file $HOME/.local/pipx/venvs/pdm/bin/python
$HOME/.local/pipx/venvs/pdm/bin/python: symbolic link to python3
  1. pypackages 目录下添加的包指向缓存目录 cache_dirpdm config cache_die <__cache_path> 修改缓存目录 $ pdm config install.cache_method [symlink | pth] 修改连接策略
    默认是 symlink,以软链接的方式链接包目录 pth,当 Python 在遍历已知的库文件目录过程中,如果发现有 .pth 文件,就会将文件中所记录的路径加入到 sys.path 设置中,于是 .pth 文件说指明的库也就可以被 Python 运行环境找到了。

全局和局部

pdm 配置分为全局和局部。命令,使用 -g 参数,读取全局的参数;没有-g 参数,默认读取本地项目下的 pyproject.toml。
pdm list -g 查看全局已安装的包。
pdm init -g 使用全局配置初始化项目

使用 pdm config auto_global true ,当本地目录没有 pyproject.toml,pdm 使用全局的 pyproject.toml。

对于 pdm config,默认打开的全局配置;使用 -l/--local 时,指定本地项目。
-p <project_path>,强制使用路径项目配置。

# 比如修改其他项目的局部配置,不仅需要加  `-p/--project`  还要加  `-l/--local`  选项
pdm config -l -p <project_path> pypi.url http://pypi.douban.com/simple

vscode 使用

确保 vscode 选择的 interpret 和 .pdm.toml 配置的相同

根据缓存机制,只需要在 setting.json 中添加"python.envFile": "${workspaceFolder}/.env"。
.env 文件中写入当前 lib 路径即可,PYTHONPATH=__pypackages__/x.x/lib

对比 conda 使用体验

pdm 注重的是项目,在项目管理不同的包。conda 注重的虚拟环境,通过切换环境管理不同的包。

项目和环境不是一回事:项目打包应该维护一个最小的包;环境是提供一个通用的运行时。

pdm 优点

  • pdm config 语法简洁;
  • pdm.sript 方便 CLI 批处理;
  • 解释器和包都是链接形式,磁盘占用资源少;

pdm 缺点

  • anaconda 有 navigatorUI 界面,方便图形操作(当然 miniconda 更和我口味
  • 在不同项目之间复用环境得反复导出,使用-p 也不太方便。

标题:PDM-基于PEP 582的python包管理
作者:bingoct
地址:https://blog.bingoct.top/articles/2022/04/14/1649917977923.html
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.