Poetry 构建的包缺少运行时依赖项

Package built by Poetry is missing runtime dependencies

我一直在从事一个项目,到目前为止只涉及构建一些云基础设施,现在我正在尝试 add a CLI 来简化 运行 一些 AWS Lambda。不幸的是,使用 poetry build 构建的 sdist 和 wheel 包似乎都不包含依赖项,所以我必须手动 pip install 所有这些到 运行 命令。基本上我

  1. 运行poetry build项目中,
  2. cd "$(mktemp --directory)",
  3. python -m venv .venv,
  4. . .venv/bin/activate,
  5. pip install /path/to/result/of/poetry/build/above,然后
  6. 运行 新的 .venv/bin/ 可执行文件。

此时可执行文件失败,因为pip 没有安装任何依赖包。 如果我 pip show PACKAGE Requires 行是空的。

Poetry 手册似乎没有指定如何 link 依赖于构建的包,那么我必须做什么呢?

我正在使用一些可选的依赖项,这会干扰构建过程吗?需要明确的是,即使是非可选依赖项也不会出现在 package 依赖项中。

pyproject.toml:

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.black]
line-length = 100

[tool.coverage.report]
exclude_lines = [
    'if TYPE_CHECKING:',
    'if __name__ == "__main__":',
    'pragma: no cover',
]
fail_under = 100

[tool.coverage.run]
branch = true
omit = [
    ".venv/*",
]

[tool.isort]
case_sensitive = true
line_length = 100
profile = "black"

[tool.mypy]
show_error_codes = true
strict = true

[[tool.mypy.overrides]]
module = [
    "jsonschema",
    "jsonschema._utils",
    "jsonschema.validators",
    "multihash",
    "pystac",
    "pystac.layout",
    "pytest_subtests",
    "smart_open",
    "linz_logger"
]
ignore_missing_imports = true

[tool.poetry]
name = "geostore"
version = "0.1.0"
description = "Central storage, management and access for important geospatial datasets developed by LINZ"
authors = [
    "Bill M. Nelson <bmnelson@linz.govt.nz>",
    "Daniel Silk <dsilk@linz.govt.nz>",
    "Ivan Mincik <ivan.mincik@gmail.com>",
    "Mitchell Paff <mpaff@linz.govt.nz>",
    "Sandro Santilli <strk@kbt.io>",
    "Simon Planzer <splanzer@linz.govt.nz>",
    "Victor Engmark <vengmark@linz.govt.nz>",
]
license = "MIT"
readme = "README.md"
homepage = "https://github.com/linz/geostore"
repository = "https://github.com/linz/geostore"
keywords = [
    "SpatioTemporal Asset Catalog (STAC)",
    "Toitū Te Whenua Land Information New Zealand",
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Environment :: Console",
    "Framework :: AWS CDK",
    "Framework :: Pytest",
    "Intended Audience :: End Users/Desktop",
    "Intended Audience :: Information Technology",
    "License :: OSI Approved :: MIT License",
    "Natural Language :: English",
    "Operating System :: POSIX",
    "Programming Language :: Python :: 3.8",
    "Topic :: Communications :: File Sharing",
    "Topic :: Scientific/Engineering :: GIS",
    "Topic :: Utilities",
    "Typing :: Typed",
]

[tool.poetry.dependencies]
python = "^3.8"
"aws-cdk.aws-dynamodb" = {version = "*", optional = true}
"aws-cdk.aws-ec2" = {version = "*", optional = true}
"aws-cdk.aws-ecr" = {version = "*", optional = true}
"aws-cdk.aws-ecr_assets" = {version = "*", optional = true}
"aws-cdk.aws-ecs" = {version = "*", optional = true}
"aws-cdk.aws-events" = {version = "*", optional = true}
"aws-cdk.aws-events-targets" = {version = "*", optional = true}
"aws-cdk.aws-iam" = {version = "*", optional = true}
"aws-cdk.aws-lambda" = {version = "*", optional = true}
"aws-cdk.aws-lambda-event-sources" = {version = "*", optional = true}
"aws-cdk.aws-lambda-python" = {version = "*", optional = true}
"aws-cdk.aws-s3" = {version = "*", optional = true}
"aws-cdk.aws-sns" = {version = "*", optional = true}
"aws-cdk.aws-stepfunctions" = {version = "*", optional = true}
"aws-cdk.aws-stepfunctions_tasks" = {version = "*", optional = true}
awscli = {version = "*", optional = true}
boto3 = "*"
cattrs = {version = "*", optional = true}
jsonschema = {version = "*", extras = ["format"], optional = true}
multihash = {version = "*", optional = true}
pynamodb = {version = "*", optional = true}
pystac = {version = "*", optional = true}
slack-sdk = {version = "*", extras = ["models", "webhook"], optional = true}
smart-open = {version = "*", extras = ["s3"], optional = true}
strict-rfc3339 = {optional = true, version = "*"}
typer = "*"
ulid-py = {version = "*", optional = true}
linz-logger = {version = "*", optional = true}

