Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 631 – 基于 PEP 508 在 pyproject.toml 中指定依赖项

作者:
Ofek Lev <ofekmeister at gmail.com>
赞助商:
Paul Ganssle <paul at ganssle.io>
讨论组:
Discourse 帖子
状态:
已废弃
类型:
标准跟踪
主题:
打包
创建日期:
2020-08-20
历史记录:
2020-08-20
替代:
621
决议:
Discourse 消息

目录

摘要

此 PEP 指定了如何在 pyproject.toml 文件中编写项目的依赖项,以便打包相关工具使用 PEP 621 中定义的字段 进行解析。

注意

此 PEP 已被接受并合并到 PEP 621 中。

条目

所有依赖项条目必须是有效的 PEP 508 字符串.

构建后端在遇到任何解析错误时应该在加载时中止。

from packaging.requirements import InvalidRequirement, Requirement

...

try:
    Requirement(entry)
except InvalidRequirement:
    # exit

规范

dependencies

每个元素必须是 条目.

[project]
dependencies = [
  'PyYAML ~= 5.0',
  'requests[security] < 3',
  'subprocess32; python_version < "3.2"',
]

optional-dependencies

每个键都是提供的选项的名称,每个值与 dependencies 字段的类型相同,即字符串数组。

[project.optional-dependencies]
tests = [
  'coverage>=5.0.3',
  'pytest',
  'pytest-benchmark[histogram]>=3.2.1',
]

示例

这是一个真实的例子,展示了如何将 docker-compose 中的定义移植过来。

[project]
dependencies = [
  'cached-property >= 1.2.0, < 2',
  'distro >= 1.5.0, < 2',
  'docker[ssh] >= 4.2.2, < 5',
  'dockerpty >= 0.4.1, < 1',
  'docopt >= 0.6.1, < 1',
  'jsonschema >= 2.5.1, < 4',
  'PyYAML >= 3.10, < 6',
  'python-dotenv >= 0.13.0, < 1',
  'requests >= 2.20.0, < 3',
  'texttable >= 0.9.0, < 2',
  'websocket-client >= 0.32.0, < 1',

  # Conditional
  'backports.shutil_get_terminal_size == 1.0.0; python_version < "3.3"',
  'backports.ssl_match_hostname >= 3.5, < 4; python_version < "3.5"',
  'colorama >= 0.4, < 1; sys_platform == "win32"',
  'enum34 >= 1.0.4, < 2; python_version < "3.4"',
  'ipaddress >= 1.0.16, < 2; python_version < "3.3"',
  'subprocess32 >= 3.5.4, < 4; python_version < "3.2"',
]

[project.optional-dependencies]
socks = [ 'PySocks >= 1.5.6, != 1.5.7, < 2' ]
tests = [
  'ddt >= 1.2.2, < 2',
  'pytest < 6',
  'mock >= 1.0.1, < 4; python_version < "3.4"',
]

实现

解析

from packaging.requirements import InvalidRequirement, Requirement

def parse_dependencies(config):
    dependencies = config.get('dependencies', [])
    if not isinstance(dependencies, list):
        raise TypeError('Field `project.dependencies` must be an array')

    for i, entry in enumerate(dependencies, 1):
        if not isinstance(entry, str):
            raise TypeError(f'Dependency #{i} of field `project.dependencies` must be a string')

        try:
            Requirement(entry)
        except InvalidRequirement as e:
            raise ValueError(f'Dependency #{i} of field `project.dependencies` is invalid: {e}')

    return dependencies

def parse_optional_dependencies(config):
    optional_dependencies = config.get('optional-dependencies', {})
    if not isinstance(optional_dependencies, dict):
        raise TypeError('Field `project.optional-dependencies` must be a table')

    optional_dependency_entries = {}

    for option, dependencies in optional_dependencies.items():
        if not isinstance(dependencies, list):
            raise TypeError(
                f'Dependencies for option `{option}` of field '
                '`project.optional-dependencies` must be an array'
            )

        entries = []

        for i, entry in enumerate(dependencies, 1):
            if not isinstance(entry, str):
                raise TypeError(
                    f'Dependency #{i} of option `{option}` of field '
                    '`project.optional-dependencies` must be a string'
                )

            try:
                Requirement(entry)
            except InvalidRequirement as e:
                raise ValueError(
                    f'Dependency #{i} of option `{option}` of field '
                    f'`project.optional-dependencies` is invalid: {e}'
                )
            else:
                entries.append(entry)

        optional_dependency_entries[option] = entries

    return optional_dependency_entries

元数据

def construct_metadata_file(metadata_object):
    """
    https://packaging.pythonlang.cn/specifications/core-metadata/
    """
    metadata_file = 'Metadata-Version: 2.1\n'

    ...

    if metadata_object.dependencies:
        # Sort dependencies to ensure reproducible builds
        for dependency in sorted(metadata_object.dependencies):
            metadata_file += f'Requires-Dist: {dependency}\n'

    if metadata_object.optional_dependencies:
        # Sort extras and dependencies to ensure reproducible builds
        for option, dependencies in sorted(metadata_object.optional_dependencies.items()):
            metadata_file += f'Provides-Extra: {option}\n'
            for dependency in sorted(dependencies):
                if ';' in dependency:
                    metadata_file += f'Requires-Dist: {dependency} and extra == "{option}"\n'
                else:
                    metadata_file += f'Requires-Dist: {dependency}; extra == "{option}"\n'

    ...

    return metadata_file

来源:https://github.com/python/peps/blob/main/peps/pep-0631.rst

最后修改时间:2023-09-09 17:39:29 GMT