pdm-project / pdm

A modern Python package and dependency manager supporting the latest PEP standards
https://pdm-project.org
MIT License
7.95k stars 404 forks source link

Allow specifying lockfile targets within `pyproject.toml` #3188

Open sneakers-the-rat opened 1 month ago

sneakers-the-rat commented 1 month ago

Is your feature/enhancement proposal related to a problem? Please describe.

I am starting to work on a project that will need some reasonably different deps across platforms (OS as well as CPU architecture) and python versions, and I would like to be able to offer a lockfile for each of them.

Separately, the current default behavior for a package without need for multiple architectures, but support for a range of python versions, (edit:) will pin a version compatible with the full range of python versions specified (if i'm reading the docs right, the cli output seems to suggest for python>=3.9,<4.0 it's targeting ~=3.9), which is a good default, but it would be nice to use the most recent package version for each python version.

I love the support for specifying lock targets (super refreshing after dealing with poetry): https://pdm-project.org/en/latest/usage/lock-targets/ as well as the ability to generate separate lockfiles as well as combine them into a single lockfile.

I could make a pre-commit/CI action to regenerate the lockfile that iterates through the intended lockfile targets, but it would be nice to be able to configure that declaratively in the pyproject.toml, both for ease of use and documentation, but also because i figure it is probably possible to make combined, multi-target locking more efficient than doing each separately.

Describe the solution you'd like

I think some syntax like this would be nice (that is basically just a config file version of the CLI args

[tool.pdm.lock]
## --------------
## `python` - Specify python versions to lock for

# the minimum python version specified in `requires-python`
python = 'minimum'

# the maximum ''
python = 'maximum'

# each minor version (3.8.*, 3.9.*) in `requires-python`
python = 'minor'

# specific python versions
python = [
  '3.9', # ~=3.9 
  '3.10.8', # ==3.10.8
  '>=3.8,<3.10' # not sure when this would be good, but...
  # ...
]

## --------------
## `platform` - Specify platforms to lock for
platform = [
  'linux',
  'manylinux_2_17_x86_64',
  # ...
]

## --------------
## `implementation` - Specify implementations to lock for
implementation = [
  'cpython', 
  'pypy',
  'pyston'
]

## --------------
## `implementation` - Specify implementations to lock for
# default, use single lockfile for all configured targets
lockfile = 'pdm.lock'

# use a pattern to generate multiple lockfiles
# e.g. unique for each target
lockfile = 'pdm-{python}-{platform}-{implementation}.lock'
# e.g. combine platforms and implementations by omitting it and causing a collision
lockfile = 'pdm-{python}.lock'

## --------------
## `target` - OR set explicit combinations (mutually exclusive with above options)
target = [
  {python="3.8", platform="linux", lockfile="pdm-38-linux.lock"},
  {python="3.9", platform="windows", lockfile="pdm-39-windows.lock"},
  # ...
]

Where if the top config variables (non-target) are used, then the values for target are calculated as product(python, platform, implementation), or the target can be set explicitly if greater control over the combination is needed.


I'd be happy to draft this PR if the maintainers are interested in this, but wanted to check first. No problem is not. obvi flexible on the syntax :)

frostming commented 1 month ago

Sounds good, it was actually in the original plan for this feature. PR welcome.

o-moe commented 1 month ago

Just a thought in this context: if no Python interpreter is explicitly specified within [tools.pdm.lock], take the one from requires-python. I still stumble upon the use case where an existing project evolves to deprecate older Python interpreter versions (i.e. moving from minimum required 3.8 to 3.10 for example) and the lock file explicitly needs to update this as well (besides the pyproject.toml) instead of automatically update with a call to pdm install (or similar).