用了好几年poetry了,各方面都还挺满意,就是lock实在太慢;
已经试用pdm+uv一段时间了,确实是快,也基本能覆盖poetry的功能。
至于为什么用pdm+uv,而不是只用uv,原因很多,有兴趣的可以去看这个https://github.com/pdm-project/pdm/discussions/3388
1. 安装pdm、uv并换源
pip install --user --upgrade pipx
pipx install pdm uv
pdm config pypi.url https://mirrors.cloud.tencent.com/pypi/simple/
mkdir -p ~/.config/uv && echo -e '[[index]]\nurl="https://pypi.tuna.tsinghua.edu.cn/simple/"\ndefault = true' > ~/.config/uv/uv.toml
2. 配置pdm全局使用uv
pdm config use_uv true
注:对于个别不想使用uv加速的项目,可以单独这样配置:pdm config --local use_uv true
3. 迁移poetry的pyproject.toml到pdm
- Old
[project]
name = "asynctor"
description = "Async functions to compare with anyio and asyncio, and toolkit to read excel with async/await."
authors = [{ name = "Waket Zheng", email = "waketzheng@gmail.com" }]
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.9"
dynamic = [ "version" ]
dependencies = [
"anyio>=3.7.1",
"eval-type-backport (>=0.2.2,<1.0.0); python_version < '3.10'",
]
# requires by anyio:
# "exceptiongroup >= 1.0.2; python_version < '3.11'",
# "typing_extensions >= 4.1; python_version < '3.11'",
[project.optional-dependencies]
xls = ["pandas>=2.2.0", "openpyxl>=3.1.0"]
fastapi = ["redis", "fastapi>=0.115.0", "httpx>=0.28.1", "asgi-lifespan>=2.1.0"]
redis = ["redis>=5.0.0"]
[project.urls]
homepage = "https://github.com/waketzheng/asynctor"
repository = "https://github.com/waketzheng/asynctor.git"
"Bug Tracker" = "https://github.com/waketzheng/asynctor/issues"
[tool.poetry]
version = "0" # Managed by poetry-plugin-version
[tool.poetry.group.dev.dependencies]
fast-dev-cli = "^0.15.1"
types-redis = "^4.6.0.20241004"
pandas-stubs = {version=">=2.2.0", python="^3.10"}
bandit = "^1.8.3"
pytest-mock = "^3.14.1"
fastapi-cdn-host = "^0.9.1"
uvicorn = "^0.34.3"
[tool.poetry.group.ci.dependencies]
coveralls = {git = "https://github.com/waketzheng/coveralls-python", rev = "4.1.1", python="^3.9"}
[tool.ruff]
line-length = 100
[tool.ruff.lint]
extend-select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up
]
[tool.ruff.lint.per-file-ignores]
"test_*.py" = ["E501"]
"scripts/test.py" = ["E501"]
"scripts/*.py" = ["UP009","UP032"]
[tool.mypy]
pretty = true
python_version = "3.9"
ignore_missing_imports = true
check_untyped_defs = true
[tool.coverage.report]
omit = ["*/tests/*", "test_*"]
exclude_lines = [
"pragma: no cover",
"@overload",
'if __name__ == "__main__":',
"if TYPE_CHECKING:",
]
[build-system]
requires = ["poetry-plugin-version"]
build-backend = "poetry_plugin_version.api"
- Diff
-[tool.poetry]
-version = "0" # Managed by poetry-plugin-version
+[tool.pdm]
+version = {source="file", path="asynctor/__init__.py"}
-[tool.poetry.group.dev.dependencies]
-fast-dev-cli = "^0.15.0"
-types-redis = "^4.6.0.20241004"
-pandas-stubs = {version=">=2.2.0", python="^3.10"}
-bandit = "^1.8.3"
-pytest-mock = "^3.14.0"
-fastapi-cdn-host = "^0.9.1"
-uvicorn = "^0.34.2"
-
-[tool.poetry.group.ci.dependencies]
-coveralls = {git = "https://github.com/waketzheng/coveralls-python", rev = "4.1.1", python="^3.9"}
+[dependency-groups]
+dev = [
+ "fast-dev-cli>=0.15.1",
+ "types-redis>=4.6.0.20241004",
+ "pandas-stubs",
+ "bandit>=1.8.3",
+ "pytest-mock>=3.14.1",
+ "fastapi-cdn-host>=0.9.1",
+ "uvicorn>=0.34.3",
+]
+ci = ["coveralls @ git+https://github.com/waketzheng/coveralls-python@4.1.1"]
[build-system]
-requires = ["poetry-plugin-version"]
-build-backend = "poetry_plugin_version.api"
+requires = ["pdm-backend"]
+build-backend = "pdm.backend"
- New
[project]
name = "asynctor"
description = "Async functions to compare with anyio and asyncio, and toolkit to read excel with async/await."
authors = [{ name = "Waket Zheng", email = "waketzheng@gmail.com" }]
readme = "README.md"
license = { text = "MIT" }
requires-python = ">=3.9"
dynamic = [ "version" ]
dependencies = [
"anyio>=3.7.1",
"eval-type-backport (>=0.2.2,<1.0.0); python_version < '3.10'",
]
# requires by anyio:
# "exceptiongroup >= 1.0.2; python_version < '3.11'",
# "typing_extensions >= 4.1; python_version < '3.11'",
[project.optional-dependencies]
xls = ["pandas>=2.2.0", "openpyxl>=3.1.0"]
fastapi = ["redis", "fastapi>=0.115.0", "httpx>=0.28.1", "asgi-lifespan>=2.1.0"]
redis = ["redis>=5.0.0"]
[project.urls]
homepage = "https://github.com/waketzheng/asynctor"
repository = "https://github.com/waketzheng/asynctor.git"
"Bug Tracker" = "https://github.com/waketzheng/asynctor/issues"
[tool.pdm]
version = {source="file", path="asynctor/__init__.py"}
[dependency-groups]
dev = [
"fast-dev-cli>=0.15.1",
"types-redis>=4.6.0.20241004",
"pandas-stubs",
"bandit>=1.8.3",
"pytest-mock>=3.14.1",
"fastapi-cdn-host>=0.9.1",
"uvicorn>=0.34.3",
]
ci = ["coveralls @ git+https://github.com/waketzheng/coveralls-python@4.1.1"]
[tool.ruff]
line-length = 100
[tool.ruff.lint]
extend-select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up
]
[tool.ruff.lint.per-file-ignores]
"test_*.py" = ["E501"]
"scripts/test.py" = ["E501"]
"scripts/*.py" = ["UP009","UP032"]
[tool.mypy]
pretty = true
python_version = "3.9"
ignore_missing_imports = true
check_untyped_defs = true
[tool.coverage.report]
omit = ["*/tests/*", "test_*"]
exclude_lines = [
"pragma: no cover",
"@overload",
'if __name__ == "__main__":',
"if TYPE_CHECKING:",
]
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
4. 修改Makefile为使用pdm
- diff
--- a/Makefile
+++ b/Makefile
@@ -11,17 +11,17 @@ help:
@echo " lint Auto-formats the code and check type hints"
up:
- poetry run fast upgrade
+ pdm run fast upgrade
deps:
- poetry install --all-extras
+ pdm install --verbose --group :all --without=ci --frozen
_check:
./scripts/check.py
check: deps _build _check
_lint:
- poetry run fast lint
+ pdm run fast lint
lint: deps _build _lint
_test:
@@ -33,7 +33,8 @@ _style:
style: deps _style
_build:
- poetry build --clean
+ rm -fR dist/
+ pdm build
build: deps _build
ci: check _build _test
5. 更新CI文件
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,49 +38,26 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- - name: Load cached Poetry installation
- id: cached-poetry
- uses: actions/cache@v4
+ - uses: actions/cache@v4
+ id: cache
with:
- path: ~/.local # the path depends on the OS
- key: poetry-0 # increment to reset cache
- - name: Install Poetry
- uses: snok/install-poetry@v1
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ hashFiles('**/pdm.lock') }}
+ - name: Set up PDM
+ uses: pdm-project/setup-pdm@v4
with:
- virtualenvs-in-project: true
- plugins: poetry-plugin-version
- - name: Load cached venv
- id: cached-poetry-dependencies
- uses: actions/cache@v4
- with:
- path: .venv
- key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('
**/poetry.lock') }}
- #----------------------------------------------
- # install dependencies if cache does not exist
- #----------------------------------------------
- - name: Install dependencies
- if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
- run: poetry install --no-interaction --no-root --all-extras --all-groups
- env:
- PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
- #----------------------------------------------
- # install your root project, if package-mode is true
- #----------------------------------------------
- - name: Install library
- run: poetry install --no-interaction
+ python-version: ${{ matrix.python-version }}
- uses: astral-sh/ruff-action@v3
- - name: Check code style and Type Hint
- run: ./scripts/check.py
- - name: build
- run: poetry build
- - name: Test with pytest
- run: poetry run fast test
+ - name: Check code style and Type Hint then Test with pytest
+ run: make ci
env:
# The hostname used to communicate with the Redis service container
REDIS_HOST: localhost
+ - name: Install library
+ run: pdm sync -d -G :all
- name: Upload Coverage
run: |
- poetry run coveralls --service=github
+ pdm run coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}