[tool.poetry.dev-dependencies]
black = "*"
boto3-stubs = {version = "*", extras = ["batch", "dynamodb", "events", "lambda", "lambda-python", "s3", "s3control", "sns", "sqs", "ssm", "stepfunctions", "sts"]}
gitlint = "*"
ipdb = "*"
isort = "*"
language-formatters-pre-commit-hooks = "*"
mutmut = "*"
mypy = "*"
pre-commit = "*"
pylint = "*"
pytest = "*"
pytest-randomly = "*"
pytest-socket = "*"
pytest-subtests = "*"
pytest-timeout = "*"
types-pkg-resources = "*"
types-python-dateutil = "*"
types-requests = "*"
types-six = "*"
types-toml = "*"

[tool.poetry.dev-dependencies.coverage]
version = "*"
extras = ["toml"]

[tool.poetry.extras]
cdk = [
    "aws-cdk.aws-dynamodb",
    "aws-cdk.aws-ec2",
    "aws-cdk.aws-ecr",
    "aws-cdk.aws-ecr_assets",
    "aws-cdk.aws-ecs",
    "aws-cdk.aws-events",
    "aws-cdk.aws-events-targets",
    "aws-cdk.aws-iam",
    "aws-cdk.aws-lambda",
    "aws-cdk.aws-lambda-event-sources",
    "aws-cdk.aws-lambda-python",
    "aws-cdk.aws-s3",
    "aws-cdk.aws-sns",
    "aws-cdk.aws-stepfunctions",
    "aws-cdk.aws-stepfunctions_tasks",
    "awscli",
    "cattrs",
]
check_files_checksums = [
    "boto3",
    "linz-logger",
    "multihash",
    "pynamodb",
]
check_stac_metadata = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "strict-rfc3339",
]
cli = [
    "boto3",
    "typer",
]
content_iterator = [
    "jsonschema",
    "linz-logger",
    "pynamodb",
]
datasets = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "pystac",
    "ulid-py",
]
dataset_versions = [
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "ulid-py",
]
import_asset_file = [
    "boto3",
    "linz-logger",
    "smart-open",
]
import_dataset = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "smart-open",
    "ulid-py",
]
import_metadata_file = [
    "boto3",
    "linz-logger",
]
import_status = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
]
notify_status_update = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "slack-sdk"
]
populate_catalog = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pystac",
]
update_dataset_catalog = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
    "ulid-py"
]
upload_status = [
    "boto3",
    "jsonschema",
    "linz-logger",
    "pynamodb",
]
validation_summary = [
    "jsonschema",
    "linz-logger",
    "pynamodb",
]

[tool.poetry.scripts]
geostore = "geostore.cli:app"

[tool.pylint.MASTER]
disable = [
    "duplicate-code",
    "missing-class-docstring",
    "missing-function-docstring",
    "missing-module-docstring",
]
load-plugins = [
    "pylint.extensions.mccabe",
]
max-complexity = 6

[tool.pytest.ini_options]
addopts = "--randomly-dont-reset-seed"
markers = [
    "infrastructure: requires a deployed infrastructure",
]
python_functions = "should_*"
testpaths = [
    "tests"
]

如您所见,boto3 和 typer 运行时间依赖项不是可选的,所以我希望在 poetry show geostore.

中看到它们

这似乎是 Poetry 中的一个错误。或者至少从文档中不清楚在您这样的情况下预期的行为是什么。

在您的 pyproject.toml 中,您根据本节的要求指定两个依赖项:

[tool.poetry.dependencies]
…
awscli = {version = "*", optional = true}
boto3 = "*"
…
typer = "*"
…

因此,与 awscli 等许多人相反,boto3typer 应该是必需的,因为 optional 属性未设置且默认为 false.但是您还在本节中将两个必需的依赖项列为“额外”:

[tool.poetry.extras]
…
cli = [
    "boto3",
    "typer",
]
…

诗歌认为这意味着它们实际上是可选的,而不是必需的。在某种程度上,这是有道理的,因为 extras 实际上是可选的。如果您检查由 Poetry 构建的 .whl wheel 文件(它只是一个 zip 存档),特别是其中的 METADATA 文件(这是安装包时 Pip 所指的),那么它包含这一行:

Requires-Dist: typer; extra == "cli"

因此该依赖项实际上是可选的:只有当用户使用 pip install geostore[cli] 明确要求时才会安装它。

解决方案很简单:从 extras 部分中删除对所需依赖项的所有引用。反正那里也不需要它们。

Poetry 文档实际上并不清楚 optional 的真正含义。该属性(目前)仅在 section on the pyproject.toml file 中简要提及。也可以争辩说,如果 optionalfalse,那么 extras 部分不应覆盖该值。